home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / COMPUPD.ZIP / UPDATE.C < prev    next >
C/C++ Source or Header  |  1988-11-24  |  29KB  |  1,049 lines

  1. /*
  2.                 UPDATE.C
  3.          Copyright (C) Seven Valleys Software 1985,1987,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.  1.0     08/01/84   CCW    Written for Seven Valleys Software
  57.  1.1     08/17/85   CCW    Add -i option, and online doc.
  58.  1.2     01/15/88   CCW    Corrected some minor errors.
  59.  2.0     11/23/88   CCW    Convert library calls to ANSI compatible
  60. */
  61.  
  62. char *VERSION = "UPDATE V2.0\n";
  63. char *COPYR   = "Copyright (C) Seven Valleys Software 1985,1987,1988\n";
  64.  
  65. /*
  66. update <file1> <file2> [<file3>] [options]
  67. Where:
  68.     <file1> is the name of the file to be updated
  69.     <file2> is the name of the delta deck
  70.     <file3> is the name of the output file (defaults to $<file1>)
  71.  
  72. [options]
  73.  
  74.     -p       Print a brief update log to PRN
  75.     -pf    Print a Full log (each update is listed) to PRN
  76.  
  77.     -l [<file>]    List a brief update log to <file> (default is UPDATE.LOG)
  78.     -lf [<file>]   List a Full update log to <file> (default is UPDATE.LOG)
  79.  
  80.     -s[S,I]    Generates sequences numbers starting with S and incremented
  81.            by I.  S defaults to 10000 and I defaults to S.
  82. ---- The following options control if the sequence numbers already
  83. ---- exist in the input file.
  84.     -xi        Input file contains sequence numbers as the first "word"
  85.            of each line. (ex: 10000 10 rem fist line).
  86.     -xio[S,I]  Input file contains sequence numbers as the first "word"
  87.            output file will also contain sequence numbers as the
  88.            first word.  If S is specified, then the output will
  89.            be resequenced starting with S.    I (the increment)
  90.            defaults to S.
  91.     -xo[S,I]   Resequence the output file.
  92.  
  93.     -c           Control file.  <file2> is the name of a control file
  94.            <file1> is the name of the output file.
  95.            <file3> is unused.
  96.            Each line of the control file contains as its
  97.            first "word" the extension of an input file.
  98.            the first line must be the extension of base file.
  99.            ex:
  100.            >> DIR COMPARE.* -->
  101.             COMPARE.CTL
  102.             COMPARE.V00
  103.             COMPARE.V01
  104.            +---------------COMPARE.CTL-------------------+
  105.            | V00 Base of COMPARE.C                 |
  106.            | V01 Add -i option and online doc         |
  107.            +---------------------------------------------+
  108.            To generate COMPARE.C
  109.            UPDATE COMPARE.C COMPARE.CTL -c
  110.  
  111. ------------ following for aide with editor shells only -----------
  112.     -i           Generate a sequence file to be used by COMPARE
  113.            on the last pass generate a external sequence file.
  114.  
  115. */
  116.  
  117. #include <stdio.h>
  118. #include <stdlib.h>
  119. #include <math.h>
  120. #include <ctype.h>
  121.  
  122. #define TRUE 1
  123. #define FALSE 0
  124. #define ERR (-2)
  125.  
  126. #define MAXLEN 256
  127. #define IOBUFSZ 4096
  128.  
  129. FILE *outfile;            /* Output file */
  130. FILE *srcfile;            /* Source file */
  131. FILE *updtfile;         /* Update file */
  132. FILE *logfile;            /* Update logfile */
  133. FILE *listfile;         /* Update logfile */
  134. FILE *ctlfile;            /* Control file */
  135. FILE *console;            /* Were to send messages */
  136. FILE *seqf;            /* Sequence file */
  137.  
  138. char *files[3];         /* Pointers to the names of the files */
  139. char *Lfile;            /* Pointer to the Logfile */
  140.  
  141. char updtname[64];        /* Update deck name */
  142. char outname[64];        /* Output file name */
  143. char ctlname[64];        /* Control file name */
  144. char srcname[64];        /* Source name */
  145. char seqname[64];        /* Sequence file name */
  146.  
  147. char sourcepath[51];
  148. char sourcename[20];        /* Filename of source */
  149. char sourceext[5];
  150.  
  151. char buf[MAXLEN];        /* Line from the source file */
  152. char updtline[MAXLEN];        /* Line from the update file */
  153. char ctlrec[MAXLEN];        /* LIne from the control file */
  154.  
  155. /* Switchs and flags */
  156. char Log,        /* Log updates to a file */
  157.     PLog,        /* Log file to print */
  158.     FLog,        /* Log file to file */
  159.     PLogF,        /* Full listing to print */
  160.     FLogF,        /* Full listing to file */
  161.     SaveFull,        /* Save the Full flag during ctl processing */
  162.     XSeqf,        /* Put sequence numbers to external seq file */
  163.     SaveXSeqf,        /* Save XSeqf flag */
  164.     Pexternal,        /* Leave sequences numbers on the output file */
  165.     SavePextern,    /* Save external on output */
  166.     Linepushed,     /* A line was pushed back in the source file */
  167.     Ctlf,        /* Using a control file */
  168.     Rseq,        /* Resequence the output file */
  169.     Full,        /* After updating the file print a full listing */
  170.     ToAFile,        /* Loging to a file */
  171.     Print = 0;        /* Log file going to print, so check for pages */
  172.  
  173. /* Method of obtaining sequence numbers */
  174. #define XTERNAL 0    /* Sequence numbers are contained in the file */
  175. #define USERSEQ 1    /* User specified sequence numbers */
  176. #define GENSEQ    2    /* Sequence numbers are equal to record num */
  177. char Seqtype = GENSEQ;
  178.  
  179. long int Seqstrt = 1;    /* Starting sequence number */
  180. long int Seqincr = 1;    /* Increment */
  181. long int Seqnum = 0;    /* Sequence number from the file */
  182.  
  183. long int Rseqstrt;        /* Resequencing numbers */
  184. long int Rseqincr;
  185. long int Rseqnum;
  186.  
  187. int updtcmd;        /* The update command from the update control card */
  188. long int Seq1;        /* Sequence numbers taken from a ucl card */
  189. long int Seq2;
  190. long int Seq3;
  191. long int Seq4;
  192.  
  193. struct ctl {            /* List of items taken from the control file */
  194.     struct ctl *next;    /* Next item */
  195.     char ext[4];        /* Extension to use */
  196. } ctla, *ctlp;            /* Anchor, and pointer */
  197.  
  198. #define galloc(c) (struct c *)malloc(sizeof( struct c))
  199. int    numupdates = 0;    /* Number of updates found in the control file */
  200.  
  201. #define LINESPERPAGE 66
  202. int curline = LINESPERPAGE+1;
  203.  
  204. char *iobuf1;
  205. char *iobuf2;
  206. char *iobuf3;
  207.  
  208. main(argc,argv)
  209. char **argv;
  210. int argc;
  211. {
  212.     int i;
  213.     char *cp;
  214.     char *c;
  215.  
  216.     console=stdout;
  217.     /* Handle the quiet option */
  218.     if(strcmp(argv[argc-1],"-q")==0) {
  219.     console=fopen("NUL","w");
  220.     argc--;
  221.     }
  222.     else {
  223.     fputs(VERSION,stderr);     /* Put out our header for version */
  224.     fputs(COPYR,stderr);     /* Put out our header for version */
  225.     fflush(stderr);
  226.     }
  227.  
  228.     if(argc<3) {
  229.        fputs("\nMission filename(s).\n",stderr);
  230.        cmndformat();
  231.        exit(12);
  232.     }
  233.  
  234.     Lfile=NULL;
  235.  
  236.     for(argc--,i=0;argc;argc--)     {
  237.     cp=*++argv;    /* Get the next token */
  238.     if(*cp=='-') {  /* Select an option */
  239.         cp++;   /* Point to the option */
  240.         switch(tolower(*cp)) {
  241.         case 'i':
  242.             XSeqf++;
  243.             break;
  244.         case 'c':        /* Control file */
  245.             Ctlf++;
  246.             Seqtype=USERSEQ;
  247.             Seqincr=Seqstrt=10000;
  248.             Seqnum=Seqstrt-Seqincr;
  249.             break;
  250.         case 'p':        /* Send logfile to a printer */
  251.             if(tolower(*(cp+1))=='f') PLogF++;
  252.             PLog++;
  253.             break;
  254.         case 'l':        /* Log the updates to a logfile */
  255.             if(tolower(*(cp+1))=='f') FLogF++;
  256.             if(argc-1) {
  257.             Lfile=*++argv;
  258.             argc--;
  259.             if(*Lfile=='-') {
  260.                 Lfile="UPDATE.LOG";
  261.                 argv--;
  262.                 argc++;
  263.              }
  264.             }
  265.             else Lfile="UPDATE.LOG";
  266.             FLog++;
  267.             break;
  268.         case 's':        /* Generate internal sequence numbers */
  269.             cp++;
  270.             Seqtype=USERSEQ;
  271.             if(isdigit(*cp)) {
  272.             cp+=stcd_l(cp,&Seqstrt);
  273.             if(*cp==',') {
  274.                 cp++;
  275.                 stcd_l(cp,&Seqincr);
  276.             }
  277.             else Seqincr=Seqstrt;
  278.             }
  279.             else Seqincr=Seqstrt=10000;
  280.             Seqnum=Seqstrt-Seqincr;
  281.             break;
  282.         case 'x':        /* Use external sequence numbers */
  283.             cp++;
  284.             if(tolower(*cp)=='i') {
  285.             Seqtype=XTERNAL;
  286.             cp++;
  287.             if(tolower(*cp)=='o') {
  288.                 Pexternal=TRUE;
  289.                 cp++;
  290.                 if(isdigit(*cp)) {
  291.                 Rseq=TRUE;
  292.                 cp+=stcd_l(cp,&Rseqstrt);
  293.                 if(*cp==',') {
  294.                     cp++;
  295.                     stcd_l(cp,&Rseqincr);
  296.                 }
  297.                 else Rseqincr=Rseqstrt;
  298.                 Rseqnum=Rseqstrt-Rseqincr;
  299.                 }
  300.             }
  301.             }
  302.             else if(tolower(*cp)=='o') {
  303.             Pexternal=TRUE;
  304.             cp++;
  305.             if(isdigit(*cp)) {
  306.                 Rseq=TRUE;
  307.                 cp+=stcd_l(cp,&Rseqstrt);
  308.                 if(*cp==',') {
  309.                 cp++;
  310.                 stcd_l(cp,&Rseqincr);
  311.                 }
  312.                 else Rseqincr=Rseqstrt;
  313.                 Rseqnum=Rseqstrt-Rseqincr;
  314.             }
  315.             }
  316.             else if(*cp=='\0') Pexternal=TRUE;
  317.             break;
  318.         default:     /* Error (unknow option) */
  319.             fprintf(stderr,"\nInvalid option -%s\n",cp);
  320.             cmndformat();
  321.             exit(12);
  322.             break;
  323.         }
  324.     }
  325.     else if(i<3) files[i++]=cp;    /* Point to the filename */
  326.     }
  327.     /* We need at least one files */
  328.  
  329.     if(i<1) {        /* Tell about the error */
  330.         fputs("\nMissing input filename.\n",stderr);
  331.         cmndformat();
  332.         exit(12);
  333.     }
  334.     parsename(files[0],sourcepath,sourcename,sourceext);
  335.  
  336.     /* If we are using a control file, and there wasn't a control file */
  337.     /* defined, generate a default id */
  338.     if(Ctlf) {
  339.         if(i<2) buildname(ctlname,sourcepath,sourcename,"CTL");
  340.         else strcpy(ctlname,files[1]);
  341.     }
  342.     else {
  343.         if(i<2) {        /* Tell about the error */
  344.             fputs("\nMissing filename(s).\n",stderr);
  345.             cmndformat();
  346.             exit(12);
  347.         }
  348.         strcpy(updtname,files[1]);
  349.         if(i==2) {
  350.             int j;
  351.             outname[0]='\0';
  352.             c=outname;
  353.             if(strlen(sourcepath)!=0) {
  354.             strcat(outname,sourcepath);
  355.             strcat(outname,"\\");
  356.             c+=2;
  357.             }
  358.             strcat(outname,"$");
  359.             c++;
  360.             for(j=1,cp=sourcename;j<8 && *cp!='\0';j++,cp++)
  361.             *c++=*cp;
  362.             if(strlen(sourceext)!=0) {
  363.             strcat(outname,".");
  364.             strcat(outname,sourceext);
  365.             }
  366.         }
  367.         else strcpy(outname,files[2]);
  368.     }
  369.     if(FLogF) { /* Handle the case of a full listing */
  370.     FLog=0;  /* Don't allow update log */
  371.     Full++; /* Turn on full listing */
  372.     if( (listfile=fopen(Lfile,"w"))==NULL) {
  373.         fprintf(stderr,"\nUnable to open list file [%s]\n",Lfile);
  374.         exit(12);
  375.     }
  376.     }
  377.     if(PLogF) { /* Handle the case of a full listing going to the printer */
  378.     PLog=0;    /* Don't allow update log to printer */
  379.     Full++;
  380.     if( (listfile=fopen("PRN","w"))==NULL) {
  381.         fprintf(stderr,"\nUnable to open list file [%s]\n","PRN");
  382.         exit(12);
  383.     }
  384.     }
  385.     /* Now open a log file */
  386.     if(PLog||FLog) Log++;
  387.  
  388.     if(Log) {
  389.     if(PLog) Lfile="PRN";
  390.     if( (logfile=fopen(Lfile,"w"))==NULL) {
  391.         fprintf(stderr,"\nUnable to open log file [%s]\n",Lfile);
  392.         exit(12);
  393.     }
  394.     }
  395.  
  396.   /* Now start updating files */
  397.     if( Ctlf ) {   /* Process the update via control file */
  398.     SaveFull = Full;    /* save the full switch */
  399.     SavePextern = Pexternal;
  400.     SaveXSeqf = XSeqf;
  401.     Full = 0;        /* Always zero */
  402.     if((ctlfile=fopen(ctlname,"r"))==NULL) {
  403.         fprintf(stderr,"\nUnable to open control file [%s]\n",ctlname);
  404.         exit(12);
  405.     }
  406.  
  407.     ctlp = &ctla;
  408.     ctlp->next=NULL;
  409.     ctlp->ext[0]='\0';
  410.  
  411.     while( fgets(ctlrec,MAXLEN,ctlfile)!=NULL )    {
  412.         if(ctlrec[0]=='*') continue;    /* Skip comments */
  413.         numupdates++;        /* Increase number of updates */
  414.         {
  415.            char *p1, *p2;
  416.            int i;
  417.            p1 = ctlrec;
  418.            p2 = (ctlp->ext);
  419.            for(i=0;*p1 != '\n' && !isspace(*p1) && i<3;i++)
  420.                *p2++ = *p1++;
  421.            *p2 = '\0';
  422.         }
  423.         ctlp->next=galloc(ctl);     /* Allocate the next item */
  424.         ctlp=ctlp->next;        /* Point to the next item */
  425.         ctlp->next=NULL;        /* Set this pointer to null*/
  426.         ctlp->ext[0]='\0';
  427.     }
  428.     numupdates--;    /* Exclude the base file */
  429.     fclose(ctlfile);
  430.  
  431.     /* Get the base file */
  432.     strcpy(srcname,sourcename);    /* Get the source name */
  433.     strcat(srcname,".");
  434.     strcat(srcname,ctla.ext);  /* Concat the extension */
  435.  
  436.     for(ctlp=ctla.next,i=0;i<numupdates-1;i++,ctlp=ctlp->next) {
  437.         buildname(updtname,sourcepath,sourcename,ctlp->ext);
  438.         if(i%2) strcpy(outname,"$updtw2$.tmp");
  439.         else    strcpy(outname,"$updtw1$.tmp");
  440.         if( (srcfile=fopen(srcname,"r"))==NULL) {
  441.             fprintf(stderr,"Unable to open source file [%s]\n",srcname);
  442.             exit(12);
  443.         }
  444.         if( (updtfile=fopen(updtname,"r"))==NULL) {
  445.             fprintf(stderr,"Unable to open update file [%s]\n",updtname);
  446.             exit(12);
  447.         }
  448.         if( (outfile=fopen(outname,"w"))==NULL) {
  449.             fprintf(stderr,"Unable to open output file [%s]\n",outname);
  450.             exit(12);
  451.         }
  452.         Rseqnum=Rseqstrt-Rseqincr;
  453.         Seqnum=Seqstrt-Seqincr;
  454.         Pexternal=TRUE;
  455.         fprintf(console,"Applying [%s]\n",updtname);
  456.         update();
  457.         if(i%2) unlink("$updtw1$.tmp");
  458.         else    unlink("$updtw2$.tmp");
  459.         Rseqnum=Rseqstrt-Rseqincr;
  460.         Seqnum=Seqstrt-Seqincr;
  461.         Pexternal=FALSE;
  462.         Seqtype=XTERNAL;
  463.         strcpy(srcname,outname);
  464.     }
  465.     buildname(outname,sourcepath,sourcename,sourceext);
  466.     buildname(updtname,sourcepath,sourcename,ctlp->ext);
  467.     Full=SaveFull;    /* Restore the full listing flag */
  468.     Pexternal=SavePextern;
  469.     XSeqf=SaveXSeqf;
  470.     }
  471.     else buildname(srcname,sourcepath,sourcename,sourceext);
  472.  
  473.     if( (srcfile=fopen(srcname,"r"))==NULL) {
  474.     fprintf(stderr,"Unable to open source file [%s]\n",srcname);
  475.     exit(12);
  476.     }
  477.     if( (updtfile=fopen(updtname,"r"))==NULL) {
  478.     fprintf(stderr,"Unable to open update file [%s]\n",updtname);
  479.     exit(12);
  480.     }
  481.     if( (outfile=fopen(outname,"w"))==NULL) {
  482.     fprintf(stderr,"Unable to open output file [%s]\n",outname);
  483.     exit(12);
  484.     }
  485.     fprintf(console,"Applying [%s]\n",updtname);
  486.     if(XSeqf) {
  487.        Pexternal++;
  488.        newext(seqname,outname,"seq");
  489.        seqf=fopen(seqname,"wb");
  490.     }
  491.     update();
  492.     if(XSeqf) fclose(seqf);
  493.  
  494.     if( Ctlf ) { unlink("$updtw1$.tmp"); unlink("$updtw2$.tmp"); }
  495.     if( Log ) {
  496.     fflush(logfile);
  497.     fclose(logfile);
  498.     }
  499.     if( Full ) {
  500.     fflush(listfile);
  501.     fclose(listfile);
  502.     }
  503. }
  504. /*---------------------------------------------------------------------*/
  505. /* srcfile = file to be updated                        */
  506. /* updtfile = update deck                           */
  507. /* outfile = output file                           */
  508. /*                                       */
  509. /* if Seqtype = XTERNAL then we pull the sequence numbers from the     */
  510. /* front of each record from srcfile.  Otherwise we generate our own   */
  511. /* numbers.  If Pexternal is true, then we write out the sequence      */
  512. /* numbers along with the output data.                       */
  513. /*                                       */
  514. /*---------------------------------------------------------------------*/
  515. update()
  516. {
  517.     char Exit;
  518.     char Firstime;
  519.  
  520.     updtcmd='*';
  521.     Exit=FALSE;
  522.     Firstime=TRUE;
  523.  
  524.     iobuf1=malloc(IOBUFSZ);
  525.     iobuf2=malloc(IOBUFSZ);
  526.     iobuf3=malloc(IOBUFSZ);
  527.     if (iobuf1)  setvbuf(srcfile,iobuf1,_IOFBF,IOBUFSZ);
  528.     if (iobuf2)  setvbuf(updtfile,iobuf2,_IOFBF,IOBUFSZ);
  529.     if (iobuf3)  setvbuf(outfile,iobuf3,_IOFBF,IOBUFSZ);
  530.  
  531.     getupdt();    /* Go prime the buffer */
  532.     while(!Exit) {
  533.     updtcmd=getcmd();    /* Get a command from input    */
  534.     if(Log) fprintf(logfile,"%s",updtline);
  535.     switch(updtcmd) {
  536.  
  537.         /* End Of File on the Update deck */
  538.         case EOF:
  539.         while( getline()!=EOF ) writeupdt(Seqnum);
  540.         Exit=1; /* Exit the    main loop */
  541.         break;
  542.  
  543.         /* Delete Lines from the input file */
  544.         case 'D':
  545.         /* Copy upto arg1 */
  546.         if( copyin(Seq1)==ERR) {
  547.             reset();
  548.             break;
  549.         }
  550.         /* Delete the lines */
  551.         if( delin(Seq2)==ERR) {
  552.             reset();
  553.             break;
  554.         }
  555.         getupdt();
  556.         break;
  557.  
  558.         /* Insert lines from the update deck */
  559.         case 'I':
  560.         /* Copy upto arg1 */
  561.         if( copyin(Seq1)==ERR) {
  562.             reset();
  563.             break;
  564.         }
  565.         if(!Linepushed) break;
  566.         getline();
  567.         writeupdt(Seqnum); /* Now copy the matching record */
  568.         copyup(Seq2,Seq3); /* Copy from update deck */
  569.         break;
  570.  
  571.         /* Replace from the update deck */
  572.         case 'R':  /* Replace from the update deck */
  573.         /* Copy upto arg1 */
  574.         if( copyin(Seq1)==ERR) {
  575.             reset();
  576.             break;
  577.         }
  578.          /* Delete the lines */
  579.         if( delin(Seq2)==ERR) {
  580.             reset();
  581.             break;
  582.         }
  583.         copyup(Seq3,Seq4);    /* Copy from update deck    */
  584.         break;
  585.  
  586.         /* Just a comment */
  587.         case '*':       /* Ignore comments */
  588.         getupdt();
  589.         break;
  590.         case 'S':
  591.         if(!Firstime) {
  592.             fprintf(stderr,"\n./ S valid only as first card in update file\n");
  593.             getupdt();
  594.             break;
  595.         }
  596.         Rseqstrt=Seq1;
  597.         Rseqincr=Seq2;
  598.         Rseqnum=Rseqstrt-Rseqincr;
  599.         getupdt();
  600.         break;
  601.         case 0:
  602.         break;
  603.         case ERR:
  604.         default:
  605.         fprintf(stderr,"\nInvalid update control record:\n%s\n",
  606.             updtline);
  607.         getupdt();
  608.         break;
  609.     }
  610.     Firstime=FALSE;
  611.     }
  612.  
  613.     fclose(srcfile);    /* Close the source file */
  614.     fclose(updtfile);    /* Close the update deck */
  615.     fclose(outfile);    /* Close the updated file */
  616.  
  617.     if(iobuf1!=NULL) free(iobuf1);
  618.     if(iobuf2!=NULL) free(iobuf2);
  619.     if(iobuf3!=NULL) free(iobuf3);
  620.     iobuf1=iobuf2=iobuf3=NULL;
  621. }
  622. int getcmd()   /* Return the command from the update deck */
  623. {
  624.     char *c;
  625.     char c1;
  626.  
  627.     if(updtcmd==EOF) return EOF;    /* Return eof char */
  628.     c = updtline;
  629.     if(*c++ != '.') return ERR;
  630.     if(*c++ != '/') return ERR;
  631.     if(!isspace(*c)) return ERR;
  632.     while(isspace(*c)) c++;
  633.     if( !isspace(*(c+1)) && *(c+1)!='\n') return ERR;
  634.     c1=toupper(*c);     /* not a command */
  635.     c++;
  636.     switch(c1) {
  637.     /* Process a possible valid command */
  638.  
  639.     case 'D': /* ./ D Seqno1 [Seqno2] [$] */
  640.         switch(getnum(&c,&Seq1)) {
  641.         case 0: /* Valid number */
  642.             break;
  643.  
  644.         default:
  645.             return ERR;
  646.             break;
  647.         }
  648.         switch(getnum(&c,&Seq2)) {
  649.         case 0:
  650.             return 'D';
  651.             break;
  652.         default:
  653.             Seq2=Seq1;
  654.             return 'D';
  655.             break;
  656.         }
  657.         break;
  658.     case 'I':       /* ./ I Seqno [$ [seqstrt [seqincr]]] */
  659.         switch(getnum(&c,&Seq1)) {
  660.         case 0:
  661.             break;
  662.         default:
  663.             return ERR;
  664.             break;
  665.         }
  666.         switch(getnum(&c,&Seq2)) {  /* This must be a $ */
  667.         case '$':
  668.             c++;
  669.             break;
  670.         default:
  671.             Seq2=Seq1+100;
  672.             Seq3=100;
  673.             return 'I';
  674.             break;
  675.         }
  676.         switch(getnum(&c,&Seq2)) {  /* Now we will try to get a number */
  677.         case 0: /* Ok we got a number for strtseq */
  678.             break;
  679.         default:
  680.             Seq2=Seq1+100;
  681.             Seq3=100;
  682.             return 'I';
  683.             break;
  684.         }
  685.         switch(getnum(&c,&Seq3)) {  /* Try for seqincr */
  686.         case 0: /* Ok return with the number.. */
  687.             return 'I';
  688.             break;
  689.         default:    /* Otherwise set the default.. */
  690.             Seq3=Seq1-Seq2;
  691.             return 'I';
  692.             break;
  693.         }
  694.         break;
  695.     case 'R':       /* ./ R Seqno1 [Seqno2] [$ [Seqstrt  [Seqincr]]]  */
  696.         switch(getnum(&c,&Seq1)) {
  697.         case 0:
  698.             break;
  699.         default:
  700.             return ERR;
  701.             break;
  702.         }
  703.         switch(getnum(&c,&Seq2)) {
  704.         case 0:
  705.             break;
  706.         case '$':
  707.             Seq2=Seq1;
  708.             break;
  709.         default:
  710.             Seq2=Seq1;
  711.             Seq3=Seq1+100;
  712.             Seq4=100;
  713.             return 'R';
  714.             break;
  715.         }
  716.         switch(getnum(&c,&Seq3)) {
  717.         case '$':
  718.             c++;
  719.             break;
  720.         default:
  721.             Seq3=Seq1+100;
  722.             Seq4=100;
  723.             return 'R';
  724.             break;
  725.         }
  726.         switch(getnum(&c,&Seq3)) {
  727.         case 0:
  728.             break;
  729.         default:
  730.             Seq3=Seq1+100;
  731.             Seq4=100;
  732.             return 'R';
  733.             break;
  734.         }
  735.         switch(getnum(&c,&Seq4)) {
  736.         case 0:
  737.             return 'R';
  738.             break;
  739.         default:
  740.             Seq4=Seq1-Seq3;
  741.             return 'R';
  742.             break;
  743.         }
  744.         break;
  745.     case 'S':       /* ./ S [Seqstrt [Seqincr]]     */
  746.         switch(getnum(&c,&Seq1)) {
  747.         case 0: /* Valid number */
  748.             break;
  749.  
  750.         default:
  751.             Seq2=Seq1=10000;
  752.             return 'S';
  753.             break;
  754.         }
  755.         switch(getnum(&c,&Seq2)) {
  756.         case 0:
  757.             return 'S';
  758.             break;
  759.         default:
  760.             Seq2=Seq1;
  761.             return 'S';
  762.             break;
  763.         }
  764.         break;
  765.     case '*':       /* ./ * [comment] */
  766.         return '*';
  767.         break;
  768.  
  769.     default:
  770.         return NULL;
  771.         break;
  772.     }
  773. }
  774.  
  775.  
  776. getupdt()
  777. {
  778.     if( fgets(updtline,MAXLEN,updtfile) == NULL ) updtcmd=EOF;
  779. }
  780.  
  781. reset() /* Here to reset after an error */
  782. {
  783.     do getupdt(); while(!iscommand());
  784. }
  785.  
  786. iscommand()  /* Look for special strings in the input from the update file */
  787. {
  788.     char *c;
  789.  
  790.     if(updtcmd==EOF) return TRUE;    /* EOF is a command */
  791.  
  792.     c = updtline;
  793.     if(*c++ != '.') return FALSE;
  794.     if(*c++ != '/') return FALSE;
  795.     if(!isspace(*c)) return FALSE;
  796.     while( isspace(*c) ) c++;
  797.     if( !isspace(*(c+1)) && *(c+1)!='\n') return FALSE;
  798.     switch(toupper(*c)) {    /* not a command */
  799.  
  800.         case 'D': return TRUE; break;
  801.         case 'I': return TRUE; break;
  802.         case 'R': return TRUE; break;
  803.         case 'S': return TRUE; break;
  804.         case '*': return TRUE; break;
  805.  
  806.         default:  return FALSE; break;
  807.     }
  808. }
  809.  
  810.  
  811. copyup(s1,s2)    /* Copy from the update file */
  812. long int s1,s2;
  813. {
  814.     if(Log) fputs(" ...Inserting:\n",logfile);
  815.     for(;;) {
  816.         getupdt();
  817.         if(iscommand()) break;
  818.         strcpy(buf,updtline);
  819.         if(Log) fprintf(logfile,"\t%s",updtline);
  820.         writeupdt(s1);      /* Write the record back */
  821.         buf[0]='\0';          /* Clear the buffer */
  822.         s1+=s2;
  823.     }
  824. }
  825. writeupdt(s)
  826. long int s;
  827. {
  828.     if(Full) {
  829.         pagechk();
  830.         if(Rseq) fprintf(listfile,"  %ld > ",Rseqnum);
  831.         else     fprintf(listfile,"  %ld > ",s);
  832.         fputs(buf,listfile);
  833.     }
  834.     if(Rseq) {
  835.         Rseqnum += Rseqincr;
  836.         fprintf(outfile,"%ld ",Rseqnum);
  837.     }
  838.     else if(Pexternal) {
  839.         if(XSeqf) fwrite(&s,sizeof(s),1,seqf);
  840.         else fprintf(outfile,"%ld ",s);
  841.     }
  842.     fputs(buf,outfile);
  843. }
  844. copyin(n)    /* Copy upto n */
  845. long int n;
  846. {
  847.     while( (getline()!=EOF) && Seqnum != n) {
  848.         if(Seqnum > n) { /* Handle a sequence error */
  849.         fprintf(stderr,"\nSequence error in update [%s]\n",updtname);
  850.         fprintf(stderr,"Input file sequence number: %ld Update sequence number %ld\n",
  851.             Seqnum,n);
  852.         fprintf(stderr,"Update record:\n\t%s\n",updtline);
  853.         return ERR;
  854.         }
  855.         writeupdt(Seqnum);    /* Write a record back */
  856.     }
  857.     if(Seqnum == n) pushline();
  858.     else return EOF;
  859. }
  860. delin(n)   /* Delete upto and including n */
  861. long int n;
  862. {
  863.     if(Log) fputs(" ...Deleting:\n",logfile);
  864.     while( (getline()!=EOF) && Seqnum != n) {
  865.         if(Log) fprintf(logfile,"\t%s",buf);
  866.         if(Seqnum>n) {    /* Handle sequence error */
  867.         fprintf(stderr,"\nSequence error in update [%s]\n",updtname);
  868.         fprintf(stderr,"Input file sequence number: %ld Update sequence number %ld\n",
  869.             Seqnum,n);
  870.         fprintf(stderr,"Update record:\n\t%s\n",updtline);
  871.         return ERR;
  872.         }
  873.     }
  874.     if(Seqnum==n) {
  875.         if(Log) fprintf(logfile,"\t%s",buf);
  876.         return;
  877.     }
  878.     else return    EOF;
  879. }
  880. pushline()    /* Mark a line for future use */
  881. {
  882.     Linepushed=1;
  883. }
  884. getline()    /* Get a line from the input file. */
  885. {
  886.     char *c;
  887.     char wrkbuf[MAXLEN];
  888.     if(Linepushed) {
  889.         Linepushed=0;
  890.         return;
  891.     }
  892.     if(fgets(wrkbuf,MAXLEN,srcfile)==NULL) return EOF;
  893.  
  894.     c=wrkbuf;
  895.  
  896.     switch(Seqtype) {
  897.     case XTERNAL:  /* Sequence numbers are part of the file */
  898.         c+=stcd_l(wrkbuf,&Seqnum);
  899.         if(*c!='\n') ++c; /* Handle a null line */
  900.         break;
  901.     case USERSEQ:
  902.     case GENSEQ:
  903.         Seqnum += Seqincr;    /* Increment sequence number */
  904.         break;
  905.     default: break;
  906.     }
  907.     strcpy(buf,c);    /* Copy from the input buffer to the string buffer */
  908.     return 0;
  909. }
  910.  
  911. stcd_l(s,n)
  912. char *s;
  913. long *n;
  914. {
  915.     int i;    /* Number of characters we picked off */
  916.     for(i=0,*n=0L;isdigit(*s);s++,i++) *n=(*n * 10)+ (*s-'0');
  917.     return i;
  918. }
  919.  
  920. getnum(s,n)
  921. char **s;
  922. long *n;
  923. {
  924.     int c;
  925.     while( isspace(**s) ) (*s)++;
  926.     if( isdigit(**s) ) {   /* Process a number .. */
  927.         (*s)+=stcd_l(*s,n);
  928.         c=0;
  929.     }
  930.     else c = (**s) ? **s  : 1;
  931.     return c; /* Return the character that we stopped on.. */
  932. }
  933. pagechk() /* Check to see if we are to do a page eject if we are printing */
  934. {
  935.     if(curline++ < LINESPERPAGE) return;
  936.     fputc('\f',listfile);
  937.     fputs(VERSION,listfile);
  938.     curline=3;
  939. }
  940. parsename(source,path,name,ext)
  941. char *source;
  942. char *path;
  943. char *name;
  944. char *ext;
  945. {
  946.    int i;
  947.  
  948.    path[0]=name[0]=ext[0]=0;
  949.    for(i=strlen(source);i;i--) {
  950.        if(source[i]=='.') {
  951.        strcpy(ext,&source[i+1]);
  952.        source[i]=0;
  953.        }
  954.        else if(source[i]==':' ||
  955.        source[i]=='\\' ||
  956.        source[i]=='/') {
  957.            strcpy(name,&source[i+1]);
  958.            source[i]=0;
  959.        }
  960.    }
  961.    if(name[0]) strcpy(path,source);
  962.    else strcpy(name,source);
  963. }
  964. buildname(new,path,name,ext)
  965. char new[];
  966. char *path;
  967. char *name;
  968. char *ext;
  969. {
  970.  
  971.     new[0]='\0';
  972.     if(strlen(path)!=0) {
  973.     strcat(new,path);
  974.     strcat(new,"\\");
  975.     }
  976.     strcat(new,name);
  977.     if(strlen(ext)!=0) {
  978.     strcat(new,".");
  979.     strcat(new,ext);
  980.     }
  981. }
  982. newext(fbuff,filename,newext)
  983. char *fbuff;
  984. char *filename;
  985. char *newext;
  986. {
  987.    register char *in, *out;
  988.    in = filename;
  989.    out = fbuff;
  990.    while ( *in && *in != '.' )
  991.        *out++ = *in++;
  992.    *out++ = '.';
  993.    in = newext;
  994.    while ( *in )
  995.        *out++ = *in++;
  996.    return;
  997. }
  998. cmndformat()
  999. {
  1000. fputs("update <file1> <file2> [<file3>] [options]\n",console);
  1001. fputs("Where:\n",console);
  1002. fputs("    <file1> is the name of the file to be updated\n",console);
  1003. fputs("    <file2> is the name of the delta deck\n",console);
  1004. fputs("    <file3> is the name of the output file (defaults to $<file1>)\n",console);
  1005. fputs("\n",console);
  1006. fputs("[options]\n",console);
  1007. fputs("\n",console);
  1008. fputs("    -p     Print a brief update log to PRN\n",console);
  1009. fputs("    -pf    Print a Full log (each update is listed) to PRN\n",console);
  1010. fputs("\n",console);
  1011. fputs("    -l [<file>]    List a brief update log to <file> (default is UPDATE.LOG)\n",console);
  1012. fputs("    -lf [<file>]   List a Full update log to <file> (default is UPDATE.LOG)\n",console);
  1013. fputs("\n",console);
  1014. fputs("    -s[S,I]    Generates sequences numbers starting with S and incremented\n",console);
  1015. fputs("               by I.  S defaults to 10000 and I defaults to S.\n",console);
  1016. fputs("---- The following options control if the sequence numbers already\n",console);
  1017. fputs("---- exist in the input file.\n",console);
  1018. fputs("    -xi        Input file contains sequence numbers as the first \"word\"\n",console);
  1019. fputs("               of each line. (ex: 10000 10 rem fist line).\n",console);
  1020. fputs("    -xio[S,I]  Input file contains sequence numbers as the first \"word\"\n",console);
  1021. fputs("               output file will also contain sequence numbers as the\n",console);
  1022. fputs("               first word.  If S is specified, then the output will\n",console);
  1023. fputs("               be resequenced starting with S.  I (the increment)\n",console);
  1024. fputs("               defaults to S.\n",console);
  1025. fputs("    -xo[S,I]   Resequence the output file.\n",console);
  1026. fputs("\n",console);
  1027. fputs("    -c         Control file.  <file2> is the name of a control file\n",console);
  1028. fputs("               <file1> is the name of the output file.\n",console);
  1029. fputs("               <file3> is unused.\n",console);
  1030. fputs("               Each line of the control file contains as its\n",console);
  1031. fputs("               first \"word\" the extension of an input file.\n",console);
  1032. fputs("               the first line must be the extension of base file.\n",console);
  1033. fputs("               ex:\n",console);
  1034. fputs("               >> DIR COMPARE.* -->\n",console);
  1035. fputs("                        COMPARE.CTL\n",console);
  1036. fputs("                        COMPARE.V00\n",console);
  1037. fputs("                        COMPARE.V01\n",console);
  1038. fputs("               +---------------COMPARE.CTL-------------------+\n",console);
  1039. fputs("               | V00 Base of COMPARE.C                       |\n",console);
  1040. fputs("               | V01 Add -i option and online doc            |\n",console);
  1041. fputs("               +---------------------------------------------+\n",console);
  1042. fputs("               To generate COMPARE.C\n",console);
  1043. fputs("               UPDATE COMPARE.C COMPARE.CTL -c\n",console);
  1044. fputs("\n",console);
  1045. fputs("------------ following for aide with editor shells only -----------\n",console);
  1046. fputs("    -i         Generate a sequence file to be used by COMPARE\n",console);
  1047. fputs("               on the last pass generate a external sequence file.\n",console);
  1048. }
  1049.