home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / COMPUPD.ZIP / COMPARE.C next >
C/C++ Source or Header  |  1988-11-21  |  23KB  |  808 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. */
  62.  
  63. char *VERSION = "COMPARE V2.4\n";
  64. char *COPYR   = "Copyright (C) Seven Valleys Software 1985,1988\n";
  65.  
  66. /*
  67.  
  68. COMPARE <file1> <file2> [options]
  69.  
  70. Where:
  71.  
  72. <file1> and <file2> are the two files to be compared
  73.  
  74. [options] are:
  75.  
  76. -l [<listing>]    Generate output to file
  77.         <listing> defaults to COMPARE.LST
  78. -w        Ignore white space between 'words'
  79. -t        Ignore case
  80. -p        Generate output to the printer
  81. -mn        Resync on n lines (default is 2)
  82. -cx,y        Only compare cols x thru y
  83.  
  84. ------------ following for update deck generation only ------------
  85. -u [<update deck>] Generate update deck to make file1 into file2
  86.         <update deck> defaults to the <name of file1>."UPT"
  87. -sx,y        Generate internal sequence numbers starting with x
  88.         and increment by y. Default if -s is omitted is 1,1
  89.         if -s is specified with out x and y then x=10000
  90.         y defaults to x
  91. -x        File1 already contains sequence numbers
  92. ------------ following for aide with editor shells only -----------
  93. -i        Use a sequence file (generated from UPDATE command)
  94.         name is <name of file1>."SEQ"
  95.         will be deleted
  96. */
  97.  
  98. #include <stdio.h>
  99. #include <stdlib.h>
  100. #include <math.h>
  101. #include <string.h>
  102. #include <ctype.h>
  103.  
  104. #define MAXLEN 256
  105.  
  106. int MINMATCH = 2;
  107.  
  108. struct line {
  109.     struct line *next;    /* Pointer to the next line */
  110.     long seqnum;    /* Current sequence number */
  111.     long len;        /* Length of the current line */
  112.     char *text;     /* Pointer to the current line */
  113. };
  114.  
  115. struct fanchor {
  116.     struct line *curr;    /* Pointer to the current line buffer */
  117.     struct line *head;    /* Pointer to the head of the list */
  118.     struct line *tail;    /* Pointer to the last line in storage */
  119.     long cline, hline, tline; /* Line numbers of Current, Head, & Tail */
  120.     char eof;        /* If EOF on this file then TRUE */
  121.     };
  122.  
  123. struct {        /* Temp */
  124.     long len;
  125.     char text[512];
  126.     } templine;
  127.  
  128. struct fanchor a,b;
  129.  
  130. FILE *outlist, *in0, *in1, *seqf;
  131. FILE *console;
  132. #define IOBUFSZ 4096
  133. char iobuf0[IOBUFSZ];
  134. char iobuf1[IOBUFSZ];
  135.  
  136. char updtname[64];        /* Update deck name */
  137. char seqname[64];        /* Name of sequence file */
  138. char *files[3];         /* Pointers to the names of the files */
  139.  
  140. char Match, Eof, Different, Edit, Print, ToAFile, XSeqf, Iwhite, Icase;
  141.  
  142. long seqstrt = 1;    /* Sequencing start */
  143. long seqincr = 1;    /* Sequencing increment */
  144. long seqcur  = 0;    /* Current sequence number */
  145. long lastmseq = 0;    /* Last matched sequence number */
  146.  
  147. int colstart = 1;    /* Column starting position for compares */
  148. int colend = MAXLEN+1;    /* Column ending position for compares */
  149.  
  150. char Seqtype = 0;    /* Type of sequencing */
  151. #define GenSeq    0    /* Generate the sequence numbers (use 10000 10000) */
  152. #define FileSeq 1    /* Seq numbers are already in the file (first 9 pos) */
  153. #define UserSeq 2    /* Use sequence start and increment specified by user */
  154. #define SeqFile 3
  155.  
  156. #define LINESPERPAGE 60
  157. int curline = LINESPERPAGE+1;
  158.  
  159. main(argc,argv)
  160. int argc;
  161. char *argv[];
  162. {
  163.     char i, *cp;
  164.     int fi;
  165.  
  166.     console=stdout;
  167.  
  168.     /* Handle the quiet option */
  169.     if(strcmp(argv[argc-1],"-q")==0) {
  170.     console=fopen("NUL","w");
  171.     argc--;
  172.     }
  173.     else {
  174.     fputs(VERSION,stderr);     /* Put out our header for version */
  175.     fputs(COPYR,stderr);     /* Put out our header for version */
  176.     fflush(stderr);
  177.     }
  178.     /* We need at least two files */
  179.     if(argc<3) {   /* Tell about the error */
  180.     fputs("\nMissing filename(s).\n",stderr);
  181.     cmndformat();
  182.     exit(12);
  183.     }
  184.  
  185.  
  186.     fi=0;
  187.     if(*argv[1]!='-')  files[fi++]=argv[1];
  188.     if(*argv[2]!='-')  files[fi++]=argv[2];
  189.  
  190.     for(i=3;i<argc;i++) {   /* process the command line options */
  191.     cp=argv[i];
  192.     if(*cp != '-') {
  193.         fprintf(stderr,"\nInvalid argument %s",cp);
  194.         cmndformat();
  195.         exit(12);
  196.     }
  197.     cp++;
  198.     switch(tolower(*cp)) {
  199.         case 't':
  200.            Icase++;
  201.            break;
  202.         case 'w':
  203.            Iwhite++;
  204.            break;
  205.         case 'i':
  206.            Seqtype=SeqFile;
  207.            XSeqf++;
  208.            break;
  209.         case 'p':       /* handle going to the printer */
  210.         if(fi<3) files[fi++]="PRN:";
  211.         Print++;
  212.         break;
  213.         case 'l':       /* use an output file */
  214.         cp=argv[i+1];
  215.         if(i+1<argc && *cp !='-'&& fi<3) {
  216.             files[fi++]=cp;
  217.             i++;
  218.         }
  219.         else
  220.             if(i+1==argc || *cp=='-'&& fi<3)
  221.             files[fi++]="COMPARE.LST";
  222.         break;
  223.         case 'u':
  224.         cp=argv[i+1];
  225.         if(i+1<argc && *cp != '-'&& fi<3) {
  226.             files[fi++]=cp;
  227.             i++;
  228.         }
  229.         Edit++;
  230.         break;
  231.         case 's':
  232.         cp++;
  233.         Seqtype=UserSeq;
  234.         if(isdigit(*cp)) {  /* Handle a number */
  235.             seqstrt = atol(cp);
  236.             cp += strspn(cp,"0123456789");
  237.             if(*cp==',') {
  238.             cp++;
  239.             seqincr = atol(cp);
  240.             }
  241.             else seqincr=seqstrt;
  242.         }
  243.         else seqstrt=seqincr=10000;
  244.         seqcur=seqstrt-seqincr;
  245.         break;
  246.         case 'x':
  247.         cp++;
  248.         Seqtype=FileSeq;
  249.         seqincr=10000;
  250.         break;
  251.         case 'c':
  252.         cp++;
  253.         if( isdigit(*cp) ) {  /* Handle a number */
  254.             colstart = atoi(cp);
  255.             cp += strspn(cp, "0123456789");
  256.             if(*cp==',') {
  257.             cp++;
  258.             colend = atoi(cp);
  259.             }
  260.         }
  261.         else {
  262.             fputs("\nMissing starting and ending column positions.\n",stderr);
  263.             cmndformat();
  264.             exit(12);
  265.         }
  266.         colend=colend-colstart+1;
  267.         break;
  268.         case 'm':
  269.         cp++;
  270.         if( isdigit(*cp) ) {  /* Handle a number */
  271.             MINMATCH = atoi(cp);
  272.             cp += strspn(cp, "0123456789");
  273.         }
  274.         else {
  275.             fputs("\nInvalid Match value.\n",stderr);
  276.             cmndformat();
  277.             exit(12);
  278.         }
  279.         break;
  280.         default:
  281.         break;
  282.     }
  283.     }
  284.  
  285.     i=fi;
  286.     /* We need at least two files */
  287.     if(i<2) {    /* Tell about the error */
  288.     fputs("\nMissing filename(s).\n",stderr);
  289.     cmndformat();
  290.     exit(12);
  291.     }
  292.     /* Now check the options specified */
  293.     if( Print && Edit ) {   /* Too many options specified */
  294.     fputs("\nConflicting options -u and -p\n",stderr);
  295.     cmndformat();
  296.     exit(12);
  297.     }
  298.     if( Print && i>3 ) {   /* Print and out file are conflicting */
  299.     fputs("\nConflicting options -p and output file\n",stderr);
  300.     cmndformat();
  301.     exit(12);
  302.     }
  303.  
  304.     if( (in0=fopen(files[0],"r"))==NULL) {   /* Error getting to file1 */
  305.     fprintf(stderr,"\nUnable to open file1 [%s]\n",files[0]);
  306.     exit(12);
  307.     }
  308.     if( (in1=fopen(files[1],"r"))==NULL) {   /* Error getting to file2 */
  309.     fprintf(stderr,"\nUnable to open file2 [%s]\n",files[1]);
  310.     exit(12);
  311.     }
  312.  
  313.     newext(updtname,files[0],"upt"); /* Generate the alt name now */
  314.     newext(seqname,files[0],"seq");  /* Generate the seq name now */
  315.  
  316.     if(i==2) files[2]="CON";
  317.     if(i==3) ToAFile=1;
  318.     if(Edit&&i==2) {
  319.     files[2]=updtname;
  320.     fprintf(console,"\nCreating update file [%s]\n",updtname);
  321.     }
  322.     if(Print) files[2]="PRN";
  323.  
  324.     if( (outlist=fopen(files[2],"w"))==NULL) {   /* Error opening file */
  325.     fprintf(stderr,"\nUnable to create output file [%s]\n",files[2]);
  326.     exit(12);
  327.     }
  328.     if(XSeqf && (seqf=fopen(seqname,"rb"))==NULL) {
  329.        /* Error opening file */
  330.        fprintf(stderr,"\nUnable to read sequence file [%s]\n",seqname);
  331.        exit(12);
  332.     }
  333.     /* Beef up performance some */
  334.  
  335.     setvbuf(in0,iobuf0,_IOFBF,IOBUFSZ);
  336.     setvbuf(in1,iobuf1,_IOFBF,IOBUFSZ);
  337.  
  338.     initialize();
  339.  
  340.     if(a.eof) fprintf(stderr,"File [%s] is empty.\n",argv[1]);
  341.     if(b.eof) fprintf(stderr,"File [%s] is empty.\n",argv[2]);
  342.     if(!Eof) {
  343.     Different=0;
  344.     compf();
  345.     if(!Different) fputs("The two files are identical.\n",console);
  346.     }
  347.     fclose(in0);
  348.     fclose(in1);
  349.     if(XSeqf) {
  350.        fclose(seqf);   /* Close the sequence file */
  351.        unlink(seqname); /* and get rid of it */
  352.    }
  353.     fflush(outlist);
  354.     fclose(outlist);
  355.     if(Different) exit(4);  /* Indicate that things are different */
  356.     exit(0);
  357. }
  358. compf()
  359. {
  360.     Match=1;    /* I.E. Beginnings of files match */
  361.     for(;;) {
  362.     if(Match) fnoteq();
  363.     else {
  364.         Different=1;
  365.         findeq();
  366.     }
  367.     if(Eof&&Match) break;
  368.     }
  369. }
  370. endfanchor(x)
  371. struct fanchor *x;
  372. {
  373.     return( (x->curr==NULL)&&x->eof );
  374. }
  375. mark(x) /* Causes beginning of fanchor to be positioned before current */
  376.     /* fanchor curr.  buffers get reclaimed, line counters reset */
  377.     /* etc. */
  378. struct fanchor *x;
  379. {
  380.     struct line *p;
  381.  
  382.     if(x->head!=NULL) {
  383.     while(x->head!=x->curr) {   /* Reclaim buffers */
  384.         p=x->head->next;
  385.         free(x->head->text);
  386.         free(x->head);
  387.         x->head=p;
  388.     }
  389.     x->hline=x->cline;
  390.     if(x->curr==NULL) {
  391.         x->tail=NULL;
  392.         x->tline=x->cline;
  393.     }
  394.     }
  395. }
  396. movecurr(x,filex) /* Filex is the input file associated with fanchor x */
  397. struct fanchor *x;   /* The curr for x is moved forward one line, reading */
  398. FILE *filex;        /* X if necessary, and incrementing the line count. */
  399. {            /* eof is set of eof is encountered on either fanchor */
  400.     if(x->curr) {
  401.     if(x->curr==x->tail) readline(x,filex);
  402.     x->curr=x->curr->next;
  403.     if(x->curr==NULL) Eof=1;
  404.     x->cline++;
  405.     }
  406.     else if(!x->eof) {
  407.     readline(x,filex);
  408.     x->curr=x->head;
  409.     x->cline=x->hline;
  410.     }
  411.     else Eof=1;
  412. }
  413. readline(x,filex)
  414. struct fanchor *x;
  415. FILE *filex;
  416. {
  417.     struct line *newline;
  418.     char *c;
  419.     long int l;
  420.     int i;
  421.     if(!x->eof) {
  422.     if( fgets(templine.text,MAXLEN,filex) ) {
  423.         i = strlen(templine.text);        /* Ensure that there is */
  424.         if(templine.text[i] != '\n') {  /* a newline at the end */
  425.          templine.text[i+1] = '\n';
  426.          templine.text[i+2] = '\0';
  427.         }
  428.         c=templine.text;    /* Point to the start of the text */
  429.         if(Edit && filex==in0) {
  430.         switch(Seqtype) {   /* Generate the sequence number */
  431.             case GenSeq:    /* We are to generate the sequence */
  432.             case UserSeq:
  433.             seqcur+=seqincr;   /* Increment */
  434.             break;
  435.             case FileSeq:   /* The first item in the file is a number */
  436.             l=seqcur;
  437.             seqcur = atol(templine.text);
  438.             c += strspn(templine.text,"0123456789");
  439.             if(seqcur!=0) seqincr=seqcur-l;
  440.             if(*c!='\n') ++c; /* Handle a null line */
  441.             break;
  442.             case SeqFile:
  443.             l=seqcur;
  444.             fread(&seqcur,sizeof(seqcur),1,seqf);
  445.             if( feof(seqf) || ferror(seqf) ) {
  446.                fprintf(stderr,"\nPremature EOF on sequence file [%s]\n",seqname);
  447.                exit(12);
  448.             }
  449.             if(seqcur!=0) seqincr=seqcur-l;
  450.             default: break;
  451.         }
  452.         }
  453.         templine.len=strlen(c)+1; /* Get the len of the line */
  454.  
  455.         newline=(struct line *)malloc(sizeof(struct line));
  456.         if(newline==NULL) { /* Out of memory */
  457.         fputs("\nInsuffecient Memory\n",stderr);
  458.         exit(12);
  459.         }
  460.         newline->text=malloc(templine.len);
  461.         if(newline->text==NULL) { /* Out of memory */
  462.         fputs("\nInsuffecient Memory\n",stderr);
  463.         exit(12);
  464.         }
  465.         strcpy(newline->text,c);
  466.         newline->seqnum=seqcur;    /* Get the current sequence number */
  467.         newline->len=templine.len;
  468.         newline->next=NULL;
  469.         if(x->tail==NULL) {
  470.         x->head=newline;
  471.         x->tline=1;
  472.         x->hline=1;
  473.         }
  474.         else {
  475.         x->tail->next=newline;
  476.         x->tline++;
  477.         }
  478.         x->tail=newline;
  479.     }
  480.     x->eof = feof(filex);
  481.     }
  482. }
  483. backtrack(x, xlines)/* Causes the current position of fanchor X to become */
  484. struct fanchor *x;  /* that of the last mark operation.  I.E. the current */
  485. int *xlines;        /* line when the fanchor was marked last becomes the */
  486. {            /* the new curr. XLINES is set to the number of lines */
  487.             /* from the new curr to the old curr inclusive */
  488.     *xlines=x->cline+1-x->hline;
  489.     x->curr=x->head;
  490.     x->cline=x->hline;
  491.     Eof=endfanchor(&a) || endfanchor(&b);
  492. }
  493. compl() /* Compare the current lines of fanchors a and b */
  494.     /* returning match to signal their (non-) equivalence */
  495.     /* EOF on both files is considered a match, but eof on */
  496.     /* only one is a mismatch */
  497. {
  498.     int cea,ceb;    /* Ending columns for file a and file b */
  499.     int i;
  500.     char *ca,*cb;
  501.  
  502.     if(a.curr==NULL || b.curr==NULL)
  503.     Match=(endfanchor(&a) && endfanchor(&b));
  504.     else {
  505.     if(Iwhite) {
  506.        Match = compx(a.curr,b.curr);
  507.        return;
  508.     }
  509.     cea = min(a.curr->len,colend);
  510.     ceb = min(b.curr->len,colend);
  511.     Match=(cea==ceb);   /* Equal lens */
  512.     if(Match) { /* The lengths match.. so lets see if we can compare them */
  513.         if(cea<=colstart) Match=0;
  514.         else {
  515.         ca=a.curr->text;
  516.         cb=b.curr->text;
  517.         ca+=colstart-1;
  518.         cb+=colstart-1;
  519.         for(i=colstart;i<cea;i++) {
  520.             if(Icase) {
  521.                if(!(Match=( tolower(*ca++)==tolower(*cb++))))
  522.                break;
  523.             }
  524.             else if(!(Match=(*ca++==*cb++)))
  525.             break;
  526.            }
  527.         }
  528.     }
  529.     }
  530. }
  531. int compx(l1,l2)
  532. struct line *l1, *l2;
  533. {
  534.    char sbuf1[MAXLEN+1], sbuf2[MAXLEN+1];
  535.    register char *c;
  536.    register int i;
  537.  
  538.    for(i=0, c = l1->text; *c; c++)
  539.        if( !isspace(*c) ) sbuf1[i++] = (Icase) ? tolower(*c) : *c ;
  540.    sbuf1[i] = '\0';
  541.  
  542.    for(i=0, c = l2->text; *c; c++)
  543.        if( !isspace(*c) ) sbuf2[i++] = (Icase) ? tolower(*c) : *c ;
  544.    sbuf2[i] = '\0';
  545.  
  546.    if(strcmp(sbuf1,sbuf2) == 0) return 1;
  547.    return 0;
  548. }
  549. fnoteq() /* Find a mismatch */
  550. {
  551.     for(;;) {
  552.     movecurr(&a,in0);
  553.     movecurr(&b,in1);
  554.     mark(&a);
  555.     mark(&b);
  556.     compl();
  557.     if(Match && a.curr != NULL)
  558.         lastmseq=a.curr->seqnum;  /* Remember the sequence number */
  559.     if(Eof || !Match) break;
  560.     }
  561. }
  562. findeq()
  563. {
  564.     char advanceb;
  565.     advanceb=1;
  566.     for(;;) {
  567.     advanceb = Eof ? endfanchor(&a):!advanceb;
  568.     if(advanceb) search(&a,in0,&b,in1);
  569.     else search(&b,in1,&a,in0);
  570.     if(Match) break;
  571.     }
  572.     report();
  573. }
  574. search(x,filex,y,filey) /* Look ahead one line on fanchor y and search */
  575. struct fanchor *x;     /* for that line backtracking on fanchor x */
  576. FILE *filex;
  577. struct fanchor *y;
  578. FILE *filey;
  579. {
  580.     int count;    /* Number of lines backtraced on x */
  581.  
  582.     movecurr(y,filey);
  583.     backtrack(x,&count);
  584.     checkfullmatch(x,filex,y,filey);
  585.     count--;
  586.     while( count!=0 && !Match ) {
  587.     movecurr(x,filex);
  588.     count--;
  589.     checkfullmatch(x,filex,y,filey);
  590.     }
  591. }
  592. checkfullmatch(      /* From the current positions of x and y, which may */
  593.     x,filex,y,filey) /* match makesure that the next MINMATCH-1 lines */
  594. struct fanchor *x;   /* also match or set match = false */
  595. struct fanchor *y;
  596. FILE *filex;
  597. FILE *filey;
  598. {
  599.     int n;
  600.     struct line *savexcur, *saveycur;
  601.     int savexline, saveyline;
  602.  
  603.     savexcur=x->curr;
  604.     saveycur=y->curr;
  605.     savexline=x->cline;
  606.     saveyline=y->cline;
  607.     compl();
  608.     for(n=MINMATCH-1; Match && n!=0;n--) {
  609.     movecurr(x,filex);
  610.     movecurr(y,filey);
  611.     compl();
  612.     }
  613.     x->curr=savexcur;
  614.     x->cline=savexline;
  615.     y->curr=saveycur;
  616.     y->cline=saveyline;
  617. }
  618. report()
  619. {
  620. #define REPLACE 0
  621. #define DELETE 1
  622. #define INSERT 2
  623. #define INSERTOF 3
  624.  
  625.     int STATE;
  626.     int lineno;
  627.     struct line *p;
  628.     struct line *alast; /* Pointer to the last unmatched lines in file a */
  629.     struct line *blast; /* and file b */
  630.     long seq1;
  631.     long seq2;
  632.     long seq3;
  633.     long seq4;
  634.  
  635.     if(!Edit) {
  636.     pagechk();
  637.     fputc('\n',outlist);
  638.     if(a.head!=a.curr)
  639.         for(lineno=a.hline,p=a.head;p!=NULL && p!=a.curr;lineno++,p=p->next) {
  640.         pagechk();
  641.         fprintf(outlist," 1 %4d> %s",lineno,p->text);
  642.         }
  643.     if(b.head!=b.curr)
  644.         for(lineno=b.hline,p=b.head;p!=NULL && p!=b.curr;lineno++,p=p->next) {
  645.         pagechk();
  646.         fprintf(outlist," 2 %4d> %s",lineno,p->text);
  647.         }
  648.     }
  649.     else {  /* Handle a Update deck */
  650.  
  651.     /* The following conditions are: */
  652.     /* a.head = first mismatched line in file 1 */
  653.     /* a.curr = first matched line in file 1 */
  654.     /* b.head = first mismatched line in file 2 */
  655.     /* b.curr = first matched line in file 2 */
  656.     alast=blast=NULL;
  657.     for(p=a.head;p!=a.curr && p!=NULL; p=p->next) alast=p;
  658.     for(p=b.head;p!=b.curr && p!=NULL; p=p->next) blast=p;
  659.  
  660.     STATE=REPLACE;
  661.  
  662.     if(alast==NULL) STATE=INSERT;
  663.     else if(blast==NULL) STATE=DELETE;
  664.  
  665.     if(STATE==INSERT && lastmseq==0) STATE=INSERTOF;
  666.  
  667.     switch(STATE) {
  668.  
  669.         case REPLACE:
  670.         seq1=a.head->seqnum; /* Get the first sequence number */
  671.  
  672.         fprintf(outlist,"./ R %ld",seq1);
  673.  
  674.         if(a.head!=alast) {
  675.             seq2=alast->seqnum;
  676.             fprintf(outlist," %ld",seq2);
  677.         }
  678.         else seq2=seq1;
  679.         if(Seqtype!=GenSeq) {
  680.             seq4=b.cline-b.hline;  /* Get the number of lines inserted */
  681.             seq2=(a.curr!=NULL)?a.curr->seqnum:seq1+(seq4*seqincr);
  682.             seq4=(seq2-seq1)/(seq4+1L);
  683.             seq3=seq1+seq4;
  684.             fprintf(outlist," $ %ld %ld",seq3,seq4);
  685.         }
  686.         fputc('\n',outlist);
  687.         for(p=b.head;p!=NULL && p!=b.curr;p=p->next)
  688.             fprintf(outlist,"%s",p->text);
  689.         break;
  690.  
  691.         case INSERTOF:
  692.         seq1=a.curr->seqnum; /* Get the first sequence number */
  693.         fprintf(outlist,"./ R %ld",seq1);
  694.         seq2=seq1;
  695.         if(Seqtype!=GenSeq) {
  696.             seq4=b.cline-b.hline+1;  /* Get the number of lines inserted */
  697.             p=a.curr->next;
  698.             seq2=(p!=NULL)?p->seqnum:seq1+(seq4*seqincr);
  699.             seq4=(p!=NULL)?(seq2-seq1)/(seq4+1L):seqincr;
  700.             seq3=seq1+seq4;
  701.             fprintf(outlist," $ %ld %ld",seq3,seq4);
  702.         }
  703.         fputc('\n',outlist);
  704.         for(p=b.head;(p!=NULL && p!=b.curr);p=p->next)
  705.             fprintf(outlist,"%s",p->text);
  706.         if(p==b.curr) fprintf(outlist,"%s",p->text);
  707.         break;
  708.  
  709.         case INSERT:
  710.         fprintf(outlist,"./ I %ld",lastmseq);
  711.         if(Seqtype!=GenSeq) {
  712.             seq1=b.cline-b.hline; /* Number of lines inserted */
  713.             p=a.curr->next;
  714.             seq2=(p!=NULL)?a.curr->seqnum:seqincr;
  715.             seq2=(p!=NULL)?(seq2-lastmseq)/(seq1+1L):seqincr;
  716.  
  717.             seq1=lastmseq+seq2;
  718.             fprintf(outlist," $ %ld %ld",seq1,seq2);
  719.         }
  720.         fputc('\n',outlist);
  721.         for(p=b.head;(p!=NULL && p!=b.curr);p=p->next)
  722.             fprintf(outlist,"%s",p->text);
  723.         break;
  724.         case DELETE:
  725.         fprintf(outlist,"./ D %ld",a.head->seqnum);
  726.         if(alast!=NULL) fprintf(outlist," %ld",alast->seqnum);
  727.         fputc('\n',outlist);
  728.         break;
  729.         default: break;
  730.     }
  731.     }
  732. }
  733. initialize()
  734. {
  735.     initfanchor(&a,in0);
  736.     initfanchor(&b,in1);
  737.     Eof=a.eof || b.eof;
  738.     templine.len=MAXLEN;
  739.     templine.text[0]='\0';
  740. }
  741. initfanchor(x,filex)
  742. struct fanchor *x;
  743. FILE *filex;
  744. {
  745.     x->curr=NULL;
  746.     x->head=NULL;
  747.     x->tail=NULL;
  748.     x->cline=0;
  749.     x->hline=0;
  750.     x->tline=0;
  751.     x->eof=feof(filex);
  752. }
  753. cmndformat()
  754. {
  755.     fputs("Command format:\n",console);
  756.     fputs("COMPARE <file1> <file2> [options]\n",console);
  757.     fputs("Where:\n",console);
  758.     fputs(" <file1> and <file2> are the two files to be compared\n",console);
  759.     fputs(" [options] are:\n",console);
  760.     fputs(" -l [<listing>]  Generate output to file\n",console);
  761.     fputs("                 <listing> defaults to COMPARE.LST\n",console);
  762.     fputs(" -t              Ignore case\n",console);
  763.     fputs(" -w              Ignore white space between 'words' in a line\n",console);
  764.     fputs(" -p              Generate output to the printer\n",console);
  765.     fputs(" -mn             Resync on n lines (default is 2)\n",console);
  766.     fputs(" -cx,y           Only compare cols x thru y\n",console);
  767.     fputs(" ------------ following for update deck generation only ------------\n",console);
  768.     fputs(" -u [<update deck>] Generate update deck to make file1 into file2\n",console);
  769.     fputs("                 <update deck> defaults to the <name of file1>.\"UPT\"\n",console);
  770.     fputs(" -sx,y           Generate internal sequence numbers starting with x\n",console);
  771.     fputs("                 and increment by y. Default if -s is omitted is 1,1\n",console);
  772.     fputs("                 if -s is specified with out x and y then x=10000\n",console);
  773.     fputs("                 y defaults to x\n",console);
  774.     fputs(" -x              File1 already contains sequence numbers\n",console);
  775.     fputs("------------ following for aide with editor shells only -----------\n",console);
  776.     fputs(" -i              Use a sequence file (generated from UPDATE command)\n",console);
  777.     fputs("                 name is <name of file1>.\"SEQ\"\n",console);
  778.     fputs("                 will be deleted\n",console);
  779. }
  780.  
  781. pagechk() /* Check to see if we are to do a page eject if we are printing */
  782. {
  783.     if(ToAFile||Print) {
  784.     if(curline++ < LINESPERPAGE) return;
  785.     fputc('\f',outlist);
  786.     fputs(VERSION,outlist);
  787.     fprintf(outlist,"\n Comparing File 1:<%s> with File 2:<%s>\n\n",files[0],files[1]);
  788.     curline=5;
  789.     }
  790. }
  791.  
  792. newext(fbuff,filename,newext)
  793. char *fbuff;
  794. char *filename;
  795. char *newext;
  796. {
  797.    register char *in, *out;
  798.    in = filename;
  799.    out = fbuff;
  800.    while ( *in && *in != '.' )
  801.        *out++ = *in++;
  802.    *out++ = '.';
  803.    in = newext;
  804.    while ( *in )
  805.        *out++ = *in++;
  806.    return;
  807. }
  808.