rsalz@uunet.uu.net (Rich Salz) (02/26/91)
Submitted-by: Paul Eggert <eggert@twinsun.com> Posting-number: Volume 24, Issue 18 Archive-name: gnudiff1.15/part03 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 3 (of 8)." # Contents: diff.c getopt.c util.c # Wrapped by eggert@ata on Mon Jan 7 11:25:29 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'diff.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'diff.c'\" else echo shar: Extracting \"'diff.c'\" \(17901 characters\) sed "s/^X//" >'diff.c' <<'END_OF_FILE' X/* GNU DIFF main routine. X Copyright (C) 1988, 1989 Free Software Foundation, Inc. X XThis file is part of GNU DIFF. X XGNU DIFF is free software; you can redistribute it and/or modify Xit under the terms of the GNU General Public License as published by Xthe Free Software Foundation; either version 1, or (at your option) Xany later version. X XGNU DIFF is distributed in the hope that it will be useful, Xbut WITHOUT ANY WARRANTY; without even the implied warranty of XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the XGNU General Public License for more details. X XYou should have received a copy of the GNU General Public License Xalong with GNU DIFF; see the file COPYING. If not, write to Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ X X/* GNU DIFF was written by Mike Haertel, David Hayes, X Richard Stallman and Len Tower. */ X X#define GDIFF_MAIN X#include "regex.h" X#include "diff.h" X#include "getopt.h" X X X/* Nonzero for -r: if comparing two directories, X compare their common subdirectories recursively. */ X Xint recursive; X X/* For debugging: don't do discard_confusing_lines. */ X Xint no_discards; X X/* Return a string containing the command options with which diff was invoked. X Spaces appear between what were separate ARGV-elements. X There is a space at the beginning but none at the end. X If there were no options, the result is an empty string. X X Arguments: OPTIONVEC, a vector containing separate ARGV-elements, and COUNT, X the length of that vector. */ X Xstatic char * Xoption_list (optionvec, count) X char **optionvec; /* Was `vector', but that collides on Alliant. */ X int count; X{ X int i; X int length = 0; X char *result; X X for (i = 0; i < count; i++) X length += strlen (optionvec[i]) + 1; X X result = (char *) xmalloc (length + 1); X result[0] = 0; X X for (i = 0; i < count; i++) X { X strcat (result, " "); X strcat (result, optionvec[i]); X } X X return result; X} X X/* The numbers 129 and 130 that appear in the fourth element X for the context and unidiff entries are used as a way of X telling the big switch in `main' how to process those options. */ X Xstatic struct option longopts[] = X{ X {"ignore-blank-lines", 0, 0, 'B'}, X {"context", 2, 0, 129}, X {"ifdef", 1, 0, 'D'}, X {"show-function-line", 1, 0, 'F'}, X {"speed-large-files", 0, 0, 'H'}, X {"ignore-matching-lines", 1, 0, 'I'}, X {"file-label", 1, 0, 'L'}, X {"entire-new-files", 0, 0, 'N'}, X {"new-files", 0, 0, 'N'}, X {"starting-file", 1, 0, 'S'}, X {"initial-tab", 0, 0, 'T'}, X {"text", 0, 0, 'a'}, X {"all-text", 0, 0, 'a'}, X {"ascii", 0, 0, 'a'}, X {"ignore-space-change", 0, 0, 'b'}, X {"minimal", 0, 0, 'd'}, X {"ed", 0, 0, 'e'}, X {"reversed-ed", 0, 0, 'f'}, X {"ignore-case", 0, 0, 'i'}, X {"print", 0, 0, 'l'}, X {"rcs", 0, 0, 'n'}, X {"show-c-function", 0, 0, 'p'}, X {"binary", 0, 0, 'q'}, X {"brief", 0, 0, 'q'}, X {"recursive", 0, 0, 'r'}, X {"report-identical-files", 0, 0, 's'}, X {"expand-tabs", 0, 0, 't'}, X {"ignore-all-space", 0, 0, 'w'}, X {"unified", 2, 0, 130}, X {"version", 0, 0, 'v'}, X {0, 0, 0, 0} X}; X Xmain (argc, argv) X int argc; X char *argv[]; X{ X int val; X int c; X int prev = -1; X int longind; X extern char *version_string; X X program = argv[0]; X X /* Do our initializations. */ X output_style = OUTPUT_NORMAL; X always_text_flag = FALSE; X ignore_space_change_flag = FALSE; X ignore_all_space_flag = FALSE; X length_varies = FALSE; X ignore_case_flag = FALSE; X ignore_blank_lines_flag = FALSE; X ignore_regexp = 0; X function_regexp = 0; X print_file_same_flag = FALSE; X entire_new_file_flag = FALSE; X no_details_flag = FALSE; X context = -1; X line_end_char = '\n'; X tab_align_flag = FALSE; X tab_expand_flag = FALSE; X recursive = FALSE; X paginate_flag = FALSE; X ifdef_string = NULL; X heuristic = FALSE; X dir_start_file = NULL; X msg_chain = NULL; X msg_chain_end = NULL; X no_discards = 0; X X /* Decode the options. */ X X while ((c = getopt_long (argc, argv, X "0123456789abBcC:dD:efF:hHiI:lL:nNpqrsS:tTuvw", X longopts, &longind)) != EOF) X { X if (c == 0) /* Long option. */ X c = longopts[longind].val; X switch (c) X { X /* All digits combine in decimal to specify the context-size. */ X case '1': X case '2': X case '3': X case '4': X case '5': X case '6': X case '7': X case '8': X case '9': X case '0': X if (context == -1) X context = 0; X /* If a context length has already been specified, X more digits allowed only if they follow right after the others. X Reject two separate runs of digits, or digits after -C. */ X else if (prev < '0' || prev > '9') X fatal ("context length specified twice"); X X context = context * 10 + c - '0'; X break; X X case 'a': X /* Treat all files as text files; never treat as binary. */ X always_text_flag = 1; X break; X X case 'b': X /* Ignore changes in amount of whitespace. */ X ignore_space_change_flag = 1; X length_varies = 1; X break; X X case 'B': X /* Ignore changes affecting only blank lines. */ X ignore_blank_lines_flag = 1; X break; X X case 'C': X case 129: /* +context[=lines] */ X case 130: /* +unified[=lines] */ X if (optarg) X { X if (context >= 0) X fatal ("context length specified twice"); X { X char *p; X for (p = optarg; *p; p++) X if (*p < '0' || *p > '9') X fatal ("invalid context length argument"); X } X context = atoi (optarg); X } X X /* Falls through. */ X case 'c': X /* Make context-style output. */ X specify_style (c == 130 ? OUTPUT_UNIFIED : OUTPUT_CONTEXT); X break; X X case 'd': X /* Don't discard lines. This makes things slower (sometimes much X slower) but will find a guaranteed minimal set of changes. */ X no_discards = 1; X break; X X case 'D': X /* Make merged #ifdef output. */ X specify_style (OUTPUT_IFDEF); X ifdef_string = optarg; X break; X X case 'e': X /* Make output that is a valid `ed' script. */ X specify_style (OUTPUT_ED); X break; X X case 'f': X /* Make output that looks vaguely like an `ed' script X but has changes in the order they appear in the file. */ X specify_style (OUTPUT_FORWARD_ED); X break; X X case 'F': X /* Show, for each set of changes, the previous line that X matches the specified regexp. Currently affects only X context-style output. */ X function_regexp = optarg; X break; X X case 'h': X /* Split the files into chunks of around 1500 lines X for faster processing. Usually does not change the result. X X This currently has no effect. */ X break; X X case 'H': X /* Turn on heuristics that speed processing of large files X with a small density of changes. */ X heuristic = 1; X break; X X case 'i': X /* Ignore changes in case. */ X ignore_case_flag = 1; X break; X X case 'I': X /* Ignore changes affecting only lines that match the X specified regexp. */ X ignore_regexp = optarg; X break; X X case 'l': X /* Pass the output through `pr' to paginate it. */ X paginate_flag = 1; X break; X X case 'L': X /* Specify file labels for `-c' output headers. */ X if (!file_label[0]) X file_label[0] = optarg; X else if (!file_label[1]) X file_label[1] = optarg; X else X fatal ("too many file label options"); X break; X X case 'n': X /* Output RCS-style diffs, like `-f' except that each command X specifies the number of lines affected. */ X specify_style (OUTPUT_RCS); X break; X X case 'N': X /* When comparing directories, if a file appears only in one X directory, treat it as present but empty in the other. */ X entire_new_file_flag = 1; X break; X X case 'p': X /* Make context-style output and show name of last C function. */ X specify_style (OUTPUT_CONTEXT); X function_regexp = "^[_a-zA-Z]"; X break; X X case 'q': X no_details_flag = 1; X break; X X case 'r': X /* When comparing directories, X recursively compare any subdirectories found. */ X recursive = 1; X break; X X case 's': X /* Print a message if the files are the same. */ X print_file_same_flag = 1; X break; X X case 'S': X /* When comparing directories, start with the specified X file name. This is used for resuming an aborted comparison. */ X dir_start_file = optarg; X break; X X case 't': X /* Expand tabs to spaces in the output so that it preserves X the alignment of the input files. */ X tab_expand_flag = 1; X break; X X case 'T': X /* Use a tab in the output, rather than a space, before the X text of an input line, so as to keep the proper alignment X in the input line without changing the characters in it. */ X tab_align_flag = 1; X break; X X case 'v': X printf ("GNU diff version %s\n", version_string); X break; X X case 'u': X /* Output the context diff in unidiff format. */ X specify_style (OUTPUT_UNIFIED); X break; X X case 'w': X /* Ignore horizontal whitespace when comparing lines. */ X ignore_all_space_flag = 1; X length_varies = 1; X break; X X default: X usage (); X } X prev = c; X } X X if (optind != argc - 2) X usage (); X X if (ignore_regexp) X { X char *val; X bzero (&ignore_regexp_compiled, sizeof ignore_regexp_compiled); X val = re_compile_pattern (ignore_regexp, strlen (ignore_regexp), X &ignore_regexp_compiled); X if (val != 0) X error ("%s: %s", ignore_regexp, val); X ignore_regexp_compiled.fastmap = (char *) xmalloc (256); X } X X if (function_regexp) X { X char *val; X bzero (&function_regexp_compiled, sizeof function_regexp_compiled); X val = re_compile_pattern (function_regexp, strlen (function_regexp), X &function_regexp_compiled); X if (val != 0) X error ("%s: %s", function_regexp, val); X function_regexp_compiled.fastmap = (char *) xmalloc (256); X } X X if (output_style != OUTPUT_CONTEXT && output_style != OUTPUT_UNIFIED) X context = 0; X else if (context == -1) X /* Default amount of context for -c. */ X context = 3; X X switch_string = option_list (argv + 1, optind - 1); X X val = compare_files (0, argv[optind], 0, argv[optind + 1], 0); X X /* Print any messages that were saved up for last. */ X print_message_queue (); X X if (ferror (stdout) || fclose (stdout) != 0) X fatal ("write error"); X exit (val); X} X Xusage () X{ X fprintf (stderr, "\ XUsage: diff [-#] [-abBcdefhHilnNprstTuvw] [-C lines] [-F regexp] [-I regexp]\n\ X [-L label [-L label]] [-S file] [-D symbol] [+ignore-blank-lines]\n\ X [+context[=lines]] [+unified[=lines]] [+ifdef=symbol]\n\ X [+show-function-line=regexp]\n"); X fprintf (stderr, "\ X [+speed-large-files] [+ignore-matching-lines=regexp] [+new-file]\n\ X [+initial-tab] [+starting-file=file] [+text] [+all-text] [+ascii]\n\ X [+minimal] [+ignore-space-change] [+ed] [+reversed-ed] [+ignore-case]\n"); X fprintf (stderr, "\ X [+print] [+rcs] [+show-c-function] [+binary] [+brief] [+recursive]\n\ X [+report-identical-files] [+expand-tabs] [+ignore-all-space]\n\ X [+file-label=label [+file-label=label]] [+version] path1 path2\n"); X exit (2); X} X Xspecify_style (style) X enum output_style style; X{ X if (output_style != OUTPUT_NORMAL X && output_style != style) X error ("conflicting specifications of output style"); X output_style = style; X} X X/* Compare two files (or dirs) with specified names X DIR0/NAME0 and DIR1/NAME1, at level DEPTH in directory recursion. X (if DIR0 is 0, then the name is just NAME0, etc.) X This is self-contained; it opens the files and closes them. X X Value is 0 if files are identical, 1 if different, X 2 if there is a problem opening them. */ X Xint Xcompare_files (dir0, name0, dir1, name1, depth) X char *dir0, *dir1; X char *name0, *name1; X int depth; X{ X static char Standard_Input[] = "Standard Input"; X struct file_data inf[2]; X register int i; X int val; X int errorcount = 0; X int stat_result[2]; X X /* If this is directory comparison, perhaps we have a file X that exists only in one of the directories. X If so, just print a message to that effect. */ X X if (! entire_new_file_flag && (name0 == 0 || name1 == 0)) X { X char *name = name0 == 0 ? name1 : name0; X char *dir = name0 == 0 ? dir1 : dir0; X message ("Only in %s: %s\n", dir, name); X /* Return 1 so that diff_dirs will return 1 ("some files differ"). */ X return 1; X } X X /* Mark any nonexistent file with -1 in the desc field. */ X /* Mark unopened files (i.e. directories) with -2. */ X X inf[0].desc = name0 == 0 ? -1 : -2; X inf[1].desc = name1 == 0 ? -1 : -2; X X /* Now record the full name of each file, including nonexistent ones. */ X X if (name0 == 0) X name0 = name1; X if (name1 == 0) X name1 = name0; X X inf[0].name = dir0 == 0 ? name0 : concat (dir0, "/", name0); X inf[1].name = dir1 == 0 ? name1 : concat (dir1, "/", name1); X X /* Stat the files. Record whether they are directories. X Record in stat_result whether stat fails. */ X X for (i = 0; i <= 1; i++) X { X bzero (&inf[i].stat, sizeof(struct stat)); X inf[i].dir_p = 0; X stat_result[i] = 0; X X if (inf[i].desc != -1) X { X char *filename = inf[i].name; X X stat_result[i] = X strcmp (filename, "-") X ? stat (filename, &inf[i].stat) X : fstat (0, &inf[i].stat); X X if (stat_result[i] < 0) X { X perror_with_name (filename); X errorcount = 1; X } X else X inf[i].dir_p = X S_IFDIR == (inf[i].stat.st_mode & S_IFMT) X && strcmp (filename, "-"); X } X } X X /* See if the two named files are actually the same physical file. X If so, we know they are identical without actually reading them. */ X X if (output_style != OUTPUT_IFDEF X && inf[0].stat.st_ino == inf[1].stat.st_ino X && inf[0].stat.st_dev == inf[1].stat.st_dev X && stat_result[0] == 0 X && stat_result[1] == 0) X { X val = 0; X goto done; X } X X if (name0 == 0) X inf[0].dir_p = inf[1].dir_p; X if (name1 == 0) X inf[1].dir_p = inf[0].dir_p; X X /* Open the files and record their descriptors. */ X X for (i = 0; i <= 1; i++) X { X if (inf[i].desc == -1) X ; X else if (!strcmp (inf[i].name, "-")) X { X inf[i].desc = 0; X inf[i].name = Standard_Input; X } X /* Don't bother opening if stat already failed. */ X else if (stat_result[i] == 0 && ! inf[i].dir_p) X { X char *filename = inf[i].name; X X inf[i].desc = open (filename, O_RDONLY, 0); X if (0 > inf[i].desc) X { X perror_with_name (filename); X errorcount = 1; X } X } X } X X if (errorcount) X { X X /* If either file should exist but fails to be opened, return 2. */ X X val = 2; X X } X else if (inf[0].dir_p && inf[1].dir_p) X { X if (output_style == OUTPUT_IFDEF) X fatal ("-D option not supported with directories"); X X /* If both are directories, compare the files in them. */ X X if (depth > 0 && !recursive) X { X /* But don't compare dir contents one level down X unless -r was specified. */ X message ("Common subdirectories: %s and %s\n", X inf[0].name, inf[1].name); X val = 0; X } X else X { X val = diff_dirs (inf[0].name, inf[1].name, X compare_files, depth, 0, 0); X } X X } X else if (depth == 0 && (inf[0].dir_p || inf[1].dir_p)) X { X X /* If only one is a directory, and it was specified in the command line, X use the file in that dir whose basename matches the other file. */ X X int dir_arg = (inf[0].dir_p ? 0 : 1); X int fnm_arg = (inf[0].dir_p ? 1 : 0); X char *p = rindex (inf[fnm_arg].name, '/'); X char *filename = concat (inf[dir_arg].name, "/", X (p ? p+1 : inf[fnm_arg].name)); X X if (inf[fnm_arg].name == Standard_Input) X fatal ("can't compare - to a directory"); X X inf[dir_arg].desc = open (filename, O_RDONLY, 0); X X if (0 > inf[dir_arg].desc) X { X perror_with_name (filename); X val = 2; X } X else X { X /* JF: patch from the net to check and make sure we can really free X this. If it's from argv[], freeing it is a *really* bad idea */ X if (0 != (dir_arg ? dir1 : dir0)) X free (inf[dir_arg].name); X inf[dir_arg].name = filename; X if (fstat (inf[dir_arg].desc, &inf[dir_arg].stat) < 0) X pfatal_with_name (inf[dir_arg].name); X X inf[dir_arg].dir_p X = (S_IFDIR == (inf[dir_arg].stat.st_mode & S_IFMT)); X if (inf[dir_arg].dir_p) X { X error ("%s is a directory but %s is not", X inf[dir_arg].name, inf[fnm_arg].name); X val = 1; X } X else X val = diff_2_files (inf, depth); X } X X } X else if (depth > 0 && (inf[0].dir_p || inf[1].dir_p)) X { X /* Perhaps we have a subdirectory that exists only in one directory. X If so, just print a message to that effect. */ X X if (inf[0].desc == -1 || inf[1].desc == -1) X { X if (entire_new_file_flag && recursive) X val = diff_dirs (inf[0].name, inf[1].name, compare_files, depth, X inf[0].desc == -1, inf[1].desc == -1); X else X { X char *dir = (inf[0].desc == -1) ? dir1 : dir0; X message ("Only in %s: %s\n", dir, name0); X val = 1; X } X } X else X { X /* We have a subdirectory in one directory X and a file in the other. */ X X if (inf[0].dir_p) X message ("%s is a directory but %s is not\n", X inf[0].name, inf[1].name); X else X message ("%s is a directory but %s is not\n", X inf[1].name, inf[0].name); X /* This is a difference. */ X val = 1; X } X } X else X { X X /* Both exist and both are ordinary files. */ X X val = diff_2_files (inf, depth); X X } X X /* Now the comparison has been done, if no error prevented it, X and VAL is the value this function will return. */ X X if (inf[0].desc >= 0) X close (inf[0].desc); X if (inf[1].desc >= 0) X close (inf[1].desc); X X done: X if (val == 0 && !inf[0].dir_p) X { X if (print_file_same_flag) X message ("Files %s and %s are identical\n", X inf[0].name, inf[1].name); X } X else X fflush (stdout); X X if (dir0 != 0) X free (inf[0].name); X if (dir1 != 0) X free (inf[1].name); X X return val; X} END_OF_FILE if test 17901 -ne `wc -c <'diff.c'`; then echo shar: \"'diff.c'\" unpacked with wrong size! fi # end of 'diff.c' fi if test -f 'getopt.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'getopt.c'\" else echo shar: Extracting \"'getopt.c'\" \(16740 characters\) sed "s/^X//" >'getopt.c' <<'END_OF_FILE' X/* Getopt for GNU. X Copyright (C) 1987, 1989, 1990 Free Software Foundation, Inc. X X This program is free software; you can redistribute it and/or modify X it under the terms of the GNU General Public License as published by X the Free Software Foundation; either version 1, or (at your option) X any later version. X X This program is distributed in the hope that it will be useful, X but WITHOUT ANY WARRANTY; without even the implied warranty of X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the X GNU General Public License for more details. X X You should have received a copy of the GNU General Public License X along with this program; if not, write to the Free Software X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ X X#ifdef __STDC__ X#define CONST const X#else X#define CONST X#endif X X/* This version of `getopt' appears to the caller like standard Unix `getopt' X but it behaves differently for the user, since it allows the user X to intersperse the options with the other arguments. X X As `getopt' works, it permutes the elements of `argv' so that, X when it is done, all the options precede everything else. Thus X all application programs are extended to handle flexible argument order. X X Setting the environment variable _POSIX_OPTION_ORDER disables permutation. X Then the behavior is completely standard. X X GNU application programs can use a third alternative mode in which X they can distinguish the relative order of options and other arguments. */ X X#include <stdio.h> X X/* If compiled with GNU C, use the built-in alloca */ X#ifdef __GNUC__ X#define alloca __builtin_alloca X#else /* not __GNUC__ */ X#ifdef sparc X#include <alloca.h> X#else Xchar *alloca (); X#endif X#endif /* not __GNUC__ */ X X#if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__) X#include <stdlib.h> X#include <string.h> X#define bcopy(s, d, n) memcpy ((d), (s), (n)) X#define index strchr X#else X X#ifdef USG X#include <string.h> X#define bcopy(s, d, n) memcpy ((d), (s), (n)) X#define index strchr X#else X#ifdef VMS X#include <string.h> X#else X#include <strings.h> X#endif Xvoid bcopy (); X#endif X Xchar *getenv (); Xchar *malloc (); X#endif X X/* For communication from `getopt' to the caller. X When `getopt' finds an option that takes an argument, X the argument value is returned here. X Also, when `ordering' is RETURN_IN_ORDER, X each non-option ARGV-element is returned here. */ X Xchar *optarg = 0; X X/* Index in ARGV of the next element to be scanned. X This is used for communication to and from the caller X and for communication between successive calls to `getopt'. X X On entry to `getopt', zero means this is the first call; initialize. X X When `getopt' returns EOF, this is the index of the first of the X non-option elements that the caller should itself scan. X X Otherwise, `optind' communicates from one call to the next X how much of ARGV has been scanned so far. */ X Xint optind = 0; X X/* The next char to be scanned in the option-element X in which the last option character we returned was found. X This allows us to pick up the scan where we left off. X X If this is zero, or a null string, it means resume the scan X by advancing to the next ARGV-element. */ X Xstatic char *nextchar; X X/* Callers store zero here to inhibit the error message X for unrecognized options. */ X Xint opterr = 1; X X/* Describe how to deal with options that follow non-option ARGV-elements. X X If the caller did not specify anything, X the default is REQUIRE_ORDER if the environment variable X _POSIX_OPTION_ORDER is defined, PERMUTE otherwise. X X REQUIRE_ORDER means don't recognize them as options; X stop option processing when the first non-option is seen. X This is what Unix does. X This mode of operation is selected by either setting the environment X variable _POSIX_OPTION_ORDER, or using `+' as the first character X of the list of option characters. X X PERMUTE is the default. We permute the contents of ARGV as we scan, X so that eventually all the non-options are at the end. This allows options X to be given in any order, even with programs that were not written to X expect this. X X RETURN_IN_ORDER is an option available to programs that were written X to expect options and other ARGV-elements in any order and that care about X the ordering of the two. We describe each non-option ARGV-element X as if it were the argument of an option with character code 1. X Using `-' as the first character of the list of option characters X selects this mode of operation. X X The special argument `--' forces an end of option-scanning regardless X of the value of `ordering'. In the case of RETURN_IN_ORDER, only X `--' can cause `getopt' to return EOF with `optind' != ARGC. */ X Xstatic enum X{ X REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER X} ordering; X X/* Describe the long-named options requested by the application. X _GETOPT_LONG_OPTIONS is a vector of `struct option' terminated by an X element containing a name which is zero. X The field `has_arg' is 1 if the option takes an argument, X 2 if it takes an optional argument. */ X Xstruct option X{ X char *name; X int has_arg; X int *flag; X int val; X}; X XCONST struct option *_getopt_long_options; X Xint _getopt_long_only = 0; X X/* Index in _GETOPT_LONG_OPTIONS of the long-named option actually found. X Only valid when a long-named option was found. */ X Xint option_index; X X/* Handle permutation of arguments. */ X X/* Describe the part of ARGV that contains non-options that have X been skipped. `first_nonopt' is the index in ARGV of the first of them; X `last_nonopt' is the index after the last of them. */ X Xstatic int first_nonopt; Xstatic int last_nonopt; X X/* Exchange two adjacent subsequences of ARGV. X One subsequence is elements [first_nonopt,last_nonopt) X which contains all the non-options that have been skipped so far. X The other is elements [last_nonopt,optind), which contains all X the options processed since those non-options were skipped. X X `first_nonopt' and `last_nonopt' are relocated so that they describe X the new indices of the non-options in ARGV after they are moved. */ X Xstatic void Xexchange (argv) X char **argv; X{ X int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *); X char **temp = (char **) alloca (nonopts_size); X X /* Interchange the two blocks of data in ARGV. */ X X bcopy (&argv[first_nonopt], temp, nonopts_size); X bcopy (&argv[last_nonopt], &argv[first_nonopt], X (optind - last_nonopt) * sizeof (char *)); X bcopy (temp, &argv[first_nonopt + optind - last_nonopt], nonopts_size); X X /* Update records for the slots the non-options now occupy. */ X X first_nonopt += (optind - last_nonopt); X last_nonopt = optind; X} X X/* Scan elements of ARGV (whose length is ARGC) for option characters X given in OPTSTRING. X X If an element of ARGV starts with '-', and is not exactly "-" or "--", X then it is an option element. The characters of this element X (aside from the initial '-') are option characters. If `getopt' X is called repeatedly, it returns successively each of the option characters X from each of the option elements. X X If `getopt' finds another option character, it returns that character, X updating `optind' and `nextchar' so that the next call to `getopt' can X resume the scan with the following option character or ARGV-element. X X If there are no more option characters, `getopt' returns `EOF'. X Then `optind' is the index in ARGV of the first ARGV-element X that is not an option. (The ARGV-elements have been permuted X so that those that are not options now come last.) X X OPTSTRING is a string containing the legitimate option characters. X If an option character is seen that is not listed in OPTSTRING, X return '?' after printing an error message. If you set `opterr' to X zero, the error message is suppressed but we still return '?'. X X If a char in OPTSTRING is followed by a colon, that means it wants an arg, X so the following text in the same ARGV-element, or the text of the following X ARGV-element, is returned in `optarg'. Two colons mean an option that X wants an optional arg; if there is text in the current ARGV-element, X it is returned in `optarg', otherwise `optarg' is set to zero. X X If OPTSTRING starts with `-' or `+', it requests different methods of X handling the non-option ARGV-elements. X See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. X X Long-named options begin with `+' instead of `-'. X Their names may be abbreviated as long as the abbreviation is unique X or is an exact match for some defined option. If they have an X argument, it follows the option name in the same ARGV-element, separated X from the option name by a `=', or else the in next ARGV-element. X When `getopt' finds a long-named option, it returns 0 if that option's X `flag' field is nonzero, the value of the option's `val' field X otherwise. */ X Xint Xgetopt (argc, argv, optstring) X int argc; X char **argv; X CONST char *optstring; X{ X optarg = 0; X X /* Initialize the internal data when the first call is made. X Start processing options with ARGV-element 1 (since ARGV-element 0 X is the program name); the sequence of previously skipped X non-option ARGV-elements is empty. */ X X if (optind == 0) X { X first_nonopt = last_nonopt = optind = 1; X X nextchar = 0; X X /* Determine how to handle the ordering of options and nonoptions. */ X X if (optstring[0] == '-') X { X ordering = RETURN_IN_ORDER; X ++optstring; X } X else if (optstring[0] == '+') X { X ordering = REQUIRE_ORDER; X ++optstring; X } X else if (getenv ("_POSIX_OPTION_ORDER") != 0) X ordering = REQUIRE_ORDER; X else X ordering = PERMUTE; X } X X if (nextchar == 0 || *nextchar == 0) X { X if (ordering == PERMUTE) X { X /* If we have just processed some options following some non-options, X exchange them so that the options come first. */ X X if (first_nonopt != last_nonopt && last_nonopt != optind) X exchange (argv); X else if (last_nonopt != optind) X first_nonopt = optind; X X /* Now skip any additional non-options X and extend the range of non-options previously skipped. */ X X while (optind < argc X && (argv[optind][0] != '-' X || argv[optind][1] == 0) X && (_getopt_long_options == 0 X || argv[optind][0] != '+' X || argv[optind][1] == 0)) X optind++; X last_nonopt = optind; X } X X /* Special ARGV-element `--' means premature end of options. X Skip it like a null option, X then exchange with previous non-options as if it were an option, X then skip everything else like a non-option. */ X X if (optind != argc && !strcmp (argv[optind], "--")) X { X optind++; X X if (first_nonopt != last_nonopt && last_nonopt != optind) X exchange (argv); X else if (first_nonopt == last_nonopt) X first_nonopt = optind; X last_nonopt = argc; X X optind = argc; X } X X /* If we have done all the ARGV-elements, stop the scan X and back over any non-options that we skipped and permuted. */ X X if (optind == argc) X { X /* Set the next-arg-index to point at the non-options X that we previously skipped, so the caller will digest them. */ X if (first_nonopt != last_nonopt) X optind = first_nonopt; X return EOF; X } X X /* If we have come to a non-option and did not permute it, X either stop the scan or describe it to the caller and pass it by. */ X X if ((argv[optind][0] != '-' || argv[optind][1] == 0) X && (_getopt_long_options == 0 X || argv[optind][0] != '+' || argv[optind][1] == 0)) X { X if (ordering == REQUIRE_ORDER) X return EOF; X optarg = argv[optind++]; X return 1; X } X X /* We have found another option-ARGV-element. X Start decoding its characters. */ X X nextchar = argv[optind] + 1; X } X X if (_getopt_long_options != 0 X && (argv[optind][0] == '+' X || (_getopt_long_only && argv[optind][0] == '-')) X ) X { X CONST struct option *p; X char *s = nextchar; X int exact = 0; X int ambig = 0; X CONST struct option *pfound = 0; X int indfound; X X while (*s && *s != '=') X s++; X X /* Test all options for either exact match or abbreviated matches. */ X for (p = _getopt_long_options, option_index = 0; p->name; X p++, option_index++) X if (!strncmp (p->name, nextchar, s - nextchar)) X { X if (s - nextchar == strlen (p->name)) X { X /* Exact match found. */ X pfound = p; X indfound = option_index; X exact = 1; X break; X } X else if (pfound == 0) X { X /* First nonexact match found. */ X pfound = p; X indfound = option_index; X } X else X /* Second nonexact match found. */ X ambig = 1; X } X X if (ambig && !exact) X { X fprintf (stderr, "%s: option `%s' is ambiguous\n", X argv[0], argv[optind]); X nextchar += strlen (nextchar); X optind++; X return '?'; X } X X if (pfound != 0) X { X option_index = indfound; X optind++; X if (*s) X { X if (pfound->has_arg > 0) X optarg = s + 1; X else X { X fprintf (stderr, X "%s: option `%c%s' doesn't allow an argument\n", X argv[0], argv[optind - 1][0], pfound->name); X nextchar += strlen (nextchar); X return '?'; X } X } X else if (pfound->has_arg == 1) X { X if (optind < argc) X optarg = argv[optind++]; X else X { X fprintf (stderr, "%s: option `%s' requires an argument\n", X argv[0], argv[optind - 1]); X nextchar += strlen (nextchar); X return '?'; X } X } X nextchar += strlen (nextchar); X if (pfound->flag) X { X *(pfound->flag) = pfound->val; X return 0; X } X return pfound->val; X } X /* Can't find it as a long option. If this is getopt_long_only, X and the option starts with '-' and is a valid short X option, then interpret it as a short option. Otherwise it's X an error. */ X if (_getopt_long_only == 0 || argv[optind][0] == '+' || X index (optstring, *nextchar) == 0) X { X if (opterr != 0) X fprintf (stderr, "%s: unrecognized option `%c%s'\n", X argv[0], argv[optind][0], nextchar); X nextchar += strlen (nextchar); X optind++; X return '?'; X } X } X X /* Look at and handle the next option-character. */ X X { X char c = *nextchar++; X char *temp = index (optstring, c); X X /* Increment `optind' when we start to process its last character. */ X if (*nextchar == 0) X optind++; X X if (temp == 0 || c == ':') X { X if (opterr != 0) X { X if (c < 040 || c >= 0177) X fprintf (stderr, "%s: unrecognized option, character code 0%o\n", X argv[0], c); X else X fprintf (stderr, "%s: unrecognized option `-%c'\n", X argv[0], c); X } X return '?'; X } X if (temp[1] == ':') X { X if (temp[2] == ':') X { X /* This is an option that accepts an argument optionally. */ X if (*nextchar != 0) X { X optarg = nextchar; X optind++; X } X else X optarg = 0; X nextchar = 0; X } X else X { X /* This is an option that requires an argument. */ X if (*nextchar != 0) X { X optarg = nextchar; X /* If we end this ARGV-element by taking the rest as an arg, X we must advance to the next element now. */ X optind++; X } X else if (optind == argc) X { X if (opterr != 0) X fprintf (stderr, "%s: option `-%c' requires an argument\n", X argv[0], c); X c = '?'; X } X else X /* We already incremented `optind' once; X increment it again when taking next ARGV-elt as argument. */ X optarg = argv[optind++]; X nextchar = 0; X } X } X return c; X } X} X X#ifdef TEST X X/* Compile with -DTEST to make an executable for use in testing X the above definition of `getopt'. */ X Xint Xmain (argc, argv) X int argc; X char **argv; X{ X int c; X int digit_optind = 0; X X while (1) X { X int this_option_optind = optind ? optind : 1; X X c = getopt (argc, argv, "abc:d:0123456789"); X if (c == EOF) X break; X X switch (c) X { X case '0': X case '1': X case '2': X case '3': X case '4': X case '5': X case '6': X case '7': X case '8': X case '9': X if (digit_optind != 0 && digit_optind != this_option_optind) X printf ("digits occur in two different argv-elements.\n"); X digit_optind = this_option_optind; X printf ("option %c\n", c); X break; X X case 'a': X printf ("option a\n"); X break; X X case 'b': X printf ("option b\n"); X break; X X case 'c': X printf ("option c with value `%s'\n", optarg); X break; X X case '?': X break; X X default: X printf ("?? getopt returned character code 0%o ??\n", c); X } X } X X if (optind < argc) X { X printf ("non-option ARGV-elements: "); X while (optind < argc) X printf ("%s ", argv[optind++]); X printf ("\n"); X } X X exit (0); X} X X#endif /* TEST */ END_OF_FILE if test 16740 -ne `wc -c <'getopt.c'`; then echo shar: \"'getopt.c'\" unpacked with wrong size! fi # end of 'getopt.c' fi if test -f 'util.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'util.c'\" else echo shar: Extracting \"'util.c'\" \(14888 characters\) sed "s/^X//" >'util.c' <<'END_OF_FILE' X/* Support routines for GNU DIFF. X Copyright (C) 1988, 1989 Free Software Foundation, Inc. X XThis file is part of GNU DIFF. X XGNU DIFF is free software; you can redistribute it and/or modify Xit under the terms of the GNU General Public License as published by Xthe Free Software Foundation; either version 1, or (at your option) Xany later version. X XGNU DIFF is distributed in the hope that it will be useful, Xbut WITHOUT ANY WARRANTY; without even the implied warranty of XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the XGNU General Public License for more details. X XYou should have received a copy of the GNU General Public License Xalong with GNU DIFF; see the file COPYING. If not, write to Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ X X#include "diff.h" X X/* Use when a system call returns non-zero status. X TEXT should normally be the file name. */ X Xvoid Xperror_with_name (text) X char *text; X{ X fprintf (stderr, "%s: ", program); X perror (text); X} X X/* Use when a system call returns non-zero status and that is fatal. */ X Xvoid Xpfatal_with_name (text) X char *text; X{ X print_message_queue (); X fprintf (stderr, "%s: ", program); X perror (text); X exit (2); X} X X/* Print an error message from the format-string FORMAT X with args ARG1 and ARG2. */ X Xvoid Xerror (format, arg, arg1) X char *format; X char *arg; X char *arg1; X{ X fprintf (stderr, "%s: ", program); X fprintf (stderr, format, arg, arg1); X fprintf (stderr, "\n"); X} X X/* Print an error message containing the string TEXT, then exit. */ X Xvoid Xfatal (message) X char *message; X{ X print_message_queue (); X error (message, ""); X exit (2); X} X X/* Like printf, except if -l in effect then save the message and print later. X This is used for things like "binary files differ" and "Only in ...". */ X Xvoid Xmessage (format, arg1, arg2) X char *format, *arg1, *arg2; X{ X if (paginate_flag) X { X struct msg *new = (struct msg *) xmalloc (sizeof (struct msg)); X if (msg_chain_end == 0) X msg_chain = msg_chain_end = new; X else X { X msg_chain_end->next = new; X msg_chain_end = new; X } X new->format = format; X new->arg1 = concat (arg1, "", ""); X new->arg2 = concat (arg2, "", ""); X new->next = 0; X } X else X printf (format, arg1, arg2); X} X X/* Output all the messages that were saved up by calls to `message'. */ X Xvoid Xprint_message_queue () X{ X struct msg *m; X X for (m = msg_chain; m; m = m->next) X printf (m->format, m->arg1, m->arg2); X} X X/* Call before outputting the results of comparing files NAME0 and NAME1 X to set up OUTFILE, the stdio stream for the output to go to. X X Usually, OUTFILE is just stdout. But when -l was specified X we fork off a `pr' and make OUTFILE a pipe to it. X `pr' then outputs to our stdout. */ X Xvoid Xsetup_output (name0, name1, depth) X char *name0, *name1; X int depth; X{ X char *name; X X /* Construct the header of this piece of diff. */ X name = (char *) xmalloc (strlen (name0) + strlen (name1) X + strlen (switch_string) + 15); X X strcpy (name, "diff"); X strcat (name, switch_string); X strcat (name, " "); X strcat (name, name0); X strcat (name, " "); X strcat (name, name1); X X if (paginate_flag) X { X int pipes[2]; X int desc; X X /* For a `pr' and make OUTFILE a pipe to it. */ X if (pipe (pipes) < 0) X pfatal_with_name ("pipe"); X X fflush (stdout); X X desc = vfork (); X if (desc < 0) X pfatal_with_name ("vfork"); X X if (desc == 0) X { X close (pipes[1]); X if (pipes[0] != fileno (stdin)) X { X if (dup2 (pipes[0], fileno (stdin)) < 0) X pfatal_with_name ("dup2"); X close (pipes[0]); X } X X if (execl (PR_FILE_NAME, PR_FILE_NAME, "-f", "-h", name, 0) < 0) X pfatal_with_name (PR_FILE_NAME); X } X else X { X close (pipes[0]); X outfile = fdopen (pipes[1], "w"); X } X } X else X { X X /* If -l was not specified, output the diff straight to `stdout'. */ X X outfile = stdout; X X /* If handling multiple files (because scanning a directory), X print which files the following output is about. */ X if (depth > 0) X printf ("%s\n", name); X } X X free (name); X} X X/* Call after the end of output of diffs for one file. X Close OUTFILE and get rid of the `pr' subfork. */ X Xvoid Xfinish_output () X{ X if (outfile != stdout) X { X fclose (outfile); X wait (0); X } X} X X/* Compare two lines (typically one from each input file) X according to the command line options. X Each line is described by a `struct line_def'. X Return 1 if the lines differ, like `bcmp'. */ X Xint Xline_cmp (s1, s2) X struct line_def *s1, *s2; X{ X register char *t1, *t2; X register char end_char = line_end_char; X int savechar; X X /* Check first for exact identity. X If that is true, return 0 immediately. X This detects the common case of exact identity X faster than complete comparison would. */ X X t1 = s1->text; X t2 = s2->text; X X /* Alter the character following line 2 so it doesn't X match that following line 1. X (We used to alter the character after line 1, X but that caused trouble if line 2 directly follows line 1.) */ X savechar = s2->text[s2->length]; X s2->text[s2->length] = s1->text[s1->length] + 1; X X /* Now find the first mismatch; this won't go past the X character we just changed. */ X while (*t1++ == *t2++); X X /* Undo the alteration. */ X s2->text[s2->length] = savechar; X X /* If the comparison stopped at the alteration, X the two lines are identical. */ X if (t2 == s2->text + s2->length + 1) X return 0; X X /* Not exactly identical, but perhaps they match anyway X when case or whitespace is ignored. */ X X if (ignore_case_flag || ignore_space_change_flag || ignore_all_space_flag) X { X t1 = s1->text; X t2 = s2->text; X X while (1) X { X register char c1 = *t1++; X register char c2 = *t2++; X X /* Ignore horizontal whitespace if -b or -w is specified. */ X X if (ignore_all_space_flag) X { X /* For -w, just skip past any spaces or tabs. */ X while (c1 == ' ' || c1 == '\t') c1 = *t1++; X while (c2 == ' ' || c2 == '\t') c2 = *t2++; X } X else if (ignore_space_change_flag) X { X /* For -b, advance past any sequence of whitespace in line 1 X and consider it just one Space, or nothing at all X if it is at the end of the line. */ X if (c1 == ' ' || c1 == '\t') X { X while (1) X { X c1 = *t1++; X if (c1 == end_char) X break; X if (c1 != ' ' && c1 != '\t') X { X --t1; X c1 = ' '; X break; X } X } X } X X /* Likewise for line 2. */ X if (c2 == ' ' || c2 == '\t') X { X while (1) X { X c2 = *t2++; X if (c2 == end_char) X break; X if (c2 != ' ' && c2 != '\t') X { X --t2; X c2 = ' '; X break; X } X } X } X } X X /* Upcase all letters if -i is specified. */ X X if (ignore_case_flag) X { X if (islower (c1)) X c1 = toupper (c1); X if (islower (c2)) X c2 = toupper (c2); X } X X if (c1 != c2) X break; X if (c1 == end_char) X return 0; X } X } X X return (1); X} X X/* Find the consecutive changes at the start of the script START. X Return the last link before the first gap. */ X Xstruct change * Xfind_change (start) X struct change *start; X{ X return start; X} X Xstruct change * Xfind_reverse_change (start) X struct change *start; X{ X return start; X} X X/* Divide SCRIPT into pieces by calling HUNKFUN and X print each piece with PRINTFUN. X Both functions take one arg, an edit script. X X HUNKFUN is called with the tail of the script X and returns the last link that belongs together with the start X of the tail. X X PRINTFUN takes a subscript which belongs together (with a null X link at the end) and prints it. */ X Xvoid Xprint_script (script, hunkfun, printfun) X struct change *script; X struct change * (*hunkfun) (); X void (*printfun) (); X{ X struct change *next = script; X X while (next) X { X struct change *this, *end; X X /* Find a set of changes that belong together. */ X this = next; X end = (*hunkfun) (next); X X /* Disconnect them from the rest of the changes, X making them a hunk, and remember the rest for next iteration. */ X next = end->link; X end->link = NULL; X#ifdef DEBUG X debug_script (this); X#endif X X /* Print this hunk. */ X (*printfun) (this); X X /* Reconnect the script so it will all be freed properly. */ X end->link = next; X } X} X X/* Print the text of a single line LINE, X flagging it with the characters in LINE_FLAG (which say whether X the line is inserted, deleted, changed, etc.). */ X Xvoid Xprint_1_line (line_flag, line) X char *line_flag; X struct line_def *line; X{ X int length = line->length; /* must be nonzero */ X const char *text = line->text; /* Help the compiler. */ X FILE *out = outfile; /* Help the compiler some more. */ X X /* If -T was specified, use a Tab between the line-flag and the text. X Otherwise use a Space (as Unix diff does). X Print neither space nor tab if line-flags are empty. */ X X if (line_flag != NULL && line_flag[0] != 0) X fprintf (out, tab_align_flag ? "%s\t" : "%s ", line_flag); X X /* Now output the contents of the line. X If -t was specified, expand tabs to spaces. X Otherwise output verbatim. */ X X if (tab_expand_flag) X { X register int column = 0; X register int i; X for (i = 0; i < line->length; i++) X { X register char c = line->text[i]; X switch (c) X { X case '\t': X column++; X while (column & 7) X { X putc (' ', out); X column++; X } X c = ' '; X break; X case '\b': X column--; X break; X default: X column++; X break; X } X putc (c, out); X } X } X else X fwrite (text, sizeof (char), length, out); X if ((line_flag == NULL || line_flag[0] != 0) && text[length - 1] != '\n' X && line_end_char == '\n') X fprintf (out, "\n\\ No newline at end of file\n"); X} X Xchange_letter (inserts, deletes) X int inserts, deletes; X{ X if (!inserts) X return 'd'; X else if (!deletes) X return 'a'; X else X return 'c'; X} X X/* Translate an internal line number (an index into diff's table of lines) X into an actual line number in the input file. X The internal line number is LNUM. FILE points to the data on the file. X X Internal line numbers count from 0 within the current chunk. X Actual line numbers count from 1 within the entire file; X in addition, they include lines ignored for comparison purposes. X X The `ltran' feature is no longer in use. */ X Xint Xtranslate_line_number (file, lnum) X struct file_data *file; X int lnum; X{ X return lnum + 1; X} X Xvoid Xtranslate_range (file, a, b, aptr, bptr) X struct file_data *file; X int a, b; X int *aptr, *bptr; X{ X *aptr = translate_line_number (file, a - 1) + 1; X *bptr = translate_line_number (file, b + 1) - 1; X} X X/* Print a pair of line numbers with SEPCHAR, translated for file FILE. X If the two numbers are identical, print just one number. X X Args A and B are internal line numbers. X We print the translated (real) line numbers. */ X Xvoid Xprint_number_range (sepchar, file, a, b) X char sepchar; X struct file_data *file; X int a, b; X{ X int trans_a, trans_b; X translate_range (file, a, b, &trans_a, &trans_b); X X /* Note: we can have B < A in the case of a range of no lines. X In this case, we should print the line number before the range, X which is B. */ X if (trans_b > trans_a) X fprintf (outfile, "%d%c%d", trans_a, sepchar, trans_b); X else X fprintf (outfile, "%d", trans_b); X} X X/* Look at a hunk of edit script and report the range of lines in each file X that it applies to. HUNK is the start of the hunk, which is a chain X of `struct change'. The first and last line numbers of file 0 are stored in X *FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1. X Note that these are internal line numbers that count from 0. X X If no lines from file 0 are deleted, then FIRST0 is LAST0+1. X X Also set *DELETES nonzero if any lines of file 0 are deleted X and set *INSERTS nonzero if any lines of file 1 are inserted. X If only ignorable lines are inserted or deleted, both are X set to 0. */ X Xvoid Xanalyze_hunk (hunk, first0, last0, first1, last1, deletes, inserts) X struct change *hunk; X int *first0, *last0, *first1, *last1; X int *deletes, *inserts; X{ X int f0, l0, f1, l1, show_from, show_to; X int i; X int nontrivial = !(ignore_blank_lines_flag || ignore_regexp); X struct change *next; X X show_from = show_to = 0; X X f0 = hunk->line0; X f1 = hunk->line1; X X for (next = hunk; next; next = next->link) X { X l0 = next->line0 + next->deleted - 1; X l1 = next->line1 + next->inserted - 1; X show_from += next->deleted; X show_to += next->inserted; X X for (i = next->line0; i <= l0 && ! nontrivial; i++) X if ((!ignore_blank_lines_flag || files[0].linbuf[i].length > 1) X && (!ignore_regexp X || 0 > re_search (&ignore_regexp_compiled, X files[0].linbuf[i].text, X files[0].linbuf[i].length, 0, X files[0].linbuf[i].length, 0))) X nontrivial = 1; X X for (i = next->line1; i <= l1 && ! nontrivial; i++) X if ((!ignore_blank_lines_flag || files[1].linbuf[i].length > 1) X && (!ignore_regexp X || 0 > re_search (&ignore_regexp_compiled, X files[1].linbuf[i].text, X files[1].linbuf[i].length, 0, X files[1].linbuf[i].length, 0))) X nontrivial = 1; X } X X *first0 = f0; X *last0 = l0; X *first1 = f1; X *last1 = l1; X X /* If all inserted or deleted lines are ignorable, X tell the caller to ignore this hunk. */ X X if (!nontrivial) X show_from = show_to = 0; X X *deletes = show_from; X *inserts = show_to; X} X X/* malloc a block of memory, with fatal error message if we can't do it. */ X XVOID * Xxmalloc (size) X unsigned size; X{ X register VOID *value; X X if (size == 0) X size = 1; X X value = (VOID *) malloc (size); X X if (!value) X fatal ("virtual memory exhausted"); X return value; X} X X/* realloc a block of memory, with fatal error message if we can't do it. */ X XVOID * Xxrealloc (old, size) X VOID *old; X unsigned int size; X{ X register VOID *value; X X if (size == 0) X size = 1; X X value = (VOID *) realloc (old, size); X X if (!value) X fatal ("virtual memory exhausted"); X return value; X} X X/* Concatenate three strings, returning a newly malloc'd string. */ X Xchar * Xconcat (s1, s2, s3) X char *s1, *s2, *s3; X{ X int len = strlen (s1) + strlen (s2) + strlen (s3); X char *new = (char *) xmalloc (len + 1); X strcpy (new, s1); X strcat (new, s2); X strcat (new, s3); X return new; X} X Xdebug_script (sp) X struct change *sp; X{ X fflush (stdout); X for (; sp; sp = sp->link) X fprintf (stderr, "%3d %3d delete %d insert %d\n", X sp->line0, sp->line1, sp->deleted, sp->inserted); X fflush (stderr); X} END_OF_FILE if test 14888 -ne `wc -c <'util.c'`; then echo shar: \"'util.c'\" unpacked with wrong size! fi # end of 'util.c' fi echo shar: End of archive 3 \(of 8\). cp /dev/null ark3isdone MISSING="" for I in 1 2 3 4 5 6 7 8 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 8 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 exit 0 # Just in case... -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.