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