diff options
author | peter <peter@FreeBSD.org> | 1995-10-28 18:51:33 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1995-10-28 18:51:33 +0000 |
commit | 27378b5694b4941bb63a62097f7ee523da0a35bb (patch) | |
tree | 9372a0168d8ef1138d4ec4ef2051198caed461de /gnu/usr.bin/diff | |
parent | 31fbfe9bebb8e48eaf39efc88875c743cf238ced (diff) | |
download | FreeBSD-src-27378b5694b4941bb63a62097f7ee523da0a35bb.zip FreeBSD-src-27378b5694b4941bb63a62097f7ee523da0a35bb.tar.gz |
Import GNU diffutils 2.7
Note, this is going to be messy.. 2.3 was vendor-branch imported, while
2.6 was done as a delta. Sigh. I'm importing this on a vendor branch so
that it will be easier to deal with next time..
(cvs-1.6 wants rcs-5.7, and rcs-5.7 suggests diffutils-2.7)
Diffstat (limited to 'gnu/usr.bin/diff')
-rw-r--r-- | gnu/usr.bin/diff/NEWS | 126 | ||||
-rw-r--r-- | gnu/usr.bin/diff/analyze.c | 548 | ||||
-rw-r--r-- | gnu/usr.bin/diff/config.h | 56 | ||||
-rw-r--r-- | gnu/usr.bin/diff/context.c | 62 | ||||
-rw-r--r-- | gnu/usr.bin/diff/diff.c | 507 | ||||
-rw-r--r-- | gnu/usr.bin/diff/diff.h | 165 | ||||
-rw-r--r-- | gnu/usr.bin/diff/diff3.c | 495 | ||||
-rw-r--r-- | gnu/usr.bin/diff/dir.c | 89 | ||||
-rw-r--r-- | gnu/usr.bin/diff/ed.c | 13 | ||||
-rw-r--r-- | gnu/usr.bin/diff/fnmatch.c | 209 | ||||
-rw-r--r-- | gnu/usr.bin/diff/fnmatch.h | 33 | ||||
-rw-r--r-- | gnu/usr.bin/diff/getopt.c | 287 | ||||
-rw-r--r-- | gnu/usr.bin/diff/getopt1.c | 8 | ||||
-rw-r--r-- | gnu/usr.bin/diff/ifdef.c | 401 | ||||
-rw-r--r-- | gnu/usr.bin/diff/io.c | 300 | ||||
-rw-r--r-- | gnu/usr.bin/diff/normal.c | 9 | ||||
-rw-r--r-- | gnu/usr.bin/diff/sdiff.c | 771 | ||||
-rw-r--r-- | gnu/usr.bin/diff/side.c | 41 | ||||
-rw-r--r-- | gnu/usr.bin/diff/system.h | 234 | ||||
-rw-r--r-- | gnu/usr.bin/diff/util.c | 355 | ||||
-rw-r--r-- | gnu/usr.bin/diff/version.c | 4 | ||||
-rw-r--r-- | gnu/usr.bin/diff/xmalloc.c | 81 |
22 files changed, 3094 insertions, 1700 deletions
diff --git a/gnu/usr.bin/diff/NEWS b/gnu/usr.bin/diff/NEWS new file mode 100644 index 0000000..dcde122 --- /dev/null +++ b/gnu/usr.bin/diff/NEWS @@ -0,0 +1,126 @@ +User-visible changes in version 2.7: + +* New diff option: --binary (useful only on non-Posix hosts) +* diff -b and -w now ignore line incompleteness; -B no longer does this. +* cmp -c now uses locale to decide which output characters to quote. +* Help and version messages are reorganized. + + +User-visible changes in version 2.6: + +* New cmp, diff, diff3, sdiff option: --help +* A new heuristic for diff greatly reduces the time needed to compare + large input files that contain many differences. +* Partly as a result, GNU diff's output is not exactly the same as before. + Usually it is a bit smaller, but sometimes it is a bit larger. + + +User-visible changes in version 2.5: + +* New cmp option: -v --version + + +User-visible changes in version 2.4: + +* New cmp option: --ignore-initial=BYTES +* New diff3 option: -T --initial-tab +* New diff option: --line-format=FORMAT +* New diff group format specifications: + <PRINTF_SPEC>[eflmnEFLMN] + A printf spec followed by one of the following letters + causes the integer corresponding to that letter to be + printed according to the printf specification. + E.g. `%5df' prints the number of the first line in the + group in the old file using the "%5d" format. + e: line number just before the group in old file; equals f - 1 + f: first line number in group in the old file + l: last line number in group in the old file + m: line number just after the group in old file; equals l + 1 + n: number of lines in group in the old file; equals l - f + 1 + E, F, L, M, N: likewise, for lines in the new file + %(A=B?T:E) + If A equals B then T else E. A and B are each either a decimal + constant or a single letter interpreted as above. T and E are + arbitrary format strings. This format spec is equivalent to T if + A's value equals B's; otherwise it is equivalent to E. For + example, `%(N=0?no:%dN) line%(N=1?:s)' is equivalent to `no lines' + if N (the number of lines in the group in the the new file) is 0, + to `1 line' if N is 1, and to `%dN lines' otherwise. + %c'C' + where C is a single character, stands for the character C. C may not + be a backslash or an apostrophe. E.g. %c':' stands for a colon. + %c'\O' + where O is a string of 1, 2, or 3 octal digits, stands for the + character with octal code O. E.g. %c'\0' stands for a null character. +* New diff line format specifications: + <PRINTF_SPEC>n + The line number, printed with <PRINTF_SPEC>. + E.g. `%5dn' prints the line number with a "%5d" format. + %c'C' + %c'\O' + The character C, or with octal code O, as above. +* Supported <PRINTF_SPEC>s have the same meaning as with printf, but must + match the extended regular expression %-*[0-9]*(\.[0-9]*)?[doxX]. +* The format spec %0 introduced in version 2.1 has been removed, since it + is incompatible with printf specs like %02d. To represent a null char, + use %c'\0' instead. +* cmp and diff now conform to Posix.2 (ISO/IEC 9945-2:1993) + if the underlying system conforms to Posix: + - Some messages' wordings are changed in minor ways. + - ``White space'' is now whatever C's `isspace' says it is. + - When comparing directories, if `diff' finds a file that is not a regular + file or a directory, it reports the file's type instead of diffing it. + (As usual, it follows symbolic links first.) + - When signaled, sdiff exits with the signal's status, not with status 2. +* Now portable to hosts where int, long, pointer, etc. are not all the same + size. +* `cmp - -' now works like `diff - -'. + + +User-visible changes in version 2.3: + +* New diff option: --horizon-lines=lines + + +User-visible changes in version 2.1: + +* New diff options: + --{old,new,unchanged}-line-format='format' + --{old,new,unchanged,changed}-group-format='format' + -U +* New diff3 option: + -A --show-all +* diff3 -m now defaults to -A, not -E. +* diff3 now takes up to three -L or --label options, not just two. + If just two options are given, they refer to the first two input files, + not the first and third input files. +* sdiff and diff -y handle incomplete lines. + + +User-visible changes in version 2.0: + +* Add sdiff and cmp programs. +* Add Texinfo documentation. +* Add configure script. +* Improve diff performance. +* New diff options: +-x --exclude +-X --exclude-from +-P --unidirectional-new-file +-W --width +-y --side-by-side +--left-column +--sdiff-merge-assist +--suppress-common-lines +* diff options renamed: +--label renamed from --file-label +--forward-ed renamed from --reversed-ed +--paginate renamed from --print +--entire-new-file renamed from --entire-new-files +--new-file renamed from --new-files +--all-text removed +* New diff3 options: +-v --version +* Add long-named equivalents for other diff3 options. +* diff options -F (--show-function-line) and -I (--ignore-matching-lines) + can now be given more than once. diff --git a/gnu/usr.bin/diff/analyze.c b/gnu/usr.bin/diff/analyze.c index 42167b9..556d388 100644 --- a/gnu/usr.bin/diff/analyze.c +++ b/gnu/usr.bin/diff/analyze.c @@ -1,5 +1,5 @@ /* Analyze file differences for GNU DIFF. - Copyright (C) 1988, 1989, 1992 Free Software Foundation, Inc. + Copyright (C) 1988, 1989, 1992, 1993 Free Software Foundation, Inc. This file is part of GNU DIFF. @@ -17,72 +17,98 @@ You should have received a copy of the GNU General Public License along with GNU DIFF; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* The basic algorithm is described in: +/* The basic algorithm is described in: "An O(ND) Difference Algorithm and its Variations", Eugene Myers, - Algorithmica Vol. 1 No. 2, 1986, p 251. */ + Algorithmica Vol. 1 No. 2, 1986, pp. 251-266; + see especially section 4.2, which describes the variation used below. + Unless the --minimal option is specified, this code uses the TOO_EXPENSIVE + heuristic, by Paul Eggert, to limit the cost to O(N**1.5 log N) + at the price of producing suboptimal output for large inputs with + many differences. -#include "diff.h" + The basic algorithm was independently discovered as described in: + "Algorithms for Approximate String Matching", E. Ukkonen, + Information and Control Vol. 64, 1985, pp. 100-118. */ -int read_files (); -void finish_output (); -void print_context_script (); -void print_ed_script (); -void print_ifdef_script (); -void print_sdiff_script (); -void print_normal_script (); -void print_rcs_script (); -void pr_forward_ed_script (); -void setup_output (); +#include "diff.h" +#include "cmpbuf.h" extern int no_discards; static int *xvec, *yvec; /* Vectors being compared. */ static int *fdiag; /* Vector, indexed by diagonal, containing - the X coordinate of the point furthest + 1 + the X coordinate of the point furthest along the given diagonal in the forward search of the edit matrix. */ static int *bdiag; /* Vector, indexed by diagonal, containing the X coordinate of the point furthest along the given diagonal in the backward search of the edit matrix. */ +static int too_expensive; /* Edit scripts longer than this are too + expensive to compute. */ + +#define SNAKE_LIMIT 20 /* Snakes bigger than this are considered `big'. */ + +struct partition +{ + int xmid, ymid; /* Midpoints of this partition. */ + int lo_minimal; /* Nonzero if low half will be analyzed minimally. */ + int hi_minimal; /* Likewise for high half. */ +}; + +static int diag PARAMS((int, int, int, int, int, struct partition *)); +static struct change *add_change PARAMS((int, int, int, int, struct change *)); +static struct change *build_reverse_script PARAMS((struct file_data const[])); +static struct change *build_script PARAMS((struct file_data const[])); +static void briefly_report PARAMS((int, struct file_data const[])); +static void compareseq PARAMS((int, int, int, int, int)); +static void discard_confusing_lines PARAMS((struct file_data[])); +static void shift_boundaries PARAMS((struct file_data[])); /* Find the midpoint of the shortest edit script for a specified portion of the two files. - We scan from the beginnings of the files, and simultaneously from the ends, + Scan from the beginnings of the files, and simultaneously from the ends, doing a breadth-first search through the space of edit-sequence. When the two searches meet, we have found the midpoint of the shortest edit sequence. - The value returned is the number of the diagonal on which the midpoint lies. - The diagonal number equals the number of inserted lines minus the number + If MINIMAL is nonzero, find the minimal edit script regardless + of expense. Otherwise, if the search is too expensive, use + heuristics to stop the search and report a suboptimal answer. + + Set PART->(XMID,YMID) to the midpoint (XMID,YMID). The diagonal number + XMID - YMID equals the number of inserted lines minus the number of deleted lines (counting only lines before the midpoint). - The edit cost is stored into *COST; this is the total number of - lines inserted or deleted (counting only lines before the midpoint). + Return the approximate edit cost; this is the total number of + lines inserted or deleted (counting only lines before the midpoint), + unless a heuristic is used to terminate the search prematurely. + + Set PART->LEFT_MINIMAL to nonzero iff the minimal edit script for the + left half of the partition is known; similarly for PART->RIGHT_MINIMAL. This function assumes that the first lines of the specified portions of the two files do not match, and likewise that the last lines do not match. The caller must trim matching lines from the beginning and end of the portions it is going to specify. - Note that if we return the "wrong" diagonal value, or if - the value of bdiag at that diagonal is "wrong", + If we return the "wrong" partitions, the worst this can do is cause suboptimal diff output. It cannot cause incorrect diff output. */ static int -diag (xoff, xlim, yoff, ylim, cost) - int xoff, xlim, yoff, ylim; - int *cost; +diag (xoff, xlim, yoff, ylim, minimal, part) + int xoff, xlim, yoff, ylim, minimal; + struct partition *part; { int *const fd = fdiag; /* Give the compiler a chance. */ int *const bd = bdiag; /* Additional help for the compiler. */ - int *const xv = xvec; /* Still more help for the compiler. */ - int *const yv = yvec; /* And more and more . . . */ - const int dmin = xoff - ylim; /* Minimum valid diagonal. */ - const int dmax = xlim - yoff; /* Maximum valid diagonal. */ - const int fmid = xoff - yoff; /* Center diagonal of top-down search. */ - const int bmid = xlim - ylim; /* Center diagonal of bottom-up search. */ + int const *const xv = xvec; /* Still more help for the compiler. */ + int const *const yv = yvec; /* And more and more . . . */ + int const dmin = xoff - ylim; /* Minimum valid diagonal. */ + int const dmax = xlim - yoff; /* Maximum valid diagonal. */ + int const fmid = xoff - yoff; /* Center diagonal of top-down search. */ + int const bmid = xlim - ylim; /* Center diagonal of bottom-up search. */ int fmin = fmid, fmax = fmid; /* Limits of top-down search. */ int bmin = bmid, bmax = bmid; /* Limits of bottom-up search. */ int c; /* Cost. */ @@ -112,17 +138,19 @@ diag (xoff, xlim, yoff, ylim, cost) y = x - d; while (x < xlim && y < ylim && xv[x] == yv[y]) ++x, ++y; - if (x - oldx > 20) + if (x - oldx > SNAKE_LIMIT) big_snake = 1; fd[d] = x; - if (odd && bmin <= d && d <= bmax && bd[d] <= fd[d]) + if (odd && bmin <= d && d <= bmax && bd[d] <= x) { - *cost = 2 * c - 1; - return d; + part->xmid = x; + part->ymid = y; + part->lo_minimal = part->hi_minimal = 1; + return 2 * c - 1; } } - /* Similar extend the bottom-up search. */ + /* Similarly extend the bottom-up search. */ bmin > dmin ? bd[--bmin - 1] = INT_MAX : ++bmin; bmax < dmax ? bd[++bmax + 1] = INT_MAX : --bmax; for (d = bmax; d >= bmin; d -= 2) @@ -137,16 +165,21 @@ diag (xoff, xlim, yoff, ylim, cost) y = x - d; while (x > xoff && y > yoff && xv[x - 1] == yv[y - 1]) --x, --y; - if (oldx - x > 20) + if (oldx - x > SNAKE_LIMIT) big_snake = 1; bd[d] = x; - if (!odd && fmin <= d && d <= fmax && bd[d] <= fd[d]) + if (!odd && fmin <= d && d <= fmax && x <= fd[d]) { - *cost = 2 * c; - return d; + part->xmid = x; + part->ymid = y; + part->lo_minimal = part->hi_minimal = 1; + return 2 * c; } } + if (minimal) + continue; + /* Heuristic: check occasionally for a diagonal that has made lots of progress compared with the edit distance. If we have any such, find the one that has made the most @@ -158,73 +191,134 @@ diag (xoff, xlim, yoff, ylim, cost) if (c > 200 && big_snake && heuristic) { int best; - int bestpos; best = 0; for (d = fmax; d >= fmin; d -= 2) { int dd = d - fmid; - if ((fd[d] - xoff)*2 - dd > 12 * (c + (dd > 0 ? dd : -dd))) + int x = fd[d]; + int y = x - d; + int v = (x - xoff) * 2 - dd; + if (v > 12 * (c + (dd < 0 ? -dd : dd))) { - if (fd[d] * 2 - dd > best - && fd[d] - xoff > 20 - && fd[d] - d - yoff > 20) + if (v > best + && xoff + SNAKE_LIMIT <= x && x < xlim + && yoff + SNAKE_LIMIT <= y && y < ylim) { - int k; - int x = fd[d]; - /* We have a good enough best diagonal; now insist that it end with a significant snake. */ - for (k = 1; k <= 20; k++) - if (xvec[x - k] != yvec[x - d - k]) - break; - - if (k == 21) - { - best = fd[d] * 2 - dd; - bestpos = d; - } + int k; + + for (k = 1; xv[x - k] == yv[y - k]; k++) + if (k == SNAKE_LIMIT) + { + best = v; + part->xmid = x; + part->ymid = y; + break; + } } } } if (best > 0) { - *cost = 2 * c - 1; - return bestpos; + part->lo_minimal = 1; + part->hi_minimal = 0; + return 2 * c - 1; } best = 0; for (d = bmax; d >= bmin; d -= 2) { int dd = d - bmid; - if ((xlim - bd[d])*2 + dd > 12 * (c + (dd > 0 ? dd : -dd))) + int x = bd[d]; + int y = x - d; + int v = (xlim - x) * 2 + dd; + if (v > 12 * (c + (dd < 0 ? -dd : dd))) { - if ((xlim - bd[d]) * 2 + dd > best - && xlim - bd[d] > 20 - && ylim - (bd[d] - d) > 20) + if (v > best + && xoff < x && x <= xlim - SNAKE_LIMIT + && yoff < y && y <= ylim - SNAKE_LIMIT) { /* We have a good enough best diagonal; now insist that it end with a significant snake. */ int k; - int x = bd[d]; - - for (k = 0; k < 20; k++) - if (xvec[x + k] != yvec[x - d + k]) - break; - if (k == 20) - { - best = (xlim - bd[d]) * 2 + dd; - bestpos = d; - } + + for (k = 0; xv[x + k] == yv[y + k]; k++) + if (k == SNAKE_LIMIT - 1) + { + best = v; + part->xmid = x; + part->ymid = y; + break; + } } } } if (best > 0) { - *cost = 2 * c - 1; - return bestpos; + part->lo_minimal = 0; + part->hi_minimal = 1; + return 2 * c - 1; } } + + /* Heuristic: if we've gone well beyond the call of duty, + give up and report halfway between our best results so far. */ + if (c >= too_expensive) + { + int fxybest, fxbest; + int bxybest, bxbest; + + fxbest = bxbest = 0; /* Pacify `gcc -Wall'. */ + + /* Find forward diagonal that maximizes X + Y. */ + fxybest = -1; + for (d = fmax; d >= fmin; d -= 2) + { + int x = min (fd[d], xlim); + int y = x - d; + if (ylim < y) + x = ylim + d, y = ylim; + if (fxybest < x + y) + { + fxybest = x + y; + fxbest = x; + } + } + + /* Find backward diagonal that minimizes X + Y. */ + bxybest = INT_MAX; + for (d = bmax; d >= bmin; d -= 2) + { + int x = max (xoff, bd[d]); + int y = x - d; + if (y < yoff) + x = yoff + d, y = yoff; + if (x + y < bxybest) + { + bxybest = x + y; + bxbest = x; + } + } + + /* Use the better of the two diagonals. */ + if ((xlim + ylim) - bxybest < fxybest - (xoff + yoff)) + { + part->xmid = fxbest; + part->ymid = fxybest - fxbest; + part->lo_minimal = 1; + part->hi_minimal = 0; + } + else + { + part->xmid = bxbest; + part->ymid = bxybest - bxbest; + part->lo_minimal = 0; + part->hi_minimal = 1; + } + return 2 * c - 1; + } } } @@ -237,19 +331,25 @@ diag (xoff, xlim, yoff, ylim, cost) The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1. Note that XLIM, YLIM are exclusive bounds. - All line numbers are origin-0 and discarded lines are not counted. */ + All line numbers are origin-0 and discarded lines are not counted. + + If MINIMAL is nonzero, find a minimal difference no matter how + expensive it is. */ static void -compareseq (xoff, xlim, yoff, ylim) - int xoff, xlim, yoff, ylim; +compareseq (xoff, xlim, yoff, ylim, minimal) + int xoff, xlim, yoff, ylim, minimal; { + int * const xv = xvec; /* Help the compiler. */ + int * const yv = yvec; + /* Slide down the bottom initial diagonal. */ - while (xoff < xlim && yoff < ylim && xvec[xoff] == yvec[yoff]) + while (xoff < xlim && yoff < ylim && xv[xoff] == yv[yoff]) ++xoff, ++yoff; /* Slide up the top initial diagonal. */ - while (xlim > xoff && ylim > yoff && xvec[xlim - 1] == yvec[ylim - 1]) + while (xlim > xoff && ylim > yoff && xv[xlim - 1] == yv[ylim - 1]) --xlim, --ylim; - + /* Handle simple cases. */ if (xoff == xlim) while (yoff < ylim) @@ -259,13 +359,12 @@ compareseq (xoff, xlim, yoff, ylim) files[0].changed_flag[files[0].realindexes[xoff++]] = 1; else { - int c, d, f, b; + int c; + struct partition part; /* Find a point of correspondence in the middle of the files. */ - d = diag (xoff, xlim, yoff, ylim, &c); - f = fdiag[d]; - b = bdiag[d]; + c = diag (xoff, xlim, yoff, ylim, minimal, &part); if (c == 1) { @@ -277,21 +376,17 @@ compareseq (xoff, xlim, yoff, ylim) #if 0 /* The two subsequences differ by a single insert or delete; record it and we are done. */ - if (d < xoff - yoff) - files[1].changed_flag[files[1].realindexes[b - d - 1]] = 1; + if (part.xmid - part.ymid < xoff - yoff) + files[1].changed_flag[files[1].realindexes[part.ymid - 1]] = 1; else - files[0].changed_flag[files[0].realindexes[b]] = 1; + files[0].changed_flag[files[0].realindexes[part.xmid]] = 1; #endif } else { - /* Use that point to split this problem into two subproblems. */ - compareseq (xoff, b, yoff, b - d); - /* This used to use f instead of b, - but that is incorrect! - It is not necessarily the case that diagonal d - has a snake from b to f. */ - compareseq (b, xlim, b - d, ylim); + /* Use the partitions to split this problem into subproblems. */ + compareseq (xoff, part.xmid, yoff, part.ymid, part.lo_minimal); + compareseq (part.xmid, xlim, part.ymid, ylim, part.hi_minimal); } } } @@ -308,7 +403,7 @@ compareseq (xoff, xlim, yoff, ylim) When we discard a line, we also mark it as a deletion or insertion so that it will be printed in the output. */ -void +static void discard_confusing_lines (filevec) struct file_data filevec[]; { @@ -341,10 +436,12 @@ discard_confusing_lines (filevec) /* Set up tables of which lines are going to be discarded. */ - discarded[0] = (char *) xmalloc (filevec[0].buffered_lines - + filevec[1].buffered_lines); + discarded[0] = xmalloc (sizeof (char) + * (filevec[0].buffered_lines + + filevec[1].buffered_lines)); discarded[1] = discarded[0] + filevec[0].buffered_lines; - bzero (discarded[0], filevec[0].buffered_lines + filevec[1].buffered_lines); + bzero (discarded[0], sizeof (char) * (filevec[0].buffered_lines + + filevec[1].buffered_lines)); /* Mark to be discarded each line that matches no line of the other file. If a line matches many lines, mark it as provisionally discardable. */ @@ -509,16 +606,15 @@ discard_confusing_lines (filevec) free (equiv_count[0]); } -/* Adjust inserts/deletes of blank lines to join changes +/* Adjust inserts/deletes of identical lines to join changes as much as possible. - We do something when a run of changed lines include a blank - line at one end and have an excluded blank line at the other. - We are free to choose which blank line is included. - `compareseq' always chooses the one at the beginning, - but usually it is cleaner to consider the following blank line - to be the "change". The only exception is if the preceding blank line - would join this change to other changes. */ + We do something when a run of changed lines include a + line at one end and have an excluded, identical line at the other. + We are free to choose which identical line is included. + `compareseq' usually chooses the one at the beginning, + but usually it is cleaner to consider the following identical line + to be the "change". */ int inhibit; @@ -534,16 +630,15 @@ shift_boundaries (filevec) for (f = 0; f < 2; f++) { char *changed = filevec[f].changed_flag; - char *other_changed = filevec[1-f].changed_flag; + char const *other_changed = filevec[1-f].changed_flag; + int const *equivs = filevec[f].equivs; int i = 0; int j = 0; int i_end = filevec[f].buffered_lines; - int preceding = -1; - int other_preceding = -1; while (1) { - int start, other_start; + int runlength, start, corresponding; /* Scan forwards to find beginning of another run of changes. Also keep track of the corresponding point in the other file. */ @@ -551,9 +646,7 @@ shift_boundaries (filevec) while (i < i_end && changed[i] == 0) { while (other_changed[j++]) - /* Non-corresponding lines in the other file - will count as the preceding batch of changes. */ - other_preceding = j; + continue; i++; } @@ -561,42 +654,67 @@ shift_boundaries (filevec) break; start = i; - other_start = j; - while (1) + /* Find the end of this run of changes. */ + + while (changed[++i]) + continue; + while (other_changed[j]) + j++; + + do { - /* Now find the end of this run of changes. */ + /* Record the length of this run of changes, so that + we can later determine whether the run has grown. */ + runlength = i - start; - while (changed[++i] != 0) - ; + /* Move the changed region back, so long as the + previous unchanged line matches the last changed one. + This merges with previous changed regions. */ - /* If the first changed line matches the following unchanged one, - and this run does not follow right after a previous run, - and there are no lines deleted from the other file here, - then classify the first changed line as unchanged - and the following line as changed in its place. */ + while (start && equivs[start - 1] == equivs[i - 1]) + { + changed[--start] = 1; + changed[--i] = 0; + while (changed[start - 1]) + start--; + while (other_changed[--j]) + continue; + } + + /* Set CORRESPONDING to the end of the changed run, at the last + point where it corresponds to a changed run in the other file. + CORRESPONDING == I_END means no such point has been found. */ + corresponding = other_changed[j - 1] ? i : i_end; - /* You might ask, how could this run follow right after another? - Only because the previous run was shifted here. */ + /* Move the changed region forward, so long as the + first changed line matches the following unchanged one. + This merges with following changed regions. + Do this second, so that if there are no merges, + the changed region is moved forward as far as possible. */ - if (i != i_end - && files[f].equivs[start] == files[f].equivs[i] - && !other_changed[j] - && !(start == preceding || other_start == other_preceding)) + while (i != i_end && equivs[start] == equivs[i]) { changed[start++] = 0; - changed[i] = 1; - /* Since one line-that-matches is now before this run - instead of after, we must advance in the other file - to keep in synch. */ - ++j; + changed[i++] = 1; + while (changed[i]) + i++; + while (other_changed[++j]) + corresponding = i; } - else - break; } + while (runlength != i - start); + + /* If possible, move the fully-merged run of changes + back to a corresponding run in the other file. */ - preceding = i; - other_preceding = j; + while (corresponding < i) + { + changed[--start] = 1; + changed[--i] = 0; + while (other_changed[--j]) + continue; + } } } } @@ -629,7 +747,7 @@ add_change (line0, line1, deleted, inserted, old) static struct change * build_reverse_script (filevec) - struct file_data filevec[]; + struct file_data const filevec[]; { struct change *script = 0; char *changed0 = filevec[0].changed_flag; @@ -667,7 +785,7 @@ build_reverse_script (filevec) static struct change * build_script (filevec) - struct file_data filevec[]; + struct file_data const filevec[]; { struct change *script = 0; char *changed0 = filevec[0].changed_flag; @@ -697,6 +815,18 @@ build_script (filevec) return script; } +/* If CHANGES, briefly report that two files differed. */ +static void +briefly_report (changes, filevec) + int changes; + struct file_data const filevec[]; +{ + if (changes) + message (no_details_flag ? "Files %s and %s differ\n" + : "Binary files %s and %s differ\n", + filevec[0].name, filevec[1].name); +} + /* Report the differences of two files. DEPTH is the current directory depth. */ int @@ -714,9 +844,10 @@ diff_2_files (filevec, depth) /* If we have detected that either file is binary, compare the two files as binary. This can happen only when the first chunk is read. - Also, -q means treat all files as binary. */ + Also, --brief without any --ignore-* options means + we can speed things up by treating the files as binary. */ - if (read_files (filevec)) + if (read_files (filevec, no_details_flag & ~ignore_some_changes)) { /* Files with different lengths must be different. */ if (filevec[0].stat.st_size != filevec[1].stat.st_size @@ -732,8 +863,8 @@ diff_2_files (filevec, depth) /* Scan both files, a buffer at a time, looking for a difference. */ { /* Allocate same-sized buffers for both files. */ - int buffer_size = max (STAT_BLOCKSIZE (filevec[0].stat), - STAT_BLOCKSIZE (filevec[1].stat)); + size_t buffer_size = buffer_lcm (STAT_BLOCKSIZE (filevec[0].stat), + STAT_BLOCKSIZE (filevec[1].stat)); for (i = 0; i < 2; i++) filevec[i].buffer = xrealloc (filevec[i].buffer, buffer_size); @@ -757,9 +888,10 @@ diff_2_files (filevec, depth) /* If the buffers differ, the files differ. */ if (filevec[0].buffered_chars != filevec[1].buffered_chars - || bcmp (filevec[0].buffer, - filevec[1].buffer, - filevec[0].buffered_chars) != 0) + || (filevec[0].buffered_chars != 0 + && memcmp (filevec[0].buffer, + filevec[1].buffer, + filevec[0].buffered_chars) != 0)) { changes = 1; break; @@ -774,10 +906,7 @@ diff_2_files (filevec, depth) } } - if (changes) - message (no_details_flag ? "Files %s and %s differ\n" - : "Binary files %s and %s differ\n", - filevec[0].name, filevec[1].name); + briefly_report (changes, filevec); } else { @@ -786,11 +915,9 @@ diff_2_files (filevec, depth) is an insertion or deletion. Allocate an extra element, always zero, at each end of each vector. */ - filevec[0].changed_flag = (char *) xmalloc (filevec[0].buffered_lines - + filevec[1].buffered_lines - + 4); - bzero (filevec[0].changed_flag, filevec[0].buffered_lines - + filevec[1].buffered_lines + 4); + size_t s = filevec[0].buffered_lines + filevec[1].buffered_lines + 4; + filevec[0].changed_flag = xmalloc (s); + bzero (filevec[0].changed_flag, s); filevec[0].changed_flag++; filevec[1].changed_flag = filevec[0].changed_flag + filevec[0].buffered_lines + 2; @@ -812,11 +939,19 @@ diff_2_files (filevec, depth) fdiag += filevec[1].nondiscarded_lines + 1; bdiag += filevec[1].nondiscarded_lines + 1; + /* Set TOO_EXPENSIVE to be approximate square root of input size, + bounded below by 256. */ + too_expensive = 1; + for (i = filevec[0].nondiscarded_lines + filevec[1].nondiscarded_lines; + i != 0; i >>= 2) + too_expensive <<= 1; + too_expensive = max (256, too_expensive); + files[0] = filevec[0]; files[1] = filevec[1]; compareseq (0, filevec[0].nondiscarded_lines, - 0, filevec[1].nondiscarded_lines); + 0, filevec[1].nondiscarded_lines, no_discards); free (fdiag - (filevec[1].nondiscarded_lines + 1)); @@ -833,50 +968,7 @@ diff_2_files (filevec, depth) else script = build_script (filevec); - if (script || ! no_diff_means_no_output) - { - /* Record info for starting up output, - to be used if and when we have some output to print. */ - setup_output (files[0].name, files[1].name, depth); - - switch (output_style) - { - case OUTPUT_CONTEXT: - print_context_script (script, 0); - break; - - case OUTPUT_UNIFIED: - print_context_script (script, 1); - break; - - case OUTPUT_ED: - print_ed_script (script); - break; - - case OUTPUT_FORWARD_ED: - pr_forward_ed_script (script); - break; - - case OUTPUT_RCS: - print_rcs_script (script); - break; - - case OUTPUT_NORMAL: - print_normal_script (script); - break; - - case OUTPUT_IFDEF: - print_ifdef_script (script); - break; - - case OUTPUT_SDIFF: - print_sdiff_script (script); - } - - finish_output (); - } - - /* Set CHANGES if we had any diffs that were printed. + /* Set CHANGES if we had any diffs. If some changes are ignored, we must scan the script to decide. */ if (ignore_blank_lines_flag || ignore_regexp_list) { @@ -895,9 +987,9 @@ diff_2_files (filevec, depth) /* Disconnect them from the rest of the changes, making them a hunk, and remember the rest for next iteration. */ next = end->link; - end->link = NULL; + end->link = 0; - /* Determine whether this hunk was printed. */ + /* Determine whether this hunk is really a difference. */ analyze_hunk (this, &first0, &last0, &first1, &last1, &deletes, &inserts); @@ -911,6 +1003,54 @@ diff_2_files (filevec, depth) else changes = (script != 0); + if (no_details_flag) + briefly_report (changes, filevec); + else + { + if (changes || ! no_diff_means_no_output) + { + /* Record info for starting up output, + to be used if and when we have some output to print. */ + setup_output (files[0].name, files[1].name, depth); + + switch (output_style) + { + case OUTPUT_CONTEXT: + print_context_script (script, 0); + break; + + case OUTPUT_UNIFIED: + print_context_script (script, 1); + break; + + case OUTPUT_ED: + print_ed_script (script); + break; + + case OUTPUT_FORWARD_ED: + pr_forward_ed_script (script); + break; + + case OUTPUT_RCS: + print_rcs_script (script); + break; + + case OUTPUT_NORMAL: + print_normal_script (script); + break; + + case OUTPUT_IFDEF: + print_ifdef_script (script); + break; + + case OUTPUT_SDIFF: + print_sdiff_script (script); + } + + finish_output (); + } + } + free (filevec[0].undiscarded); free (filevec[0].changed_flag - 1); diff --git a/gnu/usr.bin/diff/config.h b/gnu/usr.bin/diff/config.h index ed8e8ef..3d7e65b 100644 --- a/gnu/usr.bin/diff/config.h +++ b/gnu/usr.bin/diff/config.h @@ -1,9 +1,12 @@ /* config.h. Generated automatically by configure. */ -/* config.h.in. Generated automatically from configure.in by autoheader. */ +/* config.hin. Generated automatically from configure.in by autoheader. */ /* Define if using alloca.c. */ /* #undef C_ALLOCA */ +/* Define if the closedir function returns void instead of int. */ +/* #undef CLOSEDIR_VOID */ + /* Define to empty if the keyword does not work. */ /* #undef const */ @@ -11,10 +14,7 @@ This function is required for alloca.c support on those systems. */ /* #undef CRAY_STACKSEG_END */ -/* Define if you have dirent.h. */ -#define DIRENT 1 - -/* Define if you have alloca.h and it should be used (not Ultrix). */ +/* Define if you have <alloca.h> and it should be used (not on Ultrix). */ /* #undef HAVE_ALLOCA_H */ /* Define if you don't have vprintf but do have _doprnt. */ @@ -23,7 +23,7 @@ /* Define if your struct stat has st_blksize. */ #define HAVE_ST_BLKSIZE 1 -/* Define if you have vfork.h. */ +/* Define if you have <vfork.h>. */ /* #undef HAVE_VFORK_H */ /* Define if you have the vprintf function. */ @@ -32,9 +32,6 @@ /* Define if on MINIX. */ /* #undef _MINIX */ -/* Define if you don't have dirent.h, but have ndir.h. */ -/* #undef NDIR */ - /* Define to `int' if <sys/types.h> doesn't define. */ /* #undef pid_t */ @@ -63,32 +60,32 @@ /* Define if you have the ANSI C header files. */ #define STDC_HEADERS 1 -/* Define if you don't have dirent.h, but have sys/dir.h. */ -/* #undef SYSDIR */ - -/* Define if you don't have dirent.h, but have sys/ndir.h. */ -/* #undef SYSNDIR */ +/* Define if <sys/wait.h> is compatible with Posix applications. */ +#define HAVE_SYS_WAIT_H 1 /* Define vfork as fork if vfork does not work. */ /* #undef vfork */ -/* Define if the closedir function returns void instead of int. */ -/* #undef VOID_CLOSEDIR */ - -/* Define if you have dup2. */ +/* Define if you have the dup2 function. */ #define HAVE_DUP2 1 -/* Define if you have memchr. */ +/* Define if you have the memchr function. */ #define HAVE_MEMCHR 1 -/* Define if you have sigaction. */ +/* Define if you have the sigaction function. */ #define HAVE_SIGACTION 1 -/* Define if you have strerror. */ +/* Define if you have the strchr function. */ +#define HAVE_STRCHR 1 + +/* Define if you have the strerror function. */ #define HAVE_STRERROR 1 -/* Define if you have waitpid. */ -#define HAVE_WAITPID 1 +/* Define if you have the tmpnam function. */ +#define HAVE_TMPNAM 1 + +/* Define if you have the <dirent.h> header file. */ +#define HAVE_DIRENT_H 1 /* Define if you have the <fcntl.h> header file. */ #define HAVE_FCNTL_H 1 @@ -96,14 +93,23 @@ /* Define if you have the <limits.h> header file. */ #define HAVE_LIMITS_H 1 +/* Define if you have the <ndir.h> header file. */ +/* #undef HAVE_NDIR_H */ + /* Define if you have the <stdlib.h> header file. */ #define HAVE_STDLIB_H 1 /* Define if you have the <string.h> header file. */ #define HAVE_STRING_H 1 -/* Define if you have the <sys/wait.h> header file. */ -#define HAVE_SYS_WAIT_H 1 +/* Define if you have the <sys/dir.h> header file. */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define if you have the <sys/file.h> header file. */ +#define HAVE_SYS_FILE_H 1 + +/* Define if you have the <sys/ndir.h> header file. */ +/* #undef HAVE_SYS_NDIR_H */ /* Define if you have the <time.h> header file. */ #define HAVE_TIME_H 1 diff --git a/gnu/usr.bin/diff/context.c b/gnu/usr.bin/diff/context.c index 9b8fc3e..14f950c 100644 --- a/gnu/usr.bin/diff/context.c +++ b/gnu/usr.bin/diff/context.c @@ -1,5 +1,5 @@ /* Context-format output routines for GNU DIFF. - Copyright (C) 1988, 89, 91, 92 Free Software Foundation, Inc. + Copyright (C) 1988,1989,1991,1992,1993,1994 Free Software Foundation, Inc. This file is part of GNU DIFF. @@ -19,11 +19,14 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "diff.h" -static void pr_context_hunk (); -static void pr_unidiff_hunk (); -static struct change *find_hunk (); -static void mark_ignorable (); -static void find_function (); +static struct change *find_hunk PARAMS((struct change *)); +static void find_function PARAMS((struct file_data const *, int, char const **, size_t *)); +static void mark_ignorable PARAMS((struct change *)); +static void pr_context_hunk PARAMS((struct change *)); +static void pr_unidiff_hunk PARAMS((struct change *)); +static void print_context_label PARAMS ((char const *, struct file_data *, char const *)); +static void print_context_number_range PARAMS((struct file_data const *, int, int)); +static void print_unidiff_number_range PARAMS((struct file_data const *, int, int)); /* Last place find_function started searching from. */ static int find_function_last_search; @@ -35,24 +38,27 @@ static int find_function_last_match; static void print_context_label (mark, inf, label) - const char *mark; + char const *mark; struct file_data *inf; - const char *label; + char const *label; { if (label) fprintf (outfile, "%s %s\n", mark, label); - else if (inf->stat.st_mtime) - fprintf (outfile, "%s %s\t%s", mark, inf->name, ctime(&inf->stat.st_mtime)); else - /* Don't pretend that standard input is ancient. */ - fprintf (outfile, "%s %s\n", mark, inf->name); + { + char const *ct = ctime (&inf->stat.st_mtime); + if (!ct) + ct = "?\n"; + /* See Posix.2 section 4.17.6.1.4 for this format. */ + fprintf (outfile, "%s %s\t%s", mark, inf->name, ct); + } } /* Print a header for a context diff, with the file names and dates. */ void print_context_header (inf, unidiff_flag) - struct file_data *inf; + struct file_data inf[]; int unidiff_flag; { if (unidiff_flag) @@ -100,7 +106,7 @@ print_context_script (script, unidiff_flag) static void print_context_number_range (file, a, b) - struct file_data *file; + struct file_data const *file; int a, b; { int trans_a, trans_b; @@ -128,9 +134,9 @@ pr_context_hunk (hunk) { int first0, last0, first1, last1, show_from, show_to, i; struct change *next; - char *prefix; - const char *function; - int function_length; + char const *prefix; + char const *function; + size_t function_length; FILE *out; /* Determine range of line numbers involved in each file. */ @@ -234,7 +240,7 @@ pr_context_hunk (hunk) static void print_unidiff_number_range (file, a, b) - struct file_data *file; + struct file_data const *file; int a, b; { int trans_a, trans_b; @@ -262,8 +268,8 @@ pr_unidiff_hunk (hunk) { int first0, last0, first1, last1, show_from, show_to, i, j, k; struct change *next; - char *function; - int function_length; + char const *function; + size_t function_length; FILE *out; /* Determine range of line numbers involved in each file. */ @@ -317,7 +323,7 @@ pr_unidiff_hunk (hunk) if (!next || i < next->line0) { putc (tab_align_flag ? '\t' : ' ', out); - print_1_line ((char *)0, &files[0].linbuf[i++]); + print_1_line (0, &files[0].linbuf[i++]); j++; } else @@ -330,7 +336,7 @@ pr_unidiff_hunk (hunk) putc ('-', out); if (tab_align_flag) putc ('\t', out); - print_1_line ((char *)0, &files[0].linbuf[i++]); + print_1_line (0, &files[0].linbuf[i++]); } /* Then output the inserted part. */ @@ -341,7 +347,7 @@ pr_unidiff_hunk (hunk) putc ('+', out); if (tab_align_flag) putc ('\t', out); - print_1_line ((char *)0, &files[1].linbuf[j++]); + print_1_line (0, &files[1].linbuf[j++]); } /* We're done with this hunk, so on to the next! */ @@ -424,10 +430,10 @@ mark_ignorable (script) static void find_function (file, linenum, linep, lenp) - struct file_data *file; + struct file_data const *file; int linenum; - const char **linep; - int *lenp; + char const **linep; + size_t *lenp; { int i = linenum; int last = find_function_last_search; @@ -437,8 +443,8 @@ find_function (file, linenum, linep, lenp) { /* See if this line is what we want. */ struct regexp_list *r; - const char *line = file->linbuf[i]; - int len = file->linbuf[i + 1] - line; + char const *line = file->linbuf[i]; + size_t len = file->linbuf[i + 1] - line; for (r = function_regexp_list; r; r = r->next) if (0 <= re_search (&r->buf, line, len, 0, len, 0)) diff --git a/gnu/usr.bin/diff/diff.c b/gnu/usr.bin/diff/diff.c index e4eb66f..ab1549b 100644 --- a/gnu/usr.bin/diff/diff.c +++ b/gnu/usr.bin/diff/diff.c @@ -1,5 +1,5 @@ /* GNU DIFF main routine. - Copyright (C) 1988, 1989, 1992 Free Software Foundation, Inc. + Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc. This file is part of GNU DIFF. @@ -22,6 +22,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #define GDIFF_MAIN #include "diff.h" +#include <signal.h> #include "getopt.h" #include "fnmatch.h" @@ -33,14 +34,18 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #define GUTTER_WIDTH_MINIMUM 3 #endif -int diff_dirs (); -int diff_2_files (); - -static int compare_files (); -static int specify_format (); -static void add_regexp(); -static void specify_style (); -static void usage (); +static char const *filetype PARAMS((struct stat const *)); +static char *option_list PARAMS((char **, int)); +static int add_exclude_file PARAMS((char const *)); +static int ck_atoi PARAMS((char const *, int *)); +static int compare_files PARAMS((char const *, char const *, char const *, char const *, int)); +static int specify_format PARAMS((char **, char *)); +static void add_exclude PARAMS((char const *)); +static void add_regexp PARAMS((struct regexp_list **, char const *)); +static void specify_style PARAMS((enum output_style)); +static void try_help PARAMS((char const *)); +static void check_stdout PARAMS((void)); +static void usage PARAMS((void)); /* Nonzero for -r: if comparing two directories, compare their common subdirectories recursively. */ @@ -51,6 +56,11 @@ static int recursive; int no_discards; +#if HAVE_SETMODE +/* I/O mode: nonzero only if using binary input/output. */ +static int binary_I_O; +#endif + /* Return a string containing the command options with which diff was invoked. Spaces appear between what were separate ARGV-elements. There is a space at the beginning but none at the end. @@ -65,13 +75,13 @@ option_list (optionvec, count) int count; { int i; - int length = 0; + size_t length = 0; char *result; for (i = 0; i < count; i++) length += strlen (optionvec[i]) + 1; - result = (char *) xmalloc (length + 1); + result = xmalloc (length + 1); result[0] = 0; for (i = 0; i < count; i++) @@ -83,14 +93,14 @@ option_list (optionvec, count) return result; } -/* Convert STR to a positive integer, storing the result in *OUT. +/* Convert STR to a positive integer, storing the result in *OUT. If STR is not a valid integer, return -1 (otherwise 0). */ static int ck_atoi (str, out) - char *str; + char const *str; int *out; { - char *p; + char const *p; for (p = str; *p; p++) if (*p < '0' || *p > '9') return -1; @@ -101,12 +111,12 @@ ck_atoi (str, out) /* Keep track of excluded file name patterns. */ -static const char **exclude; +static char const **exclude; static int exclude_alloc, exclude_count; int excluded_filename (f) - const char *f; + char const *f; { int i; for (i = 0; i < exclude_count; i++) @@ -117,10 +127,10 @@ excluded_filename (f) static void add_exclude (pattern) - const char *pattern; + char const *pattern; { if (exclude_alloc <= exclude_count) - exclude = (const char **) + exclude = (char const **) (exclude_alloc == 0 ? xmalloc ((exclude_alloc = 64) * sizeof (*exclude)) : xrealloc (exclude, (exclude_alloc *= 2) * sizeof (*exclude))); @@ -130,13 +140,15 @@ add_exclude (pattern) static int add_exclude_file (name) - const char *name; + char const *name; { struct file_data f; char *p, *q, *lim; f.name = optarg; - f.desc = strcmp (optarg, "-") == 0 ? 0 : open (optarg, O_RDONLY, 0); + f.desc = (strcmp (optarg, "-") == 0 + ? STDIN_FILENO + : open (optarg, O_RDONLY, 0)); if (f.desc < 0 || fstat (f.desc, &f.stat) != 0) return -1; @@ -145,7 +157,7 @@ add_exclude_file (name) for (p = f.buffer, lim = p + f.buffered_chars; p < lim; p = q) { - q = memchr (p, '\n', lim - p); + q = (char *) memchr (p, '\n', lim - p); if (!q) q = lim; *q++ = 0; @@ -158,7 +170,7 @@ add_exclude_file (name) /* The numbers 129- that appear in the fourth element of some entries tell the big switch in `main' how to process those options. */ -static struct option longopts[] = +static struct option const longopts[] = { {"ignore-blank-lines", 0, 0, 'B'}, {"context", 2, 0, 'C'}, @@ -185,7 +197,6 @@ static struct option longopts[] = {"print", 0, 0, 'l'}, /* An alias, no longer recommended */ {"rcs", 0, 0, 'n'}, {"show-c-function", 0, 0, 'p'}, - {"binary", 0, 0, 'q'}, /* An alias, no longer recommended */ {"brief", 0, 0, 'q'}, {"recursive", 0, 0, 'r'}, {"report-identical-files", 0, 0, 's'}, @@ -202,11 +213,14 @@ static struct option longopts[] = {"old-line-format", 1, 0, 132}, {"new-line-format", 1, 0, 133}, {"unchanged-line-format", 1, 0, 134}, - {"old-group-format", 1, 0, 135}, - {"new-group-format", 1, 0, 136}, - {"unchanged-group-format", 1, 0, 137}, - {"changed-group-format", 1, 0, 138}, - {"horizon-lines", 1, 0, 139}, + {"line-format", 1, 0, 135}, + {"old-group-format", 1, 0, 136}, + {"new-group-format", 1, 0, 137}, + {"unchanged-group-format", 1, 0, 138}, + {"changed-group-format", 1, 0, 139}, + {"horizon-lines", 1, 0, 140}, + {"help", 0, 0, 141}, + {"binary", 0, 0, 142}, {0, 0, 0, 0} }; @@ -218,42 +232,20 @@ main (argc, argv) int val; int c; int prev = -1; - extern char *version_string; int width = DEFAULT_WIDTH; + int show_c_function = 0; - program = argv[0]; - - /* Do our initializations. */ + /* Do our initializations. */ + initialize_main (&argc, &argv); + program_name = argv[0]; output_style = OUTPUT_NORMAL; - always_text_flag = FALSE; - ignore_space_change_flag = FALSE; - ignore_all_space_flag = FALSE; - length_varies = FALSE; - ignore_case_flag = FALSE; - ignore_blank_lines_flag = FALSE; - ignore_regexp_list = NULL; - function_regexp_list = NULL; - print_file_same_flag = FALSE; - entire_new_file_flag = FALSE; - unidirectional_new_file_flag = FALSE; - no_details_flag = FALSE; context = -1; - line_end_char = '\n'; - tab_align_flag = FALSE; - tab_expand_flag = FALSE; - recursive = FALSE; - paginate_flag = FALSE; - heuristic = FALSE; - dir_start_file = NULL; - msg_chain = NULL; - msg_chain_end = NULL; - no_discards = 0; /* Decode the options. */ while ((c = getopt_long (argc, argv, "0123456789abBcC:dD:efF:hHiI:lL:nNpPqrsS:tTuU:vwW:x:X:y", - longopts, (int *)0)) != EOF) + longopts, 0)) != EOF) { switch (c) { @@ -285,14 +277,16 @@ main (argc, argv) break; case 'b': - /* Ignore changes in amount of whitespace. */ + /* Ignore changes in amount of white space. */ ignore_space_change_flag = 1; - length_varies = 1; + ignore_some_changes = 1; + ignore_some_line_changes = 1; break; case 'B': /* Ignore changes affecting only blank lines. */ ignore_blank_lines_flag = 1; + ignore_some_changes = 1; break; case 'C': /* +context[=lines] */ @@ -323,7 +317,7 @@ main (argc, argv) specify_style (OUTPUT_IFDEF); { int i, err = 0; - static const char C_ifdef_group_formats[] = + static char const C_ifdef_group_formats[] = "#ifndef %s\n%%<#endif /* not %s */\n%c#ifdef %s\n%%>#endif /* %s */\n%c%%=%c#ifndef %s\n%%<#else /* %s */\n%%>#endif /* %s */\n"; char *b = xmalloc (sizeof (C_ifdef_group_formats) + 7 * strlen(optarg) - 14 /* 7*"%s" */ @@ -376,17 +370,28 @@ main (argc, argv) case 'i': /* Ignore changes in case. */ ignore_case_flag = 1; + ignore_some_changes = 1; + ignore_some_line_changes = 1; break; case 'I': /* Ignore changes affecting only lines that match the specified regexp. */ add_regexp (&ignore_regexp_list, optarg); + ignore_some_changes = 1; break; case 'l': /* Pass the output through `pr' to paginate it. */ paginate_flag = 1; +#if !defined(SIGCHLD) && defined(SIGCLD) +#define SIGCHLD SIGCLD +#endif +#ifdef SIGCHLD + /* Pagination requires forking and waiting, and + System V fork+wait does not work if SIGCHLD is ignored. */ + signal (SIGCHLD, SIG_DFL); +#endif break; case 'L': @@ -398,7 +403,7 @@ main (argc, argv) else fatal ("too many file label options"); break; - + case 'n': /* Output RCS-style diffs, like `-f' except that each command specifies the number of lines affected. */ @@ -413,7 +418,7 @@ main (argc, argv) case 'p': /* Make context-style output and show name of last C function. */ - specify_style (OUTPUT_CONTEXT); + show_c_function = 1; add_regexp (&function_regexp_list, "^[_a-zA-Z$]"); break; @@ -429,7 +434,7 @@ main (argc, argv) break; case 'r': - /* When comparing directories, + /* When comparing directories, recursively compare any subdirectories found. */ recursive = 1; break; @@ -464,13 +469,14 @@ main (argc, argv) break; case 'v': - fprintf (stderr, "GNU diff version %s\n", version_string); - break; + printf ("diff - GNU diffutils version %s\n", version_string); + exit (0); case 'w': - /* Ignore horizontal whitespace when comparing lines. */ + /* Ignore horizontal white space when comparing lines. */ ignore_all_space_flag = 1; - length_varies = 1; + ignore_some_changes = 1; + ignore_some_line_changes = 1; break; case 'x': @@ -492,15 +498,15 @@ main (argc, argv) if (ck_atoi (optarg, &width) || width <= 0) fatal ("column width must be a positive integer"); break; - + case 129: sdiff_left_only = 1; break; - + case 130: sdiff_skip_common_lines = 1; break; - + case 131: /* sdiff-style columns output. */ specify_style (OUTPUT_SDIFF); @@ -511,40 +517,57 @@ main (argc, argv) case 133: case 134: specify_style (OUTPUT_IFDEF); + if (specify_format (&line_format[c - 132], optarg) != 0) + error ("conflicting line format", 0, 0); + break; + + case 135: + specify_style (OUTPUT_IFDEF); { - const char **form = &line_format[c - 132]; - if (*form && strcmp (*form, optarg) != 0) + int i, err = 0; + for (i = 0; i < sizeof (line_format) / sizeof (*line_format); i++) + err |= specify_format (&line_format[i], optarg); + if (err) error ("conflicting line format", 0, 0); - *form = optarg; } break; - case 135: case 136: case 137: case 138: + case 139: specify_style (OUTPUT_IFDEF); - { - const char **form = &group_format[c - 135]; - if (*form && strcmp (*form, optarg) != 0) - error ("conflicting group format", 0, 0); - *form = optarg; - } + if (specify_format (&group_format[c - 136], optarg) != 0) + error ("conflicting group format", 0, 0); break; - case 139: + case 140: if (ck_atoi (optarg, &horizon_lines) || horizon_lines < 0) fatal ("horizon must be a nonnegative integer"); break; - default: + case 141: usage (); + check_stdout (); + exit (0); + + case 142: + /* Use binary I/O when reading and writing data. + On Posix hosts, this has no effect. */ +#if HAVE_SETMODE + binary_I_O = 1; + setmode (STDOUT_FILENO, O_BINARY); +#endif + break; + + default: + try_help (0); } prev = c; } - if (optind != argc - 2) - usage (); + if (argc - optind != 2) + try_help (argc - optind < 2 ? "missing operand" : "extra operand"); { @@ -564,14 +587,21 @@ main (argc, argv) sdiff_column2_offset = sdiff_half_width ? off : width; } + if (show_c_function && output_style != OUTPUT_UNIFIED) + specify_style (OUTPUT_CONTEXT); + if (output_style != OUTPUT_CONTEXT && output_style != OUTPUT_UNIFIED) context = 0; else if (context == -1) /* Default amount of context for -c. */ context = 3; - + if (output_style == OUTPUT_IFDEF) { + /* Format arrays are char *, not char const *, + because integer formats are temporarily modified. + But it is safe to assign a constant like "%=" to a format array, + since "%=" does not format any integers. */ int i; for (i = 0; i < sizeof (line_format) / sizeof (*line_format); i++) if (!line_format[i]) @@ -598,13 +628,12 @@ main (argc, argv) switch_string = option_list (argv + 1, optind - 1); - val = compare_files (NULL, argv[optind], NULL, argv[optind + 1], 0); + val = compare_files (0, argv[optind], 0, argv[optind + 1], 0); /* Print any messages that were saved up for last. */ print_message_queue (); - if (ferror (stdout) || fclose (stdout) != 0) - fatal ("write error"); + check_stdout (); exit (val); return val; } @@ -614,14 +643,14 @@ main (argc, argv) static void add_regexp (reglist, pattern) struct regexp_list **reglist; - char *pattern; + char const *pattern; { struct regexp_list *r; - const char *m; + char const *m; r = (struct regexp_list *) xmalloc (sizeof (*r)); bzero (r, sizeof (*r)); - r->buf.fastmap = (char *) xmalloc (256); + r->buf.fastmap = xmalloc (256); m = re_compile_pattern (pattern, strlen (pattern), &r->buf); if (m != 0) error ("%s: %s", pattern, m); @@ -632,37 +661,102 @@ add_regexp (reglist, pattern) } static void -usage () +try_help (reason) + char const *reason; { - fprintf (stderr, "Usage: %s [options] from-file to-file\n", program); - fprintf (stderr, "Options:\n\ - [-abBcdefhHilnNpPqrstTuvwy] [-C lines] [-D name] [-F regexp]\n\ - [-I regexp] [-L from-label [-L to-label]] [-S starting-file] [-U lines]\n\ - [-W columns] [-x pattern] [-X pattern-file] [--exclude=pattern]\n\ - [--exclude-from=pattern-file] [--ignore-blank-lines] [--context[=lines]]\n\ - [--ifdef=name] [--show-function-line=regexp] [--speed-large-files]\n\ - [--label=from-label [--label=to-label]] [--new-file]\n"); - fprintf (stderr, "\ - [--ignore-matching-lines=regexp] [--unidirectional-new-file]\n\ - [--starting-file=starting-file] [--initial-tab] [--width=columns]\n\ - [--text] [--ignore-space-change] [--minimal] [--ed] [--forward-ed]\n\ - [--ignore-case] [--paginate] [--rcs] [--show-c-function] [--brief]\n\ - [--recursive] [--report-identical-files] [--expand-tabs] [--version]\n"); - fprintf (stderr, "\ - [--ignore-all-space] [--side-by-side] [--unified[=lines]]\n\ - [--left-column] [--suppress-common-lines] [--sdiff-merge-assist]\n\ - [--old-line-format=format] [--new-line-format=format]\n\ - [--unchanged-line-format=format]\n\ - [--old-group-format=format] [--new-group-format=format]\n\ - [--unchanged-group-format=format] [--changed-group-format=format]\n\ - [--horizon-lines=lines]\n"); + if (reason) + error ("%s", reason, 0); + error ("Try `%s --help' for more information.", program_name, 0); exit (2); -} +} + +static void +check_stdout () +{ + if (ferror (stdout) || fclose (stdout) != 0) + fatal ("write error"); +} + +static char const * const option_help[] = { +"-i --ignore-case Consider upper- and lower-case to be the same.", +"-w --ignore-all-space Ignore all white space.", +"-b --ignore-space-change Ignore changes in the amount of white space.", +"-B --ignore-blank-lines Ignore changes whose lines are all blank.", +"-I RE --ignore-matching-lines=RE Ignore changes whose lines all match RE.", +#if HAVE_SETMODE +"--binary Read and write data in binary mode.", +#endif +"-a --text Treat all files as text.\n", +"-c -C NUM --context[=NUM] Output NUM (default 2) lines of copied context.", +"-u -U NUM --unified[=NUM] Output NUM (default 2) lines of unified context.", +" -NUM Use NUM context lines.", +" -L LABEL --label LABEL Use LABEL instead of file name.", +" -p --show-c-function Show which C function each change is in.", +" -F RE --show-function-line=RE Show the most recent line matching RE.", +"-q --brief Output only whether files differ.", +"-e --ed Output an ed script.", +"-n --rcs Output an RCS format diff.", +"-y --side-by-side Output in two columns.", +" -w NUM --width=NUM Output at most NUM (default 130) characters per line.", +" --left-column Output only the left column of common lines.", +" --suppress-common-lines Do not output common lines.", +"-DNAME --ifdef=NAME Output merged file to show `#ifdef NAME' diffs.", +"--GTYPE-group-format=GFMT Similar, but format GTYPE input groups with GFMT.", +"--line-format=LFMT Similar, but format all input lines with LFMT.", +"--LTYPE-line-format=LFMT Similar, but format LTYPE input lines with LFMT.", +" LTYPE is `old', `new', or `unchanged'. GTYPE is LTYPE or `changed'.", +" GFMT may contain:", +" %< lines from FILE1", +" %> lines from FILE2", +" %= lines common to FILE1 and FILE2", +" %[-][WIDTH][.[PREC]]{doxX}LETTER printf-style spec for LETTER", +" LETTERs are as follows for new group, lower case for old group:", +" F first line number", +" L last line number", +" N number of lines = L-F+1", +" E F-1", +" M L+1", +" LFMT may contain:", +" %L contents of line", +" %l contents of line, excluding any trailing newline", +" %[-][WIDTH][.[PREC]]{doxX}n printf-style spec for input line number", +" Either GFMT or LFMT may contain:", +" %% %", +" %c'C' the single character C", +" %c'\\OOO' the character with octal code OOO\n", +"-l --paginate Pass the output through `pr' to paginate it.", +"-t --expand-tabs Expand tabs to spaces in output.", +"-T --initial-tab Make tabs line up by prepending a tab.\n", +"-r --recursive Recursively compare any subdirectories found.", +"-N --new-file Treat absent files as empty.", +"-P --unidirectional-new-file Treat absent first files as empty.", +"-s --report-identical-files Report when two files are the same.", +"-x PAT --exclude=PAT Exclude files that match PAT.", +"-X FILE --exclude-from=FILE Exclude files that match any pattern in FILE.", +"-S FILE --starting-file=FILE Start with FILE when comparing directories.\n", +"--horizon-lines=NUM Keep NUM lines of the common prefix and suffix.", +"-d --minimal Try hard to find a smaller set of changes.", +"-H --speed-large-files Assume large files and many scattered small changes.\n", +"-v --version Output version info.", +"--help Output this help.", +0 +}; + +static void +usage () +{ + char const * const *p; + + printf ("Usage: %s [OPTION]... FILE1 FILE2\n\n", program_name); + for (p = option_help; *p; p++) + printf (" %s\n", *p); + printf ("\nIf FILE1 or FILE2 is `-', read standard input.\n"); +} static int specify_format (var, value) - const char **var; - const char *value; + char **var; + char *value; { int err = *var ? strcmp (*var, value) : 0; *var = value; @@ -679,6 +773,57 @@ specify_style (style) output_style = style; } +static char const * +filetype (st) + struct stat const *st; +{ + /* See Posix.2 section 4.17.6.1.1 and Table 5-1 for these formats. + To keep diagnostics grammatical, the returned string must start + with a consonant. */ + + if (S_ISREG (st->st_mode)) + { + if (st->st_size == 0) + return "regular empty file"; + /* Posix.2 section 5.14.2 seems to suggest that we must read the file + and guess whether it's C, Fortran, etc., but this is somewhat useless + and doesn't reflect historical practice. We're allowed to guess + wrong, so we don't bother to read the file. */ + return "regular file"; + } + if (S_ISDIR (st->st_mode)) return "directory"; + + /* other Posix.1 file types */ +#ifdef S_ISBLK + if (S_ISBLK (st->st_mode)) return "block special file"; +#endif +#ifdef S_ISCHR + if (S_ISCHR (st->st_mode)) return "character special file"; +#endif +#ifdef S_ISFIFO + if (S_ISFIFO (st->st_mode)) return "fifo"; +#endif + + /* other Posix.1b file types */ +#ifdef S_TYPEISMQ + if (S_TYPEISMQ (st)) return "message queue"; +#endif +#ifdef S_TYPEISSEM + if (S_TYPEISSEM (st)) return "semaphore"; +#endif +#ifdef S_TYPEISSHM + if (S_TYPEISSHM (st)) return "shared memory object"; +#endif + + /* other popular file types */ + /* S_ISLNK is impossible with `fstat' and `stat'. */ +#ifdef S_ISSOCK + if (S_ISSOCK (st->st_mode)) return "socket"; +#endif + + return "weird file"; +} + /* Compare two files (or dirs) with specified names DIR0/NAME0 and DIR1/NAME1, at level DEPTH in directory recursion. (if DIR0 is 0, then the name is just NAME0, etc.) @@ -689,15 +834,16 @@ specify_style (style) static int compare_files (dir0, name0, dir1, name1, depth) - char *dir0, *dir1; - char *name0, *name1; + char const *dir0, *dir1; + char const *name0, *name1; int depth; { struct file_data inf[2]; register int i; int val; int same_files; - int errorcount = 0; + int failed = 0; + char *free0 = 0, *free1 = 0; /* If this is directory comparison, perhaps we have a file that exists only in one of the directories. @@ -707,15 +853,17 @@ compare_files (dir0, name0, dir1, name1, depth) || (unidirectional_new_file_flag && name1 != 0) || entire_new_file_flag)) { - char *name = name0 == 0 ? name1 : name0; - char *dir = name0 == 0 ? dir1 : dir0; + char const *name = name0 == 0 ? name1 : name0; + char const *dir = name0 == 0 ? dir1 : dir0; message ("Only in %s: %s\n", dir, name); /* Return 1 so that diff_dirs will return 1 ("some files differ"). */ return 1; } + bzero (inf, sizeof (inf)); + /* Mark any nonexistent file with -1 in the desc field. */ - /* Mark unopened files (i.e. directories) with -2. */ + /* Mark unopened files (e.g. directories) with -2. */ inf[0].desc = name0 == 0 ? -1 : -2; inf[1].desc = name1 == 0 ? -1 : -2; @@ -727,25 +875,41 @@ compare_files (dir0, name0, dir1, name1, depth) if (name1 == 0) name1 = name0; - inf[0].name = dir0 == 0 ? name0 : concat (dir0, "/", name0); - inf[1].name = dir1 == 0 ? name1 : concat (dir1, "/", name1); + inf[0].name = dir0 == 0 ? name0 : (free0 = dir_file_pathname (dir0, name0)); + inf[1].name = dir1 == 0 ? name1 : (free1 = dir_file_pathname (dir1, name1)); /* Stat the files. Record whether they are directories. */ for (i = 0; i <= 1; i++) { - bzero (&inf[i].stat, sizeof (struct stat)); - inf[i].dir_p = 0; - if (inf[i].desc != -1) { int stat_result; - if (strcmp (inf[i].name, "-") == 0) + if (i && filename_cmp (inf[i].name, inf[0].name) == 0) { - inf[i].desc = 0; - inf[i].name = "Standard Input"; - stat_result = fstat (0, &inf[i].stat); + inf[i].stat = inf[0].stat; + stat_result = 0; + } + else if (strcmp (inf[i].name, "-") == 0) + { + inf[i].desc = STDIN_FILENO; + stat_result = fstat (STDIN_FILENO, &inf[i].stat); + if (stat_result == 0 && S_ISREG (inf[i].stat.st_mode)) + { + off_t pos = lseek (STDIN_FILENO, (off_t) 0, SEEK_CUR); + if (pos == -1) + stat_result = -1; + else + { + if (pos <= inf[i].stat.st_size) + inf[i].stat.st_size -= pos; + else + inf[i].stat.st_size = 0; + /* Posix.2 4.17.6.1.4 requires current time for stdin. */ + time (&inf[i].stat.st_mtime); + } + } } else stat_result = stat (inf[i].name, &inf[i].stat); @@ -753,42 +917,46 @@ compare_files (dir0, name0, dir1, name1, depth) if (stat_result != 0) { perror_with_name (inf[i].name); - errorcount = 1; + failed = 1; } else - inf[i].dir_p = S_ISDIR (inf[i].stat.st_mode) && inf[i].desc != 0; + { + inf[i].dir_p = S_ISDIR (inf[i].stat.st_mode) && inf[i].desc != 0; + if (inf[1 - i].desc == -1) + { + inf[1 - i].dir_p = inf[i].dir_p; + inf[1 - i].stat.st_mode = inf[i].stat.st_mode; + } + } } } - if (name0 == 0) - inf[0].dir_p = inf[1].dir_p; - if (name1 == 0) - inf[1].dir_p = inf[0].dir_p; - - if (errorcount == 0 && depth == 0 && inf[0].dir_p != inf[1].dir_p) + if (! failed && depth == 0 && inf[0].dir_p != inf[1].dir_p) { /* If one is a directory, and it was specified in the command line, use the file in that dir with the other file's basename. */ int fnm_arg = inf[0].dir_p; int dir_arg = 1 - fnm_arg; - char *p = rindex (inf[fnm_arg].name, '/'); - char *filename = inf[dir_arg].name - = concat (inf[dir_arg].name, "/", (p ? p+1 : inf[fnm_arg].name)); + char const *fnm = inf[fnm_arg].name; + char const *dir = inf[dir_arg].name; + char const *p = filename_lastdirchar (fnm); + char const *filename = inf[dir_arg].name + = dir_file_pathname (dir, p ? p + 1 : fnm); - if (inf[fnm_arg].desc == 0) + if (strcmp (fnm, "-") == 0) fatal ("can't compare - to a directory"); if (stat (filename, &inf[dir_arg].stat) != 0) { perror_with_name (filename); - errorcount = 1; + failed = 1; } else inf[dir_arg].dir_p = S_ISDIR (inf[dir_arg].stat.st_mode); } - if (errorcount) + if (failed) { /* If either file should exist but does not, return 2. */ @@ -796,10 +964,8 @@ compare_files (dir0, name0, dir1, name1, depth) val = 2; } - else if ((same_files = inf[0].stat.st_ino == inf[1].stat.st_ino - && inf[0].stat.st_dev == inf[1].stat.st_dev - && inf[0].desc != -1 - && inf[1].desc != -1) + else if ((same_files = inf[0].desc != -1 && inf[1].desc != -1 + && 0 < same_file (&inf[0].stat, &inf[1].stat)) && no_diff_means_no_output) { /* The two named files are actually the same physical file. @@ -828,37 +994,43 @@ compare_files (dir0, name0, dir1, name1, depth) } } - else if (inf[0].dir_p | inf[1].dir_p) + else if ((inf[0].dir_p | inf[1].dir_p) + || (depth > 0 + && (! S_ISREG (inf[0].stat.st_mode) + || ! S_ISREG (inf[1].stat.st_mode)))) { /* Perhaps we have a subdirectory that exists only in one directory. If so, just print a message to that effect. */ if (inf[0].desc == -1 || inf[1].desc == -1) { - if (recursive + if ((inf[0].dir_p | inf[1].dir_p) + && recursive && (entire_new_file_flag || (unidirectional_new_file_flag && inf[0].desc == -1))) val = diff_dirs (inf, compare_files, depth); else { - char *dir = (inf[0].desc == -1) ? dir1 : dir0; + char const *dir = (inf[0].desc == -1) ? dir1 : dir0; + /* See Posix.2 section 4.17.6.1.1 for this format. */ message ("Only in %s: %s\n", dir, name0); val = 1; } } else { - /* We have a subdirectory in one directory - and a file in the other. */ + /* We have two files that are not to be compared. */ - message ("%s is a directory but %s is not\n", - inf[1 - inf[0].dir_p].name, inf[inf[0].dir_p].name); + /* See Posix.2 section 4.17.6.1.1 for this format. */ + message5 ("File %s is a %s while file %s is a %s\n", + inf[0].name, filetype (&inf[0].stat), + inf[1].name, filetype (&inf[1].stat)); /* This is a difference. */ val = 1; } } - else if (no_details_flag + else if ((no_details_flag & ~ignore_some_changes) && inf[0].stat.st_size != inf[1].stat.st_size && (inf[0].desc == -1 || S_ISREG (inf[0].stat.st_mode)) && (inf[1].desc == -1 || S_ISREG (inf[1].stat.st_mode))) @@ -876,7 +1048,7 @@ compare_files (dir0, name0, dir1, name1, depth) if ((inf[0].desc = open (inf[0].name, O_RDONLY, 0)) < 0) { perror_with_name (inf[0].name); - errorcount = 1; + failed = 1; } if (inf[1].desc == -2) if (same_files) @@ -884,12 +1056,19 @@ compare_files (dir0, name0, dir1, name1, depth) else if ((inf[1].desc = open (inf[1].name, O_RDONLY, 0)) < 0) { perror_with_name (inf[1].name); - errorcount = 1; + failed = 1; } - + +#if HAVE_SETMODE + if (binary_I_O) + for (i = 0; i <= 1; i++) + if (0 <= inf[i].desc) + setmode (inf[i].desc, O_BINARY); +#endif + /* Compare the files, if no error was found. */ - val = errorcount ? 2 : diff_2_files (inf, depth); + val = failed ? 2 : diff_2_files (inf, depth); /* Close the file descriptors. */ @@ -918,10 +1097,10 @@ compare_files (dir0, name0, dir1, name1, depth) else fflush (stdout); - if (dir0 != 0) - free (inf[0].name); - if (dir1 != 0) - free (inf[1].name); + if (free0) + free (free0); + if (free1) + free (free1); return val; } diff --git a/gnu/usr.bin/diff/diff.h b/gnu/usr.bin/diff/diff.h index 74f025d..66c6940 100644 --- a/gnu/usr.bin/diff/diff.h +++ b/gnu/usr.bin/diff/diff.h @@ -1,5 +1,5 @@ /* Shared definitions for GNU DIFF - Copyright (C) 1988, 89, 91, 92 Free Software Foundation, Inc. + Copyright (C) 1988, 89, 91, 92, 93 Free Software Foundation, Inc. This file is part of GNU DIFF. @@ -17,22 +17,10 @@ You should have received a copy of the GNU General Public License along with GNU DIFF; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <ctype.h> -#include <stdio.h> #include "system.h" +#include <stdio.h> #include "regex.h" -#ifndef PR_FILE_NAME -#define PR_FILE_NAME "/bin/pr" -#endif - -/* Character classes. */ -extern const char textchar[]; - -/* Is_space is a little broader than ctype.h's isspace, - because it also includes backspace and no-break space. */ -#define Is_space(c) (textchar[c] & 2) - #define TAB_WIDTH 8 /* Variables for command line options */ @@ -82,18 +70,22 @@ EXTERN int always_text_flag; /* Number of lines to keep in identical prefix and suffix. */ EXTERN int horizon_lines; -/* Ignore changes in horizontal whitespace (-b). */ +/* Ignore changes in horizontal white space (-b). */ EXTERN int ignore_space_change_flag; -/* Ignore all horizontal whitespace (-w). */ +/* Ignore all horizontal white space (-w). */ EXTERN int ignore_all_space_flag; /* Ignore changes that affect only blank lines (-B). */ EXTERN int ignore_blank_lines_flag; -/* 1 if lines may match even if their lengths are different. +/* 1 if lines may match even if their contents do not match exactly. + This depends on various options. */ +EXTERN int ignore_some_line_changes; + +/* 1 if files may match even if their contents are not byte-for-byte identical. This depends on various options. */ -EXTERN int length_varies; +EXTERN int ignore_some_changes; /* Ignore differences in case of letters (-i). */ EXTERN int ignore_case_flag; @@ -120,9 +112,6 @@ EXTERN int no_details_flag; Normally nothing is output when that happens. */ EXTERN int print_file_same_flag; -/* character that ends a line. Currently this is always `\n'. */ -EXTERN char line_end_char; - /* Output the differences with exactly 8 columns added to each line so that any tabs in the text line up properly (-T). */ EXTERN int tab_align_flag; @@ -160,13 +149,13 @@ enum line_class { }; /* Line group formats for old, new, unchanged, and changed groups. */ -EXTERN const char *group_format[CHANGED + 1]; +EXTERN char *group_format[CHANGED + 1]; /* Line formats for old, new, and unchanged lines. */ -EXTERN const char *line_format[UNCHANGED + 1]; +EXTERN char *line_format[UNCHANGED + 1]; /* If using OUTPUT_SDIFF print extra information to help the sdiff filter. */ -EXTERN int sdiff_help_sdiff; +EXTERN int sdiff_help_sdiff; /* Tell OUTPUT_SDIFF to show only the left version of common lines. */ EXTERN int sdiff_left_only; @@ -187,12 +176,12 @@ EXTERN char * switch_string; EXTERN int heuristic; /* Name of program the user invoked (for error messages). */ -EXTERN char * program; +EXTERN char *program_name; /* The result of comparison is an "edit script": a chain of `struct change'. Each `struct change' represents one place where some lines are deleted and some are inserted. - + LINE0 and LINE1 are the first affected lines in the two files (origin 0). DELETED is the number of lines deleted here from file 0. INSERTED is the number of lines inserted here in file 1. @@ -216,19 +205,19 @@ struct change struct file_data { int desc; /* File descriptor */ - char *name; /* File name */ + char const *name; /* File name */ struct stat stat; /* File status from fstat() */ int dir_p; /* nonzero if file is a directory */ /* Buffer in which text of file is read. */ char * buffer; /* Allocated size of buffer. */ - int bufsize; + size_t bufsize; /* Number of valid characters now in the buffer. */ - int buffered_chars; + size_t buffered_chars; /* Array of pointers to lines in the file. */ - const char **linbuf; + char const **linbuf; /* linbuf_base <= buffered_lines <= valid_lines <= alloc_lines. linebuf[linbuf_base ... buffered_lines - 1] are possibly differing. @@ -237,14 +226,14 @@ struct file_data { int linbuf_base, buffered_lines, valid_lines, alloc_lines; /* Pointer to end of prefix of this file to ignore when hashing. */ - const char *prefix_end; + char const *prefix_end; /* Count of lines in the prefix. There are this many lines in the file before linbuf[0]. */ int prefix_lines; /* Pointer to start of suffix of this file to ignore when hashing. */ - const char *suffix_begin; + char const *suffix_begin; /* Vector, indexed by line number, containing an equivalence code for each line. It is this vector that is actually compared with that @@ -279,57 +268,73 @@ struct file_data { EXTERN struct file_data files[2]; -/* Queue up one-line messages to be printed at the end, - when -l is specified. Each message is recorded with a `struct msg'. */ - -struct msg -{ - struct msg *next; - char *format; - char *arg1; - char *arg2; -}; - -/* Head of the chain of queues messages. */ - -EXTERN struct msg *msg_chain; - -/* Tail of the chain of queues messages. */ - -EXTERN struct msg *msg_chain_end; - /* Stdio stream to output diffs to. */ EXTERN FILE *outfile; /* Declare various functions. */ -#if __STDC__ -#define VOID void -#else -#define VOID char -#endif -VOID *xmalloc (); -VOID *xrealloc (); -char *concat (); - -int excluded_filename (); -int sip (); - -struct change *find_change (); - -void analyze_hunk (); -void begin_output (); -void error (); -void fatal (); -void message (); -void output_1_line (); -void perror_with_name (); -void pfatal_with_name (); -void print_1_line (); -void print_context_header (); -void print_message_queue (); -void print_number_range (); -void print_script (); -void slurp (); -void translate_range (); +/* analyze.c */ +int diff_2_files PARAMS((struct file_data[], int)); + +/* context.c */ +void print_context_header PARAMS((struct file_data[], int)); +void print_context_script PARAMS((struct change *, int)); + +/* diff.c */ +int excluded_filename PARAMS((char const *)); + +/* dir.c */ +int diff_dirs PARAMS((struct file_data const[], int (*) PARAMS((char const *, char const *, char const *, char const *, int)), int)); + +/* ed.c */ +void print_ed_script PARAMS((struct change *)); +void pr_forward_ed_script PARAMS((struct change *)); + +/* ifdef.c */ +void print_ifdef_script PARAMS((struct change *)); + +/* io.c */ +int read_files PARAMS((struct file_data[], int)); +int sip PARAMS((struct file_data *, int)); +void slurp PARAMS((struct file_data *)); + +/* normal.c */ +void print_normal_script PARAMS((struct change *)); + +/* rcs.c */ +void print_rcs_script PARAMS((struct change *)); + +/* side.c */ +void print_sdiff_script PARAMS((struct change *)); + +/* util.c */ +VOID *xmalloc PARAMS((size_t)); +VOID *xrealloc PARAMS((VOID *, size_t)); +char *concat PARAMS((char const *, char const *, char const *)); +char *dir_file_pathname PARAMS((char const *, char const *)); +int change_letter PARAMS((int, int)); +int line_cmp PARAMS((char const *, char const *)); +int translate_line_number PARAMS((struct file_data const *, int)); +struct change *find_change PARAMS((struct change *)); +struct change *find_reverse_change PARAMS((struct change *)); +void analyze_hunk PARAMS((struct change *, int *, int *, int *, int *, int *, int *)); +void begin_output PARAMS((void)); +void debug_script PARAMS((struct change *)); +void error PARAMS((char const *, char const *, char const *)); +void fatal PARAMS((char const *)); +void finish_output PARAMS((void)); +void message PARAMS((char const *, char const *, char const *)); +void message5 PARAMS((char const *, char const *, char const *, char const *, char const *)); +void output_1_line PARAMS((char const *, char const *, char const *, char const *)); +void perror_with_name PARAMS((char const *)); +void pfatal_with_name PARAMS((char const *)); +void print_1_line PARAMS((char const *, char const * const *)); +void print_message_queue PARAMS((void)); +void print_number_range PARAMS((int, struct file_data *, int, int)); +void print_script PARAMS((struct change *, struct change * (*) PARAMS((struct change *)), void (*) PARAMS((struct change *)))); +void setup_output PARAMS((char const *, char const *, int)); +void translate_range PARAMS((struct file_data const *, int, int, int *, int *)); + +/* version.c */ +extern char const version_string[]; diff --git a/gnu/usr.bin/diff/diff3.c b/gnu/usr.bin/diff/diff3.c index b9952fc..5d94ab8 100644 --- a/gnu/usr.bin/diff/diff3.c +++ b/gnu/usr.bin/diff/diff3.c @@ -1,5 +1,5 @@ /* Three way file comparison program (diff3) for Project GNU. - Copyright (C) 1988, 1989, 1992 Free Software Foundation, Inc. + Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,16 +17,12 @@ /* Written by Randy Smith */ -#if __STDC__ -#define VOID void -#else -#define VOID char -#endif - +#include "system.h" #include <stdio.h> -#include <ctype.h> +#include <signal.h> #include "getopt.h" -#include "system.h" + +extern char const version_string[]; /* * Internal data structures and macros for the diff3 program; includes @@ -70,7 +66,7 @@ enum diff_type { struct diff_block { int ranges[2][2]; /* Ranges are inclusive */ char **lines[2]; /* The actual lines (may contain nulls) */ - int *lengths[2]; /* Line lengths (including newlines, if any) */ + size_t *lengths[2]; /* Line lengths (including newlines, if any) */ struct diff_block *next; }; @@ -80,7 +76,7 @@ struct diff3_block { enum diff_type correspond; /* Type of diff */ int ranges[3][2]; /* Ranges are inclusive */ char **lines[3]; /* The actual lines (may contain nulls) */ - int *lengths[3]; /* Line lengths (including newlines, if any) */ + size_t *lengths[3]; /* Line lengths (including newlines, if any) */ struct diff3_block *next; }; @@ -158,6 +154,9 @@ static int flagging; /* Number of lines to keep in identical prefix and suffix. */ static int horizon_lines = 10; +/* Use a tab to align output lines (-T). */ +static int tab_align_flag; + /* If nonzero, do not output information for overlapping diffs. */ static int simple_only; @@ -174,48 +173,48 @@ static int finalwrite; /* If nonzero, output a merged file. */ static int merge; -static char *argv0; - -/* - * Forward function declarations. - */ -static int myread (); -static void fatal (); -static void perror_with_exit (); -static struct diff_block *process_diff (); -static struct diff3_block *make_3way_diff (); -static void output_diff3 (); -static int output_diff3_edscript (); -static int output_diff3_merge (); -static void usage (); - -static struct diff3_block *using_to_diff3_block (); -static int copy_stringlist (); -static struct diff3_block *create_diff3_block (); -static int compare_line_list (); - -static char *read_diff (); -static enum diff_type process_diff_control (); -static char *scan_diff_line (); - -static struct diff3_block *reverse_diff3_blocklist (); - -VOID *xmalloc (); -static VOID *xrealloc (); - -static char diff_program[] = DIFF_PROGRAM; - -static struct option longopts[] = +static char *program_name; + +static VOID *xmalloc PARAMS((size_t)); +static VOID *xrealloc PARAMS((VOID *, size_t)); + +static char *read_diff PARAMS((char const *, char const *, char **)); +static char *scan_diff_line PARAMS((char *, char **, size_t *, char *, int)); +static enum diff_type process_diff_control PARAMS((char **, struct diff_block *)); +static int compare_line_list PARAMS((char * const[], size_t const[], char * const[], size_t const[], int)); +static int copy_stringlist PARAMS((char * const[], size_t const[], char *[], size_t[], int)); +static int dotlines PARAMS((FILE *, struct diff3_block *, int)); +static int output_diff3_edscript PARAMS((FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *)); +static int output_diff3_merge PARAMS((FILE *, FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *)); +static size_t myread PARAMS((int, char *, size_t)); +static struct diff3_block *create_diff3_block PARAMS((int, int, int, int, int, int)); +static struct diff3_block *make_3way_diff PARAMS((struct diff_block *, struct diff_block *)); +static struct diff3_block *reverse_diff3_blocklist PARAMS((struct diff3_block *)); +static struct diff3_block *using_to_diff3_block PARAMS((struct diff_block *[2], struct diff_block *[2], int, int, struct diff3_block const *)); +static struct diff_block *process_diff PARAMS((char const *, char const *, struct diff_block **)); +static void check_stdout PARAMS((void)); +static void fatal PARAMS((char const *)); +static void output_diff3 PARAMS((FILE *, struct diff3_block *, int const[3], int const[3])); +static void perror_with_exit PARAMS((char const *)); +static void try_help PARAMS((char const *)); +static void undotlines PARAMS((FILE *, int, int, int)); +static void usage PARAMS((void)); + +static char const diff_program[] = DIFF_PROGRAM; + +static struct option const longopts[] = { - {"text", 0, NULL, 'a'}, - {"show-all", 0, NULL, 'A'}, - {"ed", 0, NULL, 'e'}, - {"show-overlap", 0, NULL, 'E'}, - {"label", 1, NULL, 'L'}, - {"merge", 0, NULL, 'm'}, - {"overlap-only", 0, NULL, 'x'}, - {"easy-only", 0, NULL, '3'}, - {"version", 0, NULL, 'v'}, + {"text", 0, 0, 'a'}, + {"show-all", 0, 0, 'A'}, + {"ed", 0, 0, 'e'}, + {"show-overlap", 0, 0, 'E'}, + {"label", 1, 0, 'L'}, + {"merge", 0, 0, 'm'}, + {"initial-tab", 0, 0, 'T'}, + {"overlap-only", 0, 0, 'x'}, + {"easy-only", 0, 0, '3'}, + {"version", 0, 0, 'v'}, + {"help", 0, 0, 129}, {0, 0, 0, 0} }; @@ -228,27 +227,23 @@ main (argc, argv) int argc; char **argv; { - extern char *version_string; int c, i; int mapping[3]; int rev_mapping[3]; - int incompat; + int incompat = 0; int conflicts_found; struct diff_block *thread0, *thread1, *last_block; struct diff3_block *diff3; int tag_count = 0; char *tag_strings[3]; - extern char *optarg; char *commonname; char **file; struct stat statb; - incompat = 0; - - argv0 = argv[0]; + initialize_main (&argc, &argv); + program_name = argv[0]; - while ((c = getopt_long (argc, argv, "aeimvx3AEXL:", longopts, (int *) 0)) - != EOF) + while ((c = getopt_long (argc, argv, "aeimvx3AEL:TX", longopts, 0)) != EOF) { switch (c) { @@ -283,9 +278,16 @@ main (argc, argv) case 'e': incompat++; break; - case 'v': - fprintf (stderr, "GNU diff3 version %s\n", version_string); + case 'T': + tab_align_flag = 1; break; + case 'v': + printf ("diff3 - GNU diffutils version %s\n", version_string); + exit (0); + case 129: + usage (); + check_stdout (); + exit (0); case 'L': /* Handle up to three -L options. */ if (tag_count < 3) @@ -293,10 +295,9 @@ main (argc, argv) tag_strings[tag_count++] = optarg; break; } - /* Falls through */ + try_help ("Too many labels were given. The limit is 3."); default: - usage (); - /* NOTREACHED */ + try_help (0); } } @@ -306,9 +307,11 @@ main (argc, argv) if (incompat > 1 /* Ensure at most one of -AeExX3. */ || finalwrite & merge /* -i -m would rewrite input file. */ - || (tag_count && ! flagging) /* -L requires one of -AEX. */ - || argc - optind != 3) - usage (); + || (tag_count && ! flagging)) /* -L requires one of -AEX. */ + try_help ("incompatible options"); + + if (argc - optind != 3) + try_help (argc - optind < 3 ? "missing operand" : "extra operand"); file = &argv[optind]; @@ -346,14 +349,24 @@ main (argc, argv) for (i = 0; i < 3; i++) if (strcmp (file[i], "-") != 0) - if (stat (file[i], &statb) < 0) - perror_with_exit (file[i]); - else if (S_ISDIR(statb.st_mode)) - { - fprintf (stderr, "%s: %s: Is a directory\n", argv0, file[i]); - exit (2); - } + { + if (stat (file[i], &statb) < 0) + perror_with_exit (file[i]); + else if (S_ISDIR(statb.st_mode)) + { + fprintf (stderr, "%s: %s: Is a directory\n", + program_name, file[i]); + exit (2); + } + } +#if !defined(SIGCHLD) && defined(SIGCLD) +#define SIGCHLD SIGCLD +#endif +#ifdef SIGCHLD + /* System V fork+wait does not work if SIGCHLD is ignored. */ + signal (SIGCHLD, SIG_DFL); +#endif commonname = file[rev_mapping[FILEC]]; thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block); @@ -385,26 +398,54 @@ main (argc, argv) conflicts_found = 0; } - if (ferror (stdout) || fclose (stdout) != 0) - fatal ("write error"); + check_stdout (); exit (conflicts_found); return conflicts_found; } +static void +try_help (reason) + char const *reason; +{ + if (reason) + fprintf (stderr, "%s: %s\n", program_name, reason); + fprintf (stderr, "%s: Try `%s --help' for more information.\n", + program_name, program_name); + exit (2); +} + +static void +check_stdout () +{ + if (ferror (stdout) || fclose (stdout) != 0) + fatal ("write error"); +} + /* - * Explain, patiently and kindly, how to use this program. Then exit. + * Explain, patiently and kindly, how to use this program. */ static void usage () { - fprintf (stderr, "\ -Usage: %s [options] my-file older-file your-file\n\ -Options:\n\ - [-exAEX3v] [-i|-m] [-L label1 [-L label2 [-L label3]]] [--text] [--ed]\n\ - [--merge] [--show-all] [--show-overlap] [--overlap-only] [--easy-only]\n\ - [--label=label1 [--label=label2 [--label=label3]]] [--version]\n\ - Only one of [exAEX3] is allowed\n", argv0); - exit (2); + printf ("Usage: %s [OPTION]... MYFILE OLDFILE YOURFILE\n\n", program_name); + + printf ("%s", "\ + -e --ed Output unmerged changes from OLDFILE to YOURFILE into MYFILE.\n\ + -E --show-overlap Output unmerged changes, bracketing conflicts.\n\ + -A --show-all Output all changes, bracketing conflicts.\n\ + -x --overlap-only Output overlapping changes.\n\ + -X Output overlapping changes, bracketing them.\n\ + -3 --easy-only Output unmerged nonoverlapping changes.\n\n"); + printf ("%s", "\ + -m --merge Output merged file instead of ed script (default -A).\n\ + -L LABEL --label=LABEL Use LABEL instead of file name.\n\ + -i Append `w' and `q' commands to ed scripts.\n\ + -a --text Treat all files as text.\n\ + -T --initial-tab Make tabs line up by prepending a tab.\n\n"); + printf ("%s", "\ + -v --version Output version info.\n\ + --help Output this help.\n\n"); + printf ("If a FILE is `-', read standard input.\n"); } /* @@ -436,7 +477,7 @@ Options:\n\ * Create a diff3_block, reserving space as indicated by the ranges. * * 3) Copy all of the pointers for file2 in. At least for now, - * do bcmp's between corresponding strings in the two diffs. + * do memcmp's between corresponding strings in the two diffs. * * 4) Copy all of the pointers for file0 and 1 in. Get what you * need from file2 (when there isn't a diff block, it's @@ -447,8 +488,8 @@ Options:\n\ * the common file in that diff) is the odd person out. If you used * diff blocks from both sets, check to see if files 0 and 1 match: * - * Same number of lines? If so, do a set of bcmp's (if a - * bcmp matches; copy the pointer over; it'll be easier later + * Same number of lines? If so, do a set of memcmp's (if a + * memcmp matches; copy the pointer over; it'll be easier later * if you have to do any compares). If they match, 0 & 1 are * the same. If not, all three different. * @@ -518,16 +559,11 @@ make_3way_diff (thread0, thread1) struct diff3_block *result, *tmpblock, - **result_end, - *last_diff3; + **result_end; + + struct diff3_block const *last_diff3; - static struct diff3_block zero_diff3 = { - ERROR, - { {0, 0}, {0, 0}, {0, 0} }, - { (char **) 0, (char **) 0, (char **) 0 }, - { (int *) 0, (int *) 0, (int *) 0 }, - (struct diff3_block *) 0 - }; + static struct diff3_block const zero_diff3; /* Initialization */ result = 0; @@ -539,8 +575,7 @@ make_3way_diff (thread0, thread1) while (current[0] || current[1]) { - using[0] = using[1] = last_using[0] = last_using[1] = - (struct diff_block *) 0; + using[0] = using[1] = last_using[0] = last_using[1] = 0; /* Setup low and high water threads, diffs, and marks. */ if (!current[0]) @@ -567,8 +602,7 @@ make_3way_diff (thread0, thread1) = last_using[high_water_thread] = high_water_diff; current[high_water_thread] = high_water_diff->next; - last_using[high_water_thread]->next - = (struct diff_block *) 0; + last_using[high_water_thread]->next = 0; /* And mark the other diff */ other_thread = high_water_thread ^ 0x1; @@ -591,10 +625,8 @@ make_3way_diff (thread0, thread1) /* Take it off the current list. Note that this following code assumes that other_diff enters it equal to current[high_water_thread ^ 0x1] */ - current[other_thread] - = current[other_thread]->next; - other_diff->next - = (struct diff_block *) 0; + current[other_thread] = current[other_thread]->next; + other_diff->next = 0; /* Set the high_water stuff If this comparison is equal, then this is the last pass @@ -660,7 +692,7 @@ using_to_diff3_block (using, last_using, low_thread, high_thread, last_diff3) *using[2], *last_using[2]; int low_thread, high_thread; - struct diff3_block *last_diff3; + struct diff3_block const *last_diff3; { int low[2], high[2]; struct diff3_block *result; @@ -780,21 +812,21 @@ using_to_diff3_block (using, last_using, low_thread, high_thread, last_diff3) */ static int copy_stringlist (fromptrs, fromlengths, toptrs, tolengths, copynum) - char *fromptrs[], *toptrs[]; - int *fromlengths, *tolengths; + char * const fromptrs[]; + char *toptrs[]; + size_t const fromlengths[]; + size_t tolengths[]; int copynum; { - register char - **f = fromptrs, - **t = toptrs; - register int - *fl = fromlengths, - *tl = tolengths; + register char * const *f = fromptrs; + register char **t = toptrs; + register size_t const *fl = fromlengths; + register size_t *tl = tolengths; while (copynum--) { if (*t) - { if (*fl != *tl || bcmp (*f, *t, *fl)) return 0; } + { if (*fl != *tl || memcmp (*f, *t, *fl)) return 0; } else { *t = *f ; *tl = *fl; } @@ -831,42 +863,42 @@ create_diff3_block (low0, high0, low1, high1, low2, high2) if (numlines) { D_LINEARRAY (result, FILE0) = ALLOCATE (numlines, char *); - D_LENARRAY (result, FILE0) = ALLOCATE (numlines, int); + D_LENARRAY (result, FILE0) = ALLOCATE (numlines, size_t); bzero (D_LINEARRAY (result, FILE0), (numlines * sizeof (char *))); - bzero (D_LENARRAY (result, FILE0), (numlines * sizeof (int))); + bzero (D_LENARRAY (result, FILE0), (numlines * sizeof (size_t))); } else { - D_LINEARRAY (result, FILE0) = (char **) 0; - D_LENARRAY (result, FILE0) = (int *) 0; + D_LINEARRAY (result, FILE0) = 0; + D_LENARRAY (result, FILE0) = 0; } numlines = D_NUMLINES (result, FILE1); if (numlines) { D_LINEARRAY (result, FILE1) = ALLOCATE (numlines, char *); - D_LENARRAY (result, FILE1) = ALLOCATE (numlines, int); + D_LENARRAY (result, FILE1) = ALLOCATE (numlines, size_t); bzero (D_LINEARRAY (result, FILE1), (numlines * sizeof (char *))); - bzero (D_LENARRAY (result, FILE1), (numlines * sizeof (int))); + bzero (D_LENARRAY (result, FILE1), (numlines * sizeof (size_t))); } else { - D_LINEARRAY (result, FILE1) = (char **) 0; - D_LENARRAY (result, FILE1) = (int *) 0; + D_LINEARRAY (result, FILE1) = 0; + D_LENARRAY (result, FILE1) = 0; } numlines = D_NUMLINES (result, FILE2); if (numlines) { D_LINEARRAY (result, FILE2) = ALLOCATE (numlines, char *); - D_LENARRAY (result, FILE2) = ALLOCATE (numlines, int); + D_LENARRAY (result, FILE2) = ALLOCATE (numlines, size_t); bzero (D_LINEARRAY (result, FILE2), (numlines * sizeof (char *))); - bzero (D_LENARRAY (result, FILE2), (numlines * sizeof (int))); + bzero (D_LENARRAY (result, FILE2), (numlines * sizeof (size_t))); } else { - D_LINEARRAY (result, FILE2) = (char **) 0; - D_LENARRAY (result, FILE2) = (int *) 0; + D_LINEARRAY (result, FILE2) = 0; + D_LENARRAY (result, FILE2) = 0; } /* Return */ @@ -879,20 +911,20 @@ create_diff3_block (low0, high0, low1, high1, low2, high2) */ static int compare_line_list (list1, lengths1, list2, lengths2, nl) - char *list1[], *list2[]; - int *lengths1, *lengths2; + char * const list1[], * const list2[]; + size_t const lengths1[], lengths2[]; int nl; { char - **l1 = list1, - **l2 = list2; - int + * const *l1 = list1, + * const *l2 = list2; + size_t const *lgths1 = lengths1, *lgths2 = lengths2; while (nl--) if (!*l1 || !*l2 || *lgths1 != *lgths2++ - || bcmp (*l1++, *l2++, *lgths1++)) + || memcmp (*l1++, *l2++, *lgths1++)) return 0; return 1; } @@ -903,11 +935,9 @@ compare_line_list (list1, lengths1, list2, lengths2, nl) extern char **environ; -#define DIFF_CHUNK_SIZE 10000 - static struct diff_block * process_diff (filea, fileb, last_block) - char *filea, *fileb; + char const *filea, *fileb; struct diff_block **last_block; { char *diff_contents; @@ -920,17 +950,18 @@ process_diff (filea, fileb, last_block) diff_limit = read_diff (filea, fileb, &diff_contents); scan_diff = diff_contents; block_list_end = &block_list; + bptr = 0; /* Pacify `gcc -W'. */ while (scan_diff < diff_limit) { bptr = ALLOCATE (1, struct diff_block); - bptr->lines[0] = bptr->lines[1] = (char **) 0; - bptr->lengths[0] = bptr->lengths[1] = (int *) 0; + bptr->lines[0] = bptr->lines[1] = 0; + bptr->lengths[0] = bptr->lengths[1] = 0; dt = process_diff_control (&scan_diff, bptr); if (dt == ERROR || *scan_diff != '\n') { - fprintf (stderr, "%s: diff error: ", argv0); + fprintf (stderr, "%s: diff error: ", program_name); do { putc (*scan_diff, stderr); @@ -962,7 +993,7 @@ process_diff (filea, fileb, last_block) { int numlines = D_NUMLINES (bptr, 0); bptr->lines[0] = ALLOCATE (numlines, char *); - bptr->lengths[0] = ALLOCATE (numlines, int); + bptr->lengths[0] = ALLOCATE (numlines, size_t); for (i = 0; i < numlines; i++) scan_diff = scan_diff_line (scan_diff, &(bptr->lines[0][i]), @@ -985,7 +1016,7 @@ process_diff (filea, fileb, last_block) { int numlines = D_NUMLINES (bptr, 1); bptr->lines[1] = ALLOCATE (numlines, char *); - bptr->lengths[1] = ALLOCATE (numlines, int); + bptr->lengths[1] = ALLOCATE (numlines, size_t); for (i = 0; i < numlines; i++) scan_diff = scan_diff_line (scan_diff, &(bptr->lines[1][i]), @@ -1038,9 +1069,9 @@ process_diff_control (string, db) #define SKIPWHITE(s) { while (*s == ' ' || *s == '\t') s++; } #define READNUM(s, num) \ - { if (!isdigit (*s)) return ERROR; holdnum = 0; \ - do { holdnum = (*s++ - '0' + holdnum * 10); } \ - while (isdigit (*s)); (num) = holdnum; } + { unsigned char c = *s; if (!ISDIGIT (c)) return ERROR; holdnum = 0; \ + do { holdnum = (c - '0' + holdnum * 10); } \ + while (ISDIGIT (c = *++s)); (num) = holdnum; } /* Read first set of digits */ SKIPWHITE (s); @@ -1097,19 +1128,25 @@ process_diff_control (string, db) static char * read_diff (filea, fileb, output_placement) - char *filea, *fileb; + char const *filea, *fileb; char **output_placement; { - char *argv[7]; - char horizon_arg[256]; - char **ap; - int fds[2]; char *diff_result; - int current_chunk_size; - int bytes; - int total; - int pid, w; - int wstatus; + size_t bytes, current_chunk_size, total; + int fd, wstatus; + struct stat pipestat; + + /* 302 / 1000 is log10(2.0) rounded up. Subtract 1 for the sign bit; + add 1 for integer division truncation; add 1 more for a minus sign. */ +#define INT_STRLEN_BOUND(type) ((sizeof(type)*CHAR_BIT - 1) * 302 / 1000 + 2) + +#if HAVE_FORK + + char const *argv[7]; + char horizon_arg[17 + INT_STRLEN_BOUND (int)]; + char const **ap; + int fds[2]; + pid_t pid; ap = argv; *ap++ = diff_program; @@ -1120,25 +1157,25 @@ read_diff (filea, fileb, output_placement) *ap++ = "--"; *ap++ = filea; *ap++ = fileb; - *ap = (char *) 0; + *ap = 0; - if (pipe (fds) < 0) - perror_with_exit ("pipe failed"); + if (pipe (fds) != 0) + perror_with_exit ("pipe"); pid = vfork (); if (pid == 0) { /* Child */ close (fds[0]); - if (fds[1] != fileno (stdout)) + if (fds[1] != STDOUT_FILENO) { - dup2 (fds[1], fileno (stdout)); + dup2 (fds[1], STDOUT_FILENO); close (fds[1]); } - execve (diff_program, argv, environ); + execve (diff_program, (char **) argv, environ); /* Avoid stdio, because the parent process's buffers are inherited. */ - write (fileno (stderr), diff_program, strlen (diff_program)); - write (fileno (stderr), ": not found\n", 12); + write (STDERR_FILENO, diff_program, strlen (diff_program)); + write (STDERR_FILENO, ": not found\n", 12); _exit (2); } @@ -1146,16 +1183,50 @@ read_diff (filea, fileb, output_placement) perror_with_exit ("fork failed"); close (fds[1]); /* Prevent erroneous lack of EOF */ - current_chunk_size = DIFF_CHUNK_SIZE; - diff_result = (char *) xmalloc (current_chunk_size); + fd = fds[0]; + +#else /* ! HAVE_FORK */ + + FILE *fpipe; + char *command = xmalloc (sizeof (diff_program) + 30 + INT_STRLEN_BOUND (int) + + 4 * (strlen (filea) + strlen (fileb))); + char *p; + sprintf (command, "%s -a --horizon-lines=%d -- ", + diff_program, horizon_lines); + p = command + strlen (command); + SYSTEM_QUOTE_ARG (p, filea); + *p++ = ' '; + SYSTEM_QUOTE_ARG (p, fileb); + *p = '\0'; + fpipe = popen (command, "r"); + if (!fpipe) + perror_with_exit (command); + free (command); + fd = fileno (fpipe); + +#endif /* ! HAVE_FORK */ + + current_chunk_size = 8 * 1024; + if (fstat (fd, &pipestat) == 0) + current_chunk_size = max (current_chunk_size, STAT_BLOCKSIZE (pipestat)); + + diff_result = xmalloc (current_chunk_size); total = 0; do { - bytes = myread (fds[0], + bytes = myread (fd, diff_result + total, current_chunk_size - total); total += bytes; if (total == current_chunk_size) - diff_result = (char *) xrealloc (diff_result, (current_chunk_size *= 2)); + { + if (current_chunk_size < 2 * current_chunk_size) + current_chunk_size = 2 * current_chunk_size; + else if (current_chunk_size < (size_t) -1) + current_chunk_size = (size_t) -1; + else + fatal ("files are too large to fit into memory"); + diff_result = xrealloc (diff_result, (current_chunk_size *= 2)); + } } while (bytes); if (total != 0 && diff_result[total-1] != '\n') @@ -1163,10 +1234,18 @@ read_diff (filea, fileb, output_placement) *output_placement = diff_result; - do - if ((w = wait (&wstatus)) == -1) - perror_with_exit ("wait failed"); - while (w != pid); +#if ! HAVE_FORK + + wstatus = pclose (fpipe); + +#else /* HAVE_FORK */ + + if (close (fd) != 0) + perror_with_exit ("pipe close"); + if (waitpid (pid, &wstatus, 0) < 0) + perror_with_exit ("waitpid failed"); + +#endif /* HAVE_FORK */ if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2)) fatal ("subsidiary diff failed"); @@ -1183,15 +1262,15 @@ read_diff (filea, fileb, output_placement) * are used as call-by-reference values. */ static char * -scan_diff_line (scan_ptr, set_start, set_length, limit, firstchar) +scan_diff_line (scan_ptr, set_start, set_length, limit, leadingchar) char *scan_ptr, **set_start; - int *set_length; + size_t *set_length; char *limit; - char firstchar; + int leadingchar; { char *line_ptr; - if (!(scan_ptr[0] == (firstchar) + if (!(scan_ptr[0] == leadingchar && scan_ptr[1] == ' ')) fatal ("invalid diff format; incorrect leading line chars"); @@ -1208,7 +1287,7 @@ scan_diff_line (scan_ptr, set_start, set_length, limit, firstchar) if (line_ptr < limit && *line_ptr == '\\') { if (edscript) - fprintf (stderr, "%s:", argv0); + fprintf (stderr, "%s:", program_name); else --*set_length; line_ptr++; @@ -1238,16 +1317,17 @@ static void output_diff3 (outputfile, diff, mapping, rev_mapping) FILE *outputfile; struct diff3_block *diff; - int mapping[3], rev_mapping[3]; + int const mapping[3], rev_mapping[3]; { int i; int oddoneout; char *cp; struct diff3_block *ptr; int line; - int length; + size_t length; int dontprint; static int skew_increment[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */ + char const *line_prefix = tab_align_flag ? "\t" : " "; for (ptr = diff; ptr; ptr = D_NEXT (ptr)) { @@ -1299,15 +1379,20 @@ output_diff3 (outputfile, diff, mapping, rev_mapping) if (i == dontprint) continue; - for (line = 0; line < hight - lowt + 1; line++) + if (lowt <= hight) { - fprintf (outputfile, " "); - cp = D_RELNUM (ptr, realfile, line); - length = D_RELLEN (ptr, realfile, line); - fwrite (cp, sizeof (char), length, outputfile); + line = 0; + do + { + fprintf (outputfile, line_prefix); + cp = D_RELNUM (ptr, realfile, line); + length = D_RELLEN (ptr, realfile, line); + fwrite (cp, sizeof (char), length, outputfile); + } + while (++line < hight - lowt + 1); + if (cp[length - 1] != '\n') + fprintf (outputfile, "\n\\ No newline at end of file\n"); } - if (line != 0 && cp[length - 1] != '\n') - fprintf (outputfile, "\n\\ No newline at end of file\n"); } } } @@ -1388,8 +1473,8 @@ output_diff3_edscript (outputfile, diff, mapping, rev_mapping, file0, file1, file2) FILE *outputfile; struct diff3_block *diff; - int mapping[3], rev_mapping[3]; - char *file0, *file1, *file2; + int const mapping[3], rev_mapping[3]; + char const *file0, *file1, *file2; { int leading_dot; int conflicts_found = 0, conflict; @@ -1515,8 +1600,8 @@ output_diff3_merge (infile, outputfile, diff, mapping, rev_mapping, file0, file1, file2) FILE *infile, *outputfile; struct diff3_block *diff; - int mapping[3], rev_mapping[3]; - char *file0, *file1, *file2; + int const mapping[3], rev_mapping[3]; + char const *file0, *file1, *file2; { int c, i; int conflicts_found = 0, conflict; @@ -1532,7 +1617,7 @@ output_diff3_merge (infile, outputfile, diff, mapping, rev_mapping, ((enum diff_type) (((int) DIFF_1ST) + rev_mapping[(int) b->correspond - (int) DIFF_1ST]))); - char *format_2nd = "<<<<<<< %s\n"; + char const *format_2nd = "<<<<<<< %s\n"; /* If we aren't supposed to do this output block, skip it. */ switch (type) @@ -1630,8 +1715,7 @@ reverse_diff3_blocklist (diff) { register struct diff3_block *tmp, *next, *prev; - for (tmp = diff, prev = (struct diff3_block *) 0; - tmp; tmp = next) + for (tmp = diff, prev = 0; tmp; tmp = next) { next = tmp->next; tmp->next = prev; @@ -1641,52 +1725,53 @@ reverse_diff3_blocklist (diff) return prev; } -static int +static size_t myread (fd, ptr, size) - int fd, size; + int fd; char *ptr; + size_t size; { - int result = read (fd, ptr, size); - if (result < 0) + size_t result = read (fd, ptr, size); + if (result == -1) perror_with_exit ("read failed"); return result; } -VOID * +static VOID * xmalloc (size) - unsigned size; + size_t size; { VOID *result = (VOID *) malloc (size ? size : 1); if (!result) - fatal ("virtual memory exhausted"); + fatal ("memory exhausted"); return result; } static VOID * xrealloc (ptr, size) VOID *ptr; - unsigned size; + size_t size; { VOID *result = (VOID *) realloc (ptr, size ? size : 1); if (!result) - fatal ("virtual memory exhausted"); + fatal ("memory exhausted"); return result; } static void fatal (string) - char *string; + char const *string; { - fprintf (stderr, "%s: %s\n", argv0, string); + fprintf (stderr, "%s: %s\n", program_name, string); exit (2); } static void perror_with_exit (string) - char *string; + char const *string; { int e = errno; - fprintf (stderr, "%s: ", argv0); + fprintf (stderr, "%s: ", program_name); errno = e; perror (string); exit (2); diff --git a/gnu/usr.bin/diff/dir.c b/gnu/usr.bin/diff/dir.c index a5e3e2c..036a86f 100644 --- a/gnu/usr.bin/diff/dir.c +++ b/gnu/usr.bin/diff/dir.c @@ -1,5 +1,5 @@ /* Read, sort and compare two directories. Used for GNU DIFF. - Copyright (C) 1988, 1989, 1992 Free Software Foundation, Inc. + Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc. This file is part of GNU DIFF. @@ -19,8 +19,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "diff.h" -static int compare_names (); - /* Read the directory named by DIR and store into DIRDATA a sorted vector of filenames for its contents. DIR->desc == -1 means this directory is known to be nonexistent, so set DIRDATA to an empty vector. @@ -28,31 +26,35 @@ static int compare_names (); struct dirdata { - char **files; /* Sorted names of files in dir, terminated by (char *) 0. */ + char const **names; /* Sorted names of files in dir, 0-terminated. */ char *data; /* Allocated storage for file names. */ }; +static int compare_names PARAMS((void const *, void const *)); +static int dir_sort PARAMS((struct file_data const *, struct dirdata *)); + static int dir_sort (dir, dirdata) - struct file_data *dir; + struct file_data const *dir; struct dirdata *dirdata; { - register struct direct *next; + register struct dirent *next; register int i; /* Address of block containing the files that are described. */ - char **files; + char const **names; /* Number of files in directory. */ - int nfiles; + size_t nnames; /* Allocated and used storage for file name data. */ char *data; size_t data_alloc, data_used; - dirdata->files = 0; + dirdata->names = 0; dirdata->data = 0; - nfiles = 0; + nnames = 0; + data = 0; if (dir->desc != -1) { @@ -65,7 +67,7 @@ dir_sort (dir, dirdata) data_alloc = max (1, (size_t) dir->stat.st_size); data_used = 0; - dirdata->data = data = (char *) xmalloc (data_alloc); + dirdata->data = data = xmalloc (data_alloc); /* Read the directory entries, and insert the subfiles into the `data' table. */ @@ -73,7 +75,7 @@ dir_sort (dir, dirdata) while ((errno = 0, (next = readdir (reading)) != 0)) { char *d_name = next->d_name; - size_t d_size; + size_t d_size = NAMLEN (next) + 1; /* Ignore the files `.' and `..' */ if (d_name[0] == '.' @@ -83,12 +85,11 @@ dir_sort (dir, dirdata) if (excluded_filename (d_name)) continue; - d_size = strlen (d_name) + 1; while (data_alloc < data_used + d_size) - dirdata->data = data = (char *) xrealloc (data, data_alloc *= 2); - bcopy (d_name, data + data_used, d_size); + dirdata->data = data = xrealloc (data, data_alloc *= 2); + memcpy (data + data_used, d_name, d_size); data_used += d_size; - nfiles++; + nnames++; } if (errno) { @@ -97,7 +98,7 @@ dir_sort (dir, dirdata) errno = e; return -1; } -#ifdef VOID_CLOSEDIR +#if CLOSEDIR_VOID closedir (reading); #else if (closedir (reading) != 0) @@ -105,17 +106,18 @@ dir_sort (dir, dirdata) #endif } - /* Create the `files' table from the `data' table. */ - dirdata->files = files = (char **) xmalloc (sizeof (char *) * (nfiles + 1)); - for (i = 0; i < nfiles; i++) + /* Create the `names' table from the `data' table. */ + dirdata->names = names = (char const **) xmalloc (sizeof (char *) + * (nnames + 1)); + for (i = 0; i < nnames; i++) { - files[i] = data; + names[i] = data; data += strlen (data) + 1; } - files[nfiles] = 0; + names[nnames] = 0; /* Sort the table. */ - qsort (files, nfiles, sizeof (char *), compare_names); + qsort (names, nnames, sizeof (char *), compare_names); return 0; } @@ -124,9 +126,10 @@ dir_sort (dir, dirdata) static int compare_names (file1, file2) - char **file1, **file2; + void const *file1, *file2; { - return strcmp (*file1, *file2); + return filename_cmp (* (char const *const *) file1, + * (char const *const *) file2); } /* Compare the contents of two directories named in FILEVEC[0] and FILEVEC[1]. @@ -151,8 +154,8 @@ compare_names (file1, file2) int diff_dirs (filevec, handle_file, depth) - struct file_data filevec[]; - int (*handle_file) (); + struct file_data const filevec[]; + int (*handle_file) PARAMS((char const *, char const *, char const *, char const *, int)); int depth; { struct dirdata dirdata[2]; @@ -169,42 +172,42 @@ diff_dirs (filevec, handle_file, depth) if (val == 0) { - register char **files0 = dirdata[0].files; - register char **files1 = dirdata[1].files; - char *name0 = filevec[0].name; - char *name1 = filevec[1].name; + register char const * const *names0 = dirdata[0].names; + register char const * const *names1 = dirdata[1].names; + char const *name0 = filevec[0].name; + char const *name1 = filevec[1].name; /* If `-S name' was given, and this is the topmost level of comparison, ignore all file names less than the specified starting name. */ if (dir_start_file && depth == 0) { - while (*files0 && strcmp (*files0, dir_start_file) < 0) - files0++; - while (*files1 && strcmp (*files1, dir_start_file) < 0) - files1++; + while (*names0 && filename_cmp (*names0, dir_start_file) < 0) + names0++; + while (*names1 && filename_cmp (*names1, dir_start_file) < 0) + names1++; } /* Loop while files remain in one or both dirs. */ - while (*files0 || *files1) + while (*names0 || *names1) { /* Compare next name in dir 0 with next name in dir 1. At the end of a dir, pretend the "next name" in that dir is very large. */ - int nameorder = (!*files0 ? 1 : !*files1 ? -1 - : strcmp (*files0, *files1)); - int v1 = (*handle_file) (name0, 0 < nameorder ? 0 : *files0++, - name1, nameorder < 0 ? 0 : *files1++, + int nameorder = (!*names0 ? 1 : !*names1 ? -1 + : filename_cmp (*names0, *names1)); + int v1 = (*handle_file) (name0, 0 < nameorder ? 0 : *names0++, + name1, nameorder < 0 ? 0 : *names1++, depth + 1); if (v1 > val) val = v1; } } - + for (i = 0; i < 2; i++) { - if (dirdata[i].files) - free (dirdata[i].files); + if (dirdata[i].names) + free (dirdata[i].names); if (dirdata[i].data) free (dirdata[i].data); } diff --git a/gnu/usr.bin/diff/ed.c b/gnu/usr.bin/diff/ed.c index fd051f2..717ef35 100644 --- a/gnu/usr.bin/diff/ed.c +++ b/gnu/usr.bin/diff/ed.c @@ -1,5 +1,5 @@ /* Output routines for ed-script format. - Copyright (C) 1988, 89, 91, 92 Free Software Foundation, Inc. + Copyright (C) 1988, 89, 91, 92, 93 Free Software Foundation, Inc. This file is part of GNU DIFF. @@ -19,14 +19,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "diff.h" -int change_letter (); -int translate_line_number (); -static void print_rcs_hunk (); -static void print_ed_hunk (); -static void pr_forward_ed_hunk (); -void translate_range (); -struct change *find_change (); -struct change *find_reverse_change (); +static void print_ed_hunk PARAMS((struct change *)); +static void print_rcs_hunk PARAMS((struct change *)); +static void pr_forward_ed_hunk PARAMS((struct change *)); /* Print our script as ed commands. */ diff --git a/gnu/usr.bin/diff/fnmatch.c b/gnu/usr.bin/diff/fnmatch.c new file mode 100644 index 0000000..22fa9df --- /dev/null +++ b/gnu/usr.bin/diff/fnmatch.c @@ -0,0 +1,209 @@ +/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. + +NOTE: The canonical source of this file is maintained with the GNU C Library. +Bugs can be reported to bug-glibc@prep.ai.mit.edu. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifdef HAVE_CONFIG_H +#if defined (CONFIG_BROKETS) +/* We use <config.h> instead of "config.h" so that a compilation + using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h + (which it would do because it found this file in $srcdir). */ +#include <config.h> +#else +#include "config.h" +#endif +#endif + +#include <errno.h> +#include <fnmatch.h> +#include <ctype.h> + + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS) +extern int errno; +#endif + +/* Match STRING against the filename pattern PATTERN, returning zero if + it matches, nonzero if not. */ +int +fnmatch (pattern, string, flags) + const char *pattern; + const char *string; + int flags; +{ + register const char *p = pattern, *n = string; + register char c; + +/* Note that this evalutes C many times. */ +#define FOLD(c) ((flags & FNM_CASEFOLD) && isupper (c) ? tolower (c) : (c)) + + while ((c = *p++) != '\0') + { + c = FOLD (c); + + switch (c) + { + case '?': + if (*n == '\0') + return FNM_NOMATCH; + else if ((flags & FNM_FILE_NAME) && *n == '/') + return FNM_NOMATCH; + else if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + break; + + case '\\': + if (!(flags & FNM_NOESCAPE)) + { + c = *p++; + c = FOLD (c); + } + if (FOLD (*n) != c) + return FNM_NOMATCH; + break; + + case '*': + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) + if (((flags & FNM_FILE_NAME) && *n == '/') || + (c == '?' && *n == '\0')) + return FNM_NOMATCH; + + if (c == '\0') + return 0; + + { + char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; + c1 = FOLD (c1); + for (--p; *n != '\0'; ++n) + if ((c == '[' || FOLD (*n) == c1) && + fnmatch (p, n, flags & ~FNM_PERIOD) == 0) + return 0; + return FNM_NOMATCH; + } + + case '[': + { + /* Nonzero if the sense of the character class is inverted. */ + register int not; + + if (*n == '\0') + return FNM_NOMATCH; + + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + not = (*p == '!' || *p == '^'); + if (not) + ++p; + + c = *p++; + for (;;) + { + register char cstart = c, cend = c; + + if (!(flags & FNM_NOESCAPE) && c == '\\') + cstart = cend = *p++; + + cstart = cend = FOLD (cstart); + + if (c == '\0') + /* [ (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + c = FOLD (c); + + if ((flags & FNM_FILE_NAME) && c == '/') + /* [/] can never match. */ + return FNM_NOMATCH; + + if (c == '-' && *p != ']') + { + cend = *p++; + if (!(flags & FNM_NOESCAPE) && cend == '\\') + cend = *p++; + if (cend == '\0') + return FNM_NOMATCH; + cend = FOLD (cend); + + c = *p++; + } + + if (FOLD (*n) >= cstart && FOLD (*n) <= cend) + goto matched; + + if (c == ']') + break; + } + if (!not) + return FNM_NOMATCH; + break; + + matched:; + /* Skip the rest of the [...] that already matched. */ + while (c != ']') + { + if (c == '\0') + /* [... (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + if (!(flags & FNM_NOESCAPE) && c == '\\') + /* XXX 1003.2d11 is unclear if this is right. */ + ++p; + } + if (not) + return FNM_NOMATCH; + } + break; + + default: + if (c != FOLD (*n)) + return FNM_NOMATCH; + } + + ++n; + } + + if (*n == '\0') + return 0; + + if ((flags & FNM_LEADING_DIR) && *n == '/') + /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ + return 0; + + return FNM_NOMATCH; +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ diff --git a/gnu/usr.bin/diff/fnmatch.h b/gnu/usr.bin/diff/fnmatch.h index 55cb17c..1a653ab 100644 --- a/gnu/usr.bin/diff/fnmatch.h +++ b/gnu/usr.bin/diff/fnmatch.h @@ -1,19 +1,21 @@ /* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. +NOTE: The canonical source of this file is maintained with the GNU C Library. +Bugs can be reported to bug-glibc@prep.ai.mit.edu. -This library is distributed in the hope that it will be useful, +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. -You should have received a copy of the GNU Library General Public -License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. */ +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _FNMATCH_H @@ -34,10 +36,15 @@ extern "C" { non-ANSI C where `const' is problematical. */ #endif /* C++ or ANSI C. */ + +/* We #undef these before defining them because some losing systems + (HP-UX A.08.07 for example) define these in <unistd.h>. */ +#undef FNM_PATHNAME +#undef FNM_NOESCAPE +#undef FNM_PERIOD + /* Bits set in the FLAGS argument to `fnmatch'. */ -#ifndef FNM_PATHNAME #define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */ -#endif #define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */ #define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */ diff --git a/gnu/usr.bin/diff/getopt.c b/gnu/usr.bin/diff/getopt.c index a59a013..964189d 100644 --- a/gnu/usr.bin/diff/getopt.c +++ b/gnu/usr.bin/diff/getopt.c @@ -3,7 +3,7 @@ "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu before changing it! - Copyright (C) 1987, 88, 89, 90, 91, 92, 1993 + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it @@ -20,35 +20,22 @@ along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* NOTE!!! AIX requires this to be the first thing in the file. - Do not put ANYTHING before it! */ -#if !defined (__GNUC__) && defined (_AIX) - #pragma alloca +/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. + Ditto for AIX 3.2 and <stdlib.h>. */ +#ifndef _NO_PROTO +#define _NO_PROTO #endif #ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef __GNUC__ -#define alloca __builtin_alloca -#else /* not __GNUC__ */ -#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__)))) -#include <alloca.h> -#else -#ifndef _AIX -char *alloca (); +#include <config.h> #endif -#endif /* alloca.h */ -#endif /* not __GNUC__ */ -#if !__STDC__ && !defined(const) && IN_GCC +#ifndef __STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const #define const #endif - -/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */ -#ifndef _NO_PROTO -#define _NO_PROTO #endif #include <stdio.h> @@ -67,19 +54,11 @@ char *alloca (); /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ -#undef alloca /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ #include <stdlib.h> -#else /* Not GNU C library. */ -#define __alloca alloca #endif /* GNU C library. */ -/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a - long-named option. Because this is not POSIX.2 compliant, it is - being phased out. */ -/* #define GETOPT_COMPAT */ - /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. @@ -102,7 +81,7 @@ char *alloca (); Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ -char *optarg = 0; +char *optarg = NULL; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller @@ -172,6 +151,9 @@ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries @@ -180,7 +162,6 @@ static enum in GCC. */ #include <string.h> #define my_index strchr -#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n)) #else /* Avoid depending on library functions or files @@ -202,17 +183,19 @@ my_index (str, chr) return 0; } -static void -my_bcopy (from, to, size) - const char *from; - char *to; - int size; -{ - int i; - for (i = 0; i < size; i++) - to[i] = from[i]; -} -#endif /* GNU C library. */ +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +#ifndef __STDC__ +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +#endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ @@ -236,23 +219,93 @@ static void exchange (argv) char **argv; { - int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *); - char **temp = (char **) __alloca (nonopts_size); + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; - /* Interchange the two blocks of data in ARGV. */ + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ - my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size); - my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt], - (optind - last_nonopt) * sizeof (char *)); - my_bcopy ((char *) temp, - (char *) &argv[first_nonopt + optind - last_nonopt], - nonopts_size); + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } /* Update records for the slots the non-options now occupy. */ first_nonopt += (optind - last_nonopt); last_nonopt = optind; } + +/* Initialize the internal data when the first call is made. */ + +static const char * +_getopt_initialize (optstring) + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind = 1; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + + return optstring; +} /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. @@ -319,41 +372,15 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) int *longind; int long_only; { - int option_index; - - optarg = 0; - - /* Initialize the internal data when the first call is made. - Start processing options with ARGV-element 1 (since ARGV-element 0 - is the program name); the sequence of previously skipped - non-option ARGV-elements is empty. */ + optarg = NULL; if (optind == 0) - { - first_nonopt = last_nonopt = optind = 1; - - nextchar = NULL; - - /* Determine how to handle the ordering of options and nonoptions. */ - - if (optstring[0] == '-') - { - ordering = RETURN_IN_ORDER; - ++optstring; - } - else if (optstring[0] == '+') - { - ordering = REQUIRE_ORDER; - ++optstring; - } - else if (getenv ("POSIXLY_CORRECT") != NULL) - ordering = REQUIRE_ORDER; - else - ordering = PERMUTE; - } + optstring = _getopt_initialize (optstring); if (nextchar == NULL || *nextchar == '\0') { + /* Advance to the next ARGV-element. */ + if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, @@ -364,21 +391,16 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) else if (last_nonopt != optind) first_nonopt = optind; - /* Now skip any additional non-options + /* Skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc - && (argv[optind][0] != '-' || argv[optind][1] == '\0') -#ifdef GETOPT_COMPAT - && (longopts == NULL - || argv[optind][0] != '+' || argv[optind][1] == '\0') -#endif /* GETOPT_COMPAT */ - ) + && (argv[optind][0] != '-' || argv[optind][1] == '\0')) optind++; last_nonopt = optind; } - /* Special ARGV-element `--' means premature end of options. + /* The special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ @@ -411,12 +433,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ - if ((argv[optind][0] != '-' || argv[optind][1] == '\0') -#ifdef GETOPT_COMPAT - && (longopts == NULL - || argv[optind][0] != '+' || argv[optind][1] == '\0') -#endif /* GETOPT_COMPAT */ - ) + if ((argv[optind][0] != '-' || argv[optind][1] == '\0')) { if (ordering == REQUIRE_ORDER) return EOF; @@ -425,36 +442,48 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) } /* We have found another option-ARGV-element. - Start decoding its characters. */ + Skip the initial punctuation. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + if (longopts != NULL - && ((argv[optind][0] == '-' - && (argv[optind][1] == '-' || long_only)) -#ifdef GETOPT_COMPAT - || argv[optind][0] == '+' -#endif /* GETOPT_COMPAT */ - )) + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) { + char *nameend; const struct option *p; - char *s = nextchar; + const struct option *pfound = NULL; int exact = 0; int ambig = 0; - const struct option *pfound = NULL; int indfound; + int option_index; - while (*s && *s != '=') - s++; + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; - /* Test all options for either exact match or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; - p++, option_index++) - if (!strncmp (p->name, nextchar, s - nextchar)) + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) { - if (s - nextchar == strlen (p->name)) + if (nameend - nextchar == strlen (p->name)) { /* Exact match found. */ pfound = p; @@ -469,7 +498,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) indfound = option_index; } else - /* Second nonexact match found. */ + /* Second or later nonexact match found. */ ambig = 1; } @@ -487,12 +516,12 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) { option_index = indfound; optind++; - if (*s) + if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) - optarg = s + 1; + optarg = nameend + 1; else { if (opterr) @@ -535,14 +564,12 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) } return pfound->val; } + /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' -#ifdef GETOPT_COMPAT - || argv[optind][0] == '+' -#endif /* GETOPT_COMPAT */ || my_index (optstring, *nextchar) == NULL) { if (opterr) @@ -562,7 +589,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) } } - /* Look at and handle the next option-character. */ + /* Look at and handle the next short option-character. */ { char c = *nextchar++; @@ -576,16 +603,11 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) { if (opterr) { -#if 0 - if (c < 040 || c >= 0177) - fprintf (stderr, "%s: unrecognized option, character code 0%o\n", - argv[0], c); + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c); else - fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c); -#else - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c); -#endif + fprintf (stderr, "%s: invalid option -- %c\n", argv[0], c); } optopt = c; return '?'; @@ -601,7 +623,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) optind++; } else - optarg = 0; + optarg = NULL; nextchar = NULL; } else @@ -618,14 +640,9 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) { if (opterr) { -#if 0 - fprintf (stderr, "%s: option `-%c' requires an argument\n", - argv[0], c); -#else /* 1003.2 specifies the format of this message. */ fprintf (stderr, "%s: option requires an argument -- %c\n", argv[0], c); -#endif } optopt = c; if (optstring[0] == ':') diff --git a/gnu/usr.bin/diff/getopt1.c b/gnu/usr.bin/diff/getopt1.c index a32615c..725c653 100644 --- a/gnu/usr.bin/diff/getopt1.c +++ b/gnu/usr.bin/diff/getopt1.c @@ -17,14 +17,18 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef HAVE_CONFIG_H -#include "config.h" +#include <config.h> #endif #include "getopt.h" -#if !__STDC__ && !defined(const) && IN_GCC +#ifndef __STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const #define const #endif +#endif #include <stdio.h> diff --git a/gnu/usr.bin/diff/ifdef.c b/gnu/usr.bin/diff/ifdef.c index c5dde5c..2834cbd 100644 --- a/gnu/usr.bin/diff/ifdef.c +++ b/gnu/usr.bin/diff/ifdef.c @@ -1,5 +1,5 @@ /* #ifdef-format output routines for GNU DIFF. - Copyright (C) 1989, 91, 92 Free Software Foundation, Inc. + Copyright (C) 1989, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. This file is part of GNU DIFF. @@ -21,10 +21,19 @@ and this notice must be preserved on all copies. */ #include "diff.h" -static void format_ifdef (); -static void print_ifdef_hunk (); -static void print_ifdef_lines (); -struct change *find_change (); +struct group +{ + struct file_data const *file; + int from, upto; /* start and limit lines for this group of lines */ +}; + +static char *format_group PARAMS((FILE *, char *, int, struct group const *)); +static char *scan_char_literal PARAMS((char *, int *)); +static char *scan_printf_spec PARAMS((char *)); +static int groups_letter_value PARAMS((struct group const *, int)); +static void format_ifdef PARAMS((char *, int, int, int, int)); +static void print_ifdef_hunk PARAMS((struct change *)); +static void print_ifdef_lines PARAMS((FILE *, char *, struct group const *)); static int next_line; @@ -40,7 +49,8 @@ print_ifdef_script (script) { begin_output (); format_ifdef (group_format[UNCHANGED], next_line, files[0].valid_lines, - 0, -1); + next_line - files[0].valid_lines + files[1].valid_lines, + files[1].valid_lines); } } @@ -53,7 +63,7 @@ print_ifdef_hunk (hunk) struct change *hunk; { int first0, last0, first1, last1, deletes, inserts; - const char *format; + char *format; /* Determine range of line numbers involved in each file. */ analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts); @@ -68,7 +78,8 @@ print_ifdef_hunk (hunk) /* Print lines up to this change. */ if (next_line < first0) - format_ifdef (group_format[UNCHANGED], next_line, first0, 0, -1); + format_ifdef (group_format[UNCHANGED], next_line, first0, + next_line - first0 + first1, first1); /* Print this change. */ next_line = last0 + 1; @@ -76,87 +87,223 @@ print_ifdef_hunk (hunk) } /* Print a set of lines according to FORMAT. - Lines BEG0 up to END0 are from the first file. - If END1 is -1, then the second file's lines are identical to the first; - otherwise, lines BEG1 up to END1 are from the second file. */ + Lines BEG0 up to END0 are from the first file; + lines BEG1 up to END1 are from the second file. */ static void format_ifdef (format, beg0, end0, beg1, end1) - const char *format; + char *format; int beg0, end0, beg1, end1; { - register FILE *out = outfile; + struct group groups[2]; + + groups[0].file = &files[0]; + groups[0].from = beg0; + groups[0].upto = end0; + groups[1].file = &files[1]; + groups[1].from = beg1; + groups[1].upto = end1; + format_group (outfile, format, '\0', groups); +} + +/* Print to file OUT a set of lines according to FORMAT. + The format ends at the first free instance of ENDCHAR. + Yield the address of the terminating character. + GROUPS specifies which lines to print. + If OUT is zero, do not actually print anything; just scan the format. */ + +static char * +format_group (out, format, endchar, groups) + register FILE *out; + char *format; + int endchar; + struct group const *groups; +{ register char c; - register const char *f = format; + register char *f = format; - while ((c = *f++) != 0) + while ((c = *f) != endchar && c != 0) { + f++; if (c == '%') - switch ((c = *f++)) - { - case 0: - return; - - case '<': - /* Print lines deleted from first file. */ - print_ifdef_lines (line_format[OLD], &files[0], beg0, end0); - continue; - - case '=': - /* Print common lines. */ - print_ifdef_lines (line_format[UNCHANGED], &files[0], beg0, end0); - continue; - - case '>': - /* Print lines inserted from second file. */ - if (end1 == -1) - print_ifdef_lines (line_format[NEW], &files[0], beg0, end0); - else - print_ifdef_lines (line_format[NEW], &files[1], beg1, end1); - continue; - - case '0': - c = 0; - break; - - default: - break; - } - putc (c, out); - } + { + char *spec = f; + switch ((c = *f++)) + { + case '%': + break; + + case '(': + /* Print if-then-else format e.g. `%(n=1?thenpart:elsepart)'. */ + { + int i, value[2]; + FILE *thenout, *elseout; + + for (i = 0; i < 2; i++) + { + unsigned char f0 = f[0]; + if (ISDIGIT (f0)) + { + value[i] = atoi (f); + while (ISDIGIT ((unsigned char) *++f)) + continue; + } + else + { + value[i] = groups_letter_value (groups, f0); + if (value[i] < 0) + goto bad_format; + f++; + } + if (*f++ != "=?"[i]) + goto bad_format; + } + if (value[0] == value[1]) + thenout = out, elseout = 0; + else + thenout = 0, elseout = out; + f = format_group (thenout, f, ':', groups); + if (*f) + { + f = format_group (elseout, f + 1, ')', groups); + if (*f) + f++; + } + } + continue; + + case '<': + /* Print lines deleted from first file. */ + print_ifdef_lines (out, line_format[OLD], &groups[0]); + continue; + + case '=': + /* Print common lines. */ + print_ifdef_lines (out, line_format[UNCHANGED], &groups[0]); + continue; + + case '>': + /* Print lines inserted from second file. */ + print_ifdef_lines (out, line_format[NEW], &groups[1]); + continue; + + default: + { + int value; + char *speclim; + + f = scan_printf_spec (spec); + if (!f) + goto bad_format; + speclim = f; + c = *f++; + switch (c) + { + case '\'': + f = scan_char_literal (f, &value); + if (!f) + goto bad_format; + break; + + default: + value = groups_letter_value (groups, c); + if (value < 0) + goto bad_format; + break; + } + if (out) + { + /* Temporarily replace e.g. "%3dnx" with "%3d\0x". */ + *speclim = 0; + fprintf (out, spec - 1, value); + /* Undo the temporary replacement. */ + *speclim = c; + } + } + continue; + + bad_format: + c = '%'; + f = spec; + break; + } + } + if (out) + putc (c, out); + } + return f; +} + +/* For the line group pair G, return the number corresponding to LETTER. + Return -1 if LETTER is not a group format letter. */ +static int +groups_letter_value (g, letter) + struct group const *g; + int letter; +{ + if (ISUPPER (letter)) + { + g++; + letter = tolower (letter); + } + switch (letter) + { + case 'e': return translate_line_number (g->file, g->from) - 1; + case 'f': return translate_line_number (g->file, g->from); + case 'l': return translate_line_number (g->file, g->upto) - 1; + case 'm': return translate_line_number (g->file, g->upto); + case 'n': return g->upto - g->from; + default: return -1; + } } -/* Use FORMAT to print each line of CURRENT starting with FROM - and continuing up to UPTO. */ +/* Print to file OUT, using FORMAT to print the line group GROUP. + But do nothing if OUT is zero. */ static void -print_ifdef_lines (format, current, from, upto) - const char *format; - const struct file_data *current; - int from, upto; +print_ifdef_lines (out, format, group) + register FILE *out; + char *format; + struct group const *group; { - const char * const *linbuf = current->linbuf; + struct file_data const *file = group->file; + char const * const *linbuf = file->linbuf; + int from = group->from, upto = group->upto; + + if (!out) + return; /* If possible, use a single fwrite; it's faster. */ - if (!tab_expand_flag && strcmp (format, "%l\n") == 0) - fwrite (linbuf[from], sizeof (char), - linbuf[upto] + (linbuf[upto][-1] != '\n') - linbuf[from], - outfile); - else if (!tab_expand_flag && strcmp (format, "%L") == 0) - fwrite (linbuf[from], sizeof (char), linbuf[upto] - linbuf[from], outfile); - else - for (; from < upto; from++) - { - register FILE *out = outfile; - register char c; - register const char *f = format; + if (!tab_expand_flag && format[0] == '%') + { + if (format[1] == 'l' && format[2] == '\n' && !format[3]) + { + fwrite (linbuf[from], sizeof (char), + linbuf[upto] + (linbuf[upto][-1] != '\n') - linbuf[from], + out); + return; + } + if (format[1] == 'L' && !format[2]) + { + fwrite (linbuf[from], sizeof (char), + linbuf[upto] - linbuf[from], out); + return; + } + } - while ((c = *f++) != 0) - { - if (c == '%') + for (; from < upto; from++) + { + register char c; + register char *f = format; + + while ((c = *f++) != 0) + { + if (c == '%') + { + char *spec = f; switch ((c = *f++)) { - case 0: - goto format_done; + case '%': + break; case 'l': output_1_line (linbuf[from], @@ -168,16 +315,114 @@ print_ifdef_lines (format, current, from, upto) output_1_line (linbuf[from], linbuf[from + 1], 0, 0); continue; - case '0': - c = 0; - break; - default: + { + int value; + char *speclim; + + f = scan_printf_spec (spec); + if (!f) + goto bad_format; + speclim = f; + c = *f++; + switch (c) + { + case '\'': + f = scan_char_literal (f, &value); + if (!f) + goto bad_format; + break; + + case 'n': + value = translate_line_number (file, from); + break; + + default: + goto bad_format; + } + /* Temporarily replace e.g. "%3dnx" with "%3d\0x". */ + *speclim = 0; + fprintf (out, spec - 1, value); + /* Undo the temporary replacement. */ + *speclim = c; + } + continue; + + bad_format: + c = '%'; + f = spec; break; } - putc (c, out); + } + putc (c, out); + } + } +} + +/* Scan the character literal represented in the string LIT; LIT points just + after the initial apostrophe. Put the literal's value into *INTPTR. + Yield the address of the first character after the closing apostrophe, + or zero if the literal is ill-formed. */ +static char * +scan_char_literal (lit, intptr) + char *lit; + int *intptr; +{ + register char *p = lit; + int value, digits; + char c = *p++; + + switch (c) + { + case 0: + case '\'': + return 0; + + case '\\': + value = 0; + while ((c = *p++) != '\'') + { + unsigned digit = c - '0'; + if (8 <= digit) + return 0; + value = 8 * value + digit; } + digits = p - lit - 2; + if (! (1 <= digits && digits <= 3)) + return 0; + break; + + default: + value = c; + if (*p++ != '\'') + return 0; + break; + } + *intptr = value; + return p; +} + +/* Scan optional printf-style SPEC of the form `-*[0-9]*(.[0-9]*)?[cdoxX]'. + Return the address of the character following SPEC, or zero if failure. */ +static char * +scan_printf_spec (spec) + register char *spec; +{ + register unsigned char c; - format_done:; - } + while ((c = *spec++) == '-') + continue; + while (ISDIGIT (c)) + c = *spec++; + if (c == '.') + while (ISDIGIT (c = *spec++)) + continue; + switch (c) + { + case 'c': case 'd': case 'o': case 'x': case 'X': + return spec; + + default: + return 0; + } } diff --git a/gnu/usr.bin/diff/io.c b/gnu/usr.bin/diff/io.c index a0633cd..6605915 100644 --- a/gnu/usr.bin/diff/io.c +++ b/gnu/usr.bin/diff/io.c @@ -1,5 +1,5 @@ /* File I/O for GNU DIFF. - Copyright (C) 1988, 1989, 1992 Free Software Foundation, Inc. + Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc. This file is part of GNU DIFF. @@ -26,51 +26,14 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Given a hash value and a new character, return a new hash value. */ #define HASH(h, c) ((c) + ROL (h, 7)) -int line_cmp (); - /* Guess remaining number of lines from number N of lines so far, size S so far, and total size T. */ #define GUESS_LINES(n,s,t) (((t) - (s)) / ((n) < 10 ? 32 : (s) / ((n)-1)) + 5) /* Type used for fast prefix comparison in find_identical_ends. */ -typedef long word; - -/* Character classes. */ -const char textchar[] = { - /* ISO 8859 */ - 0, 0, 0, 0, 0, 0, 0, 0, - 2, 2, 1, 2, 2, 2, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 2, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 2, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1 -}; +#ifndef word +#define word int +#endif /* Lines are put into equivalence classes (of lines that match in line_cmp). Each equivalence class is represented by one of these structures, @@ -80,14 +43,15 @@ struct equivclass { int next; /* Next item in this bucket. */ unsigned hash; /* Hash of lines in this class. */ - const char *line; /* A line that fits this class. */ - int length; /* The length of that line. */ + char const *line; /* A line that fits this class. */ + size_t length; /* That line's length, not counting its newline. */ }; -/* Hash-table: array of buckets, each being a chain of equivalence classes. */ +/* Hash-table: array of buckets, each being a chain of equivalence classes. + buckets[-1] is reserved for incomplete lines. */ static int *buckets; - -/* Number of buckets in the hash table array. */ + +/* Number of buckets in the hash table array, not counting buckets[-1]. */ static int nbuckets; /* Array in which the equivalence classes are allocated. @@ -100,13 +64,17 @@ static int equivs_index; /* Number of elements allocated in the array `equivs'. */ static int equivs_alloc; + +static void find_and_hash_each_line PARAMS((struct file_data *)); +static void find_identical_ends PARAMS((struct file_data[])); +static void prepare_text_end PARAMS((struct file_data *)); /* Check for binary files and compare them for exact identity. */ /* Return 1 if BUF contains a non text character. SIZE is the number of characters in BUF. */ -#define binary_file_p(buf, size) (size != 0 && memchr (buf, '\0', size) != 0) +#define binary_file_p(buf, size) (memchr (buf, '\0', size) != 0) /* Get ready to read the current file. Return nonzero if SKIP_TEST is zero, @@ -121,38 +89,38 @@ sip (current, skip_test) if (current->desc < 0) { /* Leave room for a sentinel. */ - current->buffer = xmalloc (sizeof (word)); current->bufsize = sizeof (word); - current->buffered_chars = 0; + current->buffer = xmalloc (current->bufsize); } else { - current->bufsize = current->buffered_chars - = STAT_BLOCKSIZE (current->stat); - - if (S_ISREG (current->stat.st_mode)) - /* Get the size out of the stat block. - Allocate enough room for appended newline and sentinel. - Allocate at least one block, to prevent overrunning the buffer - when comparing growing binary files. */ - current->bufsize = max (current->bufsize, - current->stat.st_size + sizeof (word) + 1); - + current->bufsize = STAT_BLOCKSIZE (current->stat); current->buffer = xmalloc (current->bufsize); - if (skip_test) - current->buffered_chars = 0; - else + + if (! skip_test) { /* Check first part of file to see if it's a binary file. */ - current->buffered_chars = read (current->desc, - current->buffer, - current->buffered_chars); - if (current->buffered_chars < 0) +#if HAVE_SETMODE + int oldmode = setmode (current->desc, O_BINARY); +#endif + size_t n = read (current->desc, current->buffer, current->bufsize); + if (n == -1) pfatal_with_name (current->name); - return binary_file_p (current->buffer, current->buffered_chars); + current->buffered_chars = n; +#if HAVE_SETMODE + if (oldmode != O_BINARY) + { + if (lseek (current->desc, - (off_t) n, SEEK_CUR) == -1) + pfatal_with_name (current->name); + setmode (current->desc, oldmode); + current->buffered_chars = 0; + } +#endif + return binary_file_p (current->buffer, n); } } - + + current->buffered_chars = 0; return 0; } @@ -162,7 +130,7 @@ void slurp (current) struct file_data *current; { - int cc; + size_t cc; if (current->desc < 0) /* The file is nonexistent. */ @@ -170,13 +138,22 @@ slurp (current) else if (S_ISREG (current->stat.st_mode)) { /* It's a regular file; slurp in the rest all at once. */ - cc = current->stat.st_size - current->buffered_chars; - if (cc) + + /* Get the size out of the stat block. + Allocate enough room for appended newline and sentinel. */ + cc = current->stat.st_size + 1 + sizeof (word); + if (current->bufsize < cc) + { + current->bufsize = cc; + current->buffer = xrealloc (current->buffer, cc); + } + + if (current->buffered_chars < current->stat.st_size) { cc = read (current->desc, current->buffer + current->buffered_chars, - cc); - if (cc < 0) + current->stat.st_size - current->buffered_chars); + if (cc == -1) pfatal_with_name (current->name); current->buffered_chars += cc; } @@ -189,21 +166,20 @@ slurp (current) if (current->buffered_chars == current->bufsize) { current->bufsize = current->bufsize * 2; - current->buffer = (char *) xrealloc (current->buffer, - current->bufsize); + current->buffer = xrealloc (current->buffer, current->bufsize); } cc = read (current->desc, current->buffer + current->buffered_chars, current->bufsize - current->buffered_chars); if (cc == 0) break; - if (cc < 0) + if (cc == -1) pfatal_with_name (current->name); current->buffered_chars += cc; } /* Allocate just enough room for appended newline and sentinel. */ - current->bufsize = current->buffered_chars + sizeof (word) + 1; - current->buffer = (char *) xrealloc (current->buffer, current->bufsize); + current->bufsize = current->buffered_chars + 1 + sizeof (word); + current->buffer = xrealloc (current->buffer, current->bufsize); } } @@ -215,12 +191,13 @@ find_and_hash_each_line (current) struct file_data *current; { unsigned h; - const unsigned char *p = (const unsigned char *) current->prefix_end; + unsigned char const *p = (unsigned char const *) current->prefix_end; unsigned char c; - int i, length, *bucket; + int i, *bucket; + size_t length; /* Cache often-used quantities in local variables to help the compiler. */ - const char **linbuf = current->linbuf; + char const **linbuf = current->linbuf; int alloc_lines = current->alloc_lines; int line = 0; int linbuf_base = current->linbuf_base; @@ -228,16 +205,13 @@ find_and_hash_each_line (current) struct equivclass *eqs = equivs; int eqs_index = equivs_index; int eqs_alloc = equivs_alloc; - const char *suffix_begin = current->suffix_begin; - const char *bufend = current->buffer + current->buffered_chars; - const char *incomplete_tail - = current->missing_newline && ROBUST_OUTPUT_STYLE (output_style) - ? bufend : (const char *) 0; - int varies = length_varies; - - while ((const char *) p < suffix_begin) + char const *suffix_begin = current->suffix_begin; + char const *bufend = current->buffer + current->buffered_chars; + int use_line_cmp = ignore_some_line_changes; + + while ((char const *) p < suffix_begin) { - const char *ip = (const char *) p; + char const *ip = (char const *) p; /* Compute the equivalence class for this line. */ @@ -249,44 +223,52 @@ find_and_hash_each_line (current) if (ignore_all_space_flag) while ((c = *p++) != '\n') { - if (! Is_space (c)) - h = HASH (h, isupper (c) ? tolower (c) : c); + if (! ISSPACE (c)) + h = HASH (h, ISUPPER (c) ? tolower (c) : c); } else if (ignore_space_change_flag) while ((c = *p++) != '\n') { - if (c == ' ' || c == '\t') + if (ISSPACE (c)) { - while ((c = *p++) == ' ' || c == '\t') - ; - if (c == '\n') - break; + for (;;) + { + c = *p++; + if (!ISSPACE (c)) + break; + if (c == '\n') + goto hashing_done; + } h = HASH (h, ' '); } /* C is now the first non-space. */ - h = HASH (h, isupper (c) ? tolower (c) : c); + h = HASH (h, ISUPPER (c) ? tolower (c) : c); } else while ((c = *p++) != '\n') - h = HASH (h, isupper (c) ? tolower (c) : c); + h = HASH (h, ISUPPER (c) ? tolower (c) : c); } else { if (ignore_all_space_flag) while ((c = *p++) != '\n') { - if (! Is_space (c)) + if (! ISSPACE (c)) h = HASH (h, c); } else if (ignore_space_change_flag) while ((c = *p++) != '\n') { - if (c == ' ' || c == '\t') + if (ISSPACE (c)) { - while ((c = *p++) == ' ' || c == '\t') - ; - if (c == '\n') - break; + for (;;) + { + c = *p++; + if (!ISSPACE (c)) + break; + if (c == '\n') + goto hashing_done; + } h = HASH (h, ' '); } /* C is now the first non-space. */ @@ -296,9 +278,25 @@ find_and_hash_each_line (current) while ((c = *p++) != '\n') h = HASH (h, c); } + hashing_done:; bucket = &buckets[h % nbuckets]; - length = (const char *) p - ip - ((const char *) p == incomplete_tail); + length = (char const *) p - ip - 1; + + if ((char const *) p == bufend + && current->missing_newline + && ROBUST_OUTPUT_STYLE (output_style)) + { + /* This line is incomplete. If this is significant, + put the line into bucket[-1]. */ + if (! (ignore_space_change_flag | ignore_all_space_flag)) + bucket = &buckets[-1]; + + /* Omit the inserted newline when computing linbuf later. */ + p--; + bufend = suffix_begin = (char const *) p; + } + for (i = *bucket; ; i = eqs[i].next) if (!i) { @@ -314,11 +312,20 @@ find_and_hash_each_line (current) *bucket = i; break; } - else if (eqs[i].hash == h - && (eqs[i].length == length || varies) - && ! line_cmp (eqs[i].line, eqs[i].length, ip, length)) - /* Reuse existing equivalence class. */ - break; + else if (eqs[i].hash == h) + { + char const *eqline = eqs[i].line; + + /* Reuse existing equivalence class if the lines are identical. + This detects the common case of exact identity + faster than complete comparison would. */ + if (eqs[i].length == length && memcmp (eqline, ip, length) == 0) + break; + + /* Reuse existing class if line_cmp reports the lines equal. */ + if (use_line_cmp && line_cmp (eqline, ip) == 0) + break; + } /* Maybe increase the size of the line table. */ if (line == alloc_lines) @@ -326,7 +333,7 @@ find_and_hash_each_line (current) /* Double (alloc_lines - linbuf_base) by adding to alloc_lines. */ alloc_lines = 2 * alloc_lines - linbuf_base; cureqs = (int *) xrealloc (cureqs, alloc_lines * sizeof (*cureqs)); - linbuf = (const char **) xrealloc (linbuf + linbuf_base, + linbuf = (char const **) xrealloc (linbuf + linbuf_base, (alloc_lines - linbuf_base) * sizeof (*linbuf)) - linbuf_base; @@ -341,24 +348,21 @@ find_and_hash_each_line (current) for (i = 0; ; i++) { /* Record the line start for lines in the suffix that we care about. - Record one more line start than lines, + Record one more line start than lines, so that we can compute the length of any buffered line. */ if (line == alloc_lines) { /* Double (alloc_lines - linbuf_base) by adding to alloc_lines. */ alloc_lines = 2 * alloc_lines - linbuf_base; - linbuf = (const char **) xrealloc (linbuf + linbuf_base, + linbuf = (char const **) xrealloc (linbuf + linbuf_base, (alloc_lines - linbuf_base) * sizeof (*linbuf)) - linbuf_base; } - linbuf[line] = (const char *) p; - - if ((const char *) p == bufend) - { - linbuf[line] -= (const char *) p == incomplete_tail; - break; - } + linbuf[line] = (char const *) p; + + if ((char const *) p == bufend) + break; if (context <= i && no_diff_means_no_output) break; @@ -381,13 +385,13 @@ find_and_hash_each_line (current) /* Prepare the end of the text. Make sure it's initialized. Make sure text ends in a newline, - but remember that we had to add one unless -B is in effect. */ + but remember that we had to add one. */ static void prepare_text_end (current) struct file_data *current; { - int buffered_chars = current->buffered_chars; + size_t buffered_chars = current->buffered_chars; char *p = current->buffer; if (buffered_chars == 0 || p[buffered_chars - 1] == '\n') @@ -396,9 +400,9 @@ prepare_text_end (current) { p[buffered_chars++] = '\n'; current->buffered_chars = buffered_chars; - current->missing_newline = ! ignore_blank_lines_flag; + current->missing_newline = 1; } - + /* Don't use uninitialized storage when planting or using sentinels. */ if (p) bzero (p + buffered_chars, sizeof (word)); @@ -413,12 +417,12 @@ find_identical_ends (filevec) { word *w0, *w1; char *p0, *p1, *buffer0, *buffer1; - const char *end0, *beg0; - const char **linbuf0, **linbuf1; + char const *end0, *beg0; + char const **linbuf0, **linbuf1; int i, lines; - int n0, n1, alloc_lines0, alloc_lines1; + size_t n0, n1, tem; + int alloc_lines0, alloc_lines1; int buffered_prefix, prefix_count, prefix_mask; - int tem; slurp (&filevec[0]); if (filevec[0].desc != filevec[1].desc) @@ -564,7 +568,7 @@ find_identical_ends (filevec) } lines = 0; - linbuf0 = (const char **) xmalloc (alloc_lines0 * sizeof (*linbuf0)); + linbuf0 = (char const **) xmalloc (alloc_lines0 * sizeof (*linbuf0)); /* If the prefix is needed, find the prefix lines. */ if (! (no_diff_means_no_output @@ -577,7 +581,7 @@ find_identical_ends (filevec) { int l = lines++ & prefix_mask; if (l == alloc_lines0) - linbuf0 = (const char **) xrealloc (linbuf0, (alloc_lines0 *= 2) + linbuf0 = (char const **) xrealloc (linbuf0, (alloc_lines0 *= 2) * sizeof(*linbuf0)); linbuf0[l] = p0; while (*p0++ != '\n') @@ -593,7 +597,7 @@ find_identical_ends (filevec) = (buffered_prefix + GUESS_LINES (lines, filevec[1].prefix_end - buffer1, tem) + context); - linbuf1 = (const char **) xmalloc (alloc_lines1 * sizeof (*linbuf1)); + linbuf1 = (char const **) xmalloc (alloc_lines1 * sizeof (*linbuf1)); if (buffered_prefix != lines) { @@ -621,7 +625,7 @@ find_identical_ends (filevec) /* Largest primes less than some power of two, for nbuckets. Values range from useful to preposterous. If one of these numbers isn't prime after all, don't blame it on me, blame it on primes (6) . . . */ -static const int primes[] = +static int const primes[] = { 509, 1021, @@ -630,6 +634,7 @@ static const int primes[] = 8191, 16381, 32749, +#if 32767 < INT_MAX 65521, 131071, 262139, @@ -646,20 +651,23 @@ static const int primes[] = 536870909, 1073741789, 2147483647, +#endif 0 }; /* Given a vector of two file_data objects, read the file associated with each one, and build the table of equivalence classes. - Return 1 if either file appears to be a binary file. */ + Return 1 if either file appears to be a binary file. + If PRETEND_BINARY is nonzero, pretend they are binary regardless. */ int -read_files (filevec) +read_files (filevec, pretend_binary) struct file_data filevec[]; + int pretend_binary; { int i; - int skip_test = always_text_flag | no_details_flag; - int appears_binary = no_details_flag | sip (&filevec[0], skip_test); + int skip_test = always_text_flag | pretend_binary; + int appears_binary = pretend_binary | sip (&filevec[0], skip_test); if (filevec[0].desc != filevec[1].desc) appears_binary |= sip (&filevec[1], skip_test | appears_binary); @@ -670,7 +678,13 @@ read_files (filevec) filevec[1].buffered_chars = filevec[0].buffered_chars; } if (appears_binary) - return 1; + { +#if HAVE_SETMODE + setmode (filevec[0].desc, O_BINARY); + setmode (filevec[1].desc, O_BINARY); +#endif + return 1; + } find_identical_ends (filevec); @@ -685,16 +699,16 @@ read_files (filevec) abort (); nbuckets = primes[i]; - buckets = (int *) xmalloc (nbuckets * sizeof (*buckets)); - bzero (buckets, nbuckets * sizeof (*buckets)); + buckets = (int *) xmalloc ((nbuckets + 1) * sizeof (*buckets)); + bzero (buckets++, (nbuckets + 1) * sizeof (*buckets)); - for (i = 0; i < 2; ++i) + for (i = 0; i < 2; i++) find_and_hash_each_line (&filevec[i]); filevec[0].equiv_max = filevec[1].equiv_max = equivs_index; free (equivs); - free (buckets); + free (buckets - 1); return 0; } diff --git a/gnu/usr.bin/diff/normal.c b/gnu/usr.bin/diff/normal.c index a0cf479..4d9e23c 100644 --- a/gnu/usr.bin/diff/normal.c +++ b/gnu/usr.bin/diff/normal.c @@ -1,5 +1,5 @@ /* Normal-format output routines for GNU DIFF. - Copyright (C) 1988, 1989 Free Software Foundation, Inc. + Copyright (C) 1988, 1989, 1993 Free Software Foundation, Inc. This file is part of GNU DIFF. @@ -20,10 +20,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "diff.h" -int change_letter (); -void print_normal_hunk (); -void print_number_range (); -struct change *find_change (); +static void print_normal_hunk PARAMS((struct change *)); /* Print the edit-script SCRIPT as a normal diff. INF points to an array of descriptions of the two files. */ @@ -39,7 +36,7 @@ print_normal_script (script) This is a contiguous portion of a complete edit script, describing changes in consecutive lines. */ -void +static void print_normal_hunk (hunk) struct change *hunk; { diff --git a/gnu/usr.bin/diff/sdiff.c b/gnu/usr.bin/diff/sdiff.c index 7f1019e..b64f1d0 100644 --- a/gnu/usr.bin/diff/sdiff.c +++ b/gnu/usr.bin/diff/sdiff.c @@ -1,5 +1,5 @@ /* SDIFF -- interactive merge front end to diff - Copyright (C) 1992 Free Software Foundation, Inc. + Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. This file is part of GNU DIFF. @@ -19,18 +19,13 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* GNU SDIFF was written by Thomas Lord. */ -#include <stdio.h> -#include <ctype.h> #include "system.h" +#include <stdio.h> #include <signal.h> #include "getopt.h" -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif - /* Size of chunks read from files which must be parsed into lines. */ -#define SDIFF_BUFSIZE 65536 +#define SDIFF_BUFSIZE ((size_t) 65536) /* Default name of the diff program */ #ifndef DIFF_PROGRAM @@ -38,33 +33,69 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #endif /* Users' editor of nonchoice */ -#ifndef DEFAULT_EDITOR -#define DEFAULT_EDITOR "ed" +#ifndef DEFAULT_EDITOR_PROGRAM +#define DEFAULT_EDITOR_PROGRAM "ed" #endif -extern char *version_string; -static char const *prog; +extern char version_string[]; +static char const *program_name; static char const *diffbin = DIFF_PROGRAM; -static char const *edbin = DEFAULT_EDITOR; +static char const *edbin = DEFAULT_EDITOR_PROGRAM; +static char const **diffargv; static char *tmpname; static int volatile tmpmade; + +#if HAVE_FORK static pid_t volatile diffpid; +#endif struct line_filter; -static void diffarg (); /* (char *); */ -static void execdiff (); /* (int, char const *, char const *, char const *); */ -static int edit (); /* (struct line_filter *left, int lenl, struct - line_filter *right, int lenr, FILE *outfile); */ -static int interact (); /* (struct line_filter *diff, - struct line_filter *left, - struct line_filter *right, FILE *outfile); */ -static void trapsigs (); /* (void); */ + +static FILE *ck_fopen PARAMS((char const *, char const *)); +static RETSIGTYPE catchsig PARAMS((int)); +static VOID *xmalloc PARAMS((size_t)); +static char const *expand_name PARAMS((char *, int, char const *)); +static int edit PARAMS((struct line_filter *, int, struct line_filter *, int, FILE*)); +static int interact PARAMS((struct line_filter *, struct line_filter *, struct line_filter *, FILE*)); +static int lf_snarf PARAMS((struct line_filter *, char *, size_t)); +static int skip_white PARAMS((void)); +static size_t ck_fread PARAMS((char *, size_t, FILE *)); +static size_t lf_refill PARAMS((struct line_filter *)); +static void checksigs PARAMS((void)); +static void ck_fclose PARAMS((FILE *)); +static void ck_fflush PARAMS((FILE *)); +static void ck_fwrite PARAMS((char const *, size_t, FILE *)); +static void cleanup PARAMS((void)); +static void diffarg PARAMS((char const *)); +static void execdiff PARAMS((void)); +static void exiterr PARAMS((void)); +static void fatal PARAMS((char const *)); +static void flush_line PARAMS((void)); +static void give_help PARAMS((void)); +static void lf_copy PARAMS((struct line_filter *, int, FILE *)); +static void lf_init PARAMS((struct line_filter *, FILE *)); +static void lf_skip PARAMS((struct line_filter *, int)); +static void perror_fatal PARAMS((char const *)); +static void trapsigs PARAMS((void)); +static void try_help PARAMS((char const *)); +static void untrapsig PARAMS((int)); +static void usage PARAMS((void)); + /* this lossage until the gnu libc conquers the universe */ -#define TMPNAMSIZE 1024 +#if HAVE_TMPNAM +#define private_tempnam() tmpnam ((char *) 0) +#else +#ifndef PVT_tmpdir #define PVT_tmpdir "/tmp" -static char *private_tempnam (); /* (const char *, const char *, int, int *); */ -static int diraccess (); +#endif +#ifndef TMPDIR_ENV +#define TMPDIR_ENV "TMPDIR" +#endif +static char *private_tempnam PARAMS((void)); +static int exists PARAMS((char const *)); +#endif +static int diraccess PARAMS((char const *)); /* Options: */ @@ -74,45 +105,72 @@ static char *out_file; /* do not print common lines if true, set by -s option */ static int suppress_common_flag; -static struct option longopts[] = +static struct option const longopts[] = { - {"ignore-blank-lines", 0, NULL, 'B'}, - {"speed-large-files", 0, NULL, 'H'}, - {"ignore-matching-lines", 1, NULL, 'I'}, - {"ignore-all-space", 0, NULL, 'W'}, /* swap W and w for historical reasons */ - {"text", 0, NULL, 'a'}, - {"ignore-space-change", 0, NULL, 'b'}, - {"minimal", 0, NULL, 'd'}, - {"ignore-case", 0, NULL, 'i'}, - {"left-column", 0, NULL, 'l'}, - {"output", 1, NULL, 'o'}, - {"suppress-common-lines", 0, NULL, 's'}, - {"expand-tabs", 0, NULL, 't'}, - {"width", 1, NULL, 'w'}, - {"version", 0, NULL, 'v'}, - {NULL, 0, NULL, 0} + {"ignore-blank-lines", 0, 0, 'B'}, + {"speed-large-files", 0, 0, 'H'}, + {"ignore-matching-lines", 1, 0, 'I'}, + {"ignore-all-space", 0, 0, 'W'}, /* swap W and w for historical reasons */ + {"text", 0, 0, 'a'}, + {"ignore-space-change", 0, 0, 'b'}, + {"minimal", 0, 0, 'd'}, + {"ignore-case", 0, 0, 'i'}, + {"left-column", 0, 0, 'l'}, + {"output", 1, 0, 'o'}, + {"suppress-common-lines", 0, 0, 's'}, + {"expand-tabs", 0, 0, 't'}, + {"width", 1, 0, 'w'}, + {"version", 0, 0, 'v'}, + {"help", 0, 0, 129}, + {0, 0, 0, 0} }; -/* prints usage message and quits */ static void -usage () +try_help (reason) + char const *reason; { - fprintf (stderr, "Usage: %s [options] from-file to-file\n", prog); - fprintf (stderr, "Options:\n\ - [-abBdHilstv] [-I regexp] [-o outfile] [-w columns]\n\ - [--text] [--minimal] [--speed-large-files] [--expand-tabs]\n\ - [--ignore-case] [--ignore-matching-lines=regexp]\n\ - [--ignore-space-change] [--ignore-blank-lines] [--ignore-all-space]\n\ - [--suppress-common-lines] [--left-column] [--output=outfile]\n\ - [--version] [--width=columns]\n"); + if (reason) + fprintf (stderr, "%s: %s\n", program_name, reason); + fprintf (stderr, "%s: Try `%s --help' for more information.\n", + program_name, program_name); exit (2); } static void +usage () +{ + printf ("Usage: %s [OPTIONS]... FILE1 FILE2\n\n", program_name); + printf ("%s", "\ + -o FILE --output=FILE Operate interactively, sending output to FILE.\n\n"); + printf ("%s", "\ + -i --ignore-case Consider upper- and lower-case to be the same.\n\ + -W --ignore-all-space Ignore all white space.\n\ + -b --ignore-space-change Ignore changes in the amount of white space.\n\ + -B --ignore-blank-lines Ignore changes whose lines are all blank.\n\ + -I RE --ignore-matching-lines=RE Ignore changes whose lines all match RE.\n\ + -a --text Treat all files as text.\n\n"); + printf ("%s", "\ + -w NUM --width=NUM Output at most NUM (default 130) characters per line.\n\ + -l --left-column Output only the left column of common lines.\n\ + -s --suppress-common-lines Do not output common lines.\n\n"); + printf ("\ + -t --expand-tabs Expand tabs to spaces in output.\n\n"); + printf ("%s", "\ + -d --minimal Try hard to find a smaller set of changes.\n\ + -H --speed-large-files Assume large files and many scattered small changes.\n\n"); + printf ("%s", "\ + -v --version Output version info.\n\ + --help Output this help.\n\n\ +If FILE1 or FILE2 is `-', read standard input.\n"); +} + +static void cleanup () { +#if HAVE_FORK if (0 < diffpid) kill (diffpid, SIGPIPE); +#endif if (tmpmade) unlink (tmpname); } @@ -121,23 +179,26 @@ static void exiterr () { cleanup (); + untrapsig (0); + checksigs (); exit (2); } static void fatal (msg) - char *msg; + char const *msg; { - fprintf (stderr, "%s: %s\n", prog, msg); + fprintf (stderr, "%s: %s\n", program_name, msg); exiterr (); } static void perror_fatal (msg) - char *msg; + char const *msg; { int e = errno; - fprintf (stderr, "%s: ", prog); + checksigs (); + fprintf (stderr, "%s: ", program_name); errno = e; perror (msg); exiterr (); @@ -145,19 +206,19 @@ perror_fatal (msg) /* malloc freely or DIE! */ -char * +static VOID * xmalloc (size) size_t size; { - char *r = malloc (size); + VOID *r = (VOID *) malloc (size); if (!r) - fatal ("virtual memory exhausted"); + fatal ("memory exhausted"); return r; } static FILE * ck_fopen (fname, type) - char *fname, *type; + char const *fname, *type; { FILE *r = fopen (fname, type); if (!r) @@ -165,18 +226,6 @@ ck_fopen (fname, type) return r; } - -static FILE * -ck_fdopen (fd, type) - int fd; - char *type; -{ - FILE *r = fdopen (fd, type); - if (!r) - perror_fatal ("fdopen"); - return r; -} - static void ck_fclose (f) FILE *f; @@ -199,7 +248,7 @@ ck_fread (buf, size, f) static void ck_fwrite (buf, size, f) - char *buf; + char const *buf; size_t size; FILE *f; { @@ -215,72 +264,26 @@ ck_fflush (f) perror_fatal ("output error"); } -#if !HAVE_MEMCHR -char * -memchr (s, c, n) - char *s; - int c; - size_t n; -{ - unsigned char *p = (unsigned char *) s, *lim = p + n; - for (; p < lim; p++) - if (*p == c) - return (char *) p; - return 0; -} -#endif - -#ifndef HAVE_WAITPID -/* Emulate waitpid well enough for sdiff, which has at most two children. */ -static pid_t -waitpid (pid, stat_loc, options) - pid_t pid; - int *stat_loc; - int options; -{ - static int ostatus; - static pid_t opid; - int npid, status; - - if (pid == opid) - { - opid = 0; - status = ostatus; - } - else - while ((npid = wait (&status)) != pid) - { - if (npid < 0) - return npid; - opid = npid; - ostatus = status; - } - *stat_loc = status; - return pid; -} -#endif - static char const * -expand_name (name, isdir, other_name) +expand_name (name, is_dir, other_name) char *name; - int isdir; + int is_dir; char const *other_name; { if (strcmp (name, "-") == 0) fatal ("cannot interactively merge standard input"); - if (!isdir) + if (!is_dir) return name; else { /* Yield NAME/BASE, where BASE is OTHER_NAME's basename. */ - const char - *p = rindex (other_name, '/'), - *base = p ? p+1 : other_name; + char const *p = filename_lastdirchar (other_name); + char const *base = p ? p+1 : other_name; size_t namelen = strlen (name), baselen = strlen (base); char *r = xmalloc (namelen + baselen + 2); - bcopy (name, r, namelen); + memcpy (r, name, namelen); r[namelen] = '/'; - bcopy (base, r + namelen + 1, baselen + 1); + memcpy (r + namelen + 1, base, baselen + 1); return r; } } @@ -313,6 +316,7 @@ lf_refill (lf) lf->bufpos = lf->buffer; lf->buflim = lf->buffer + s; lf->buflim[0] = '\n'; + checksigs (); return s; } @@ -327,7 +331,7 @@ lf_copy (lf, lines, outfile) while (lines) { - lf->bufpos = memchr (lf->bufpos, '\n', lf->buflim - lf->bufpos); + lf->bufpos = (char *) memchr (lf->bufpos, '\n', lf->buflim - lf->bufpos); if (! lf->bufpos) { ck_fwrite (start, lf->buflim - start, outfile); @@ -353,7 +357,7 @@ lf_skip (lf, lines) { while (lines) { - lf->bufpos = memchr (lf->bufpos, '\n', lf->buflim - lf->bufpos); + lf->bufpos = (char *) memchr (lf->bufpos, '\n', lf->buflim - lf->bufpos); if (! lf->bufpos) { if (! lf_refill (lf)) @@ -378,11 +382,11 @@ lf_snarf (lf, buffer, bufsize) for (;;) { - char *next = memchr (start, '\n', lf->buflim + 1 - start); + char *next = (char *) memchr (start, '\n', lf->buflim + 1 - start); size_t s = next - start; if (bufsize <= s) return 0; - bcopy (start, buffer, s); + memcpy (buffer, start, s); if (next < lf->buflim) { buffer[s] = 0; @@ -405,20 +409,24 @@ main (argc, argv) char *argv[]; { int opt; - int version_requested = 0; - char *editor = getenv ("EDITOR"); - char *differ = getenv ("DIFF"); + char *editor; + char *differ; + + initialize_main (&argc, &argv); + program_name = argv[0]; - prog = argv[0]; + editor = getenv ("EDITOR"); if (editor) edbin = editor; + differ = getenv ("DIFF"); if (differ) diffbin = differ; diffarg ("diff"); /* parse command line args */ - while ((opt=getopt_long (argc, argv, "abBdHiI:lo:stvw:W", longopts, (int *)0)) != EOF) + while ((opt = getopt_long (argc, argv, "abBdHiI:lo:stvw:W", longopts, 0)) + != EOF) { switch (opt) { @@ -468,10 +476,8 @@ main (argc, argv) break; case 'v': - version_requested = 1; - fprintf (stderr, "GNU sdiff version %s\n", version_string); - ck_fflush (stderr); - break; + printf ("sdiff - GNU diffutils version %s\n", version_string); + exit (0); case 'w': diffarg ("-W"); @@ -482,27 +488,36 @@ main (argc, argv) diffarg ("-w"); break; - default: + case 129: usage (); + if (ferror (stdout) || fclose (stdout) != 0) + fatal ("write error"); + exit (0); + + default: + try_help (0); } } - /* check: did user just want version message? if so exit. */ - if (version_requested && argc - optind == 0) - exit (0); - if (argc - optind != 2) - usage (); + try_help (argc - optind < 2 ? "missing operand" : "extra operand"); if (! out_file) - /* easy case: diff does everything for us */ - execdiff (suppress_common_flag, "-y", argv[optind], argv[optind + 1]); + { + /* easy case: diff does everything for us */ + if (suppress_common_flag) + diffarg ("--suppress-common-lines"); + diffarg ("-y"); + diffarg ("--"); + diffarg (argv[optind]); + diffarg (argv[optind + 1]); + diffarg (0); + execdiff (); + } else { FILE *left, *right, *out, *diffout; - int diff_fds[2]; int interact_ok; - pid_t pid; struct line_filter lfilt; struct line_filter rfilt; struct line_filter diff_filt; @@ -517,33 +532,66 @@ main (argc, argv) right = ck_fopen (expand_name (argv[optind + 1], rightdir, argv[optind]), "r"); out = ck_fopen (out_file, "w"); - if (pipe (diff_fds)) - perror_fatal ("pipe"); + diffarg ("--sdiff-merge-assist"); + diffarg ("--"); + diffarg (argv[optind]); + diffarg (argv[optind + 1]); + diffarg (0); trapsigs (); - diffpid = pid = vfork (); +#if ! HAVE_FORK + { + size_t cmdsize = 1; + char *p, *command; + int i; + + for (i = 0; diffargv[i]; i++) + cmdsize += 4 * strlen (diffargv[i]) + 3; + command = p = xmalloc (cmdsize); + for (i = 0; diffargv[i]; i++) + { + char const *a = diffargv[i]; + SYSTEM_QUOTE_ARG (p, a); + *p++ = ' '; + } + p[-1] = '\0'; + diffout = popen (command, "r"); + if (!diffout) + perror_fatal (command); + free (command); + } +#else /* HAVE_FORK */ + { + int diff_fds[2]; - if (pid == 0) - { - signal (SIGINT, SIG_IGN); /* in case user interrupts editor */ - signal (SIGPIPE, SIG_DFL); + if (pipe (diff_fds) != 0) + perror_fatal ("pipe"); - close (diff_fds[0]); - if (diff_fds[1] != fileno (stdout)) - { - dup2 (diff_fds[1], fileno (stdout)); - close (diff_fds[1]); - } + diffpid = vfork (); + if (diffpid < 0) + perror_fatal ("fork failed"); + if (!diffpid) + { + signal (SIGINT, SIG_IGN); /* in case user interrupts editor */ + signal (SIGPIPE, SIG_DFL); - execdiff (0, "--sdiff-merge-assist", argv[optind], argv[optind + 1]); - } + close (diff_fds[0]); + if (diff_fds[1] != STDOUT_FILENO) + { + dup2 (diff_fds[1], STDOUT_FILENO); + close (diff_fds[1]); + } - if (pid < 0) - perror_fatal ("fork failed"); + execdiff (); + } - close (diff_fds[1]); - diffout = ck_fdopen (diff_fds[0], "r"); + close (diff_fds[1]); + diffout = fdopen (diff_fds[0], "r"); + if (!diffout) + perror_fatal ("fdopen"); + } +#endif /* HAVE_FORK */ lf_init (&diff_filt, diffout); lf_init (&lfilt, left); @@ -551,7 +599,6 @@ main (argc, argv) interact_ok = interact (&diff_filt, &lfilt, &rfilt, out); - ck_fclose (diffout); ck_fclose (left); ck_fclose (right); ck_fclose (out); @@ -559,9 +606,17 @@ main (argc, argv) { int wstatus; - if (waitpid (pid, &wstatus, 0) < 0) - perror_fatal ("wait failed"); +#if ! HAVE_FORK + wstatus = pclose (diffout); +#else + ck_fclose (diffout); + while (waitpid (diffpid, &wstatus, 0) < 0) + if (errno == EINTR) + checksigs (); + else + perror_fatal ("wait failed"); diffpid = 0; +#endif if (tmpmade) { @@ -570,22 +625,22 @@ main (argc, argv) } if (! interact_ok) - exit (2); + exiterr (); if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2)) fatal ("Subsidiary diff failed"); + untrapsig (0); + checksigs (); exit (WEXITSTATUS (wstatus)); } } return 0; /* Fool -Wall . . . */ } -static char **diffargv; - static void diffarg (a) - char *a; + char const *a; { static unsigned diffargs, diffargsmax; @@ -593,11 +648,12 @@ diffarg (a) { if (! diffargsmax) { - diffargv = (char **) xmalloc (sizeof (char)); + diffargv = (char const **) xmalloc (sizeof (char)); diffargsmax = 8; } diffargsmax *= 2; - diffargv = (char **) realloc (diffargv, diffargsmax * sizeof (char *)); + diffargv = (char const **) realloc (diffargv, + diffargsmax * sizeof (char const *)); if (! diffargv) fatal ("out of memory"); } @@ -605,21 +661,11 @@ diffarg (a) } static void -execdiff (differences_only, option, file1, file2) - int differences_only; - char *option, *file1, *file2; +execdiff () { - if (differences_only) - diffarg ("--suppress-common-lines"); - diffarg (option); - diffarg ("--"); - diffarg (file1); - diffarg (file2); - diffarg (0); - - execvp (diffbin, diffargv); - write (fileno (stderr), diffbin, strlen (diffbin)); - write (fileno (stderr), ": not found\n", 12); + execvp (diffbin, (char **) diffargv); + write (STDERR_FILENO, diffbin, strlen (diffbin)); + write (STDERR_FILENO, ": not found\n", 12); _exit (2); } @@ -628,47 +674,129 @@ execdiff (differences_only, option, file1, file2) /* Signal handling */ -static int volatile ignore_signals; +#define NUM_SIGS (sizeof (sigs) / sizeof (*sigs)) +static int const sigs[] = { +#ifdef SIGHUP + SIGHUP, +#endif +#ifdef SIGQUIT + SIGQUIT, +#endif +#ifdef SIGTERM + SIGTERM, +#endif +#ifdef SIGXCPU + SIGXCPU, +#endif +#ifdef SIGXFSZ + SIGXFSZ, +#endif + SIGINT, + SIGPIPE +}; -static void +/* Prefer `sigaction' if it is available, since `signal' can lose signals. */ +#if HAVE_SIGACTION +static struct sigaction initial_action[NUM_SIGS]; +#define initial_handler(i) (initial_action[i].sa_handler) +#else +static RETSIGTYPE (*initial_action[NUM_SIGS]) (); +#define initial_handler(i) (initial_action[i]) +#endif + +static int volatile ignore_SIGINT; +static int volatile signal_received; +static int sigs_trapped; + +static RETSIGTYPE catchsig (s) int s; { - signal (s, catchsig); - if (! ignore_signals) +#if ! HAVE_SIGACTION + signal (s, SIG_IGN); +#endif + if (! (s == SIGINT && ignore_SIGINT)) + signal_received = s; +} + +static void +trapsigs () +{ + int i; + +#if HAVE_SIGACTION + struct sigaction catchaction; + bzero (&catchaction, sizeof (catchaction)); + catchaction.sa_handler = catchsig; +#ifdef SA_INTERRUPT + /* Non-Posix BSD-style systems like SunOS 4.1.x need this + so that `read' calls are interrupted properly. */ + catchaction.sa_flags = SA_INTERRUPT; +#endif + sigemptyset (&catchaction.sa_mask); + for (i = 0; i < NUM_SIGS; i++) + sigaddset (&catchaction.sa_mask, sigs[i]); + for (i = 0; i < NUM_SIGS; i++) { - cleanup (); - _exit (2); + sigaction (sigs[i], 0, &initial_action[i]); + if (initial_handler (i) != SIG_IGN + && sigaction (sigs[i], &catchaction, 0) != 0) + fatal ("signal error"); + } +#else /* ! HAVE_SIGACTION */ + for (i = 0; i < NUM_SIGS; i++) + { + initial_action[i] = signal (sigs[i], SIG_IGN); + if (initial_handler (i) != SIG_IGN + && signal (sigs[i], catchsig) != SIG_IGN) + fatal ("signal error"); } +#endif /* ! HAVE_SIGACTION */ + +#if !defined(SIGCHLD) && defined(SIGCLD) +#define SIGCHLD SIGCLD +#endif +#ifdef SIGCHLD + /* System V fork+wait does not work if SIGCHLD is ignored. */ + signal (SIGCHLD, SIG_DFL); +#endif + + sigs_trapped = 1; } +/* Untrap signal S, or all trapped signals if S is zero. */ static void -trapsigs () +untrapsig (s) + int s; { - static int const sigs[] = { -# ifdef SIGHUP - SIGHUP, -# endif -# ifdef SIGQUIT - SIGQUIT, -# endif -# ifdef SIGTERM - SIGTERM, -# endif -# ifdef SIGXCPU - SIGXCPU, -# endif -# ifdef SIGXFSZ - SIGXFSZ, -# endif - SIGINT, - SIGPIPE - }; - int const *p; - - for (p = sigs; p < sigs + sizeof (sigs) / sizeof (*sigs); p++) - if (signal (*p, SIG_IGN) != SIG_IGN && signal (*p, catchsig) != SIG_IGN) - fatal ("signal error"); + int i; + + if (sigs_trapped) + for (i = 0; i < NUM_SIGS; i++) + if ((!s || sigs[i] == s) && initial_handler (i) != SIG_IGN) +#if HAVE_SIGACTION + sigaction (sigs[i], &initial_action[i], 0); +#else + signal (sigs[i], initial_action[i]); +#endif +} + +/* Exit if a signal has been received. */ +static void +checksigs () +{ + int s = signal_received; + if (s) + { + cleanup (); + + /* Yield an exit status indicating that a signal was received. */ + untrapsig (s); + kill (getpid (), s); + + /* That didn't work, so exit with error status. */ + exit (2); + } } @@ -691,8 +819,13 @@ static int skip_white () { int c; - while (isspace (c = getchar ()) && c != '\n') - ; + for (;;) + { + c = getchar (); + if (!ISSPACE (c) || c == '\n') + break; + checksigs (); + } if (ferror (stdin)) perror_fatal ("input error"); return c; @@ -723,6 +856,8 @@ edit (left, lenl, right, lenr, outfile) int cmd0, cmd1; int gotcmd = 0; + cmd1 = 0; /* Pacify `gcc -W'. */ + while (!gotcmd) { if (putchar ('%') != '%') @@ -773,8 +908,10 @@ edit (left, lenl, right, lenr, outfile) } /* falls through */ default: - give_help (); flush_line (); + /* falls through */ + case '\n': + give_help (); continue; } } @@ -798,7 +935,7 @@ edit (left, lenl, right, lenr, outfile) case 'q': return 0; case 'e': - if (! tmpname && ! (tmpname = private_tempnam (0, "sdiff", 1, 0))) + if (! tmpname && ! (tmpname = private_tempnam ())) perror_fatal ("temporary file name"); tmpmade = 1; @@ -819,10 +956,17 @@ edit (left, lenl, right, lenr, outfile) ck_fflush (tmp); { - pid_t pid; int wstatus; +#if ! HAVE_FORK + char *command = xmalloc (strlen (edbin) + strlen (tmpname) + 2); + sprintf (command, "%s %s", edbin, tmpname); + wstatus = system (command); + free (command); +#else /* HAVE_FORK */ + pid_t pid; - ignore_signals = 1; + ignore_SIGINT = 1; + checksigs (); pid = vfork (); if (pid == 0) @@ -835,8 +979,8 @@ edit (left, lenl, right, lenr, outfile) argv[i++] = 0; execvp (edbin, (char **) argv); - write (fileno (stderr), edbin, strlen (edbin)); - write (fileno (stderr), ": not found\n", 12); + write (STDERR_FILENO, edbin, strlen (edbin)); + write (STDERR_FILENO, ": not found\n", 12); _exit (1); } @@ -844,12 +988,15 @@ edit (left, lenl, right, lenr, outfile) perror_fatal ("fork failed"); while (waitpid (pid, &wstatus, 0) < 0) - if (errno != EINTR) + if (errno == EINTR) + checksigs (); + else perror_fatal ("wait failed"); - ignore_signals = 0; + ignore_SIGINT = 0; +#endif /* HAVE_FORK */ - if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 1)) + if (wstatus != 0) fatal ("Subsidiary editor failed"); } @@ -858,11 +1005,14 @@ edit (left, lenl, right, lenr, outfile) { /* SDIFF_BUFSIZE is too big for a local var in some compilers, so we allocate it dynamically. */ - char *buf = (char *) xmalloc (SDIFF_BUFSIZE); + char *buf = xmalloc (SDIFF_BUFSIZE); size_t size; while ((size = ck_fread (buf, SDIFF_BUFSIZE, tmp)) != 0) - ck_fwrite (buf, size, outfile); + { + checksigs (); + ck_fwrite (buf, size, outfile); + } ck_fclose (tmp); free (buf); @@ -878,7 +1028,7 @@ edit (left, lenl, right, lenr, outfile) -/* Alternately reveal bursts of diff output and handle user editing comands. */ +/* Alternately reveal bursts of diff output and handle user commands. */ static int interact (diff, left, right, outfile) struct line_filter *diff; @@ -894,6 +1044,8 @@ interact (diff, left, right, outfile) if (snarfed <= 0) return snarfed; + checksigs (); + switch (diff_help[0]) { case ' ': @@ -902,7 +1054,7 @@ interact (diff, left, right, outfile) case 'i': { int lenl = atoi (diff_help + 1), lenr, lenmax; - char *p = index (diff_help, ','); + char *p = strchr (diff_help, ','); if (!p) fatal (diff_help); @@ -921,7 +1073,7 @@ interact (diff, left, right, outfile) case 'c': { int lenl = atoi (diff_help + 1), lenr; - char *p = index (diff_help, ','); + char *p = strchr (diff_help, ','); if (!p) fatal (diff_help); @@ -941,127 +1093,88 @@ interact (diff, left, right, outfile) /* temporary lossage: this is torn from gnu libc */ -/* Return nonzero if DIR is an existent directory. */ +/* Return nonzero if DIR is an existing directory. */ static int diraccess (dir) - const char *dir; + char const *dir; { struct stat buf; return stat (dir, &buf) == 0 && S_ISDIR (buf.st_mode); } -/* Return nonzero if FILE exists. */ +#if ! HAVE_TMPNAM + +/* Return zero if we know that FILE does not exist. */ static int exists (file) - const char *file; + char const *file; { struct stat buf; - return stat (file, &buf) == 0; + return stat (file, &buf) == 0 || errno != ENOENT; } /* These are the characters used in temporary filenames. */ -static const char letters[] = +static char const letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; -/* Generate a temporary filename. - If DIR_SEARCH is nonzero, DIR and PFX are used as - described for tempnam. If not, a temporary filename - in P_tmpdir with no special prefix is generated. If LENPTR - is not NULL, *LENPTR is set the to length (including the - terminating '\0') of the resultant filename, which is returned. - This goes through a cyclic pattern of all possible filenames - consisting of five decimal digits of the current pid and three - of the characters in `letters'. Data for tempnam and tmpnam - is kept separate, but when tempnam is using P_tmpdir and no - prefix (i.e, it is identical to tmpnam), the same data is used. - Each potential filename is tested for an already-existing file of - the same name, and no name of an existing file will be returned. - When the cycle reaches its end (12345ZZZ), NULL is returned. */ - - +/* Generate a temporary filename and return it (in a newly allocated buffer). + Use the prefix "dif" as in tempnam. + This goes through a cyclic pattern of all possible + filenames consisting of five decimal digits of the current pid and three + of the characters in `letters'. Each potential filename is + tested for an already-existing file of the same name, and no name of an + existing file will be returned. When the cycle reaches its end + return 0. */ static char * -private_tempnam (dir, pfx, dir_search, lenptr) - const char *dir; - const char *pfx; - int dir_search; - size_t *lenptr; +private_tempnam () { - static const char tmpdir[] = PVT_tmpdir; - static struct - { - char buf[3]; - char *s; - size_t i; - } infos[2], *info; - static char buf[TMPNAMSIZE]; - static pid_t oldpid = 0; + char const *dir = getenv (TMPDIR_ENV); + static char const tmpdir[] = PVT_tmpdir; + size_t index; + char *buf; pid_t pid = getpid (); - register size_t len, plen; + size_t dlen; - if (dir_search) - { - register const char *d = getenv ("TMPDIR"); - if (d != NULL && !diraccess (d)) - d = NULL; - if (d == NULL && dir != NULL && diraccess (dir)) - d = dir; - if (d == NULL && diraccess (tmpdir)) - d = tmpdir; - if (d == NULL && diraccess ("/tmp")) - d = "/tmp"; - if (d == NULL) - { - errno = ENOENT; - return NULL; - } - dir = d; - } - else + if (!dir) dir = tmpdir; - if (pfx != NULL && *pfx != '\0') - { - plen = strlen (pfx); - if (plen > 5) - plen = 5; - } - else - plen = 0; + dlen = strlen (dir); - if (dir != tmpdir && !strcmp (dir, tmpdir)) - dir = tmpdir; - info = &infos[(plen == 0 && dir == tmpdir) ? 1 : 0]; + /* Remove trailing slashes from the directory name. */ + while (dlen && dir[dlen - 1] == '/') + --dlen; - if (pid != oldpid) - { - oldpid = pid; - info->buf[0] = info->buf[1] = info->buf[2] = '0'; - info->s = &info->buf[0]; - info->i = 0; - } + buf = xmalloc (dlen + 1 + 3 + 5 + 1 + 3 + 1); - len = strlen (dir) + 1 + plen + 8; - for (;;) + sprintf (buf, "%.*s/.", (int) dlen, dir); + if (diraccess (buf)) { - *info->s = letters[info->i]; - sprintf (buf, "%s/%.*s%.5d%.3s", dir, (int) plen, pfx, - pid % 100000, info->buf); - if (!exists (buf)) - break; - ++info->i; - if (info->i > sizeof (letters) - 1) + for (index = 0; + index < ((sizeof (letters) - 1) * (sizeof (letters) - 1) + * (sizeof (letters) - 1)); + ++index) { - info->i = 0; - if (info->s == &info->buf[2]) - { - errno = EEXIST; - return NULL; - } - ++info->s; + /* Construct a file name and see if it already exists. + + We use a single counter in INDEX to cycle each of three + character positions through each of 62 possible letters. */ + + sprintf (buf, "%.*s/dif%.5lu.%c%c%c", (int) dlen, dir, + (unsigned long) pid % 100000, + letters[index % (sizeof (letters) - 1)], + letters[(index / (sizeof (letters) - 1)) + % (sizeof (letters) - 1)], + letters[index / ((sizeof (letters) - 1) * + (sizeof (letters) - 1))]); + + if (!exists (buf)) + return buf; } + errno = EEXIST; } - if (lenptr != NULL) - *lenptr = len; - return buf; + /* Don't free buf; `free' might change errno. We'll exit soon anyway. */ + return 0; } + +#endif /* ! HAVE_TMPNAM */ diff --git a/gnu/usr.bin/diff/side.c b/gnu/usr.bin/diff/side.c index a3d6d8b..a150b5e 100644 --- a/gnu/usr.bin/diff/side.c +++ b/gnu/usr.bin/diff/side.c @@ -21,10 +21,11 @@ and this notice must be preserved on all copies. */ #include "diff.h" - -static void print_sdiff_hunk (); -static void print_sdiff_common_lines (); -static void print_1sdiff_line (); +static unsigned print_half_line PARAMS((char const * const *, unsigned, unsigned)); +static unsigned tab_from_to PARAMS((unsigned, unsigned)); +static void print_1sdiff_line PARAMS((char const * const *, int, char const * const *)); +static void print_sdiff_common_lines PARAMS((int, int)); +static void print_sdiff_hunk PARAMS((struct change *)); /* Next line number to be printed in the two input files. */ static int next0, next1; @@ -70,12 +71,12 @@ tab_from_to (from, to) */ static unsigned print_half_line (line, indent, out_bound) - const char * const *line; + char const * const *line; unsigned indent, out_bound; { FILE *out = outfile; register unsigned in_position = 0, out_position = 0; - register const char + register char const *text_pointer = line[0], *text_limit = line[1]; @@ -132,21 +133,21 @@ print_half_line (line, indent, out_bound) case '\f': case '\v': + control_char: if (in_position < out_bound) putc (c, out); break; default: - { - register unsigned p = in_position; - if (textchar[c]) - in_position++; - if (p < out_bound) - { - out_position = in_position; - putc (c, out); - } - } + if (! ISPRINT (c)) + goto control_char; + /* falls through */ + case ' ': + if (in_position++ < out_bound) + { + out_position = in_position; + putc (c, out); + } break; case '\n': @@ -159,21 +160,21 @@ print_half_line (line, indent, out_bound) /* * Print side by side lines with a separator in the middle. - * NULL parameters are taken to indicate whitespace text. + * 0 parameters are taken to indicate white space text. * Blank lines that can easily be caught are reduced to a single newline. */ static void print_1sdiff_line (left, sep, right) - const char * const *left; + char const * const *left; int sep; - const char * const *right; + char const * const *right; { FILE *out = outfile; unsigned hw = sdiff_half_width, c2o = sdiff_column2_offset; unsigned col = 0; int put_newline = 0; - + if (left) { if (left[1][-1] == '\n') diff --git a/gnu/usr.bin/diff/system.h b/gnu/usr.bin/diff/system.h index b17d39a..d60af60 100644 --- a/gnu/usr.bin/diff/system.h +++ b/gnu/usr.bin/diff/system.h @@ -1,5 +1,5 @@ /* System dependent declarations. - Copyright (C) 1988, 1989, 1992, 1993 Free Software Foundation, Inc. + Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc. This file is part of GNU DIFF. @@ -17,20 +17,74 @@ You should have received a copy of the GNU General Public License along with GNU DIFF; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* We must define `volatile' and `const' first (the latter inside config.h), + so that they're used consistently in all system includes. */ +#if !__STDC__ +#ifndef volatile +#define volatile +#endif +#endif +#include <config.h> + #include <sys/types.h> #include <sys/stat.h> +#if __STDC__ +#define PARAMS(args) args +#define VOID void +#else +#define PARAMS(args) () +#define VOID char +#endif + +#if STAT_MACROS_BROKEN +#undef S_ISBLK +#undef S_ISCHR +#undef S_ISDIR +#undef S_ISFIFO +#undef S_ISREG +#undef S_ISSOCK +#endif #ifndef S_ISDIR #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) #endif #ifndef S_ISREG #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) #endif +#if !defined(S_ISBLK) && defined(S_IFBLK) +#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) +#endif +#if !defined(S_ISCHR) && defined(S_IFCHR) +#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) +#endif +#if !defined(S_ISFIFO) && defined(S_IFFIFO) +#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFFIFO) +#endif +#if !defined(S_ISSOCK) && defined(S_IFSOCK) +#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) +#endif #if HAVE_UNISTD_H #include <unistd.h> #endif +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 +#endif +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 1 +#endif +#ifndef STDERR_FILENO +#define STDERR_FILENO 2 +#endif + #if HAVE_TIME_H #include <time.h> #else @@ -40,8 +94,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #if HAVE_FCNTL_H #include <fcntl.h> #else +#if HAVE_SYS_FILE_H #include <sys/file.h> #endif +#endif #if !HAVE_DUP2 #define dup2(f,t) (close (t), fcntl (f,F_DUPFD,t)) @@ -52,89 +108,102 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #endif #if HAVE_SYS_WAIT_H -#ifndef _POSIX_VERSION -/* Prevent the NeXT prototype using union wait from causing problems. */ -#define wait system_wait -#endif #include <sys/wait.h> -#ifndef _POSIX_VERSION -#undef wait #endif -#endif /* HAVE_SYS_WAIT_H */ - #ifndef WEXITSTATUS -#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) -#undef WIFEXITED /* Avoid 4.3BSD incompatibility with Posix. */ +#define WEXITSTATUS(stat_val) ((unsigned) (stat_val) >> 8) #endif #ifndef WIFEXITED #define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif +#ifndef STAT_BLOCKSIZE #if HAVE_ST_BLKSIZE #define STAT_BLOCKSIZE(s) (s).st_blksize #else -#define STAT_BLOCKSIZE(s) (S_ISREG ((s).st_mode) ? 8192 : 4096) +#define STAT_BLOCKSIZE(s) (8 * 1024) #endif - -#if DIRENT || defined (_POSIX_VERSION) -#include <dirent.h> -#ifdef direct -#undef direct #endif -#define direct dirent -#else /* ! (DIRENT || defined (_POSIX_VERSION)) */ -#if SYSNDIR -#include <sys/ndir.h> -#else -#if SYSDIR -#include <sys/dir.h> + +#if HAVE_DIRENT_H +# include <dirent.h> +# define NAMLEN(dirent) strlen((dirent)->d_name) #else -#include <ndir.h> +# define dirent direct +# define NAMLEN(dirent) ((dirent)->d_namlen) +# if HAVE_SYS_NDIR_H +# include <sys/ndir.h> +# endif +# if HAVE_SYS_DIR_H +# include <sys/dir.h> +# endif +# if HAVE_NDIR_H +# include <ndir.h> +# endif #endif -#endif -#endif /* ! (DIRENT || defined (_POSIX_VERSION)) */ #if HAVE_VFORK_H #include <vfork.h> #endif -#if HAVE_STRING_H || STDC_HEADERS -#include <string.h> -#ifndef index -#define index strchr +#if HAVE_STDLIB_H +#include <stdlib.h> +#else +VOID *malloc (); +VOID *realloc (); #endif -#ifndef rindex -#define rindex strrchr +#ifndef getenv +char *getenv (); #endif -#ifndef bcopy -#define bcopy(s,d,n) memcpy (d,s,n) + +#if HAVE_LIMITS_H +#include <limits.h> #endif -#ifndef bcmp -#define bcmp(s1,s2,n) memcmp (s1,s2,n) +#ifndef INT_MAX +#define INT_MAX 2147483647 #endif -#ifndef bzero -#define bzero(s,n) memset (s,0,n) +#ifndef CHAR_BIT +#define CHAR_BIT 8 #endif + +#if STDC_HEADERS || HAVE_STRING_H +# include <string.h> +# ifndef bzero +# define bzero(s, n) memset (s, 0, n) +# endif #else -#include <strings.h> -#endif -#if !HAVE_MEMCHR && !STDC_HEADERS -char *memchr (); +# if !HAVE_STRCHR +# define strchr index +# define strrchr rindex +# endif +char *strchr (), *strrchr (); +# if !HAVE_MEMCHR +# define memcmp(s1, s2, n) bcmp (s1, s2, n) +# define memcpy(d, s, n) bcopy (s, d, n) +void *memchr (); +# endif #endif +#include <ctype.h> +/* CTYPE_DOMAIN (C) is nonzero if the unsigned char C can safely be given + as an argument to <ctype.h> macros like `isspace'. */ #if STDC_HEADERS -#include <stdlib.h> -#include <limits.h> -#else -char *getenv (); -char *malloc (); -char *realloc (); -#if __STDC__ || __GNUC__ -#include "limits.h" +#define CTYPE_DOMAIN(c) 1 #else -#define INT_MAX 2147483647 -#define CHAR_BIT 8 +#define CTYPE_DOMAIN(c) ((unsigned) (c) <= 0177) +#endif +#ifndef ISPRINT +#define ISPRINT(c) (CTYPE_DOMAIN (c) && isprint (c)) +#endif +#ifndef ISSPACE +#define ISSPACE(c) (CTYPE_DOMAIN (c) && isspace (c)) #endif +#ifndef ISUPPER +#define ISUPPER(c) (CTYPE_DOMAIN (c) && isupper (c)) +#endif + +#ifndef ISDIGIT +#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9) #endif #include <errno.h> @@ -142,18 +211,57 @@ char *realloc (); extern int errno; #endif -#ifdef TRUE -#undef TRUE +#ifdef min +#undef min #endif -#ifdef FALSE -#undef FALSE +#ifdef max +#undef max #endif -#define TRUE 1 -#define FALSE 0 +#define min(a,b) ((a) <= (b) ? (a) : (b)) +#define max(a,b) ((a) >= (b) ? (a) : (b)) + +/* This section contains Posix-compliant defaults for macros + that are meant to be overridden by hand in config.h as needed. */ -#if !__STDC__ -#define volatile +#ifndef filename_cmp +#define filename_cmp(a, b) strcmp (a, b) #endif -#define min(a,b) ((a) <= (b) ? (a) : (b)) -#define max(a,b) ((a) >= (b) ? (a) : (b)) +#ifndef filename_lastdirchar +#define filename_lastdirchar(filename) strrchr (filename, '/') +#endif + +#ifndef HAVE_FORK +#define HAVE_FORK 1 +#endif + +#ifndef HAVE_SETMODE +#define HAVE_SETMODE 0 +#endif + +#ifndef initialize_main +#define initialize_main(argcp, argvp) +#endif + +/* Do struct stat *S, *T describe the same file? Answer -1 if unknown. */ +#ifndef same_file +#define same_file(s,t) ((s)->st_ino==(t)->st_ino && (s)->st_dev==(t)->st_dev) +#endif + +/* Place into Q a quoted version of A suitable for `popen' or `system', + incrementing Q and junking A. + Do not increment Q by more than 4 * strlen (A) + 2. */ +#ifndef SYSTEM_QUOTE_ARG +#define SYSTEM_QUOTE_ARG(q, a) \ + { \ + *(q)++ = '\''; \ + for (; *(a); *(q)++ = *(a)++) \ + if (*(a) == '\'') \ + { \ + *(q)++ = '\''; \ + *(q)++ = '\\'; \ + *(q)++ = '\''; \ + } \ + *(q)++ = '\''; \ + } +#endif diff --git a/gnu/usr.bin/diff/util.c b/gnu/usr.bin/diff/util.c index e72fd4d..bbc3bff 100644 --- a/gnu/usr.bin/diff/util.c +++ b/gnu/usr.bin/diff/util.c @@ -1,5 +1,5 @@ /* Support routines for GNU DIFF. - Copyright (C) 1988, 1989, 1992 Free Software Foundation, Inc. + Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc. This file is part of GNU DIFF. @@ -19,15 +19,40 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "diff.h" +#ifndef PR_PROGRAM +#define PR_PROGRAM "/bin/pr" +#endif + +/* Queue up one-line messages to be printed at the end, + when -l is specified. Each message is recorded with a `struct msg'. */ + +struct msg +{ + struct msg *next; + char const *format; + char const *arg1; + char const *arg2; + char const *arg3; + char const *arg4; +}; + +/* Head of the chain of queues messages. */ + +static struct msg *msg_chain; + +/* Tail of the chain of queues messages. */ + +static struct msg **msg_chain_end = &msg_chain; + /* Use when a system call returns non-zero status. TEXT should normally be the file name. */ void perror_with_name (text) - char *text; + char const *text; { int e = errno; - fprintf (stderr, "%s: ", program); + fprintf (stderr, "%s: ", program_name); errno = e; perror (text); } @@ -36,11 +61,11 @@ perror_with_name (text) void pfatal_with_name (text) - char *text; + char const *text; { int e = errno; print_message_queue (); - fprintf (stderr, "%s: ", program); + fprintf (stderr, "%s: ", program_name); errno = e; perror (text); exit (2); @@ -51,11 +76,9 @@ pfatal_with_name (text) void error (format, arg, arg1) - char *format; - char *arg; - char *arg1; + char const *format, *arg, *arg1; { - fprintf (stderr, "%s: ", program); + fprintf (stderr, "%s: ", program_name); fprintf (stderr, format, arg, arg1); fprintf (stderr, "\n"); } @@ -64,7 +87,7 @@ error (format, arg, arg1) void fatal (m) - char *m; + char const *m; { print_message_queue (); error ("%s", m, 0); @@ -76,28 +99,32 @@ fatal (m) void message (format, arg1, arg2) - char *format, *arg1, *arg2; + char const *format, *arg1, *arg2; +{ + message5 (format, arg1, arg2, 0, 0); +} + +void +message5 (format, arg1, arg2, arg3, arg4) + char const *format, *arg1, *arg2, *arg3, *arg4; { if (paginate_flag) { struct msg *new = (struct msg *) xmalloc (sizeof (struct msg)); - if (msg_chain_end == 0) - msg_chain = msg_chain_end = new; - else - { - msg_chain_end->next = new; - msg_chain_end = new; - } new->format = format; new->arg1 = concat (arg1, "", ""); new->arg2 = concat (arg2, "", ""); + new->arg3 = arg3 ? concat (arg3, "", "") : 0; + new->arg4 = arg4 ? concat (arg4, "", "") : 0; new->next = 0; + *msg_chain_end = new; + msg_chain_end = &new->next; } else { if (sdiff_help_sdiff) putchar (' '); - printf (format, arg1, arg2); + printf (format, arg1, arg2, arg3, arg4); } } @@ -109,7 +136,7 @@ print_message_queue () struct msg *m; for (m = msg_chain; m; m = m->next) - printf (m->format, m->arg1, m->arg2); + printf (m->format, m->arg1, m->arg2, m->arg3, m->arg4); } /* Call before outputting the results of comparing files NAME0 and NAME1 @@ -119,13 +146,13 @@ print_message_queue () we fork off a `pr' and make OUTFILE a pipe to it. `pr' then outputs to our stdout. */ -static char *current_name0; -static char *current_name1; +static char const *current_name0; +static char const *current_name1; static int current_depth; void setup_output (name0, name1, depth) - char *name0, *name1; + char const *name0, *name1; int depth; { current_name0 = name0; @@ -134,6 +161,10 @@ setup_output (name0, name1, depth) outfile = 0; } +#if HAVE_FORK +static pid_t pr_pid; +#endif + void begin_output () { @@ -143,49 +174,63 @@ begin_output () return; /* Construct the header of this piece of diff. */ - name = (char *) xmalloc (strlen (current_name0) + strlen (current_name1) - + strlen (switch_string) + 15); - - strcpy (name, "diff"); - strcat (name, switch_string); - strcat (name, " "); - strcat (name, current_name0); - strcat (name, " "); - strcat (name, current_name1); + name = xmalloc (strlen (current_name0) + strlen (current_name1) + + strlen (switch_string) + 7); + /* Posix.2 section 4.17.6.1.1 specifies this format. But there is a + bug in the first printing (IEEE Std 1003.2-1992 p 251 l 3304): + it says that we must print only the last component of the pathnames. + This requirement is silly and does not match historical practice. */ + sprintf (name, "diff%s %s %s", switch_string, current_name0, current_name1); if (paginate_flag) { + /* Make OUTFILE a pipe to a subsidiary `pr'. */ + +#if HAVE_FORK int pipes[2]; - int desc; - /* For a `pr' and make OUTFILE a pipe to it. */ - if (pipe (pipes) < 0) + if (pipe (pipes) != 0) pfatal_with_name ("pipe"); fflush (stdout); - desc = vfork (); - if (desc < 0) + pr_pid = vfork (); + if (pr_pid < 0) pfatal_with_name ("vfork"); - if (desc == 0) + if (pr_pid == 0) { close (pipes[1]); - if (pipes[0] != fileno (stdin)) + if (pipes[0] != STDIN_FILENO) { - if (dup2 (pipes[0], fileno (stdin)) < 0) + if (dup2 (pipes[0], STDIN_FILENO) < 0) pfatal_with_name ("dup2"); close (pipes[0]); } - if (execl (PR_FILE_NAME, PR_FILE_NAME, "-f", "-h", name, 0) < 0) - pfatal_with_name (PR_FILE_NAME); + execl (PR_PROGRAM, PR_PROGRAM, "-f", "-h", name, 0); + pfatal_with_name (PR_PROGRAM); } else { close (pipes[0]); outfile = fdopen (pipes[1], "w"); - } + if (!outfile) + pfatal_with_name ("fdopen"); + } +#else /* ! HAVE_FORK */ + char *command = xmalloc (4 * strlen (name) + strlen (PR_PROGRAM) + 10); + char *p; + char const *a = name; + sprintf (command, "%s -f -h ", PR_PROGRAM); + p = command + strlen (command); + SYSTEM_QUOTE_ARG (p, a); + *p = 0; + outfile = popen (command, "w"); + if (!outfile) + pfatal_with_name (command); + free (command); +#endif /* ! HAVE_FORK */ } else { @@ -226,8 +271,19 @@ finish_output () { if (outfile != 0 && outfile != stdout) { - fclose (outfile); - wait (0); + int wstatus; + if (ferror (outfile)) + fatal ("write error"); +#if ! HAVE_FORK + wstatus = pclose (outfile); +#else /* HAVE_FORK */ + if (fclose (outfile) != 0) + pfatal_with_name ("write error"); + if (waitpid (pr_pid, &wstatus, 0) < 0) + pfatal_with_name ("waitpid"); +#endif /* HAVE_FORK */ + if (wstatus != 0) + fatal ("subsidiary pr failed"); } outfile = 0; @@ -235,58 +291,44 @@ finish_output () /* Compare two lines (typically one from each input file) according to the command line options. - Return 1 if the lines differ, like `bcmp'. */ + For efficiency, this is invoked only when the lines do not match exactly + but an option like -i might cause us to ignore the difference. + Return nonzero if the lines differ. */ int -line_cmp (s1, len1, s2, len2) - const char *s1, *s2; - int len1, len2; +line_cmp (s1, s2) + char const *s1, *s2; { - register const unsigned char *t1, *t2; - register unsigned char end_char = line_end_char; - - /* Check first for exact identity. - If that is true, return 0 immediately. - This detects the common case of exact identity - faster than complete comparison would. */ + register unsigned char const *t1 = (unsigned char const *) s1; + register unsigned char const *t2 = (unsigned char const *) s2; - if (len1 == len2 && bcmp (s1, s2, len1) == 0) - return 0; - - /* Not exactly identical, but perhaps they match anyway - when case or whitespace is ignored. */ - - if (ignore_case_flag || ignore_space_change_flag || ignore_all_space_flag) + while (1) { - t1 = (const unsigned char *) s1; - t2 = (const unsigned char *) s2; + register unsigned char c1 = *t1++; + register unsigned char c2 = *t2++; - while (1) + /* Test for exact char equality first, since it's a common case. */ + if (c1 != c2) { - register unsigned char c1 = *t1++; - register unsigned char c2 = *t2++; - - /* Ignore horizontal whitespace if -b or -w is specified. */ + /* Ignore horizontal white space if -b or -w is specified. */ if (ignore_all_space_flag) { /* For -w, just skip past any white space. */ - while (Is_space (c1)) c1 = *t1++; - while (Is_space (c2)) c2 = *t2++; + while (ISSPACE (c1) && c1 != '\n') c1 = *t1++; + while (ISSPACE (c2) && c2 != '\n') c2 = *t2++; } else if (ignore_space_change_flag) { - /* For -b, advance past any sequence of whitespace in line 1 + /* For -b, advance past any sequence of white space in line 1 and consider it just one Space, or nothing at all if it is at the end of the line. */ - if (c1 == ' ' || c1 == '\t') + if (ISSPACE (c1)) { - while (1) + while (c1 != '\n') { c1 = *t1++; - if (c1 == end_char) - break; - if (c1 != ' ' && c1 != '\t') + if (! ISSPACE (c1)) { --t1; c1 = ' '; @@ -296,14 +338,12 @@ line_cmp (s1, len1, s2, len2) } /* Likewise for line 2. */ - if (c2 == ' ' || c2 == '\t') + if (ISSPACE (c2)) { - while (1) + while (c2 != '\n') { c2 = *t2++; - if (c2 == end_char) - break; - if (c2 != ' ' && c2 != '\t') + if (! ISSPACE (c2)) { --t2; c2 = ' '; @@ -311,23 +351,44 @@ line_cmp (s1, len1, s2, len2) } } } + + if (c1 != c2) + { + /* If we went too far when doing the simple test + for equality, go back to the first non-white-space + character in both sides and try again. */ + if (c2 == ' ' && c1 != '\n' + && (unsigned char const *) s1 + 1 < t1 + && ISSPACE(t1[-2])) + { + --t1; + continue; + } + if (c1 == ' ' && c2 != '\n' + && (unsigned char const *) s2 + 1 < t2 + && ISSPACE(t2[-2])) + { + --t2; + continue; + } + } } - /* Upcase all letters if -i is specified. */ + /* Lowercase all letters if -i is specified. */ if (ignore_case_flag) { - if (islower (c1)) - c1 = toupper (c1); - if (islower (c2)) - c2 = toupper (c2); + if (ISUPPER (c1)) + c1 = tolower (c1); + if (ISUPPER (c2)) + c2 = tolower (c2); } if (c1 != c2) break; - if (c1 == end_char) - return 0; } + if (c1 == '\n') + return 0; } return (1); @@ -364,8 +425,8 @@ find_reverse_change (start) void print_script (script, hunkfun, printfun) struct change *script; - struct change * (*hunkfun) (); - void (*printfun) (); + struct change * (*hunkfun) PARAMS((struct change *)); + void (*printfun) PARAMS((struct change *)); { struct change *next = script; @@ -380,7 +441,7 @@ print_script (script, hunkfun, printfun) /* Disconnect them from the rest of the changes, making them a hunk, and remember the rest for next iteration. */ next = end->link; - end->link = NULL; + end->link = 0; #ifdef DEBUG debug_script (this); #endif @@ -399,18 +460,18 @@ print_script (script, hunkfun, printfun) void print_1_line (line_flag, line) - const char *line_flag; - const char * const *line; + char const *line_flag; + char const * const *line; { - const char *text = line[0], *limit = line[1]; /* Help the compiler. */ + char const *text = line[0], *limit = line[1]; /* Help the compiler. */ FILE *out = outfile; /* Help the compiler some more. */ - const char *flag_format = 0; + char const *flag_format = 0; /* If -T was specified, use a Tab between the line-flag and the text. Otherwise use a Space (as Unix diff does). Print neither space nor tab if line-flags are empty. */ - if (line_flag != NULL && line_flag[0] != 0) + if (line_flag && *line_flag) { flag_format = tab_align_flag ? "%s\t" : "%s "; fprintf (out, flag_format, line_flag); @@ -418,8 +479,7 @@ print_1_line (line_flag, line) output_1_line (text, limit, flag_format, line_flag); - if ((line_flag == NULL || line_flag[0] != 0) && limit[-1] != '\n' - && line_end_char == '\n') + if ((!line_flag || line_flag[0]) && limit[-1] != '\n') fprintf (out, "\n\\ No newline at end of file\n"); } @@ -430,15 +490,15 @@ print_1_line (line_flag, line) void output_1_line (text, limit, flag_format, line_flag) - const char *text, *limit, *flag_format, *line_flag; + char const *text, *limit, *flag_format, *line_flag; { if (!tab_expand_flag) fwrite (text, sizeof (char), limit - text, outfile); else { register FILE *out = outfile; - register char c; - register const char *t = text; + register unsigned char c; + register char const *t = text; register unsigned column = 0; while (t < limit) @@ -469,11 +529,8 @@ output_1_line (text, limit, flag_format, line_flag) break; default: - if (textchar[(unsigned char) c]) + if (ISPRINT (c)) column++; - /* fall into */ - case '\f': - case '\v': putc (c, out); break; } @@ -501,7 +558,7 @@ change_letter (inserts, deletes) int translate_line_number (file, lnum) - struct file_data *file; + struct file_data const *file; int lnum; { return lnum + file->prefix_lines + 1; @@ -509,7 +566,7 @@ translate_line_number (file, lnum) void translate_range (file, a, b, aptr, bptr) - struct file_data *file; + struct file_data const *file; int a, b; int *aptr, *bptr; { @@ -525,7 +582,7 @@ translate_range (file, a, b, aptr, bptr) void print_number_range (sepchar, file, a, b) - char sepchar; + int sepchar; struct file_data *file; int a, b; { @@ -544,7 +601,7 @@ print_number_range (sepchar, file, a, b) /* Look at a hunk of edit script and report the range of lines in each file that it applies to. HUNK is the start of the hunk, which is a chain of `struct change'. The first and last line numbers of file 0 are stored in - *FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1. + *FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1. Note that these are internal line numbers that count from 0. If no lines from file 0 are deleted, then FIRST0 is LAST0+1. @@ -560,28 +617,29 @@ analyze_hunk (hunk, first0, last0, first1, last1, deletes, inserts) int *first0, *last0, *first1, *last1; int *deletes, *inserts; { - int f0, l0, f1, l1, show_from, show_to; + int l0, l1, show_from, show_to; int i; - int nontrivial = !(ignore_blank_lines_flag || ignore_regexp_list); + int trivial = ignore_blank_lines_flag || ignore_regexp_list; struct change *next; show_from = show_to = 0; - f0 = hunk->line0; - f1 = hunk->line1; + *first0 = hunk->line0; + *first1 = hunk->line1; - for (next = hunk; next; next = next->link) + next = hunk; + do { l0 = next->line0 + next->deleted - 1; l1 = next->line1 + next->inserted - 1; show_from += next->deleted; show_to += next->inserted; - for (i = next->line0; i <= l0 && ! nontrivial; i++) + for (i = next->line0; i <= l0 && trivial; i++) if (!ignore_blank_lines_flag || files[0].linbuf[i][0] != '\n') { struct regexp_list *r; - const char *line = files[0].linbuf[i]; + char const *line = files[0].linbuf[i]; int len = files[0].linbuf[i + 1] - line; for (r = ignore_regexp_list; r; r = r->next) @@ -589,15 +647,15 @@ analyze_hunk (hunk, first0, last0, first1, last1, deletes, inserts) break; /* Found a match. Ignore this line. */ /* If we got all the way through the regexp list without finding a match, then it's nontrivial. */ - if (r == NULL) - nontrivial = 1; + if (!r) + trivial = 0; } - for (i = next->line1; i <= l1 && ! nontrivial; i++) + for (i = next->line1; i <= l1 && trivial; i++) if (!ignore_blank_lines_flag || files[1].linbuf[i][0] != '\n') { struct regexp_list *r; - const char *line = files[1].linbuf[i]; + char const *line = files[1].linbuf[i]; int len = files[1].linbuf[i + 1] - line; for (r = ignore_regexp_list; r; r = r->next) @@ -605,20 +663,19 @@ analyze_hunk (hunk, first0, last0, first1, last1, deletes, inserts) break; /* Found a match. Ignore this line. */ /* If we got all the way through the regexp list without finding a match, then it's nontrivial. */ - if (r == NULL) - nontrivial = 1; + if (!r) + trivial = 0; } } + while ((next = next->link) != 0); - *first0 = f0; *last0 = l0; - *first1 = f1; *last1 = l1; /* If all inserted or deleted lines are ignorable, tell the caller to ignore this hunk. */ - if (!nontrivial) + if (trivial) show_from = show_to = 0; *deletes = show_from; @@ -629,7 +686,7 @@ analyze_hunk (hunk, first0, last0, first1, last1, deletes, inserts) VOID * xmalloc (size) - unsigned size; + size_t size; { register VOID *value; @@ -639,7 +696,7 @@ xmalloc (size) value = (VOID *) malloc (size); if (!value) - fatal ("virtual memory exhausted"); + fatal ("memory exhausted"); return value; } @@ -648,7 +705,7 @@ xmalloc (size) VOID * xrealloc (old, size) VOID *old; - unsigned int size; + size_t size; { register VOID *value; @@ -658,7 +715,7 @@ xrealloc (old, size) value = (VOID *) realloc (old, size); if (!value) - fatal ("virtual memory exhausted"); + fatal ("memory exhausted"); return value; } @@ -666,15 +723,24 @@ xrealloc (old, size) char * concat (s1, s2, s3) - char *s1, *s2, *s3; + char const *s1, *s2, *s3; { - int len = strlen (s1) + strlen (s2) + strlen (s3); - char *new = (char *) xmalloc (len + 1); - strcpy (new, s1); - strcat (new, s2); - strcat (new, s3); + size_t len = strlen (s1) + strlen (s2) + strlen (s3); + char *new = xmalloc (len + 1); + sprintf (new, "%s%s%s", s1, s2, s3); return new; } + +/* Yield the newly malloc'd pathname + of the file in DIR whose filename is FILE. */ + +char * +dir_file_pathname (dir, file) + char const *dir, *file; +{ + char const *p = filename_lastdirchar (dir); + return concat (dir, "/" + (p && !p[1]), file); +} void debug_script (sp) @@ -686,18 +752,3 @@ debug_script (sp) sp->line0, sp->line1, sp->deleted, sp->inserted); fflush (stderr); } - -#if !HAVE_MEMCHR -char * -memchr (s, c, n) - char *s; - int c; - size_t n; -{ - unsigned char *p = (unsigned char *) s, *lim = p + n; - for (; p < lim; p++) - if (*p == c) - return (char *) p; - return 0; -} -#endif diff --git a/gnu/usr.bin/diff/version.c b/gnu/usr.bin/diff/version.c index cb9d3b9..0299397 100644 --- a/gnu/usr.bin/diff/version.c +++ b/gnu/usr.bin/diff/version.c @@ -1,3 +1,5 @@ /* Version number of GNU diff. */ -char *version_string = "2.3"; +#include <config.h> + +char const version_string[] = "2.7"; diff --git a/gnu/usr.bin/diff/xmalloc.c b/gnu/usr.bin/diff/xmalloc.c new file mode 100644 index 0000000..dc44ba4 --- /dev/null +++ b/gnu/usr.bin/diff/xmalloc.c @@ -0,0 +1,81 @@ +/* xmalloc.c -- malloc with out of memory checking + Copyright (C) 1990, 1991, 1993 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#if __STDC__ +#define VOID void +#else +#define VOID char +#endif + +#include <sys/types.h> + +#if STDC_HEADERS +#include <stdlib.h> +#else +VOID *malloc (); +VOID *realloc (); +void free (); +#endif + +#if __STDC__ && defined (HAVE_VPRINTF) +void error (int, int, char const *, ...); +#else +void error (); +#endif + +/* Allocate N bytes of memory dynamically, with error checking. */ + +VOID * +xmalloc (n) + size_t n; +{ + VOID *p; + + p = malloc (n); + if (p == 0) + /* Must exit with 2 for `cmp'. */ + error (2, 0, "memory exhausted"); + return p; +} + +/* Change the size of an allocated block of memory P to N bytes, + with error checking. + If P is NULL, run xmalloc. + If N is 0, run free and return NULL. */ + +VOID * +xrealloc (p, n) + VOID *p; + size_t n; +{ + if (p == 0) + return xmalloc (n); + if (n == 0) + { + free (p); + return 0; + } + p = realloc (p, n); + if (p == 0) + /* Must exit with 2 for `cmp'. */ + error (2, 0, "memory exhausted"); + return p; +} |