714 lines
18 KiB
C
714 lines
18 KiB
C
/* GNU DIFF main routine.
|
||
Copyright (C) 1988, 1989 Free Software Foundation, Inc.
|
||
|
||
This file is part of GNU DIFF.
|
||
|
||
GNU DIFF 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 1, or (at your option)
|
||
any later version.
|
||
|
||
GNU DIFF 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 GNU DIFF; see the file COPYING. If not, write to
|
||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||
|
||
/* GNU DIFF was written by Mike Haertel, David Hayes,
|
||
Richard Stallman and Len Tower. */
|
||
|
||
#define GDIFF_MAIN
|
||
#include "regex.h"
|
||
#include "diff.h"
|
||
#include <getopt.h>
|
||
|
||
|
||
/* Nonzero for -r: if comparing two directories,
|
||
compare their common subdirectories recursively. */
|
||
|
||
int recursive;
|
||
|
||
/* For debugging: don't do discard_confusing_lines. */
|
||
|
||
int no_discards;
|
||
|
||
/* 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.
|
||
If there were no options, the result is an empty string.
|
||
|
||
Arguments: OPTIONVEC, a vector containing separate ARGV-elements, and COUNT,
|
||
the length of that vector. */
|
||
|
||
static char *
|
||
option_list (optionvec, count)
|
||
char **optionvec; /* Was `vector', but that collides on Alliant. */
|
||
int count;
|
||
{
|
||
int i;
|
||
int length = 0;
|
||
char *result;
|
||
|
||
for (i = 0; i < count; i++)
|
||
length += strlen (optionvec[i]) + 1;
|
||
|
||
result = (char *) xmalloc (length + 1);
|
||
result[0] = 0;
|
||
|
||
for (i = 0; i < count; i++)
|
||
{
|
||
strcat (result, " ");
|
||
strcat (result, optionvec[i]);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
int xargc;
|
||
char **xargv;
|
||
int gnudiffopts;
|
||
int sgidiffopts;
|
||
|
||
VOID
|
||
usage ()
|
||
{
|
||
fprintf (stderr, "Usage: diff [-bcefhilnrstw -Dstring -Sname -xpattern ] file1 file2\n");
|
||
fprintf (stderr, "\tGNU diff options: [-# -aBdHNpqTuv -Cnum -Fregexp -Iregexp -Llabel]\n");
|
||
exit (2);
|
||
}
|
||
|
||
VOID
|
||
specify_style (style)
|
||
enum output_style style;
|
||
{
|
||
if (output_style != OUTPUT_NORMAL
|
||
&& output_style != style)
|
||
error ("conflicting specifications of output style");
|
||
output_style = style;
|
||
}
|
||
|
||
main (argc, argv)
|
||
int argc;
|
||
char *argv[];
|
||
{
|
||
int val;
|
||
int c;
|
||
int prev = -1;
|
||
extern char *version_string;
|
||
extern char *optarg;
|
||
extern int optind;
|
||
extern void setxpat(char *);
|
||
|
||
program = argv[0];
|
||
|
||
/* Do our initializations. */
|
||
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 = 0;
|
||
function_regexp = 0;
|
||
print_file_same_flag = FALSE;
|
||
entire_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;
|
||
ifdef_string = NULL;
|
||
heuristic = FALSE;
|
||
dir_start_file = NULL;
|
||
msg_chain = NULL;
|
||
msg_chain_end = NULL;
|
||
no_discards = 0;
|
||
gnudiffopts = 0;
|
||
sgidiffopts = 0;
|
||
xargc = 0;
|
||
xargv = xmalloc ((argc+1) * sizeof(*xargv));
|
||
bzero (xargv, (argc+1) * sizeof(*xargv));
|
||
/*
|
||
* Put all but the last 2 args (the filenames to diff)
|
||
* in the xargv[] vector, to be passed to odiff by tryodiff().
|
||
*
|
||
* If "diff -r dir1 dir2" calls odiff on a big file
|
||
* somewhere, must call odiff with "diff -r file1 file2"
|
||
* not with original "dir1 dir2" args. Otherwise get
|
||
* all output repeated -- see SGI PV Incident 234771.
|
||
* Would be better to also trim -r, but that seems
|
||
* harder, and I can't see that it matters. pj.
|
||
*/
|
||
while (xargc < argc - 2) {
|
||
xargv[xargc] = argv[xargc];
|
||
xargc++;
|
||
}
|
||
xargv[xargc+2] = 0;
|
||
|
||
/* Decode the options. */
|
||
|
||
while ((c = getopt (argc, argv,
|
||
"0123456789abBcC:dD:efF:hHiI:lL:nNpqrsS:tTuvwx:"
|
||
)) != EOF)
|
||
{
|
||
switch (c)
|
||
{
|
||
/* All digits combine in decimal to specify the context-size. */
|
||
case '1': gnudiffopts++;
|
||
case '2': gnudiffopts++;
|
||
case '3': gnudiffopts++;
|
||
case '4': gnudiffopts++;
|
||
case '5': gnudiffopts++;
|
||
case '6': gnudiffopts++;
|
||
case '7': gnudiffopts++;
|
||
case '8': gnudiffopts++;
|
||
case '9': gnudiffopts++;
|
||
case '0': gnudiffopts++;
|
||
if (context == -1)
|
||
context = 0;
|
||
/* If a context length has already been specified,
|
||
more digits allowed only if they follow right after the others.
|
||
Reject two separate runs of digits, or digits after -C. */
|
||
else if (prev < '0' || prev > '9')
|
||
fatal ("context length specified twice");
|
||
|
||
context = context * 10 + c - '0';
|
||
break;
|
||
|
||
case 'a': gnudiffopts++;
|
||
/* Treat all files as text files; never treat as binary. */
|
||
always_text_flag = 1;
|
||
break;
|
||
|
||
case 'b': sgidiffopts++;
|
||
/* Ignore changes in amount of whitespace. */
|
||
ignore_space_change_flag = 1;
|
||
length_varies = 1;
|
||
break;
|
||
|
||
case 'B': gnudiffopts++;
|
||
/* Ignore changes affecting only blank lines. */
|
||
ignore_blank_lines_flag = 1;
|
||
break;
|
||
|
||
case 'C': gnudiffopts++;
|
||
if (optarg)
|
||
{
|
||
if (context >= 0)
|
||
fatal ("context length specified twice");
|
||
{
|
||
char *p;
|
||
for (p = optarg; *p; p++)
|
||
if (*p < '0' || *p > '9')
|
||
fatal ("invalid context length argument");
|
||
}
|
||
context = atoi (optarg);
|
||
}
|
||
|
||
/* Falls through. */
|
||
case 'c': sgidiffopts++;
|
||
/* Make context-style output. */
|
||
specify_style (c == 130 ? OUTPUT_UNIFIED : OUTPUT_CONTEXT);
|
||
break;
|
||
|
||
case 'd': gnudiffopts++;
|
||
/* Don't discard lines. This makes things slower (sometimes much
|
||
slower) but will find a guaranteed minimal set of changes. */
|
||
no_discards = 1;
|
||
break;
|
||
|
||
case 'D': sgidiffopts++;
|
||
/* Make merged #ifdef output. */
|
||
specify_style (OUTPUT_IFDEF);
|
||
ifdef_string = optarg;
|
||
break;
|
||
|
||
case 'e': sgidiffopts++;
|
||
/* Make output that is a valid `ed' script. */
|
||
specify_style (OUTPUT_ED);
|
||
break;
|
||
|
||
case 'f': sgidiffopts++;
|
||
/* Make output that looks vaguely like an `ed' script
|
||
but has changes in the order they appear in the file. */
|
||
specify_style (OUTPUT_FORWARD_ED);
|
||
break;
|
||
|
||
case 'F': gnudiffopts++;
|
||
/* Show, for each set of changes, the previous line that
|
||
matches the specified regexp. Currently affects only
|
||
context-style output. */
|
||
function_regexp = optarg;
|
||
break;
|
||
|
||
case 'h': sgidiffopts++;
|
||
/* Split the files into chunks of around 1500 lines
|
||
for faster processing. Usually does not change the result.
|
||
|
||
This currently has no effect. */
|
||
break;
|
||
|
||
case 'H': gnudiffopts++;
|
||
/* Turn on heuristics that speed processing of large files
|
||
with a small density of changes. */
|
||
heuristic = 1;
|
||
break;
|
||
|
||
case 'i': sgidiffopts++;
|
||
/* Ignore changes in case. */
|
||
ignore_case_flag = 1;
|
||
break;
|
||
|
||
case 'I': gnudiffopts++;
|
||
/* Ignore changes affecting only lines that match the
|
||
specified regexp. */
|
||
ignore_regexp = optarg;
|
||
break;
|
||
|
||
case 'l': sgidiffopts++;
|
||
/* Pass the output through `pr' to paginate it. */
|
||
paginate_flag = 1;
|
||
break;
|
||
|
||
case 'L': gnudiffopts++;
|
||
/* Specify file labels for `-c' output headers. */
|
||
if (!file_label[0])
|
||
file_label[0] = optarg;
|
||
else if (!file_label[1])
|
||
file_label[1] = optarg;
|
||
else
|
||
fatal ("too many file label options");
|
||
break;
|
||
|
||
case 'n': sgidiffopts++;
|
||
/* Output RCS-style diffs, like `-f' except that each command
|
||
specifies the number of lines affected. */
|
||
specify_style (OUTPUT_RCS);
|
||
break;
|
||
|
||
case 'N': gnudiffopts++;
|
||
/* When comparing directories, if a file appears only in one
|
||
directory, treat it as present but empty in the other. */
|
||
entire_new_file_flag = 1;
|
||
break;
|
||
|
||
case 'p': gnudiffopts++;
|
||
/* Make context-style output and show name of last C function. */
|
||
specify_style (OUTPUT_CONTEXT);
|
||
function_regexp = "^[_a-zA-Z]";
|
||
break;
|
||
|
||
case 'q': gnudiffopts++;
|
||
no_details_flag = 1;
|
||
break;
|
||
|
||
case 'r': sgidiffopts++;
|
||
/* When comparing directories,
|
||
recursively compare any subdirectories found. */
|
||
recursive = 1;
|
||
break;
|
||
|
||
case 's': sgidiffopts++;
|
||
/* Print a message if the files are the same. */
|
||
print_file_same_flag = 1;
|
||
break;
|
||
|
||
case 'S': sgidiffopts++;
|
||
/* When comparing directories, start with the specified
|
||
file name. This is used for resuming an aborted comparison. */
|
||
dir_start_file = optarg;
|
||
break;
|
||
|
||
case 't': sgidiffopts++;
|
||
/* Expand tabs to spaces in the output so that it preserves
|
||
the alignment of the input files. */
|
||
tab_expand_flag = 1;
|
||
break;
|
||
|
||
case 'T': gnudiffopts++;
|
||
/* Use a tab in the output, rather than a space, before the
|
||
text of an input line, so as to keep the proper alignment
|
||
in the input line without changing the characters in it. */
|
||
tab_align_flag = 1;
|
||
break;
|
||
|
||
case 'v': gnudiffopts++;
|
||
printf ("GNU diff version %s\n", version_string);
|
||
break;
|
||
|
||
case 'u': gnudiffopts++;
|
||
/* Output the context diff in unidiff format. */
|
||
specify_style (OUTPUT_UNIFIED);
|
||
break;
|
||
|
||
case 'w': sgidiffopts++;
|
||
/* Ignore horizontal whitespace when comparing lines. */
|
||
ignore_all_space_flag = 1;
|
||
length_varies = 1;
|
||
break;
|
||
|
||
case 'x': sgidiffopts++;
|
||
setxpat(optarg);
|
||
break;
|
||
|
||
default:
|
||
usage ();
|
||
}
|
||
prev = c;
|
||
}
|
||
|
||
if (optind != argc - 2)
|
||
usage ();
|
||
|
||
if (ignore_regexp)
|
||
{
|
||
char *val;
|
||
bzero (&ignore_regexp_compiled, sizeof ignore_regexp_compiled);
|
||
val = re_compile_pattern (ignore_regexp, strlen (ignore_regexp),
|
||
&ignore_regexp_compiled);
|
||
if (val != 0)
|
||
error ("%s: %s", ignore_regexp, val);
|
||
ignore_regexp_compiled.fastmap = (char *) xmalloc (256);
|
||
}
|
||
|
||
if (function_regexp)
|
||
{
|
||
char *val;
|
||
bzero (&function_regexp_compiled, sizeof function_regexp_compiled);
|
||
val = re_compile_pattern (function_regexp, strlen (function_regexp),
|
||
&function_regexp_compiled);
|
||
if (val != 0)
|
||
error ("%s: %s", function_regexp, val);
|
||
function_regexp_compiled.fastmap = (char *) xmalloc (256);
|
||
}
|
||
|
||
if (output_style != OUTPUT_CONTEXT && output_style != OUTPUT_UNIFIED)
|
||
context = 0;
|
||
else if (context == -1)
|
||
/* Default amount of context for -c. */
|
||
context = 3;
|
||
|
||
switch_string = option_list (argv + 1, optind - 1);
|
||
|
||
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");
|
||
exit (val);
|
||
}
|
||
|
||
static char *
|
||
type( mode_t mode )
|
||
{
|
||
if(S_ISFIFO(mode))
|
||
return("fifo");
|
||
else if(S_ISCHR(mode))
|
||
return("character special");
|
||
else if(S_ISBLK(mode))
|
||
return("block special");
|
||
else if(S_ISREG(mode))
|
||
return("regular");
|
||
else if(S_ISLNK(mode))
|
||
return("symbolic link");
|
||
else if(S_ISSOCK(mode))
|
||
return("socket");
|
||
else
|
||
return("unknown");
|
||
}
|
||
|
||
/* 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.)
|
||
This is self-contained; it opens the files and closes them.
|
||
|
||
Value is 0 if files are identical, 1 if different,
|
||
2 if there is a problem opening them. */
|
||
|
||
int
|
||
compare_files (dir0, name0, dir1, name1, depth)
|
||
char *dir0, *dir1;
|
||
char *name0, *name1;
|
||
int depth;
|
||
{
|
||
static char Standard_Input[] = "Standard Input";
|
||
struct file_data inf[2];
|
||
register int i;
|
||
int val;
|
||
int errorcount = 0; /* Bit 1 for stat or open errors */
|
||
/* Bit 2 for fifo, block and character special */
|
||
int stat_result[2];
|
||
|
||
/* If this is directory comparison, perhaps we have a file
|
||
that exists only in one of the directories.
|
||
If so, just print a message to that effect. */
|
||
|
||
if (! entire_new_file_flag && (name0 == 0 || name1 == 0))
|
||
{
|
||
char *name = name0 == 0 ? name1 : name0;
|
||
char *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;
|
||
}
|
||
|
||
/* Mark any nonexistent file with -1 in the desc field. */
|
||
/* Mark unopened files (i.e. directories) with -2. */
|
||
|
||
inf[0].desc = name0 == 0 ? -1 : -2;
|
||
inf[1].desc = name1 == 0 ? -1 : -2;
|
||
|
||
/* Now record the full name of each file, including nonexistent ones. */
|
||
|
||
if (name0 == 0)
|
||
name0 = name1;
|
||
if (name1 == 0)
|
||
name1 = name0;
|
||
|
||
inf[0].name = dir0 == 0 ? name0 : concat (dir0, "/", name0);
|
||
inf[1].name = dir1 == 0 ? name1 : concat (dir1, "/", name1);
|
||
|
||
/* Stat the files. Record whether they are directories.
|
||
Record in stat_result whether stat fails. */
|
||
|
||
for (i = 0; i <= 1; i++)
|
||
{
|
||
bzero (&inf[i].stat, sizeof(struct stat));
|
||
inf[i].dir_p = 0;
|
||
stat_result[i] = 0;
|
||
|
||
if (inf[i].desc != -1)
|
||
{
|
||
char *filename = inf[i].name;
|
||
|
||
stat_result[i] =
|
||
strcmp (filename, "-")
|
||
? stat (filename, &inf[i].stat)
|
||
: fstat (0, &inf[i].stat);
|
||
|
||
if (stat_result[i] < 0)
|
||
{
|
||
perror_with_name (filename);
|
||
errorcount |= 1;
|
||
}
|
||
else
|
||
inf[i].dir_p =
|
||
S_IFDIR == (inf[i].stat.st_mode & S_IFMT)
|
||
&& strcmp (filename, "-");
|
||
}
|
||
}
|
||
|
||
/* See if the two named files are actually the same physical file.
|
||
If so, we know they are identical without actually reading them. */
|
||
|
||
if (output_style != OUTPUT_IFDEF
|
||
&& inf[0].stat.st_ino == inf[1].stat.st_ino
|
||
&& inf[0].stat.st_dev == inf[1].stat.st_dev
|
||
&& stat_result[0] == 0
|
||
&& stat_result[1] == 0)
|
||
{
|
||
val = 0;
|
||
goto done;
|
||
}
|
||
|
||
if (name0 == 0)
|
||
inf[0].dir_p = inf[1].dir_p;
|
||
if (name1 == 0)
|
||
inf[1].dir_p = inf[0].dir_p;
|
||
|
||
/* Open the files and record their descriptors. */
|
||
|
||
for (i = 0; i <= 1; i++)
|
||
{
|
||
if (inf[i].desc == -1)
|
||
;
|
||
else if (!strcmp (inf[i].name, "-"))
|
||
{
|
||
inf[i].desc = 0;
|
||
inf[i].name = Standard_Input;
|
||
}
|
||
/* Don't bother opening if stat already failed. */
|
||
else if (stat_result[i] == 0 && ! inf[i].dir_p)
|
||
{
|
||
char *filename = inf[i].name;
|
||
|
||
/* If both are directories */
|
||
#ifdef sgi
|
||
if(dir0 != 0 && dir1 != 0)
|
||
#else
|
||
if(strchr(inf[0].name,'/') && strchr(inf[1].name,'/'))
|
||
#endif
|
||
{
|
||
/* Check for a fifo, block or character special */
|
||
if(inf[i].stat.st_mode & (S_IFIFO|S_IFCHR|S_IFBLK))
|
||
errorcount |= 2;
|
||
}
|
||
if(!(errorcount&2))
|
||
{
|
||
inf[i].desc = open (filename, O_RDONLY, 0);
|
||
if (0 > inf[i].desc)
|
||
{
|
||
perror_with_name (filename);
|
||
errorcount |= 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (errorcount)
|
||
{
|
||
if(errorcount & 2)
|
||
{
|
||
fprintf(stdout,"File %s is a %s while file %s is a %s\n",
|
||
inf[0].name,type(inf[0].stat.st_mode),
|
||
inf[1].name,type(inf[1].stat.st_mode));
|
||
|
||
}
|
||
/* If either file should exist but fails to be opened, return 2.
|
||
if it was just a file type mismatch, return 1 */
|
||
|
||
val = (errorcount & 1) ? 2 : 1;
|
||
|
||
}
|
||
else if (inf[0].dir_p && inf[1].dir_p)
|
||
{
|
||
if (output_style == OUTPUT_IFDEF)
|
||
fatal ("-D option not supported with directories");
|
||
|
||
/* If both are directories, compare the files in them. */
|
||
|
||
if (depth > 0 && !recursive)
|
||
{
|
||
/* But don't compare dir contents one level down
|
||
unless -r was specified. */
|
||
message ("Common subdirectories: %s and %s\n",
|
||
inf[0].name, inf[1].name);
|
||
val = 0;
|
||
}
|
||
else
|
||
{
|
||
val = diff_dirs (inf[0].name, inf[1].name,
|
||
compare_files, depth, 0, 0);
|
||
}
|
||
|
||
}
|
||
else if (depth == 0 && (inf[0].dir_p || inf[1].dir_p))
|
||
{
|
||
|
||
/* If only one is a directory, and it was specified in the command line,
|
||
use the file in that dir whose basename matches the other file. */
|
||
|
||
int dir_arg = (inf[0].dir_p ? 0 : 1);
|
||
int fnm_arg = (inf[0].dir_p ? 1 : 0);
|
||
char *p = rindex (inf[fnm_arg].name, '/');
|
||
char *filename = concat (inf[dir_arg].name, "/",
|
||
(p ? p+1 : inf[fnm_arg].name));
|
||
|
||
if (inf[fnm_arg].name == Standard_Input)
|
||
fatal ("can't compare - to a directory");
|
||
|
||
inf[dir_arg].desc = open (filename, O_RDONLY, 0);
|
||
|
||
if (0 > inf[dir_arg].desc)
|
||
{
|
||
perror_with_name (filename);
|
||
val = 2;
|
||
}
|
||
else
|
||
{
|
||
/* JF: patch from the net to check and make sure we can really free
|
||
this. If it's from argv[], freeing it is a *really* bad idea */
|
||
if (0 != (dir_arg ? dir1 : dir0))
|
||
free (inf[dir_arg].name);
|
||
inf[dir_arg].name = filename;
|
||
if (fstat (inf[dir_arg].desc, &inf[dir_arg].stat) < 0)
|
||
pfatal_with_name (inf[dir_arg].name);
|
||
|
||
inf[dir_arg].dir_p
|
||
= (S_IFDIR == (inf[dir_arg].stat.st_mode & S_IFMT));
|
||
if (inf[dir_arg].dir_p)
|
||
{
|
||
error ("%s is a directory but %s is not",
|
||
inf[dir_arg].name, inf[fnm_arg].name);
|
||
val = 1;
|
||
}
|
||
else
|
||
val = diff_2_files (inf, depth);
|
||
}
|
||
|
||
}
|
||
else if (depth > 0 && (inf[0].dir_p || inf[1].dir_p))
|
||
{
|
||
/* 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 (entire_new_file_flag && recursive)
|
||
val = diff_dirs (inf[0].name, inf[1].name, compare_files, depth,
|
||
inf[0].desc == -1, inf[1].desc == -1);
|
||
else
|
||
{
|
||
char *dir = (inf[0].desc == -1) ? dir1 : dir0;
|
||
message ("Only in %s: %s\n", dir, name0);
|
||
val = 1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* We have a subdirectory in one directory
|
||
and a file in the other. */
|
||
|
||
if (inf[0].dir_p)
|
||
message ("%s is a directory but %s is not\n",
|
||
inf[0].name, inf[1].name);
|
||
else
|
||
message ("%s is a directory but %s is not\n",
|
||
inf[1].name, inf[0].name);
|
||
/* This is a difference. */
|
||
val = 1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
|
||
/* Both exist and both are ordinary files. */
|
||
|
||
val = diff_2_files (inf, depth);
|
||
|
||
}
|
||
|
||
/* Now the comparison has been done, if no error prevented it,
|
||
and VAL is the value this function will return. */
|
||
|
||
if (inf[0].desc >= 0)
|
||
close (inf[0].desc);
|
||
if (inf[1].desc >= 0)
|
||
close (inf[1].desc);
|
||
|
||
done:
|
||
if (val == 0 && !inf[0].dir_p)
|
||
{
|
||
if (print_file_same_flag)
|
||
message ("Files %s and %s are identical\n",
|
||
inf[0].name, inf[1].name);
|
||
}
|
||
else
|
||
fflush (stdout);
|
||
|
||
if (dir0 != 0)
|
||
free (inf[0].name);
|
||
if (dir1 != 0)
|
||
free (inf[1].name);
|
||
|
||
return val;
|
||
}
|