home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 134_01 / diff.c < prev    next >
Text File  |  1985-08-21  |  10KB  |  415 lines

  1. /*    DIFF - File Comparator    */
  2.  
  3. /*    Copyright (c) 1983 by Kevin B. Kenny
  4.  
  5.     Released to the BDS `C' Users' Group for non-commercial distribution
  6.     only.
  7.  
  8.     Kevin Kenny
  9.     729-A E. Cochise Dr.
  10.     Phoenix, Arizona   85020
  11. */
  12.  
  13.  
  14. #include <bdscio.h>
  15. #include <dio.h>
  16. #include <cmdutil.h>
  17.  
  18. /*    Command line options     */
  19.  
  20. int dispmode;            /* Display mode */
  21. #define DM_NORM 0            /* Normal display */
  22. #define DM_ALTER 1            /* Display alterations only */
  23. #define DM_MATCH 2            /* Display matching lines */
  24.  
  25. int resync;            /* Resynchronization count */
  26. char * header;            /* Header for display */
  27. int blanksf;            /* Flag = 1 if blanks s/b compressed */
  28. int single;            /* Flag = 1 to ignore case differences */
  29. int debug;            /* Flag = 1 if debugging */
  30. char * file1;            /* Name of first file */
  31. char * file2;            /* Name of second file */
  32.  
  33. /*    Input file status    */
  34.  
  35. FILE file [2];            /* IObuf's of input files */
  36.  
  37. struct file_line {
  38.     struct file_line *next, *prev;    /* Chain linkage */
  39.     int line_no;            /* Line number in file */
  40.     char * line_text;        /* Text of the line */
  41.     };
  42. struct file_line * first_line [2];    /* First line from file in memory */
  43. struct file_line * last_line [2];    /* Last line from file in memory */
  44. struct file_line * cur_line [2];    /* Current line in memory */
  45. int linenumb [2];            /* Last line read from each file */
  46. int eofhit [2];                /* EOF read in from file */
  47.  
  48. /*    Status of resynchronizer    */
  49.  
  50. int equal;              /* Flag to indicate equality */
  51. int match;                /* Flag to indicate match reached */
  52. int left;                /* File being read backwards */
  53. int right;                /* FIle being read forwards */
  54. int loffset;                /* Number of mismatches in "left" */
  55. int roffset;                /* Number of mismatches in "right" */
  56. int difflen [2];            /* Number of mismatches by file */
  57. int hold;                /* Working word for pointer switches */
  58.  
  59. main (argc, argv)
  60.     int argc;
  61.     char ** argv;
  62.     {
  63.     _allocp = NULL;
  64.     dioinit (&argc, argv);
  65.     getopts (argc, argv);
  66.     setup ();
  67.     rundiff ();
  68.     dioflush ();
  69.     }
  70.  
  71. /*     Read an process the options from the command line    */
  72.  
  73. struct option optable [7];    /* Option descriptions for procarg */
  74.  
  75. getopts (argc, argv)
  76.     int argc;
  77.     char ** argv;
  78.     {
  79.  
  80.     int info;        /* Information item returned from procarg */
  81.     int error;        /* Error flag */
  82.  
  83.     initv (optable, EOF,
  84. #define FILE_OPT -1            /* File name */
  85.         "Alterations", NAKED_KWD,
  86. #define ALTER_OPT 0            /* Flag to show just changed text */
  87.         "Matching", NAKED_KWD,
  88. #define MATCH_OPT 1            /* Flag to show just matching text */
  89.         "Resynchronize", NVAL_KWD,
  90. #define RESYN_OPT 2            /* Line count for resynchronization */
  91.         "Header", SVAL_KWD,
  92. #define HEAD_OPT 3            /* Header for output lines */
  93.         "Blanks", NAKED_KWD,
  94. #define BLANK_OPT 4            /* Ignore multiple blanks */
  95.         "Singlecase", NAKED_KWD,
  96. #define SINGLE_OPT 5
  97.         "Zdebug", NAKED_KWD,
  98. #define DEBUG_OPT 6            /* Turn on internal traces */
  99.         EOF);
  100.  
  101.     dispmode = DM_NORM;        /* Set default options */
  102.     resync = 3;
  103.     header = "-------------------------------------------------- ";
  104.     blanksf = FALSE;
  105.     debug = FALSE;
  106.     single = FALSE;
  107.     file1 = NULL;
  108.     file2 = NULL;
  109.  
  110.     ++argv; --argc;        /* Discard command name from argv */
  111.  
  112.     error = FALSE;        /* No error has occurred yet */
  113.  
  114.     while (argc) {        /* Process one command option */
  115.         switch (procarg (&argc, &argv, optable, &info)) {
  116.  
  117.             case ALTER_OPT:
  118.             dispmode = DM_ALTER; break;
  119.             case MATCH_OPT:
  120.             dispmode = DM_MATCH; break;
  121.             case RESYN_OPT:
  122.             resync = info; break;
  123.             case HEAD_OPT:
  124.             header = info; break;
  125.             case BLANK_OPT:
  126.             blanksf = TRUE; break;
  127.             case SINGLE_OPT:
  128.             single = TRUE; break;
  129.             case DEBUG_OPT:
  130.             debug = TRUE; break;
  131.             case FILE_OPT:
  132.             if (file1 == NULL) file1 = info;
  133.             else if (file2 == NULL) file2 = info;
  134.             else error = TRUE;
  135.             break;
  136.             default:
  137.             error = TRUE;
  138.             }
  139.         }
  140.  
  141.     if (file2 == NULL || error) {
  142.         showsyntax ("diff <file1> <file2>", optable);
  143.         exit ();
  144.         }
  145.     }
  146.  
  147. /*    Set up the DIFF process        */
  148.  
  149. setup () {
  150.  
  151.     if (fopen (file1, file [0]) == ERROR) {
  152.         fprintf (STD_ERR, "%s: can't open file.\n", file1);
  153.         exit ();
  154.         }
  155.     if (fopen (file2, file [1]) == ERROR) {
  156.         fprintf (STD_ERR, "%s: can't open file.\n", file2);
  157.         exit ();
  158.         }
  159.     first_line [0] = first_line [1] =
  160.     last_line [0] = last_line [1] =
  161.     cur_line [0] = cur_line [1] =        NULL;
  162.     linenumb [0] = linenumb [1] = 0;
  163.     eofhit [0] = eofhit [1] = FALSE;
  164.     equal = TRUE;        /* equal so far; */
  165.     fprintf (STD_ERR, "K**2 DIFF version 83-06-07\n");
  166.     fprintf (STD_ERR, "copyright (c) 1983 by Kevin Kenny.\n");
  167.     }
  168.  
  169. /*    Do the DIFF process        */
  170.  
  171. rundiff () {
  172.     while (!ateof (0) || !ateof (1)) {    /* Run until end of files */
  173.         domatch ();            /* Handle matching lines */
  174.         if (ateof (0) && ateof (1)) break;
  175.         equal = FALSE;            /* We've found a difference */
  176.         synch ();            /* Get us back in sync */
  177.         dodiff ();            /* Handle changed lines */
  178.         }
  179.     if (equal) fprintf (STD_ERR, "\nTwo files are equal.");
  180.     }
  181.  
  182. /*    Do matching lines        */
  183.  
  184. domatch () {
  185.     if (debug) fprintf (STD_ERR, "in Domatch\n");
  186.     if (!atmatch ()) return;        /* Handle non-match at start */
  187.     
  188.     if (dispmode == DM_MATCH)         /* Displaying matches? */
  189.         printf ("%s%d, %d\n", header, lineno (0), lineno (1));
  190.  
  191.     while (atmatch () && !ateof(0)) {
  192.         if (dispmode == DM_MATCH)    /* Display matching lines */
  193.             printf ("%s", curline (0));
  194.         advance (0); advance (1);    /* Bump past matching lines */
  195.         discard (0); discard (1);    /* Throw away matched lines */
  196.         }
  197.     }
  198.  
  199. /*    Resynchronize comparison when mismatched lines found    */
  200.  
  201. synch () {
  202.     if (debug) fprintf (STD_ERR, "in synch\n");
  203.     left = 0;            /* Move pointer leftward from
  204.                        current position in first file */
  205.     right = 1;            /* Move pointer rightward in second
  206.                        file. */
  207.     loffset = roffset = 0;        /* Both pointers at current line */
  208.  
  209.     do {
  210.         ++roffset; advance (right);
  211.                     /* Move pointer rightward */
  212.         if (--loffset >= 0)     /* Back leftward pointer up */
  213.             backup (left);
  214.         else {            /* Pointer reached divergence point */
  215.             if (bdos (6, 0xFF) == 0x03) {
  216.                 fprintf (STD_ERR, "\nDIFF aborted.");
  217.                 exit ();
  218.                 }
  219.             hold = right; right = left; left = hold;
  220.                     /* Swap input files */
  221.             loffset = roffset; roffset = 0;
  222.                     /* Switch pointers */
  223.             }
  224.  
  225.         if (debug) fprintf (STD_ERR,
  226.             "synch loop: left=%d right=%d loffset=%d roffset=%d\n",
  227.                     left, right, loffset, roffset);
  228.  
  229.         match = TRUE;        /* Innocent until proven guilty */
  230.         for (hold = 0; hold < resync; ++hold) {
  231.             if (!atmatch ()) {    /* Test if at least "resync" */
  232.                 match = FALSE;    /* consecutive lines match   */
  233.                 break;
  234.                 }
  235.             advance (0); advance (1);
  236.                         /* Advance over matched lines*/
  237.             }
  238.         while (hold) {
  239.             backup (0); backup (1);    /* Back up over matched lines*/
  240.             --hold;
  241.             }
  242.         
  243.         } while (!match);    /* Repeat synch until match found */
  244.  
  245.     difflen [left] = loffset;
  246.     difflen [right] = roffset;
  247.     while (loffset) {
  248.         backup (left); --loffset;
  249.         }            /* Back up over unmatched data */
  250.     while (roffset) {
  251.         backup (right); --roffset;
  252.         }
  253.     }
  254.  
  255. /*    Process differences    */
  256.  
  257. dodiff () {
  258.  
  259.     if (debug) fprintf (STD_ERR, "in dodiff\n");
  260.  
  261.     if (dispmode != DM_MATCH) printf ("%s     %d", header, lineno (0));
  262.     if (dispmode == DM_ALTER && difflen [0] != 0)
  263.         printf (", %d", lineno (0) + difflen [0] - 1);
  264.     if (dispmode != DM_MATCH) printf ("\n");
  265.  
  266.     for (hold = 0; hold < difflen [0]; ++hold) {
  267.         if (dispmode == DM_NORM)
  268.             printf ("%s", curline (0));
  269.         advance (0);
  270.         }
  271.  
  272.     if (dispmode == DM_NORM) printf ("%s%d\n", header, lineno (1));
  273.  
  274.     for (hold = 0; hold < difflen [1]; ++hold) {
  275.         if (dispmode != DM_MATCH)
  276.             printf ("%s", curline (1));
  277.         advance (1);
  278.         }
  279.  
  280.     }
  281.  
  282. /*    Test if a file is at EOF    */
  283.  
  284. int ateof (f)
  285.     int f;
  286.     {
  287.     prepbuf (f);
  288.     return (cur_line [f] -> line_text == EOF);
  289.     }
  290.  
  291. /*    Return the current line of a file    */
  292.  
  293. char * curline (f)
  294.     int f;
  295.     {
  296.     prepbuf (f);
  297.     return (cur_line [f] -> line_text);
  298.     }
  299.  
  300. /*    Return the current line number within file */
  301.  
  302. int lineno (f)
  303.     int f;
  304.     {
  305.     prepbuf (f);
  306.     return (cur_line [f] -> line_no);
  307.     }
  308.  
  309. /*    Test if the current lines of the two files match     */
  310.  
  311. int atmatch () {
  312.     char *s1, *s2;
  313.     if (debug) fprintf (STD_ERR, "in atmatch\n");
  314.  
  315.     prepbuf (0); prepbuf (1);
  316.     if (ateof (0) && ateof (1)) return (TRUE);
  317.     if (ateof (0) || ateof (1)) return (FALSE);
  318.  
  319.     s1 = curline (0); s2 = curline (1);
  320.     while (        *s1 == *s2
  321.        ||  (blanksf && isspace (*s1) && isspace (*s2))
  322.        ||  (single  && tolower (*s1) == tolower (*s2))) {
  323.         if (*s1 == 0) return (TRUE);
  324.         if (blanksf && isspace (*s1)) {
  325.             while (isspace (*++s1));
  326.             while (isspace (*++s2));
  327.             }
  328.         else {
  329.             ++s1; ++s2;
  330.             }
  331.         }
  332.     return (FALSE);
  333.     }
  334.  
  335. /*    Advance to the next line of a file     */
  336.  
  337. advance (f) 
  338.     int f;
  339.     {
  340.     cur_line [f] = cur_line [f] -> next;
  341.     prepbuf (f);
  342.     }
  343.  
  344. /*    Back up to the proevious line in a file */
  345.  
  346. backup (f)
  347.     int f;
  348.     {
  349.     if ((cur_line [f] = cur_line [f] -> prev) == NULL) {
  350.         fprintf (STD_ERR, "\nin backup: can't happen");
  351.         exit ();
  352.         }
  353.     }
  354.  
  355. /*    Discard all lines in memory up to the present point    */
  356.  
  357. discard (f)
  358.     int f;
  359.     {
  360.     while (first_line [f] != cur_line [f]) {
  361.         if (first_line [f] -> line_text != EOF)
  362.             free (first_line [f] -> line_text);
  363.         hold = first_line [f] -> next;
  364.         free (first_line [f]);
  365.         first_line [f] = hold;
  366.         }
  367.     if (first_line [f] == NULL) {
  368.         last_line [f] = NULL;
  369.         }
  370.     }
  371.  
  372. /*    Bring the current line to memory if it isn't there    */
  373.  
  374. prepbuf (f)
  375.     int f;
  376.     {
  377.     struct file_line * newl; char * txt;
  378.         char text [MAXLINE];
  379.     if (cur_line [f] != NULL) return;
  380.  
  381.     newl = alloc (sizeof (* newl));
  382.     if (!newl) goto punt;
  383.     if (!eofhit [f] && fgets (text, file [f])) {
  384.         txt = alloc (strlen (text) + 1);
  385.         if (!txt) goto punt;
  386.         movmem (text, txt, strlen (text) + 1);
  387.         newl -> line_text = txt;
  388.         }
  389.     else {
  390.         newl -> line_text = EOF;
  391.         eofhit [f] = TRUE;
  392.         }
  393.     newl -> line_no = ++ linenumb [f];
  394.  
  395.     if (last_line [f] != NULL) {
  396.         last_line [f] -> next = newl;
  397.         }
  398.     else {
  399.         first_line [f] = newl;
  400.         }
  401.  
  402.     newl -> prev = last_line [f];
  403.     newl -> next = NULL;
  404.     last_line [f] = cur_line [f] = newl;
  405.     return;
  406.  
  407. punt:    fprintf (STD_ERR, "Files have too many differences to compare.");
  408.     exit();
  409.     }
  410. ] -> line_text);
  411.         hold = first_line [f] -> next;
  412.         free (first_line [f]);
  413.         first_line [f] = hold;
  414.         }
  415.     if (first_line