diff --git a/.gitignore b/.gitignore index 9dfbe26..0e163f8 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,7 @@ lib/config.h lib/config.hin lib/configmake.h lib/ctype.h +lib/dirent.h lib/error.h lib/errno.h lib/fcntl.h diff --git a/NEWS b/NEWS index f879394..192500d 100644 --- a/NEWS +++ b/NEWS @@ -37,6 +37,10 @@ GNU diffutils NEWS -*- outline -*- diff -ly no longer mishandles non-ASCII input [bug#64461 introduced in 2.9] + diff - A/B now works correctly when standard input is a directory, + by reading a file named B in that directory. + [bug present since "the beginning"] + * Noteworthy changes in release 3.10 (2023-05-21) [stable] diff --git a/bootstrap.conf b/bootstrap.conf index d9c42a6..98f94cf 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -45,6 +45,7 @@ exitfail extensions extern-inline fcntl +fdopendir file-type filenamecat flexmember diff --git a/src/analyze.c b/src/analyze.c index ba0de04..a6a0bec 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -30,8 +30,10 @@ #define OFFSET lin #define OFFSET_MAX LIN_MAX #define EXTRA_CONTEXT_FIELDS /* none */ -#define NOTE_DELETE(c, x) (files[0].changed[files[0].realindexes[x]] = true) -#define NOTE_INSERT(c, y) (files[1].changed[files[1].realindexes[y]] = true) +#define NOTE_DELETE(c, x) \ + (curr.file[0].changed[curr.file[0].realindexes[x]] = true) +#define NOTE_INSERT(c, y) \ + (curr.file[1].changed[curr.file[1].realindexes[y]] = true) #define USE_HEURISTIC #include @@ -554,8 +556,7 @@ diff_2_files (struct comparison *cmp) lin too_expensive = (lin) 1 << ((floor_log2 (diags) >> 1) + 1); ctxt.too_expensive = MAX (4096, too_expensive); - files[0] = cmp->file[0]; - files[1] = cmp->file[1]; + curr = *cmp; compareseq (0, cmp->file[0].nondiscarded_lines, 0, cmp->file[1].nondiscarded_lines, minimal, &ctxt); @@ -613,7 +614,7 @@ diff_2_files (struct comparison *cmp) to be used if and when we have some output to print. */ setup_output (file_label[0] ? file_label[0] : cmp->file[0].name, file_label[1] ? file_label[1] : cmp->file[1].name, - !!cmp->parent); + cmp->parent != &noparent); switch (output_style) { diff --git a/src/context.c b/src/context.c index 79f8271..c6d880a 100644 --- a/src/context.c +++ b/src/context.c @@ -105,7 +105,7 @@ print_context_script (struct change *script, bool unidiff) for (struct change *e = script; e; e = e->link) e->ignore = false; - find_function_last_search = - files[0].prefix_lines; + find_function_last_search = - curr.file[0].prefix_lines; find_function_last_match = LIN_MAX; if (unidiff) @@ -174,22 +174,22 @@ pr_context_hunk (struct change *hunk) /* Include a context's width before and after. */ - lin minus_prefix_lines = files[0].prefix_lines; + lin minus_prefix_lines = curr.file[0].prefix_lines; first0 = MAX (first0 - context, minus_prefix_lines); first1 = MAX (first1 - context, minus_prefix_lines); - if (last0 < files[0].valid_lines - context) + if (last0 < curr.file[0].valid_lines - context) last0 += context; else - last0 = files[0].valid_lines - 1; - if (last1 < files[1].valid_lines - context) + last0 = curr.file[0].valid_lines - 1; + if (last1 < curr.file[1].valid_lines - context) last1 += context; else - last1 = files[1].valid_lines - 1; + last1 = curr.file[1].valid_lines - 1; /* If desired, find the preceding function definition line in file 0. */ char const *function = nullptr; if (function_regexp.fastmap) - function = find_function (files[0].linbuf, first0); + function = find_function (curr.file[0].linbuf, first0); begin_output (); FILE *out = outfile; @@ -202,7 +202,7 @@ pr_context_hunk (struct change *hunk) putc ('\n', out); set_color_context (LINE_NUMBER_CONTEXT); fputs ("*** ", out); - print_context_number_range (&files[0], first0, last0); + print_context_number_range (&curr.file[0], first0, last0); fputs (" ****", out); set_color_context (RESET_CONTEXT); putc ('\n', out); @@ -231,16 +231,16 @@ pr_context_hunk (struct change *hunk) Otherwise it is "deleted". */ prefix = (next->inserted > 0 ? "!" : "-"); } - print_1_line_nl (prefix, &files[0].linbuf[i], true); + print_1_line_nl (prefix, &curr.file[0].linbuf[i], true); set_color_context (RESET_CONTEXT); - if (files[0].linbuf[i + 1][-1] == '\n') + if (curr.file[0].linbuf[i + 1][-1] == '\n') putc ('\n', out); } } set_color_context (LINE_NUMBER_CONTEXT); fputs ("--- ", out); - print_context_number_range (&files[1], first1, last1); + print_context_number_range (&curr.file[1], first1, last1); fputs (" ----", out); set_color_context (RESET_CONTEXT); putc ('\n', out); @@ -269,9 +269,9 @@ pr_context_hunk (struct change *hunk) Otherwise it is "inserted". */ prefix = (next->deleted > 0 ? "!" : "+"); } - print_1_line_nl (prefix, &files[1].linbuf[i], true); + print_1_line_nl (prefix, &curr.file[1].linbuf[i], true); set_color_context (RESET_CONTEXT); - if (files[1].linbuf[i + 1][-1] == '\n') + if (curr.file[1].linbuf[i + 1][-1] == '\n') putc ('\n', out); } } @@ -317,31 +317,31 @@ pr_unidiff_hunk (struct change *hunk) /* Include a context's width before and after. */ - lin minus_prefix_lines = - files[0].prefix_lines; + lin minus_prefix_lines = - curr.file[0].prefix_lines; first0 = MAX (first0 - context, minus_prefix_lines); first1 = MAX (first1 - context, minus_prefix_lines); - if (last0 < files[0].valid_lines - context) + if (last0 < curr.file[0].valid_lines - context) last0 += context; else - last0 = files[0].valid_lines - 1; - if (last1 < files[1].valid_lines - context) + last0 = curr.file[0].valid_lines - 1; + if (last1 < curr.file[1].valid_lines - context) last1 += context; else - last1 = files[1].valid_lines - 1; + last1 = curr.file[1].valid_lines - 1; /* If desired, find the preceding function definition line in file 0. */ char const *function = nullptr; if (function_regexp.fastmap) - function = find_function (files[0].linbuf, first0); + function = find_function (curr.file[0].linbuf, first0); begin_output (); FILE *out = outfile; set_color_context (LINE_NUMBER_CONTEXT); fputs ("@@ -", out); - print_unidiff_number_range (&files[0], first0, last0); + print_unidiff_number_range (&curr.file[0], first0, last0); fputs (" +", out); - print_unidiff_number_range (&files[1], first1, last1); + print_unidiff_number_range (&curr.file[1], first1, last1); fputs (" @@", out); set_color_context (RESET_CONTEXT); @@ -361,7 +361,7 @@ pr_unidiff_hunk (struct change *hunk) if (!next || i < next->line0) { - char const *const *line = &files[0].linbuf[i++]; + char const *const *line = &curr.file[0].linbuf[i++]; if (! (suppress_blank_empty && **line == '\n')) putc (initial_tab ? '\t' : ' ', out); print_1_line (nullptr, line); @@ -375,7 +375,7 @@ pr_unidiff_hunk (struct change *hunk) while (k--) { - char const *const *line = &files[0].linbuf[i++]; + char const *const *line = &curr.file[0].linbuf[i++]; set_color_context (DELETE_CONTEXT); putc ('-', out); if (initial_tab && ! (suppress_blank_empty && **line == '\n')) @@ -394,7 +394,7 @@ pr_unidiff_hunk (struct change *hunk) while (k--) { - char const *const *line = &files[1].linbuf[j++]; + char const *const *line = &curr.file[1].linbuf[j++]; set_color_context (ADD_CONTEXT); putc ('+', out); if (initial_tab && ! (suppress_blank_empty && **line == '\n')) diff --git a/src/diff.c b/src/diff.c index 5430461..afe9f44 100644 --- a/src/diff.c +++ b/src/diff.c @@ -823,6 +823,9 @@ main (int argc, char **argv) int exit_status = EXIT_SUCCESS; + noparent.file[0].desc = AT_FDCWD; + noparent.file[1].desc = AT_FDCWD; + if (from_file) { if (to_file) @@ -830,7 +833,7 @@ main (int argc, char **argv) else for (; optind < argc; optind++) { - int status = compare_files (nullptr, from_file, argv[optind]); + int status = compare_files (&noparent, from_file, argv[optind]); if (exit_status < status) exit_status = status; } @@ -840,7 +843,7 @@ main (int argc, char **argv) if (to_file) for (; optind < argc; optind++) { - int status = compare_files (nullptr, argv[optind], to_file); + int status = compare_files (&noparent, argv[optind], to_file); if (exit_status < status) exit_status = status; } @@ -854,7 +857,8 @@ main (int argc, char **argv) try_help ("extra operand '%s'", argv[optind + 2]); } - exit_status = compare_files (nullptr, argv[optind], argv[optind + 1]); + exit_status = compare_files (&noparent, + argv[optind], argv[optind + 1]); } } @@ -1148,7 +1152,7 @@ dir_p (struct comparison const *pcmp, int f) /* Compare two files (or dirs) with parent comparison PARENT and names NAME0 and NAME1. - (If PARENT is null, then the first name is just NAME0, etc.) + (If PARENT == &NOPARENT, then the first name is just NAME0, etc.) This is self-contained; it opens the files and closes them. Value is EXIT_SUCCESS if files are the same, EXIT_FAILURE if @@ -1192,7 +1196,7 @@ compare_files (struct comparison const *parent, char *free0; char *free1; - if (!parent) + if (parent == &noparent) { free0 = nullptr; free1 = nullptr; @@ -1242,11 +1246,17 @@ compare_files (struct comparison const *parent, set_mtime_to_now (&cmp.file[f].stat); } } - else if ((no_dereference_symlinks - ? lstat (cmp.file[f].name, &cmp.file[f].stat) - : stat (cmp.file[f].name, &cmp.file[f].stat)) - != 0) - cmp.file[f].desc = errno_encode (errno); + else + { + char const *name = cmp.file[f].name; + if (fstatat (parent->file[f].desc, + (parent->file[f].desc < 0 ? name + : last_component (name)), + &cmp.file[f].stat, + no_dereference_symlinks ? AT_SYMLINK_NOFOLLOW : 0) + < 0) + cmp.file[f].desc = errno_encode (errno); + } } } @@ -1263,7 +1273,7 @@ compare_files (struct comparison const *parent, && cmp.file[f].stat.st_size == 0) : ((cmp.file[f].desc == errno_encode (ENOENT) || cmp.file[f].desc == errno_encode (EBADF)) - && ! parent + && parent == &noparent && (cmp.file[1 - f].desc == UNOPENED || cmp.file[1 - f].desc == STDIN_FILENO)))) cmp.file[f].desc = NONEXISTENT; @@ -1288,7 +1298,7 @@ compare_files (struct comparison const *parent, } } - if (status == EXIT_SUCCESS && ! parent && !no_directory + if (status == EXIT_SUCCESS && !no_directory && parent == &noparent && dir_p (&cmp, 0) != dir_p (&cmp, 1)) { /* If one is a directory, and it was specified in the command line, @@ -1297,17 +1307,21 @@ compare_files (struct comparison const *parent, int fnm_arg = dir_p (&cmp, 0); int dir_arg = 1 - fnm_arg; char const *fnm = cmp.file[fnm_arg].name; - char const *dir = cmp.file[dir_arg].name; + char const *base_fnm = last_component (fnm); char const *filename = cmp.file[dir_arg].name = free0 - = find_dir_file_pathname (dir, last_component (fnm)); + = find_dir_file_pathname (&cmp.file[dir_arg], base_fnm); if (STREQ (fnm, "-")) fatal ("cannot compare '-' to a directory"); - if ((no_dereference_symlinks - ? lstat (filename, &cmp.file[dir_arg].stat) - : stat (filename, &cmp.file[dir_arg].stat)) - != 0) + int dirdesc = cmp.file[dir_arg].desc; + cmp.file[dir_arg].desc = UNOPENED; + noparent.file[dir_arg].desc = dirdesc < 0 ? AT_FDCWD : dirdesc; + if (fstatat (noparent.file[dir_arg].desc, + dirdesc < 0 ? filename : base_fnm, + &cmp.file[dir_arg].stat, + no_dereference_symlinks ? AT_SYMLINK_NOFOLLOW : 0) + < 0) { perror_with_name (filename); status = EXIT_TROUBLE; @@ -1343,7 +1357,7 @@ compare_files (struct comparison const *parent, /* If both are directories, compare the files in them. */ - if (parent && !recursive) + if (!recursive && parent != &noparent) { /* But don't compare dir contents one level down unless -r was specified. @@ -1355,7 +1369,7 @@ compare_files (struct comparison const *parent, status = diff_dirs (&cmp, compare_files); } else if ((dir_p (&cmp, 0) | dir_p (&cmp, 1)) - || (parent + || (parent != &noparent && !((S_ISREG (cmp.file[0].stat.st_mode) || S_ISLNK (cmp.file[0].stat.st_mode)) && (S_ISREG (cmp.file[1].stat.st_mode) @@ -1399,7 +1413,7 @@ compare_files (struct comparison const *parent, else if (S_ISLNK (cmp.file[0].stat.st_mode) || S_ISLNK (cmp.file[1].stat.st_mode)) { - /* We get here only if we use lstat(), not stat(). */ + /* We get here only if we are not dereferencing symlinks. */ dassert (no_dereference_symlinks); if (S_ISLNK (cmp.file[0].stat.st_mode) @@ -1464,52 +1478,45 @@ compare_files (struct comparison const *parent, /* Open the files and record their descriptors. */ - int oflags = O_RDONLY | (binary ? O_BINARY : 0); + int oflags = (O_RDONLY | (binary ? O_BINARY : 0) + | (no_dereference_symlinks ? O_NOFOLLOW : 0)); - if (cmp.file[0].desc == UNOPENED) - { - cmp.file[0].desc = open (cmp.file[0].name, oflags); - if (cmp.file[0].desc < 0) - { - perror_with_name (cmp.file[0].name); - status = EXIT_TROUBLE; - } - } - if (cmp.file[1].desc == UNOPENED) - { - if (same_files) - cmp.file[1].desc = cmp.file[0].desc; - else - { - cmp.file[1].desc = open (cmp.file[1].name, oflags); - if (cmp.file[1].desc < 0) - { - perror_with_name (cmp.file[1].name); - status = EXIT_TROUBLE; - } - } - } + for (int f = 0; f < 2; f++) + if (cmp.file[f].desc == UNOPENED) + { + if (f && same_files) + cmp.file[f].desc = cmp.file[0].desc; + else + { + int dirfd = parent->file[f].desc; + char const *name = cmp.file[f].name; + char const *nm = dirfd < 0 ? name : last_component (name); + cmp.file[f].desc = openat (dirfd, nm, oflags); + if (cmp.file[f].desc < 0) + { + perror_with_name (name); + status = EXIT_TROUBLE; + } + } + } /* Compare the files, if no error was found. */ if (status == EXIT_SUCCESS) status = diff_2_files (&cmp); - - /* Close the file descriptors. */ - - if (0 <= cmp.file[0].desc && close (cmp.file[0].desc) != 0) - { - perror_with_name (cmp.file[0].name); - status = EXIT_TROUBLE; - } - if (0 <= cmp.file[1].desc && cmp.file[0].desc != cmp.file[1].desc - && close (cmp.file[1].desc) != 0) - { - perror_with_name (cmp.file[1].name); - status = EXIT_TROUBLE; - } } + + /* Close any input files. */ + for (int f = 0; f < 2; f++) + if ((f == 0 || cmp.file[f].desc != cmp.file[0].desc) + && (cmp.file[f].dirstream ? closedir (cmp.file[f].dirstream) < 0 + : 0 <= cmp.file[f].desc && close (cmp.file[f].desc) < 0)) + { + perror_with_name (cmp.file[f].name); + status = EXIT_TROUBLE; + } + /* Now the comparison has been done, if no error prevented it, and STATUS is the value this function will return. */ diff --git a/src/diff.h b/src/diff.h index 663d65d..1726f21 100644 --- a/src/diff.h +++ b/src/diff.h @@ -276,6 +276,10 @@ struct file_data { char const *name; /* File name */ struct stat stat; /* File status */ + /* Directory stream corresponding to DESC, if it has been fdopendir'ed. + Null otherwise. */ + DIR *dirstream; + /* Buffer in which text of file is read. */ word *buffer; @@ -345,13 +349,23 @@ enum { UNOPENED = -2 }; /* unopened file (e.g. directory) */ struct comparison { + /* The two files. */ struct file_data file[2]; - struct comparison const *parent; /* parent, if a recursive comparison */ + + /* The parent comparison, or &noparent if at the top level. */ + struct comparison const *parent; }; /* Describe the two files currently being compared. */ -XTERN struct file_data files[2]; +XTERN struct comparison curr; + +/* A placeholder for the parent of the top level comparison. + Only the desc slots are used; although they are typically AT_FDCWD, + one might be nonnegative for a directory at the top level + for 'diff DIR FILE' or 'diff FILE DIR'. */ + +XTERN struct comparison noparent; /* Stdio stream to output diffs to. */ @@ -368,10 +382,10 @@ extern void print_context_header (struct file_data[], extern void print_context_script (struct change *, bool); /* dir.c */ -extern int diff_dirs (struct comparison const *, +extern int diff_dirs (struct comparison *, int (*) (struct comparison const *, char const *, char const *)); -extern char *find_dir_file_pathname (char const *, char const *) +extern char *find_dir_file_pathname (struct file_data *, char const *) ATTRIBUTE_MALLOC ATTRIBUTE_DEALLOC_FREE ATTRIBUTE_RETURNS_NONNULL; diff --git a/src/dir.c b/src/dir.c index c3af9b5..9cd4efd 100644 --- a/src/dir.c +++ b/src/dir.c @@ -20,6 +20,7 @@ #include "diff.h" #include +#include #include #include #include @@ -44,14 +45,17 @@ static jmp_buf failed_locale_specific_sorting; static bool dir_loop (struct comparison const *, int); -/* Read the directory named by DIR and store into DIRDATA a sorted +/* Given the parent directory PARENTDIRFD (negative for current dir), + read the directory named by DIR and store into DIRDATA a sorted vector of filenames for its contents. - DIR->desc == NONEXISTENT means this directory is known to be - nonexistent, so set DIRDATA to an empty vector. + Use DIR's basename if PARENTDIRFD is nonnegative, for efficiency. + If DIR->desc == NONEXISTENT, this directory is known to be + nonexistent so set DIRDATA to an empty vector; + otherwise, update DIR->desc and DIR->dirstream as needed. Return true if successful, false (setting errno) otherwise. */ static bool -dir_read (struct file_data const *dir, struct dirdata *dirdata) +dir_read (int parentdirfd, struct file_data *dir, struct dirdata *dirdata) { /* Number of files in directory. */ idx_t nnames = 0; @@ -65,9 +69,22 @@ dir_read (struct file_data const *dir, struct dirdata *dirdata) if (dir->desc != NONEXISTENT) { /* Open the directory and check for errors. */ - DIR *reading = opendir (dir->name); + int dirfd = dir->desc; + if (dirfd < 0) + { + dirfd = openat (parentdirfd, + (parentdirfd < 0 ? dir->name + : last_component (dir->name)), + (O_RDONLY | O_DIRECTORY + | (no_dereference_symlinks ? O_NOFOLLOW : 0))); + if (dirfd < 0) + return false; + dir->desc = dirfd; + } + DIR *reading = fdopendir (dirfd); if (!reading) return false; + dir->dirstream = reading; /* Initialize the table of filenames. */ @@ -105,13 +122,8 @@ dir_read (struct file_data const *dir, struct dirdata *dirdata) nnames++; } - int readdir_errno = errno; - if (closedir (reading) < 0 || readdir_errno) - { - if (readdir_errno) - errno = readdir_errno; - return false; - } + if (errno) + return false; } /* Create the 'names' table from the 'data' table. */ @@ -183,8 +195,9 @@ compare_names_for_qsort (void const *file1, void const *file2) This is a top-level routine; it does everything necessary for diff on two directories. - CMP->file[0].desc == NONEXISTENT says directory CMP->file[0] doesn't exist, - but pretend it is empty. Likewise for CMP->file[1]. + If CMP->file[0].desc == NONEXISTENT, directory CMP->file[0] doesn't exist + and pretend it is empty. Otherwise, update CMP->file[0].desc and + CMP->file[0].dirstream as needed. Likewise for CMP->file[1]. HANDLE_FILE is a caller-provided subroutine called to handle each file. It gets three operands: CMP, name of file in dir 0, name of file in dir 1. @@ -197,7 +210,7 @@ compare_names_for_qsort (void const *file1, void const *file2) or EXIT_TROUBLE if trouble is encountered in opening files. */ int -diff_dirs (struct comparison const *cmp, +diff_dirs (struct comparison *cmp, int (*handle_file) (struct comparison const *, char const *, char const *)) { @@ -213,7 +226,7 @@ diff_dirs (struct comparison const *cmp, struct dirdata dirdata[2]; int volatile val = EXIT_SUCCESS; for (int i = 0; i < 2; i++) - if (! dir_read (&cmp->file[i], &dirdata[i])) + if (! dir_read (cmp->parent->file[i].desc, &cmp->file[i], &dirdata[i])) { perror_with_name (cmp->file[i].name); val = EXIT_TROUBLE; @@ -317,7 +330,7 @@ dir_loop (struct comparison const *cmp, int i) /* Find a matching filename in a directory. */ char * -find_dir_file_pathname (char const *dir, char const *file) +find_dir_file_pathname (struct file_data *dir, char const *file) { /* IF_LINT due to GCC bug 21161. */ char const *IF_LINT (volatile) match = file; @@ -326,35 +339,26 @@ find_dir_file_pathname (char const *dir, char const *file) dirdata.names = nullptr; dirdata.data = nullptr; - if (ignore_file_name_case) + if (ignore_file_name_case && dir_read (AT_FDCWD, dir, &dirdata)) { - struct file_data filedata; - filedata.name = dir; - filedata.desc = 0; - - if (dir_read (&filedata, &dirdata)) - { - locale_specific_sorting = true; - if (setjmp (failed_locale_specific_sorting)) - match = file; /* longjmp may mess up MATCH. */ - else + locale_specific_sorting = true; + if (setjmp (failed_locale_specific_sorting)) + match = file; /* longjmp may mess up MATCH. */ + else + for (char const **p = dirdata.names; *p; p++) + if (compare_names (*p, file) == 0) { - for (char const **p = dirdata.names; *p; p++) - if (compare_names (*p, file) == 0) - { - if (file_name_cmp (*p, file) == 0) - { - match = *p; - break; - } - if (match == file) - match = *p; - } + if (file_name_cmp (*p, file) == 0) + { + match = *p; + break; + } + if (match == file) + match = *p; } - } } - char *val = file_name_concat (dir, match, nullptr); + char *val = file_name_concat (dir->name, match, nullptr); free (dirdata.names); free (dirdata.data); return val; diff --git a/src/ed.c b/src/ed.c index 44bf1be..b3172dc 100644 --- a/src/ed.c +++ b/src/ed.c @@ -51,7 +51,7 @@ print_ed_hunk (struct change *hunk) begin_output (); /* Print out the line number header for this hunk */ - print_number_range (',', &files[0], f0, l0); + print_number_range (',', &curr.file[0], f0, l0); fputc (change_letter[changes], outfile); fputc ('\n', outfile); @@ -67,7 +67,8 @@ print_ed_hunk (struct change *hunk) fputs ("a\n", outfile); insert_mode = true; } - if (files[1].linbuf[i][0] == '.' && files[1].linbuf[i][1] == '\n') + if (curr.file[1].linbuf[i][0] == '.' + && curr.file[1].linbuf[i][1] == '\n') { /* The file's line is just a dot, and it would exit insert mode. Precede the dot with another dot, exit @@ -76,7 +77,7 @@ print_ed_hunk (struct change *hunk) insert_mode = false; } else - print_1_line ("", &files[1].linbuf[i]); + print_1_line ("", &curr.file[1].linbuf[i]); } if (insert_mode) @@ -108,7 +109,7 @@ pr_forward_ed_hunk (struct change *hunk) begin_output (); fputc (change_letter[changes], outfile); - print_number_range (' ', files, f0, l0); + print_number_range (' ', &curr.file[0], f0, l0); fputc ('\n', outfile); /* If deletion only, print just the number range. */ @@ -120,7 +121,7 @@ pr_forward_ed_hunk (struct change *hunk) and the lines from file 2. */ for (lin i = f1; i <= l1; i++) - print_1_line ("", &files[1].linbuf[i]); + print_1_line ("", &curr.file[1].linbuf[i]); fputs (".\n", outfile); } @@ -149,7 +150,7 @@ print_rcs_hunk (struct change *hunk) begin_output (); lin tf0, tl0, tf1, tl1; - translate_range (&files[0], f0, l0, &tf0, &tl0); + translate_range (&curr.file[0], f0, l0, &tf0, &tl0); if (changes & OLD) { @@ -162,12 +163,12 @@ print_rcs_hunk (struct change *hunk) if (changes & NEW) { /* Take last-line-number from file 0 and # lines from file 1. */ - translate_range (&files[1], f1, l1, &tf1, &tl1); + translate_range (&curr.file[1], f1, l1, &tf1, &tl1); fprintf (outfile, "a%"pI"d %"pI"d\n", tl0, tf1 <= tl1 ? tl1 - tf1 + 1 : 1); /* Print the inserted lines. */ for (lin i = f1; i <= l1; i++) - print_1_line ("", &files[1].linbuf[i]); + print_1_line ("", &curr.file[1].linbuf[i]); } } diff --git a/src/ifdef.c b/src/ifdef.c index 1bc76c8..6192d55 100644 --- a/src/ifdef.c +++ b/src/ifdef.c @@ -49,15 +49,15 @@ static lin next_line1; void print_ifdef_script (struct change *script) { - next_line0 = next_line1 = - files[0].prefix_lines; + next_line0 = next_line1 = - curr.file[0].prefix_lines; print_script (script, find_change, print_ifdef_hunk); - if (next_line0 < files[0].valid_lines - || next_line1 < files[1].valid_lines) + if (next_line0 < curr.file[0].valid_lines + || next_line1 < curr.file[1].valid_lines) { begin_output (); format_ifdef (group_format[UNCHANGED], - next_line0, files[0].valid_lines, - next_line1, files[1].valid_lines); + next_line0, curr.file[0].valid_lines, + next_line1, curr.file[1].valid_lines); } } @@ -99,8 +99,8 @@ format_ifdef (char const *format, lin beg0, lin end0, lin beg1, lin end1) { format_group (outfile, format, '\0', ((struct group const[]) - {{.file = &files[0], .from = beg0, .upto = end0}, - {.file = &files[1], .from = beg1, .upto = end1}})); + {{.file = &curr.file[0], .from = beg0, .upto = end0}, + {.file = &curr.file[1], .from = beg1, .upto = end1}})); } /* Print to file OUT a set of lines according to FORMAT. diff --git a/src/normal.c b/src/normal.c index 1792fd0..7672ecd 100644 --- a/src/normal.c +++ b/src/normal.c @@ -48,9 +48,9 @@ print_normal_hunk (struct change *hunk) /* Print out the line number header for this hunk */ set_color_context (LINE_NUMBER_CONTEXT); - print_number_range (',', &files[0], first0, last0); + print_number_range (',', &curr.file[0], first0, last0); fputc (change_letter[changes], outfile); - print_number_range (',', &files[1], first1, last1); + print_number_range (',', &curr.file[1], first1, last1); set_color_context (RESET_CONTEXT); fputc ('\n', outfile); @@ -60,9 +60,9 @@ print_normal_hunk (struct change *hunk) for (lin i = first0; i <= last0; i++) { set_color_context (DELETE_CONTEXT); - print_1_line_nl ("<", &files[0].linbuf[i], true); + print_1_line_nl ("<", &curr.file[0].linbuf[i], true); set_color_context (RESET_CONTEXT); - if (files[0].linbuf[i + 1][-1] == '\n') + if (curr.file[0].linbuf[i + 1][-1] == '\n') putc ('\n', outfile); } } @@ -76,9 +76,9 @@ print_normal_hunk (struct change *hunk) for (lin i = first1; i <= last1; i++) { set_color_context (ADD_CONTEXT); - print_1_line_nl (">", &files[1].linbuf[i], true); + print_1_line_nl (">", &curr.file[1].linbuf[i], true); set_color_context (RESET_CONTEXT); - if (files[1].linbuf[i + 1][-1] == '\n') + if (curr.file[1].linbuf[i + 1][-1] == '\n') putc ('\n', outfile); } } diff --git a/src/side.c b/src/side.c index ab43ad9..a4b471e 100644 --- a/src/side.c +++ b/src/side.c @@ -37,10 +37,11 @@ print_sdiff_script (struct change *script) { begin_output (); - next0 = next1 = - files[0].prefix_lines; + next0 = next1 = - curr.file[0].prefix_lines; print_script (script, find_change, print_sdiff_hunk); - print_sdiff_common_lines (files[0].valid_lines, files[1].valid_lines); + print_sdiff_common_lines (curr.file[0].valid_lines, + curr.file[1].valid_lines); } /* Tab from column FROM to column TO, where FROM <= TO. Yield TO. */ @@ -275,13 +276,13 @@ print_sdiff_common_lines (lin limit0, lin limit1) if (!left_column) { while (i0 != limit0 && i1 != limit1) - print_1sdiff_line (&files[0].linbuf[i0++], ' ', - &files[1].linbuf[i1++]); + print_1sdiff_line (&curr.file[0].linbuf[i0++], ' ', + &curr.file[1].linbuf[i1++]); while (i1 != limit1) - print_1sdiff_line (0, ')', &files[1].linbuf[i1++]); + print_1sdiff_line (0, ')', &curr.file[1].linbuf[i1++]); } while (i0 != limit0) - print_1sdiff_line (&files[0].linbuf[i0++], '(', 0); + print_1sdiff_line (&curr.file[0].linbuf[i0++], '(', 0); } next0 = limit0; @@ -315,7 +316,8 @@ print_sdiff_hunk (struct change *hunk) { lin i, j; for (i = first0, j = first1; i <= last0 && j <= last1; i++, j++) - print_1sdiff_line (&files[0].linbuf[i], '|', &files[1].linbuf[j]); + print_1sdiff_line (&curr.file[0].linbuf[i], '|', + &curr.file[1].linbuf[j]); changes = (i <= last0 ? OLD : 0) + (j <= last1 ? NEW : 0); next0 = first0 = i; next1 = first1 = j; @@ -326,7 +328,7 @@ print_sdiff_hunk (struct change *hunk) { lin j; for (j = first1; j <= last1; ++j) - print_1sdiff_line (0, '>', &files[1].linbuf[j]); + print_1sdiff_line (0, '>', &curr.file[1].linbuf[j]); next1 = j; } @@ -335,7 +337,7 @@ print_sdiff_hunk (struct change *hunk) { lin i; for (i = first0; i <= last0; ++i) - print_1sdiff_line (&files[0].linbuf[i], '<', 0); + print_1sdiff_line (&curr.file[0].linbuf[i], '<', 0); next0 = i; } } diff --git a/src/util.c b/src/util.c index 30fb531..69b7831 100644 --- a/src/util.c +++ b/src/util.c @@ -989,19 +989,9 @@ begin_output (void) free (name); /* A special header is needed at the beginning of context output. */ - switch (output_style) - { - case OUTPUT_CONTEXT: - print_context_header (files, (char const *const *)names, false); - break; - - case OUTPUT_UNIFIED: - print_context_header (files, (char const *const *)names, true); - break; - - default: - break; - } + if (output_style == OUTPUT_CONTEXT || output_style == OUTPUT_UNIFIED) + print_context_header (curr.file, (char const *const *) names, + output_style == OUTPUT_UNIFIED); if (names[0] != current_name0) free (names[0]); @@ -1370,8 +1360,9 @@ analyze_hunk (struct change *hunk, bool skip_leading_white_space = skip_white_space && IGNORE_SPACE_CHANGE <= ignore_white_space; - char const *const *linbuf0 = files[0].linbuf; /* Help the compiler. */ - char const *const *linbuf1 = files[1].linbuf; + /* Help the compiler. */ + char const *const *linbuf0 = curr.file[0].linbuf; + char const *const *linbuf1 = curr.file[1].linbuf; lin show_from = 0, show_to = 0; diff --git a/tests/stdin b/tests/stdin index 94b7542..0fd9e7e 100755 --- a/tests/stdin +++ b/tests/stdin @@ -5,7 +5,9 @@ fail=0 -cat < exp || fail=1 +echo a > a || framework_failure_ +echo b > b || framework_failure_ +cat <<'EOF' > exp || framework_failure_ --- - +++ b @@ -1 +1 @@ @@ -13,12 +15,17 @@ cat < exp || fail=1 +b EOF -echo a > a -echo b > b - returns_ 1 diff -u - b < a > out 2> err || fail=1 # Remove date and time. -sed -e 's/^\([-+*][-+*][-+*] [^ ]*\) .*/\1/' out > k; mv k out -compare exp out || fail=1 +sed -e 's/^\([-+*][-+*][-+*] [^ ]*\) .*/\1/' out >outk || framework_failure_ +compare exp outk || fail=1 +compare /dev/null err || fail=1 + +mkdir d || framework_failure_ +echo a >d/a || framework_failure_ + +diff -u - a out 2>err || fail=1 +compare /dev/null out || fail=1 +compare /dev/null err || fail=1 Exit $fail