home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / rcs57pc3.zip / diff16 / diff.c < prev    next >
C/C++ Source or Header  |  1996-02-29  |  23KB  |  823 lines

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