home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / zip / gnu / diff115.lzh / DIFF115 / DIFF.C < prev    next >
C/C++ Source or Header  |  1991-01-30  |  19KB  |  704 lines

  1. /* GNU DIFF main routine.
  2.    Copyright (C) 1988, 1989 Free Software Foundation, Inc.
  3.  
  4. This file is part of GNU DIFF.
  5.  
  6. GNU DIFF is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. GNU DIFF is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU DIFF; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /* GNU DIFF was written by Mike Haertel, David Hayes,
  21.    Richard Stallman and Len Tower.  */
  22.  
  23. #define GDIFF_MAIN
  24. #include "regex.h"
  25. #include "diff.h"
  26. #include "getopt.h"
  27.  
  28.  
  29. /* Nonzero for -r: if comparing two directories,
  30.    compare their common subdirectories recursively.  */
  31.  
  32. int recursive;
  33.  
  34. /* For debugging: don't do discard_confusing_lines.  */
  35.  
  36. int no_discards;
  37.  
  38. /* Return a string containing the command options with which diff was invoked.
  39.    Spaces appear between what were separate ARGV-elements.
  40.    There is a space at the beginning but none at the end.
  41.    If there were no options, the result is an empty string.
  42.  
  43.    Arguments: OPTIONVEC, a vector containing separate ARGV-elements, and COUNT,
  44.    the length of that vector.  */
  45.  
  46. static char *
  47. option_list (optionvec, count)
  48.      char **optionvec;  /* Was `vector', but that collides on Alliant.  */
  49.      int count;
  50. {
  51.   int i;
  52.   int length = 0;
  53.   char *result;
  54.  
  55.   for (i = 0; i < count; i++)
  56.     length += strlen (optionvec[i]) + 1;
  57.  
  58.   result = (char *) xmalloc (length + 1);
  59.   result[0] = 0;
  60.  
  61.   for (i = 0; i < count; i++)
  62.     {
  63.       strcat (result, " ");
  64.       strcat (result, optionvec[i]);
  65.     }
  66.  
  67.   return result;
  68. }
  69.  
  70. /* The numbers 129 and 130 that appear in the fourth element
  71.    for the context and unidiff entries are used as a way of
  72.    telling the big switch in `main' how to process those options.  */
  73.  
  74. static struct option longopts[] =
  75. {
  76.   {"ignore-blank-lines", 0, 0, 'B'},
  77.   {"context", 2, 0, 129},
  78.   {"ifdef", 1, 0, 'D'},
  79.   {"show-function-line", 1, 0, 'F'},
  80.   {"speed-large-files", 0, 0, 'H'},
  81.   {"ignore-matching-lines", 1, 0, 'I'},
  82.   {"file-label", 1, 0, 'L'},
  83.   {"entire-new-files", 0, 0, 'N'},
  84.   {"new-files", 0, 0, 'N'},
  85.   {"starting-file", 1, 0, 'S'},
  86.   {"initial-tab", 0, 0, 'T'},
  87.   {"text", 0, 0, 'a'},
  88.   {"all-text", 0, 0, 'a'},
  89.   {"ascii", 0, 0, 'a'},
  90.   {"ignore-space-change", 0, 0, 'b'},
  91.   {"minimal", 0, 0, 'd'},
  92.   {"ed", 0, 0, 'e'},
  93.   {"reversed-ed", 0, 0, 'f'},
  94.   {"ignore-case", 0, 0, 'i'},
  95.   {"print", 0, 0, 'l'},
  96.   {"rcs", 0, 0, 'n'},
  97.   {"show-c-function", 0, 0, 'p'},
  98.   {"binary", 0, 0, 'q'},
  99.   {"brief", 0, 0, 'q'},
  100.   {"recursive", 0, 0, 'r'},
  101.   {"report-identical-files", 0, 0, 's'},
  102.   {"expand-tabs", 0, 0, 't'},
  103.   {"ignore-all-space", 0, 0, 'w'},
  104.   {"unified", 2, 0, 130},
  105.   {"version", 0, 0, 'v'},
  106.   {0, 0, 0, 0}
  107. };
  108.  
  109. main (argc, argv)
  110.      int argc;
  111.      char *argv[];
  112. {
  113.   int val;
  114.   int c;
  115.   int prev = -1;
  116.   int longind;
  117.   extern char *version_string;
  118.  
  119.   program = argv[0];
  120.  
  121.   /* Do our initializations. */
  122.   output_style = OUTPUT_NORMAL;
  123.   always_text_flag = FALSE;
  124.   ignore_space_change_flag = FALSE;
  125.   ignore_all_space_flag = FALSE;
  126.   length_varies = FALSE;
  127.   ignore_case_flag = FALSE;
  128.   ignore_blank_lines_flag = FALSE;
  129.   ignore_regexp = 0;
  130.   function_regexp = 0;
  131.   print_file_same_flag = FALSE;
  132.   entire_new_file_flag = FALSE;
  133.   no_details_flag = FALSE;
  134.   context = -1;
  135.   line_end_char = '\n';
  136.   tab_align_flag = FALSE;
  137.   tab_expand_flag = FALSE;
  138.   recursive = FALSE;
  139.   paginate_flag = FALSE;
  140.   ifdef_string = NULL;
  141.   heuristic = FALSE;
  142.   dir_start_file = NULL;
  143.   msg_chain = NULL;
  144.   msg_chain_end = NULL;
  145.   no_discards = 0;
  146.  
  147.   /* Decode the options.  */
  148.  
  149.   while ((c = getopt_long (argc, argv,
  150.                "0123456789abBcC:dD:efF:hHiI:lL:nNpqrsS:tTuvw",
  151.                longopts, &longind)) != EOF)
  152.     {
  153.       if (c == 0)        /* Long option. */
  154.     c = longopts[longind].val;
  155.       switch (c)
  156.     {
  157.       /* All digits combine in decimal to specify the context-size.  */
  158.     case '1':
  159.     case '2':
  160.     case '3':
  161.     case '4':
  162.     case '5':
  163.     case '6':
  164.     case '7':
  165.     case '8':
  166.     case '9':
  167.     case '0':
  168.       if (context == -1)
  169.         context = 0;
  170.       /* If a context length has already been specified,
  171.          more digits allowed only if they follow right after the others.
  172.          Reject two separate runs of digits, or digits after -C.  */
  173.       else if (prev < '0' || prev > '9')
  174.         fatal ("context length specified twice");
  175.  
  176.       context = context * 10 + c - '0';
  177.       break;
  178.  
  179.     case 'a':
  180.       /* Treat all files as text files; never treat as binary.  */
  181.       always_text_flag = 1;
  182.       break;
  183.  
  184.     case 'b':
  185.       /* Ignore changes in amount of whitespace.  */
  186.       ignore_space_change_flag = 1;
  187.       length_varies = 1;
  188.       break;
  189.  
  190.     case 'B':
  191.       /* Ignore changes affecting only blank lines.  */
  192.       ignore_blank_lines_flag = 1;
  193.       break;
  194.  
  195.     case 'C':
  196.     case 129:        /* +context[=lines] */
  197.     case 130:        /* +unified[=lines] */
  198.       if (optarg)
  199.         {
  200.           if (context >= 0)
  201.         fatal ("context length specified twice");
  202.           {
  203.         char *p;
  204.         for (p = optarg; *p; p++)
  205.           if (*p < '0' || *p > '9')
  206.             fatal ("invalid context length argument");
  207.           }
  208.           context = atoi (optarg);
  209.         }
  210.  
  211.       /* Falls through.  */
  212.     case 'c':
  213.       /* Make context-style output.  */
  214.       specify_style (c == 130 ? OUTPUT_UNIFIED : OUTPUT_CONTEXT);
  215.       break;
  216.  
  217.     case 'd':
  218.       /* Don't discard lines.  This makes things slower (sometimes much
  219.          slower) but will find a guaranteed minimal set of changes.  */
  220.       no_discards = 1;
  221.       break;
  222.  
  223.     case 'D':
  224.       /* Make merged #ifdef output.  */
  225.       specify_style (OUTPUT_IFDEF);
  226.       ifdef_string = optarg;
  227.       break;
  228.  
  229.     case 'e':
  230.       /* Make output that is a valid `ed' script.  */
  231.       specify_style (OUTPUT_ED);
  232.       break;
  233.  
  234.     case 'f':
  235.       /* Make output that looks vaguely like an `ed' script
  236.          but has changes in the order they appear in the file.  */
  237.       specify_style (OUTPUT_FORWARD_ED);
  238.       break;
  239.  
  240.     case 'F':
  241.       /* Show, for each set of changes, the previous line that
  242.          matches the specified regexp.  Currently affects only
  243.          context-style output.  */
  244.       function_regexp = optarg;
  245.       break;
  246.  
  247.     case 'h':
  248.       /* Split the files into chunks of around 1500 lines
  249.          for faster processing.  Usually does not change the result.
  250.  
  251.          This currently has no effect.  */
  252.       break;
  253.  
  254.     case 'H':
  255.       /* Turn on heuristics that speed processing of large files
  256.          with a small density of changes.  */
  257.       heuristic = 1;
  258.       break;
  259.  
  260.     case 'i':
  261.       /* Ignore changes in case.  */
  262.       ignore_case_flag = 1;
  263.       break;
  264.  
  265.     case 'I':
  266.       /* Ignore changes affecting only lines that match the
  267.          specified regexp.  */
  268.       ignore_regexp = optarg;
  269.       break;
  270.  
  271.     case 'l':
  272.       /* Pass the output through `pr' to paginate it.  */
  273. #if !NO_PAGINATE
  274.       /* AKP 1/91: see util.c about the NO_PAGINATE flag */
  275.       paginate_flag = 1;
  276. #else
  277.       fatal("This diff can't pipe through pr!");
  278. #endif
  279.       break;
  280.  
  281.     case 'L':
  282.       /* Specify file labels for `-c' output headers.  */
  283.       if (!file_label[0])
  284.         file_label[0] = optarg;
  285.       else if (!file_label[1])
  286.         file_label[1] = optarg;
  287.       else
  288.         fatal ("too many file label options");
  289.       break;
  290.  
  291.     case 'n':
  292.       /* Output RCS-style diffs, like `-f' except that each command
  293.          specifies the number of lines affected.  */
  294.       specify_style (OUTPUT_RCS);
  295.       break;
  296.  
  297.     case 'N':
  298.       /* When comparing directories, if a file appears only in one
  299.          directory, treat it as present but empty in the other.  */
  300.       entire_new_file_flag = 1;
  301.       break;
  302.  
  303.     case 'p':
  304.       /* Make context-style output and show name of last C function.  */
  305.       specify_style (OUTPUT_CONTEXT);
  306.       function_regexp = "^[_a-zA-Z]";
  307.       break;
  308.  
  309.     case 'q':
  310.       no_details_flag = 1;
  311.       break;
  312.  
  313.     case 'r':
  314.       /* When comparing directories, 
  315.          recursively compare any subdirectories found.  */
  316.       recursive = 1;
  317.       break;
  318.  
  319.     case 's':
  320.       /* Print a message if the files are the same.  */
  321.       print_file_same_flag = 1;
  322.       break;
  323.  
  324.     case 'S':
  325.       /* When comparing directories, start with the specified
  326.          file name.  This is used for resuming an aborted comparison.  */
  327.       dir_start_file = optarg;
  328.       break;
  329.  
  330.     case 't':
  331.       /* Expand tabs to spaces in the output so that it preserves
  332.          the alignment of the input files.  */
  333.       tab_expand_flag = 1;
  334.       break;
  335.  
  336.     case 'T':
  337.       /* Use a tab in the output, rather than a space, before the
  338.          text of an input line, so as to keep the proper alignment
  339.          in the input line without changing the characters in it.  */
  340.       tab_align_flag = 1;
  341.       break;
  342.  
  343.     case 'v':
  344.       printf ("GNU diff version %s\n", version_string);
  345. #if DONT_USE_STAT_INO || NO_PAGINATE
  346.       printf ("Modified for TOS by Allan Pratt, atari!apratt\n");
  347. #endif
  348.       break;
  349.  
  350.     case 'u':
  351.       /* Output the context diff in unidiff format.  */
  352.       specify_style (OUTPUT_UNIFIED);
  353.       break;
  354.  
  355.     case 'w':
  356.       /* Ignore horizontal whitespace when comparing lines.  */
  357.       ignore_all_space_flag = 1;
  358.       length_varies = 1;
  359.       break;
  360.  
  361.     default:
  362.       usage ();
  363.     }
  364.       prev = c;
  365.     }
  366.  
  367.   if (optind != argc - 2)
  368.     usage ();
  369.  
  370.   if (ignore_regexp)
  371.     {
  372.       char *val;
  373.       bzero (&ignore_regexp_compiled, sizeof ignore_regexp_compiled);
  374.       val = re_compile_pattern (ignore_regexp, strlen (ignore_regexp),
  375.                 &ignore_regexp_compiled);
  376.       if (val != 0)
  377.     error ("%s: %s", ignore_regexp, val);
  378.       ignore_regexp_compiled.fastmap = (char *) xmalloc (256);
  379.     }
  380.  
  381.   if (function_regexp)
  382.     {
  383.       char *val;
  384.       bzero (&function_regexp_compiled, sizeof function_regexp_compiled);
  385.       val = re_compile_pattern (function_regexp, strlen (function_regexp),
  386.                 &function_regexp_compiled);
  387.       if (val != 0)
  388.     error ("%s: %s", function_regexp, val);
  389.       function_regexp_compiled.fastmap = (char *) xmalloc (256);
  390.     }
  391.  
  392.   if (output_style != OUTPUT_CONTEXT && output_style != OUTPUT_UNIFIED)
  393.     context = 0;
  394.   else if (context == -1)
  395.     /* Default amount of context for -c.  */
  396.     context = 3;
  397.  
  398.   switch_string = option_list (argv + 1, optind - 1);
  399.  
  400.   val = compare_files (0, argv[optind], 0, argv[optind + 1], 0);
  401.  
  402.   /* Print any messages that were saved up for last.  */
  403.   print_message_queue ();
  404.  
  405.   if (ferror (stdout) || fclose (stdout) != 0)
  406.     fatal ("write error");
  407.   exit (val);
  408. }
  409.  
  410. usage ()
  411. {
  412.   fprintf (stderr, "\
  413. Usage: diff [-#] [-abBcdefhHilnNprstTuvw] [-C lines] [-F regexp] [-I regexp]\n\
  414.        [-L label [-L label]] [-S file] [-D symbol] [+ignore-blank-lines]\n\
  415.        [+context[=lines]] [+unified[=lines]] [+ifdef=symbol]\n\
  416.        [+show-function-line=regexp]\n");
  417.   fprintf (stderr, "\
  418.        [+speed-large-files] [+ignore-matching-lines=regexp] [+new-file]\n\
  419.        [+initial-tab] [+starting-file=file] [+text] [+all-text] [+ascii]\n\
  420.        [+minimal] [+ignore-space-change] [+ed] [+reversed-ed] [+ignore-case]\n");
  421.   fprintf (stderr, "\
  422.        [+print] [+rcs] [+show-c-function] [+binary] [+brief] [+recursive]\n\
  423.        [+report-identical-files] [+expand-tabs] [+ignore-all-space]\n\
  424.        [+file-label=label [+file-label=label]] [+version] path1 path2\n");
  425.   exit (2);
  426.  
  427. specify_style (style)
  428.      enum output_style style;
  429. {
  430.   if (output_style != OUTPUT_NORMAL
  431.       && output_style != style)
  432.     error ("conflicting specifications of output style");
  433.   output_style = style;
  434. }
  435.  
  436. /* Compare two files (or dirs) with specified names
  437.    DIR0/NAME0 and DIR1/NAME1, at level DEPTH in directory recursion.
  438.    (if DIR0 is 0, then the name is just NAME0, etc.)
  439.    This is self-contained; it opens the files and closes them.
  440.  
  441.    Value is 0 if files are identical, 1 if different,
  442.    2 if there is a problem opening them.  */
  443.  
  444. int
  445. compare_files (dir0, name0, dir1, name1, depth)
  446.      char *dir0, *dir1;
  447.      char *name0, *name1;
  448.      int depth;
  449. {
  450.   static char Standard_Input[] = "Standard Input";
  451.   struct file_data inf[2];
  452.   register int i;
  453.   int val;
  454.   int errorcount = 0;
  455.   int stat_result[2];
  456.  
  457.   /* If this is directory comparison, perhaps we have a file
  458.      that exists only in one of the directories.
  459.      If so, just print a message to that effect.  */
  460.  
  461.   if (! entire_new_file_flag && (name0 == 0 || name1 == 0))
  462.     {
  463.       char *name = name0 == 0 ? name1 : name0;
  464.       char *dir = name0 == 0 ? dir1 : dir0;
  465.       message ("Only in %s: %s\n", dir, name);
  466.       /* Return 1 so that diff_dirs will return 1 ("some files differ").  */
  467.       return 1;
  468.     }
  469.  
  470.   /* Mark any nonexistent file with -1 in the desc field.  */
  471.   /* Mark unopened files (i.e. directories) with -2. */
  472.  
  473.   inf[0].desc = name0 == 0 ? -1 : -2;
  474.   inf[1].desc = name1 == 0 ? -1 : -2;
  475.  
  476.   /* Now record the full name of each file, including nonexistent ones.  */
  477.  
  478.   if (name0 == 0)
  479.     name0 = name1;
  480.   if (name1 == 0)
  481.     name1 = name0;
  482.  
  483.   inf[0].name = dir0 == 0 ? name0 : concat (dir0, "/", name0);
  484.   inf[1].name = dir1 == 0 ? name1 : concat (dir1, "/", name1);
  485.  
  486.   /* Stat the files.  Record whether they are directories.
  487.      Record in stat_result whether stat fails.  */
  488.  
  489.   for (i = 0; i <= 1; i++)
  490.     {
  491.       bzero (&inf[i].stat, sizeof(struct stat));
  492.       inf[i].dir_p = 0;
  493.       stat_result[i] = 0;
  494.  
  495.       if (inf[i].desc != -1)
  496.     {
  497.       char *filename = inf[i].name;
  498.  
  499.       stat_result[i] = 
  500.         strcmp (filename, "-")
  501.           ? stat (filename, &inf[i].stat)
  502.           : fstat (0, &inf[i].stat);
  503.           
  504.       if (stat_result[i] < 0)
  505.         {
  506.           perror_with_name (filename);
  507.           errorcount = 1;
  508.         }
  509.       else
  510.         inf[i].dir_p = 
  511.           S_IFDIR == (inf[i].stat.st_mode & S_IFMT)
  512.           && strcmp (filename, "-");
  513.     }
  514.     }
  515.  
  516. #if !DONT_USE_STAT_INO
  517.   /* AKP: see analyze.c for comments on DONT_USE_STAT_INO */
  518.   /* See if the two named files are actually the same physical file.
  519.      If so, we know they are identical without actually reading them.  */
  520.  
  521.   if (output_style != OUTPUT_IFDEF
  522.       && inf[0].stat.st_ino == inf[1].stat.st_ino
  523.       && inf[0].stat.st_dev == inf[1].stat.st_dev
  524.       && stat_result[0] == 0
  525.       && stat_result[1] == 0)
  526.     {
  527.       val = 0;
  528.       goto done;
  529.     }
  530. #endif
  531.  
  532.   if (name0 == 0)
  533.     inf[0].dir_p = inf[1].dir_p;
  534.   if (name1 == 0)
  535.     inf[1].dir_p = inf[0].dir_p;
  536.  
  537.   /* Open the files and record their descriptors.  */
  538.  
  539.   for (i = 0; i <= 1; i++)
  540.     {
  541.       if (inf[i].desc == -1)
  542.     ;
  543.       else if (!strcmp (inf[i].name, "-"))
  544.     {
  545.       inf[i].desc = 0;
  546.       inf[i].name = Standard_Input;
  547.     }
  548.       /* Don't bother opening if stat already failed.  */
  549.       else if (stat_result[i] == 0 && ! inf[i].dir_p)
  550.     {
  551.       char *filename = inf[i].name;
  552.  
  553.       inf[i].desc = open (filename, O_RDONLY, 0);
  554.       if (0 > inf[i].desc)
  555.         {
  556.           perror_with_name (filename);
  557.           errorcount = 1;
  558.         }
  559.     }
  560.     }
  561.  
  562.   if (errorcount)
  563.     {
  564.  
  565.       /* If either file should exist but fails to be opened, return 2.  */
  566.  
  567.       val = 2;
  568.  
  569.     }
  570.   else if (inf[0].dir_p && inf[1].dir_p)
  571.     {
  572.       if (output_style == OUTPUT_IFDEF)
  573.     fatal ("-D option not supported with directories");
  574.  
  575.       /* If both are directories, compare the files in them.  */
  576.  
  577.       if (depth > 0 && !recursive)
  578.     {
  579.       /* But don't compare dir contents one level down
  580.          unless -r was specified.  */
  581.       message ("Common subdirectories: %s and %s\n",
  582.            inf[0].name, inf[1].name);
  583.       val = 0;
  584.     }
  585.       else
  586.     {
  587.       val = diff_dirs (inf[0].name, inf[1].name, 
  588.                compare_files, depth, 0, 0);
  589.     }
  590.  
  591.     }
  592.   else if (depth == 0 && (inf[0].dir_p || inf[1].dir_p))
  593.     {
  594.  
  595.       /* If only one is a directory, and it was specified in the command line,
  596.      use the file in that dir whose basename matches the other file.  */
  597.  
  598.       int dir_arg = (inf[0].dir_p ? 0 : 1);
  599.       int fnm_arg = (inf[0].dir_p ? 1 : 0);
  600.       char *p = rindex (inf[fnm_arg].name, '/');
  601.       char *filename = concat (inf[dir_arg].name,  "/",
  602.                    (p ? p+1 : inf[fnm_arg].name));
  603.  
  604.       if (inf[fnm_arg].name == Standard_Input)
  605.     fatal ("can't compare - to a directory");
  606.  
  607.       inf[dir_arg].desc = open (filename, O_RDONLY, 0);
  608.  
  609.       if (0 > inf[dir_arg].desc)
  610.     {
  611.       perror_with_name (filename);
  612.       val = 2;
  613.     }
  614.       else
  615.     {
  616.       /* JF: patch from the net to check and make sure we can really free
  617.          this.  If it's from argv[], freeing it is a *really* bad idea */
  618.       if (0 != (dir_arg ? dir1 : dir0))
  619.         free (inf[dir_arg].name);
  620.       inf[dir_arg].name = filename;
  621.       if (fstat (inf[dir_arg].desc, &inf[dir_arg].stat) < 0)
  622.         pfatal_with_name (inf[dir_arg].name);
  623.  
  624.       inf[dir_arg].dir_p
  625.         = (S_IFDIR == (inf[dir_arg].stat.st_mode & S_IFMT));
  626.       if (inf[dir_arg].dir_p)
  627.         {
  628.           error ("%s is a directory but %s is not",
  629.              inf[dir_arg].name, inf[fnm_arg].name);
  630.           val = 1;
  631.         }
  632.       else
  633.         val = diff_2_files (inf, depth);
  634.     }
  635.  
  636.     }
  637.   else if (depth > 0 && (inf[0].dir_p || inf[1].dir_p))
  638.     {
  639.       /* Perhaps we have a subdirectory that exists only in one directory.
  640.      If so, just print a message to that effect.  */
  641.  
  642.       if (inf[0].desc == -1 || inf[1].desc == -1)
  643.     {
  644.       if (entire_new_file_flag && recursive)
  645.         val = diff_dirs (inf[0].name, inf[1].name, compare_files, depth,
  646.                  inf[0].desc == -1, inf[1].desc == -1);
  647.       else
  648.         {
  649.           char *dir = (inf[0].desc == -1) ? dir1 : dir0;
  650.           message ("Only in %s: %s\n", dir, name0);
  651.           val = 1;
  652.         }
  653.     }
  654.       else
  655.     {
  656.       /* We have a subdirectory in one directory
  657.          and a file in the other.  */
  658.  
  659.       if (inf[0].dir_p)
  660.         message ("%s is a directory but %s is not\n",
  661.              inf[0].name, inf[1].name);
  662.       else
  663.         message ("%s is a directory but %s is not\n",
  664.              inf[1].name, inf[0].name);
  665.       /* This is a difference.  */
  666.       val = 1;
  667.     }
  668.     }
  669.   else
  670.     {
  671.  
  672.       /* Both exist and both are ordinary files.  */
  673.  
  674.       val = diff_2_files (inf, depth);
  675.  
  676.     }
  677.  
  678.   /* Now the comparison has been done, if no error prevented it,
  679.      and VAL is the value this function will return.  */
  680.  
  681.   if (inf[0].desc >= 0)
  682.     close (inf[0].desc);
  683.   if (inf[1].desc >= 0)
  684.     close (inf[1].desc);
  685.  
  686.  done:
  687.   if (val == 0 && !inf[0].dir_p)
  688.     {
  689.       if (print_file_same_flag)
  690.     message ("Files %s and %s are identical\n",
  691.          inf[0].name, inf[1].name);
  692.     }
  693.   else
  694.     fflush (stdout);
  695.  
  696.   if (dir0 != 0)
  697.     free (inf[0].name);
  698.   if (dir1 != 0)
  699.     free (inf[1].name);
  700.  
  701.   return val;
  702. }
  703.