home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 8 Other / 08-Other.zip / ETOOLS.ZIP / COMPARE.C next >
C/C++ Source or Header  |  1992-02-07  |  30KB  |  989 lines

  1. /*
  2.                                COMPARE.C
  3.              Copyright (C) Seven Valleys Software 1985,1988
  4.          Written for Seven Valleys Software by Cheyenne Wills &
  5.                     Released For Public Distribution
  6.                           All Rights Reserved
  7.  
  8.   Permission is granted to freely distribute this code, but not for
  9. profit, provided that this notice and the following disclaimer are
  10. included in their entirety and without modifications of any sort.  This
  11. work may not be sold, or modified and sold, or included in any other
  12. work to be sold, (except for a nominal media charge), without the
  13. written permission of the author.
  14.  
  15.   Permission is granted to modify the source code and distribute it in
  16. modified form PROVIDED that the authors of any modifications identify
  17. themselves with name and address following this header and that all such
  18. modifications are clearly indicated as to location and purpose, with
  19. descriptive comments that clearly indicate modified lines.
  20.  
  21.   The author would appreciate hearing of any modifications that may be
  22. made, but makes no guarantees that such modifications will be
  23. distributed with future releases of this program.
  24.  
  25. Author's address:
  26.  
  27.         Cheyenne C. Wills
  28.         12 West Locust St.
  29.         Mechanicsburg, Pa. 17055
  30.         (717) 697-5198
  31.  
  32.         Written for
  33.         Seven Valley's Software
  34.         P.O. Box 99
  35.         Glen Rock, Pa 17327
  36.  
  37. Disclaimer:
  38.  
  39.   No guarantees or warranties of any kind: This code is distributed
  40. "AS IS" without any warranty of any kind, either expressed or implied,
  41. including, but not limited to the implied warranties of merchantability
  42. and fitness for a particular purpose.  You are soley responsible for the
  43. selection of the program to achieve your intended results and for the
  44. results actually obtained.  Should the program prove defective, you (and
  45. not the author) assume the entire cost of all necessary servicing,
  46. repair, or correction.
  47.  
  48.   Neither the author nor anyone else who has been involved in the
  49. creation, production or delivery of this program shall be liable for any
  50. direct, indirect, consequential or incidental damages arising out of the
  51. use or inability to use this program.
  52.  
  53.                                History:
  54. Version    Date    Author                 Reason
  55. -------  --------  ------  ---------------------------------------------
  56.  2.0     08/01/84   CCW    Written for Seven Valleys Software
  57.  2.1     08/15/85   CCW    Added -i option and online doc
  58.  2.2     02/05/86   CCW    Added -t and -w options
  59.  2.3     01/21/88   CCW    OS/2 Support
  60.  2.4     11/21/88   CCW    Make more portable (ANSI)
  61.  2.5     11/19/91   JPW    cleaned up indents, added descriptive report
  62.  2.6     01/14/92   JPW    fixed an eof bug, misc more cleanup, drop 1st ff
  63. */
  64.  
  65. char *VERSION = "COMPARE V2.6\n";
  66. char *COPYR   = "Copyright (C) Seven Valleys Software 1985,1988\n";
  67.  
  68. /*
  69.  
  70. COMPARE <file1> <file2> [options]
  71.  
  72. Where:
  73.  
  74. <file1> and <file2> are the two files to be compared
  75.  
  76. [options] are:
  77.  
  78. -l [<listing>]  Generate output to file
  79.                 <listing> defaults to COMPARE.LST
  80. -w              Ignore white space between 'words'
  81. -t              Ignore case
  82. -p              Generate output to the printer
  83. -mn             Resync on n lines (default is 4)
  84. -cx,y           Only compare cols x thru y
  85.  
  86. ------------ following for update deck generation only ------------
  87. -u [<update deck>] Generate update deck to make file1 into file2
  88.                 <update deck> defaults to the <name of file1>."UPT"
  89. -sx,y           Generate internal sequence numbers starting with x
  90.                 and increment by y. Default if -s is omitted is 1,1
  91.                 if -s is specified with out x and y then x=10000
  92.                 y defaults to x
  93. -x              File1 already contains sequence numbers
  94. ------------ following for aide with editor shells only -----------
  95. -i              Use a sequence file (generated from UPDATE command)
  96.                 name is <name of file1>."SEQ"
  97.                 will be deleted
  98. */
  99.  
  100. #include <stdio.h>
  101. #include <stdlib.h>
  102. #include <math.h>
  103. #include <string.h>
  104. #include <ctype.h>
  105.  
  106. #define MAXLEN 256
  107.  
  108. int MINMATCH = 4;
  109.  
  110. struct line
  111. {
  112.     struct line *next;  /* Pointer to the next line */
  113.     long seqnum;    /* Current sequence number */
  114.     long len;       /* Length of the current line */
  115.     char *text;     /* Pointer to the current line */
  116. };
  117.  
  118. struct fanchor
  119. {
  120.     struct line *curr;  /* Pointer to the current line buffer */
  121.     struct line *head;  /* Pointer to the head of the list */
  122.     struct line *tail;  /* Pointer to the last line in storage */
  123.     long cline, hline, tline; /* Line numbers of Current, Head, & Tail */
  124.     char eof;           /* If EOF on this file then TRUE */
  125. };
  126.  
  127. struct
  128. {        /* Temp */
  129.     long len;
  130.     char text[512];
  131. } templine;
  132.  
  133. struct fanchor a,b;
  134.  
  135. FILE *outlist, *in0, *in1, *seqf;
  136. FILE *console;
  137. #define IOBUFSZ 4096
  138. char iobuf0[IOBUFSZ];
  139. char iobuf1[IOBUFSZ];
  140.  
  141. char updtname[64];              /* Update deck name */
  142. char seqname[64];               /* Name of sequence file */
  143. char *files[3];                 /* Pointers to the names of the files */
  144.  
  145. char Match, Eof, Different, Edit, Print, ToAFile, XSeqf, Iwhite, Icase;
  146.  
  147. long seqstrt = 1;       /* Sequencing start */
  148. long seqincr = 1;       /* Sequencing increment */
  149. long seqcur  = 0;       /* Current sequence number */
  150. long lastmseq = 0;      /* Last matched sequence number */
  151.  
  152. int colstart = 1;       /* Column starting position for compares */
  153. int colend = MAXLEN+1;  /* Column ending position for compares */
  154.  
  155. char Seqtype = 0;       /* Type of sequencing */
  156. #define GenSeq  0       /* Generate the sequence numbers (use 10000 10000) */
  157. #define FileSeq 1       /* Seq numbers are already in the file (first 9 pos) */
  158. #define UserSeq 2       /* Use sequence start and increment specified by user */
  159. #define SeqFile 3
  160.  
  161. #define LINESPERPAGE 58
  162. int curline = 52;   /* LINESPERPAGE+1; ---removed to prevent initial ff */
  163.                     /* this should give a few lines in addition to the  */
  164.                     /* tlib header before getting to the 'meat'         */
  165.  
  166. /*----------------------------------------------------------------------------*/
  167. /* {main: Main compare routine                                                */
  168. /*                                                                            */
  169. /*   Original Author: CCW                                                     */
  170. /*----------------------------------------------------------------------------*/
  171. main(argc,argv)
  172. int argc;
  173. char *argv[];
  174. {
  175.     char i, *cp;
  176.     int fi;
  177.  
  178.     console=stdout;
  179.  
  180.     /* Handle the quiet option */
  181.     if(strcmp(argv[argc-1],"-q")==0)
  182.     {
  183.         console=fopen("NUL","w");
  184.         argc--;
  185.     }
  186.     else
  187.     {
  188.         fputs(VERSION,stderr);   /* Put out our header for version */
  189.         fputs(COPYR,stderr);     /* Put out our header for version */
  190.         fflush(stderr);
  191.     }
  192.  
  193.     /* We need at least two files */
  194.     if(argc<3)
  195.     {   /* Tell about the error */
  196.         fputs("\nMissing filename(s).\n",stderr);
  197.         cmndformat();
  198.         exit(12);
  199.     }
  200.  
  201.  
  202.     fi=0;
  203.     if(*argv[1]!='-')  files[fi++]=argv[1];
  204.     if(*argv[2]!='-')  files[fi++]=argv[2];
  205.  
  206.     for(i=3;i<argc;i++)
  207.     {   /* process the command line options */
  208.         cp=argv[i];
  209.         if(*cp != '-')
  210.         {
  211.             fprintf(stderr,"\nInvalid argument %s",cp);
  212.             cmndformat();
  213.             exit(12);
  214.         }
  215.         cp++;
  216.         switch(tolower(*cp))
  217.         {
  218.             case 't':
  219.             Icase++;
  220.             break;
  221.             case 'w':
  222.             Iwhite++;
  223.             break;
  224.             case 'i':
  225.             Seqtype=SeqFile;
  226.             XSeqf++;
  227.             break;
  228.             case 'p':       /* handle going to the printer */
  229.             if(fi<3)
  230.                 files[fi++]="PRN:";
  231.             Print++;
  232.             break;
  233.             case 'l':       /* use an output file */
  234.             cp=argv[i+1];
  235.             if(i+1<argc && *cp !='-'&& fi<3)
  236.             {
  237.                 files[fi++]=cp;
  238.                 i++;
  239.             }
  240.             else
  241.                 if(i+1==argc || *cp=='-'&& fi<3)
  242.                     files[fi++]="COMPARE.LST";
  243.             break;
  244.         case 'u':
  245.             cp=argv[i+1];
  246.             if(i+1<argc && *cp != '-'&& fi<3)
  247.             {
  248.                 files[fi++]=cp;
  249.                 i++;
  250.             }
  251.             Edit++;
  252.             break;
  253.         case 's':
  254.             cp++;
  255.             Seqtype=UserSeq;
  256.             if(isdigit(*cp))
  257.             {  /* Handle a number */
  258.                 seqstrt = atol(cp);
  259.                 cp += strspn(cp,"0123456789");
  260.                 if(*cp==',')
  261.                 {
  262.                     cp++;
  263.                     seqincr = atol(cp);
  264.                 }
  265.                     else seqincr=seqstrt;
  266.             }
  267.             else
  268.                 seqstrt=seqincr=10000;
  269.             seqcur=seqstrt-seqincr;
  270.             break;
  271.         case 'x':
  272.             cp++;
  273.             Seqtype=FileSeq;
  274.             seqincr=10000;
  275.             break;
  276.         case 'c':
  277.             cp++;
  278.             if( isdigit(*cp) )
  279.             {  /* Handle a number */
  280.                 colstart = atoi(cp);
  281.                 cp += strspn(cp, "0123456789");
  282.                 if(*cp==',')
  283.                 {
  284.                     cp++;
  285.                     colend = atoi(cp);
  286.                 }
  287.             }
  288.             else
  289.             {
  290.                 fputs("\nMissing starting and ending column positions.\n",stderr);
  291.                 cmndformat();
  292.                 exit(12);
  293.             }
  294.             colend=colend-colstart+1;
  295.             break;
  296.         case 'm':
  297.             cp++;
  298.             if( isdigit(*cp) )
  299.             {  /* Handle a number */
  300.                 MINMATCH = atoi(cp);
  301.                 cp += strspn(cp, "0123456789");
  302.             }
  303.             else
  304.             {
  305.                 fputs("\nInvalid Match value.\n",stderr);
  306.                 cmndformat();
  307.                 exit(12);
  308.             }
  309.             break;
  310.             default:
  311.             break;
  312.         }    /* switch */
  313.     }    /* for loop process args */
  314.  
  315.     i=fi;
  316.     /* We need at least two files */
  317.     if(i<2)
  318.     {   /* Tell about the error */
  319.         fputs("\nMissing filename(s).\n",stderr);
  320.         cmndformat();
  321.         exit(12);
  322.     }
  323.     /* Now check the options specified */
  324.     if( Print && Edit )
  325.     {   /* Too many options specified */
  326.         fputs("\nConflicting options -u and -p\n",stderr);
  327.         cmndformat();
  328.         exit(12);
  329.     }
  330.     if( Print && i>3 )
  331.     {   /* Print and out file are conflicting */
  332.         fputs("\nConflicting options -p and output file\n",stderr);
  333.         cmndformat();
  334.         exit(12);
  335.     }
  336.  
  337.     if( (in0=fopen(files[0],"r"))==NULL)
  338.     {   /* Error getting to file1 */
  339.         fprintf(stderr,"\nUnable to open file1 [%s]\n",files[0]);
  340.         exit(12);
  341.     }
  342.     if( (in1=fopen(files[1],"r"))==NULL)
  343.     {   /* Error getting to file2 */
  344.         fprintf(stderr,"\nUnable to open file2 [%s]\n",files[1]);
  345.         exit(12);
  346.     }
  347.  
  348.     newext(updtname,files[0],"upt"); /* Generate the alt name now */
  349.     newext(seqname,files[0],"seq");  /* Generate the seq name now */
  350.  
  351.     if(i==2)
  352.     {
  353.         files[2]="CON";
  354.         ToAFile=1;   /* added to print header to con also */
  355.     }
  356.  
  357.  
  358.     if(i==3)
  359.         ToAFile=1;
  360.  
  361.     if(Edit&&i==2)
  362.     {
  363.         files[2]=updtname;
  364.         fprintf(console,"\nCreating update file [%s]\n",updtname);
  365.     }
  366.     if(Print)
  367.         files[2]="PRN";
  368.  
  369.     if( (outlist=fopen(files[2],"w"))==NULL)
  370.     {   /* Error opening file */
  371.         fprintf(stderr,"\nUnable to create output file [%s]\n",files[2]);
  372.         exit(12);
  373.     }
  374.  
  375.     if(XSeqf && (seqf=fopen(seqname,"rb"))==NULL)
  376.     {
  377.        /* Error opening file */
  378.        fprintf(stderr,"\nUnable to read sequence file [%s]\n",seqname);
  379.        exit(12);
  380.     }
  381.  
  382.     /* Beef up performance some */
  383.     setvbuf(in0,iobuf0,_IOFBF,IOBUFSZ);
  384.     setvbuf(in1,iobuf1,_IOFBF,IOBUFSZ);
  385.  
  386.     initialize();
  387.  
  388.     if(a.eof)
  389.         fprintf(stderr,"File [%s] is empty.\n",argv[1]);
  390.  
  391.     if(b.eof)
  392.         fprintf(stderr,"File [%s] is empty.\n",argv[2]);
  393.  
  394.     if(!Eof)
  395.     {
  396.         Different=0;
  397.         compf();
  398.         if(!Different) fputs("The two files are identical.\n",console);
  399.         }
  400.         fclose(in0);
  401.         fclose(in1);
  402.         if(XSeqf)
  403.         {
  404.             fclose(seqf);   /* Close the sequence file */
  405.             unlink(seqname); /* and get rid of it */
  406.         }
  407.         fflush(outlist);
  408.         fclose(outlist);
  409.  
  410.         if(Different)
  411.             exit(4);  /* Indicate that things are different */
  412.  
  413.         exit(0);
  414.     }
  415.  
  416. compf()
  417. {
  418.     Match=1;    /* I.E. Beginnings of files match */
  419.     for(;;)
  420.     {
  421.     if(Match)
  422.         fnoteq();
  423.     else
  424.     {
  425.             Different=1;
  426.             findeq();
  427.         }
  428.     if(Eof&&Match)
  429.         break;
  430.     }
  431. }
  432.  
  433. endfanchor(x)
  434. struct fanchor *x;
  435. {
  436.     return( (x->curr==NULL)&&x->eof );
  437. }
  438.  
  439. mark(x) /* Causes beginning of fanchor to be positioned before current */
  440.         /* fanchor curr.  buffers get reclaimed, line counters reset */
  441.         /* etc. */
  442. struct fanchor *x;
  443. {
  444.     struct line *p;
  445.  
  446.     if(x->head!=NULL)
  447.     {
  448.         while(x->head!=x->curr)
  449.         {   /* Reclaim buffers */
  450.             p=x->head->next;
  451.             free(x->head->text);
  452.             free(x->head);
  453.             x->head=p;
  454.         }
  455.         x->hline=x->cline;
  456.         if(x->curr==NULL)
  457.         {
  458.             x->tail=NULL;
  459.             x->tline=x->cline;
  460.         }
  461.     }
  462. }
  463.  
  464. movecurr(x,filex) /* Filex is the input file associated with fanchor x */
  465. struct fanchor *x;   /* The curr for x is moved forward one line, reading */
  466. FILE *filex;        /* X if necessary, and incrementing the line count. */
  467. {                   /* eof is set of eof is encountered on either fanchor */
  468.     if(x->curr)
  469.     {
  470.         if(x->curr==x->tail)
  471.             readline(x,filex);
  472.         x->curr=x->curr->next;
  473.         if(x->curr==NULL)
  474.             Eof=1;
  475.         x->cline++;
  476.     }
  477.     else
  478.         if(!x->eof)
  479.         {
  480.             readline(x,filex);
  481.             x->curr=x->head;
  482.             x->cline=x->hline;
  483.         }
  484.         else
  485.             Eof=1;
  486. }
  487.  
  488. readline(x,filex)
  489. struct fanchor *x;
  490. FILE *filex;
  491. {
  492.     struct line *newline;
  493.     char *c;
  494.     long int l;
  495.     int i;
  496.     if(!x->eof)
  497.     {
  498.         if( fgets(templine.text,MAXLEN,filex) )
  499.         {
  500.             i = strlen(templine.text);      /* Ensure that there is */
  501.             if(templine.text[i] != '\n')
  502.             {  /* a newline at the end */
  503.                 templine.text[i+1] = '\n';
  504.                 templine.text[i+2] = '\0';
  505.             }
  506.             c=templine.text;    /* Point to the start of the text */
  507.             if(Edit && filex==in0)
  508.             {
  509.                 switch(Seqtype)
  510.                 {   /* Generate the sequence number */
  511.                 case GenSeq:    /* We are to generate the sequence */
  512.  
  513.                 case UserSeq:
  514.                     seqcur+=seqincr;   /* Increment */
  515.                     break;
  516.  
  517.                 case FileSeq:   /* The first item in the file is a number */
  518.                     l=seqcur;
  519.                     seqcur = atol(templine.text);
  520.                     c += strspn(templine.text,"0123456789");
  521.                     if(seqcur!=0)
  522.                         seqincr=seqcur-l;
  523.                     if(*c!='\n')
  524.                         ++c; /* Handle a null line */
  525.                     break;
  526.  
  527.                 case SeqFile:
  528.                     l=seqcur;
  529.                     fread(&seqcur,sizeof(seqcur),1,seqf);
  530.                     if( feof(seqf) || ferror(seqf) )
  531.                     {
  532.                         fprintf(stderr,"\nPremature EOF on sequence file [%s]\n",seqname);
  533.                         exit(12);
  534.                     }
  535.                     if(seqcur!=0) seqincr=seqcur-l;
  536.  
  537.                 default:
  538.                     break;
  539.                 }
  540.             }
  541.             templine.len=strlen(c)+1; /* Get the len of the line */
  542.  
  543.             newline=(struct line *)malloc(sizeof(struct line));
  544.             if(newline==NULL)
  545.             { /* Out of memory */
  546.                 fputs("\nInsuffecient Memory\n",stderr);
  547.                 exit(12);
  548.             }
  549.  
  550.             newline->text=malloc((short)templine.len);
  551.  
  552.             if(newline->text==NULL)
  553.             { /* Out of memory */
  554.                 fputs("\nInsuffecient Memory\n",stderr);
  555.                 exit(12);
  556.             }
  557.             strcpy(newline->text,c);
  558.             newline->seqnum=seqcur;    /* Get the current sequence number */
  559.             newline->len=templine.len;
  560.             newline->next=NULL;
  561.             if(x->tail==NULL)
  562.             {
  563.                 x->head=newline;
  564.                 x->tline=1;
  565.                 x->hline=1;
  566.             }
  567.             else
  568.             {
  569.                 x->tail->next=newline;
  570.                 x->tline++;
  571.             }
  572.             x->tail=newline;
  573.         }
  574.         x->eof = feof(filex);
  575.     }
  576. }
  577.  
  578. backtrack(x, xlines)/* Causes the current position of fanchor X to become */
  579. struct fanchor *x;  /* that of the last mark operation.  I.E. the current */
  580. int *xlines;        /* line when the fanchor was marked last becomes the */
  581. {                   /* the new curr. XLINES is set to the number of lines */
  582.                     /* from the new curr to the old curr inclusive */
  583.     *xlines=x->cline+1-x->hline;
  584.     x->curr=x->head;
  585.     x->cline=x->hline;
  586.     Eof=endfanchor(&a) || endfanchor(&b);
  587. }
  588. compl() /* Compare the current lines of fanchors a and b */
  589.         /* returning match to signal their (non-) equivalence */
  590.         /* EOF on both files is considered a match, but eof on */
  591.         /* only one is a mismatch */
  592. {
  593.     int cea,ceb;    /* Ending columns for file a and file b */
  594.     int i;
  595.     char *ca,*cb;
  596.  
  597.     if(a.curr==NULL || b.curr==NULL)
  598.         Match=(endfanchor(&a) && endfanchor(&b));
  599.     else
  600.     {
  601.         if(Iwhite)
  602.         {
  603.             Match = compx(a.curr,b.curr);
  604.             return 0;    /* added 0 to prevent warning */
  605.         }
  606.         cea = min(a.curr->len,colend);
  607.         ceb = min(b.curr->len,colend);
  608.         Match=(cea==ceb);   /* Equal lens */
  609.         if(Match)
  610.         { /* The lengths match.. so lets see if we can compare them */
  611.             if(cea<=colstart)
  612.                Match=0;
  613.             else
  614.             {
  615.                 ca=a.curr->text;
  616.                 cb=b.curr->text;
  617.                 ca+=colstart-1;
  618.                 cb+=colstart-1;
  619.                 for(i=colstart;i<cea;i++)
  620.                 {
  621.                     if(Icase)
  622.                     {
  623.                         if(!(Match=( tolower(*ca++)==tolower(*cb++))))
  624.                         break;
  625.                     }
  626.                     else
  627.                         if(!(Match=(*ca++==*cb++)))
  628.                             break;
  629.                 }
  630.             }
  631.         }
  632.     }
  633. }
  634.  
  635. int compx(l1,l2)
  636. struct line *l1, *l2;
  637. {
  638.     char sbuf1[MAXLEN+1], sbuf2[MAXLEN+1];
  639.     register char *c;
  640.     register int i;
  641.  
  642.     for(i=0, c = l1->text; *c; c++)
  643.         if( !isspace(*c) )
  644.             sbuf1[i++] = (Icase) ? tolower(*c) : *c ;
  645.     sbuf1[i] = '\0';
  646.  
  647.     for(i=0, c = l2->text; *c; c++)
  648.         if( !isspace(*c) ) sbuf2[i++] = (Icase) ? tolower(*c) : *c ;
  649.     sbuf2[i] = '\0';
  650.  
  651.     if(strcmp(sbuf1,sbuf2) == 0)
  652.         return 1;
  653.  
  654.     return 0;
  655. }
  656.  
  657. fnoteq() /* Find a mismatch */
  658. {
  659.     for(;;)
  660.     {
  661.         movecurr(&a,in0);
  662.         movecurr(&b,in1);
  663.         mark(&a);
  664.         mark(&b);
  665.     compl();
  666.  
  667.         if(Match && a.curr != NULL)
  668.         lastmseq=a.curr->seqnum;  /* Remember the sequence number */
  669.  
  670.     if(Eof || !Match)
  671.         break;
  672.     }
  673. }
  674.  
  675. findeq()
  676. {
  677.     char advanceb;
  678.     advanceb=1;
  679.     for(;;)
  680.     {
  681.         advanceb = Eof ? endfanchor(&a):!advanceb;
  682.  
  683.         if(advanceb)
  684.             search(&a,in0,&b,in1);
  685.         else
  686.             search(&b,in1,&a,in0);
  687.  
  688.         if(Match)
  689.             break;
  690.     }
  691.     report();
  692. }
  693. search(x,filex,y,filey) /* Look ahead one line on fanchor y and search */
  694. struct fanchor *x;       /* for that line backtracking on fanchor x */
  695. FILE *filex;
  696. struct fanchor *y;
  697. FILE *filey;
  698. {
  699.     int count;  /* Number of lines backtraced on x */
  700.  
  701.     movecurr(y,filey);
  702.     backtrack(x,&count);
  703.     checkfullmatch(x,filex,y,filey);
  704.     count--;
  705.     while( count!=0 && !Match )
  706.     {
  707.         movecurr(x,filex);
  708.         count--;
  709.         checkfullmatch(x,filex,y,filey);
  710.     }
  711. }
  712. checkfullmatch(      /* From the current positions of x and y, which may */
  713.     x,filex,y,filey) /* match makesure that the next MINMATCH-1 lines */
  714. struct fanchor *x;   /* also match or set match = false */
  715. struct fanchor *y;
  716. FILE *filex;
  717. FILE *filey;
  718. {
  719.     int n;
  720.     struct line *savexcur, *saveycur;
  721.     int savexline, saveyline;
  722.  
  723.     savexcur=x->curr;
  724.     saveycur=y->curr;
  725.     savexline=x->cline;
  726.     saveyline=y->cline;
  727.     compl();
  728.     for(n=MINMATCH-1; Match && n!=0;n--)
  729.     {
  730.         movecurr(x,filex);
  731.         movecurr(y,filey);
  732.         compl();
  733.     }
  734.     x->curr=savexcur;
  735.     x->cline=savexline;
  736.     y->curr=saveycur;
  737.     y->cline=saveyline;
  738. }
  739.  
  740. report()
  741. {
  742. #define REPLACE 0
  743. #define DELETE 1
  744. #define INSERT 2
  745. #define INSERTOF 3
  746.  
  747.     int STATE;
  748.     int lineno;
  749.     struct line *p;
  750.     struct line *alast; /* Pointer to the last unmatched lines in file a */
  751.     struct line *blast; /* and file b */
  752.     long seq1;
  753.     long seq2;
  754.     long seq3;
  755.     long seq4;
  756.  
  757.     /* The following conditions are: */
  758.     /* a.head = first mismatched line in file 1 */
  759.     /* a.curr = first matched line in file 1 */
  760.     /* b.head = first mismatched line in file 2 */
  761.     /* b.curr = first matched line in file 2 */
  762.     alast=blast=NULL;
  763.     for(p=a.head;p!=a.curr && p!=NULL; p=p->next)
  764.         alast=p;
  765.  
  766.     for(p=b.head;p!=b.curr && p!=NULL; p=p->next)
  767.         blast=p;
  768.  
  769.     STATE=REPLACE;
  770.  
  771.     if(alast==NULL)
  772.         STATE=INSERT;
  773.     else
  774.         if(blast==NULL)
  775.             STATE=DELETE;
  776.  
  777.     if(STATE==INSERT && a.curr==NULL)
  778.         STATE=INSERTOF;
  779.  
  780.     if(!Edit)
  781.     {
  782.         switch(STATE)
  783.         {
  784.             case REPLACE:
  785.                 pagechk();
  786.                 fprintf(outlist,"\nMismatch: file A, lines %ld to %ld not equal to file B, lines %ld to %ld",a.hline,a.cline - 1,b.hline,b.cline - 1);
  787.                 break;
  788.  
  789.             case INSERTOF:
  790.                 pagechk();
  791.                 fprintf(outlist,"\nMismatch: extra text on file B");
  792.                 break;
  793.  
  794.             case INSERT:
  795.                 pagechk();
  796.                 fprintf(outlist,"\nMismatch: inserted text before line %ld in file A",a.hline);
  797.                 break;
  798.  
  799.             case DELETE:
  800.                 pagechk();
  801.                 fprintf(outlist,"\nMismatch: lines %ld to %ld deleted from file A",a.hline,a.cline - 1,b.hline,b.cline - 1);
  802.                 break;
  803.  
  804.             default:
  805.                 break;
  806.         }
  807.  
  808.         pagechk();
  809.         fputc('\n',outlist);
  810.         if(a.head!=a.curr)
  811.         for(lineno=a.hline,p=a.head;p!=NULL && p!=a.curr;lineno++,p=p->next)
  812.         {
  813.             pagechk();
  814.             fprintf(outlist," A %4d> %s",lineno,p->text);
  815.             }
  816.         if(b.head!=b.curr)
  817.             for(lineno=b.hline,p=b.head;p!=NULL && p!=b.curr;lineno++,p=p->next)
  818.             {
  819.                 pagechk();
  820.                 fprintf(outlist," B %4d> %s",lineno,p->text);
  821.             }
  822.     }
  823.     else    /* Edit true */
  824.     {  /* Handle an Update deck */
  825.  
  826.         switch(STATE)
  827.         {
  828.             case REPLACE:
  829.                 seq1=a.head->seqnum; /* Get the first sequence number */
  830.  
  831.                 fprintf(outlist,"./ R %ld",seq1);
  832.  
  833.                 if(a.head!=alast)
  834.                 {
  835.                     seq2=alast->seqnum;
  836.                     fprintf(outlist," %ld",seq2);
  837.                 }
  838.                 else
  839.                     seq2=seq1;
  840.                 if(Seqtype!=GenSeq)
  841.                 {
  842.                     seq4=b.cline-b.hline;  /* Get the number of lines inserted */
  843.                     seq2=(a.curr!=NULL)?a.curr->seqnum:seq1+(seq4*seqincr);
  844.                     seq4=(seq2-seq1)/(seq4+1L);
  845.                     seq3=seq1+seq4;
  846.                     fprintf(outlist," $ %ld %ld",seq3,seq4);
  847.                 }
  848.                 fputc('\n',outlist);
  849.                 for(p=b.head;p!=NULL && p!=b.curr;p=p->next)
  850.                 fprintf(outlist,"%s",p->text);
  851.                 break;
  852.  
  853.             case INSERTOF:
  854.                 seq1=a.curr->seqnum; /* Get the first sequence number */
  855.                 fprintf(outlist,"./ R %ld",seq1);
  856.                 seq2=seq1;
  857.                 if(Seqtype!=GenSeq)
  858.                 {
  859.                     seq4=b.cline-b.hline+1;  /* Get the number of lines inserted */
  860.                     p=a.curr->next;
  861.                     seq2=(p!=NULL)?p->seqnum:seq1+(seq4*seqincr);
  862.                     seq4=(p!=NULL)?(seq2-seq1)/(seq4+1L):seqincr;
  863.                     seq3=seq1+seq4;
  864.                     fprintf(outlist," $ %ld %ld",seq3,seq4);
  865.                 }
  866.                 fputc('\n',outlist);
  867.                 for(p=b.head;(p!=NULL && p!=b.curr);p=p->next)
  868.                     fprintf(outlist,"%s",p->text);
  869.                 if(p==b.curr)
  870.                     fprintf(outlist,"%s",p->text);
  871.                 break;
  872.  
  873.             case INSERT:
  874.                 fprintf(outlist,"./ I %ld",lastmseq);
  875.                 if(Seqtype!=GenSeq)
  876.                 {
  877.                     seq1=b.cline-b.hline; /* Number of lines inserted */
  878.                     p=a.curr->next;
  879.                     seq2=(p!=NULL)?a.curr->seqnum:seqincr;
  880.                     seq2=(p!=NULL)?(seq2-lastmseq)/(seq1+1L):seqincr;
  881.  
  882.                     seq1=lastmseq+seq2;
  883.                     fprintf(outlist," $ %ld %ld",seq1,seq2);
  884.                 }
  885.                 fputc('\n',outlist);
  886.                 for(p=b.head;(p!=NULL && p!=b.curr);p=p->next)
  887.                 fprintf(outlist,"%s",p->text);
  888.                 break;
  889.  
  890.             case DELETE:
  891.                 fprintf(outlist,"./ D %ld",a.head->seqnum);
  892.                 if(alast!=NULL)
  893.                     fprintf(outlist," %ld",alast->seqnum);
  894.                 fputc('\n',outlist);
  895.                 break;
  896.  
  897.             default:
  898.                 break;
  899.         }
  900.     }
  901. }
  902.  
  903. initialize()
  904. {
  905.     initfanchor(&a,in0);
  906.     initfanchor(&b,in1);
  907.     Eof=a.eof || b.eof;
  908.     templine.len=MAXLEN;
  909.     templine.text[0]='\0';
  910.  
  911.     fputc('\n',outlist);
  912.     fputs(VERSION,outlist);
  913.     fprintf(outlist,"\n Comparing File A:<%s> with File B:<%s>\n\n",files[0],files[1]);
  914.  
  915. }
  916.  
  917. initfanchor(x,filex)
  918. struct fanchor *x;
  919. FILE *filex;
  920. {
  921.     x->curr=NULL;
  922.     x->head=NULL;
  923.     x->tail=NULL;
  924.     x->cline=0;
  925.     x->hline=0;
  926.     x->tline=0;
  927.     x->eof=feof(filex);
  928. }
  929.  
  930. cmndformat()
  931. {
  932.     fputs("Command format:\n",console);
  933.     fputs("COMPARE <file1> <file2> [options]\n",console);
  934.     fputs("Where:\n",console);
  935.     fputs(" <file1> and <file2> are the two files to be compared\n",console);
  936.     fputs(" [options] are:\n",console);
  937.     fputs(" -l [<listing>]  Generate output to file\n",console);
  938.     fputs("                 <listing> defaults to COMPARE.LST\n",console);
  939.     fputs(" -t              Ignore case\n",console);
  940.     fputs(" -w              Ignore white space between 'words' in a line\n",console);
  941.     fputs(" -p              Generate output to the printer\n",console);
  942.     fputs(" -mn             Resync on n lines (default is 4)\n",console);
  943.     fputs(" -cx,y           Only compare cols x thru y\n",console);
  944.     fputs(" ------------ following for update deck generation only ------------\n",console);
  945.     fputs(" -u [<update deck>] Generate update deck to make file1 into file2\n",console);
  946.     fputs("                 <update deck> defaults to the <name of file1>.\"UPT\"\n",console);
  947.     fputs(" -sx,y           Generate internal sequence numbers starting with x\n",console);
  948.     fputs("                 and increment by y. Default if -s is omitted is 1,1\n",console);
  949.     fputs("                 if -s is specified with out x and y then x=10000\n",console);
  950.     fputs("                 y defaults to x\n",console);
  951.     fputs(" -x              File1 already contains sequence numbers\n",console);
  952.     fputs("------------ following for aide with editor shells only -----------\n",console);
  953.     fputs(" -i              Use a sequence file (generated from UPDATE command)\n",console);
  954.     fputs("                 name is <name of file1>.\"SEQ\"\n",console);
  955.     fputs("                 will be deleted\n",console);
  956. }
  957.  
  958. pagechk() /* Check to see if we are to do a page eject if we are printing */
  959. {
  960.     if(ToAFile||Print)
  961.     {
  962.         if(curline++ < LINESPERPAGE)
  963.             return 0;       /* added 0 to prevent warning */
  964.         fputc('\n',outlist);
  965.         fputc('\f',outlist);
  966.         fputs(VERSION,outlist);
  967.         fprintf(outlist,"\n Comparing File A:<%s> with File B:<%s>\n\n",files[0],files[1]);
  968.         curline=5;
  969.     }
  970. }
  971.  
  972. newext(fbuff,filename,newext)
  973. char *fbuff;
  974. char *filename;
  975. char *newext;
  976. {
  977.    register char *in, *out;
  978.    in = filename;
  979.    out = fbuff;
  980.    while ( *in && *in != '.' )
  981.        *out++ = *in++;
  982.    *out++ = '.';
  983.    in = newext;
  984.    while ( *in )
  985.        *out++ = *in++;
  986.    return 0;  /* added 0 to prevent warning */
  987. }
  988.  
  989.