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/util.c | |
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/util.c')
-rw-r--r-- | gnu/usr.bin/diff/util.c | 355 |
1 files changed, 203 insertions, 152 deletions
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 |