home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / RCS_SRC.ZIP / RCSSYN.C < prev    next >
C/C++ Source or Header  |  1991-01-15  |  18KB  |  570 lines

  1. /*
  2.  *                     RCS file input
  3.  */
  4. #ifndef lint
  5. static char rcsid[]= "$Id: rcssyn.c,v 4.6 89/05/01 15:13:32 narten Exp $ Purdue CS";
  6. #endif
  7. /*********************************************************************************
  8.  *                       Syntax Analysis.
  9.  *                       Keyword table
  10.  *                       Testprogram: define SYNDB
  11.  *                       Compatibility with Release 2: define COMPAT2
  12.  *********************************************************************************
  13.  */
  14.  
  15. /* Copyright (C) 1982, 1988, 1989 Walter Tichy
  16.    Distributed under license by the Free Software Foundation, Inc.
  17.  
  18. This file is part of RCS.
  19.  
  20. RCS is free software; you can redistribute it and/or modify
  21. it under the terms of the GNU General Public License as published by
  22. the Free Software Foundation; either version 1, or (at your option)
  23. any later version.
  24.  
  25. RCS is distributed in the hope that it will be useful,
  26. but WITHOUT ANY WARRANTY; without even the implied warranty of
  27. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  28. GNU General Public License for more details.
  29.  
  30. You should have received a copy of the GNU General Public License
  31. along with RCS; see the file COPYING.  If not, write to
  32. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  33.  
  34. Report problems and direct all questions to:
  35.  
  36.     rcs-bugs@cs.purdue.edu
  37.  
  38. */
  39.  
  40.  
  41. /* $Log:    rcssyn.c,v $
  42.  * Revision 4.6  89/05/01  15:13:32  narten
  43.  * changed copyright header to reflect current distribution rules
  44.  * 
  45.  * Revision 4.5  88/11/08  12:00:37  narten
  46.  * changes from  eggert@sm.unisys.com (Paul Eggert)
  47.  * 
  48.  * Revision 4.5  88/08/09  19:13:21  eggert
  49.  * Allow cc -R; remove lint.
  50.  * 
  51.  * Revision 4.4  87/12/18  11:46:16  narten
  52.  * more lint cleanups (Guy Harris)
  53.  * 
  54.  * Revision 4.3  87/10/18  10:39:36  narten
  55.  * Updating version numbers. Changes relative to 1.1 actually relative to
  56.  * 4.1
  57.  * 
  58.  * Revision 1.3  87/09/24  14:00:49  narten
  59.  * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
  60.  * warnings)
  61.  * 
  62.  * Revision 1.2  87/03/27  14:22:40  jenkins
  63.  * Port to suns
  64.  * 
  65.  * Revision 1.1  84/01/23  14:50:40  kcs
  66.  * Initial revision
  67.  * 
  68.  * Revision 4.1  83/03/28  11:38:49  wft
  69.  * Added parsing and printing of default branch.
  70.  * 
  71.  * Revision 3.6  83/01/15  17:46:50  wft
  72.  * Changed readdelta() to initialize selector and log-pointer.
  73.  * Changed puttree to check for selector==DELETE; putdtext() uses DELNUMFORM.
  74.  *
  75.  * Revision 3.5  82/12/08  21:58:58  wft
  76.  * renamed Commentleader to Commleader.
  77.  *
  78.  * Revision 3.4  82/12/04  13:24:40  wft
  79.  * Added routine gettree(), which updates keeplock after reading the
  80.  * delta tree.
  81.  *
  82.  * Revision 3.3  82/11/28  21:30:11  wft
  83.  * Reading and printing of Suffix removed; version COMPAT2 skips the
  84.  * Suffix for files of release 2 format. Fixed problems with printing nil.
  85.  *
  86.  * Revision 3.2  82/10/18  21:18:25  wft
  87.  * renamed putdeltatext to putdtext.
  88.  *
  89.  * Revision 3.1  82/10/11  19:45:11  wft
  90.  * made sure getc() returns into an integer.
  91.  */
  92.  
  93.  
  94.  
  95. /*
  96. #define COMPAT2
  97. /* version COMPAT2 reads files of the format of release 2 and 3, but
  98.  * generates files of release 3 format. Need not be defined if no
  99.  * old RCS files generated with release 2 exist.
  100.  */
  101. /*
  102. #define SYNDB
  103. /* version SYNDB is for debugging the syntax analysis for RCS files.
  104.  * SYNDB performs additional error checks.
  105.  */
  106. /*
  107. #define SYNTEST
  108. /* version SYNTEST inputs a RCS file and then prints out its internal
  109.  * data structures.
  110. */
  111.  
  112. #include "rcsbase.h"
  113. extern FILE * finptr;        /*RCS input file*/
  114. extern char * getid();
  115. extern struct hshentry * getnum();
  116. extern int    getkey();
  117. extern int    getlex();
  118. extern        readstring();
  119. extern        savestring();
  120.  
  121. /* forward */
  122. char * getkeyval();
  123.  
  124. /* keyword table */
  125.  
  126. char Kaccess[]   = "access";
  127. char Kauthor[]   = "author";
  128. char Kbranch[]   = "branch";
  129. char Kbranches[] = "branches";
  130. char Kcomment[]  = "comment";
  131. char Kdate[]     = "date";
  132. char Kdesc[]     = "desc";
  133. char Khead[]     = "head";
  134. char Klocks[]    = "locks";
  135. char Klog[]      = "log";
  136. char Knext[]     = "next";
  137. char Kstate[]    = "state";
  138. char Kstrict[]   = "strict";
  139. #ifdef COMPAT2
  140. char Ksuffix[]   = "suffix";
  141. #endif
  142. char Ksymbols[]  = "symbols";
  143. char Ktext[]     = "text";
  144.  
  145. #define COMMLENGTH 20
  146. char              Commleader[COMMLENGTH];
  147. char            * Comment;
  148. struct access   * AccessList;
  149. struct access   * LastAccess;
  150. struct assoc    * Symbols;
  151. struct assoc    * LastSymbol;
  152. struct lock     * Locks;
  153. struct lock     * LastLock;
  154. int               StrictLocks;
  155. struct hshentry * Head;
  156. struct hshentry * Dbranch;
  157. int               TotalDeltas;
  158.  
  159.  
  160.  
  161. getadmin()
  162. /* Function: Reads an <admin> and initializes the globals
  163.  * AccessList, LastAccess, Symbols, LastSymbol,
  164.  * Locks, LastLock, StrictLocks, Head, Comment, TotalDeltas;
  165.  */
  166. {
  167.         register char   * id;
  168.         struct access   * newaccess;
  169.         struct assoc    * newassoc;
  170.         struct lock     * newlock;
  171.         struct hshentry * delta;
  172.  
  173.         Comment="";
  174.         AccessList=LastAccess=nil;
  175.         Symbols=LastSymbol=nil;
  176.         Locks=LastLock=nil;
  177.         Dbranch = Head = nil;
  178.         TotalDeltas=0;
  179.  
  180.         if (!getkey(Khead)) fatserror("Missing head");
  181.         Head=getnum();
  182. #       ifdef SYNDB
  183.         if (Head&&((countnumflds(Head->num)%2)!=0))
  184.                 serror("Delta number required for head");
  185. #       endif
  186.         if (!getlex(SEMI)) serror("Missing ';' after head");
  187.  
  188.         if (getkey(Kbranch)) { /* optional */
  189.                 Dbranch=getnum();
  190.                 if (!getlex(SEMI)) serror("Missing ';' after branch list");
  191.         }
  192.  
  193.  
  194. #ifdef COMPAT2
  195.         /* read suffix. Only in release 2 format */
  196.         if (getkey(Ksuffix)) {
  197.                 if (nexttok==STRING) {
  198.                         readstring(); nextlex(); /*through away the suffix*/
  199.                 } elsif(nexttok==ID) {
  200.                         nextlex();
  201.                 }
  202.                 if (!getlex(SEMI)) serror("Missing ';' after %s",Ksuffix);
  203.         }
  204. #endif
  205.  
  206.         if (!getkey(Kaccess)) fatserror("Missing access list");
  207.         while (id=getid()) {
  208.                 newaccess = (struct access *)talloc(sizeof(struct access));
  209.                 newaccess->login = id;
  210.                 newaccess->nextaccess = nil;
  211.                 if (AccessList == nil) {
  212.                         AccessList=LastAccess=newaccess;
  213.                 } else {
  214.                         LastAccess=LastAccess->nextaccess=newaccess;
  215.                 }
  216.         }
  217.         if (!getlex(SEMI)) serror("Missing ';' after access list");
  218.  
  219.         if (!getkey(Ksymbols)) fatserror("Missing symbols");
  220.         while (id = getid()) {
  221.                 if (!getlex(COLON))
  222.                         serror("Missing ':' in symbolic name definition");
  223.                 if (!(delta=getnum())) {
  224.                         serror("Missing number in symbolic name definition");
  225.                 } else { /*add new pair to association list*/
  226.                         newassoc=(struct assoc *)talloc(sizeof(struct assoc));
  227.                         newassoc->symbol=id;
  228.                         newassoc->delta=delta;
  229.                         newassoc->nextassoc=nil;
  230.                         if (Symbols == nil) {
  231.                                 Symbols=LastSymbol=newassoc;
  232.                         } else {
  233.                                 LastSymbol=LastSymbol->nextassoc=newassoc;
  234.                         }
  235.                 }
  236.         }
  237.         if (!getlex(SEMI)) serror("Missing ';' after symbolic names");
  238.  
  239.         if (!getkey(Klocks)) serror("Missing locks");
  240.         while (id = getid()) {
  241.                 if (!getlex(COLON))
  242.                         serror("Missing ':' in lock");
  243.                 if (!(delta=getnum())) {
  244.                         serror("Missing number in lock");
  245.                 } else { /*add new pair to lock list*/
  246. #                       ifdef SYNDB
  247.                         if ((countnumflds(delta->num)%2)!=0)
  248.                                 serror("Delta number required for lock");
  249. #                       endif
  250.                         newlock=(struct lock *)talloc(sizeof(struct lock));
  251.                         newlock->login=id;
  252.                         newlock->delta=delta;
  253.                         newlock->nextlock=nil;
  254.                         if (Locks == nil) {
  255.                                 Locks=LastLock=newlock;
  256.                         } else {
  257.                                 LastLock=LastLock->nextlock=newlock;
  258.                         }
  259.                 }
  260.         }
  261.         if (!getlex(SEMI)) serror("Missing ';' after locks");
  262.         if (!getkey(Kstrict)) {
  263.                 StrictLocks = false;
  264.         } else {
  265.                 StrictLocks = true;
  266.                 if (!getlex(SEMI)) serror("Missing ';' after keyword %s",Kstrict);
  267.         }
  268.         if (getkey(Kcomment) && (nexttok==STRING)) {
  269.                 VOID savestring(Commleader,COMMLENGTH);nextlex();
  270.                 Comment=Commleader;
  271.                 if (!getlex(SEMI)) serror("Missing ';' after %s",Kcomment);
  272.         }
  273. }
  274.  
  275.  
  276.  
  277. getdelta()
  278. /* Function: reads a delta block.
  279.  * returns false if the current block does not start with a number.
  280.  */
  281. {
  282.         register struct hshentry * Delta, * num;
  283.         struct branchhead * LastBranch, * NewBranch;
  284.  
  285.         if (!(Delta=getnum())) return false;
  286. #       ifdef SYNDB
  287.         if ((countnumflds(Delta->num)%2)!=0)
  288.                 serror("Delta number required");
  289. #       endif
  290.  
  291.         hshenter = false; /*Don't enter dates into hashtable*/
  292.         Delta->date = getkeyval(Kdate, NUM, false);
  293.         hshenter=true;    /*reset hshenter for revision numbers.*/
  294.  
  295.         Delta->author = getkeyval(Kauthor, ID, false);
  296.  
  297.         Delta->state = getkeyval(Kstate, ID, true);
  298.  
  299.         if (!getkey(Kbranches)) fatserror("Missing branches");
  300.         Delta->branches = LastBranch=nil;
  301.         while (num=getnum()) {
  302. #               ifdef SYNDB
  303.                 if ((countnumflds(num->num)%2)!=0)
  304.                         serror("Delta number required");
  305. #               endif
  306.                 NewBranch = (struct branchhead *)talloc(sizeof(struct branchhead));
  307.                 NewBranch->hsh = num;
  308.                 NewBranch->nextbranch = nil;
  309.                 if (LastBranch == nil) {
  310.                         Delta->branches=LastBranch=NewBranch;
  311.                 } else {
  312.                         LastBranch=LastBranch->nextbranch=NewBranch;
  313.                 }
  314.         }
  315.         if (!getlex(SEMI)) serror("Missing ';' after branches");
  316.  
  317.         if (!getkey(Knext)) fatserror("Missing next");
  318.         Delta->next=num=getnum();
  319. #       ifdef SYNDB
  320.         if (num&&((countnumflds(num->num)%2)!=0))
  321.                 serror("Delta number required");
  322. #       endif
  323.         if (!getlex(SEMI)) serror("Missing ';' after next");
  324.         Delta->log=Delta->lockedby = nil;
  325.         Delta->selector = '\0';
  326.         TotalDeltas++;
  327.         return (true);
  328. }
  329.  
  330.  
  331. gettree()
  332. /* Function: Reads in the delta tree with getdelta(), then
  333.  * updates the lockedby fields.
  334.  */
  335. {       struct lock * currlock;
  336.         while (getdelta());
  337.         currlock=Locks;
  338.         while (currlock) {
  339.                 currlock->delta->lockedby = currlock->login;
  340.                 currlock = currlock->nextlock;
  341.         }
  342. }
  343.  
  344.  
  345. getdesc(prdesc)
  346. int  prdesc;
  347. /* Function: read in descriptive text
  348.  * nexttok is not advanced afterwards.
  349.  * if prdesc==true, the text is printed to stdout.
  350.  */
  351. {
  352.  
  353.         if (!getkey(Kdesc) || (nexttok!=STRING)) fatserror("Missing descriptive text");
  354.         if (prdesc)
  355.                 printstring();  /*echo string*/
  356.         else    readstring();   /*skip string*/
  357. }
  358.  
  359.  
  360.  
  361.  
  362.  
  363.  
  364. char * getkeyval(keyword, token, optional)
  365. enum tokens token; char * keyword; int optional;
  366. /* reads a pair of the form
  367.  * <keyword> <token> ;
  368.  * where token is one of <id> or <num>. optional indicates whether
  369.  * <token> is optional. A pointer to
  370.  * the acutal character string of <id> or <num) is returned.
  371.  * Getkeyval terminates the program on missing keyword or token, continues
  372.  * on missing ;.
  373.  */
  374. {
  375.         register char * val;
  376.  
  377.         if (!getkey(keyword)) {
  378.                 fatserror("Missing %s", keyword);
  379.         }
  380.         if (nexttok==token) {
  381.                 val = NextString;
  382.                 nextlex();
  383.         } else {
  384.                 if (!optional) {fatserror("Missing %s", keyword); }
  385.                 else val = nil;
  386.         }
  387.         if (!getlex(SEMI)) serror("Missing ';' after %s",keyword);
  388.         return(val);
  389. }
  390.  
  391.  
  392.  
  393.  
  394. putadmin(fout)
  395. register FILE * fout;
  396. /* Function: Print the <admin> node read with getadmin() to file fout.
  397.  * Assumption: Variables AccessList, Symbols, Locks, StrictLocks,
  398.  * and Head have been set.
  399.  */
  400. {       struct assoc  * curassoc;
  401.         struct lock   * curlock;
  402.         struct access * curaccess;
  403.         register char * sp;
  404.  
  405.         VOID fputs(Khead,fout); VOID fputs("     ",fout);
  406.         if (Head) VOID fputs(Head->num,fout);
  407.  
  408.         VOID fprintf(fout,";\n%s   ",Kbranch);
  409.         if (Dbranch) VOID fputs(Dbranch->num,fout);
  410.  
  411.         VOID fprintf(fout,";\n%s  ",Kaccess);
  412.         curaccess = AccessList;
  413.         if (curaccess==nil) VOID putc(' ',fout);
  414.         while (curaccess) {
  415.                VOID putc(' ',fout);
  416.                VOID fputs(curaccess->login,fout);
  417.                curaccess = curaccess->nextaccess;
  418.         }
  419.         VOID fprintf(fout,";\n%s ",Ksymbols);
  420.         curassoc = Symbols;
  421.         if (curassoc==nil) VOID putc(' ',fout);
  422.         while (curassoc) {
  423.                VOID fprintf(fout," %s:%s",curassoc->symbol, curassoc->delta->num);
  424.                curassoc = curassoc->nextassoc;
  425.         }
  426.         VOID fprintf(fout,";\n%s   ",Klocks);
  427.         curlock = Locks;
  428.         if (curlock==nil) VOID putc(' ',fout);
  429.         while (curlock) {
  430.                VOID fprintf(fout," %s:%s",curlock->login, curlock->delta->num);
  431.                curlock = curlock->nextlock;
  432.         }
  433.         if (StrictLocks) VOID fprintf(fout,"; %s",Kstrict);
  434.         VOID fprintf(fout,";\n%s  %c",Kcomment,SDELIM);
  435.         if((sp=Comment)!=nil) {
  436.                while (*sp) if (putc(*sp++,fout)==SDELIM) VOID putc(SDELIM,fout);
  437.         }
  438.         VOID fprintf(fout,"%c;\n\n",SDELIM);
  439. }
  440.  
  441.  
  442.  
  443.  
  444. putdelta(node,fout)
  445. register struct hshentry * node;
  446. register FILE * fout;
  447. /* Function: prints a <delta> node to fout;
  448.  */
  449. {      struct branchhead * nextbranch;
  450.  
  451.         if (node == nil) return;
  452.  
  453.         VOID fprintf(fout,"\n%s\n",node->num);
  454.         VOID fprintf(fout,"%s     %s;  %s %s;  %s ",
  455.                 Kdate,node->date,Kauthor,node->author,Kstate);
  456.         if (node->state!=nil) VOID fputs(node->state,fout);
  457.         VOID fputs(";\nbranches",fout);
  458.         nextbranch = node->branches;
  459.         if (nextbranch==nil) VOID putc(' ',fout);
  460.         while (nextbranch) {
  461.                VOID putc(' ',fout);
  462.                VOID fputs(nextbranch->hsh->num,fout);
  463.                nextbranch = nextbranch->nextbranch;
  464.         }
  465.  
  466.         VOID fprintf(fout,";\n%s     ",Knext);
  467.         if (node->next!=nil) VOID fputs(node->next->num,fout);
  468.         VOID fputs(";\n",fout);
  469.  
  470. }
  471.  
  472.  
  473.  
  474.  
  475. puttree(root,fout)
  476. struct hshentry * root;
  477. register FILE * fout;
  478. /* Function: prints the delta tree in preorder to fout, starting with root.
  479.  */
  480. {       struct branchhead * nextbranch;
  481.  
  482.         if (root==nil) return;
  483.  
  484.         if (root->selector !=DELETE)putdelta(root,fout);
  485.         /* selector DELETE means deleted; set by rcs -o */
  486.  
  487.         puttree(root->next,fout);
  488.  
  489.         nextbranch = root->branches;
  490.         while (nextbranch) {
  491.              puttree(nextbranch->hsh,fout);
  492.              nextbranch = nextbranch->nextbranch;
  493.         }
  494. }
  495.  
  496.  
  497.  
  498. int putdtext(num,log,srcfilename,fout)
  499. char * num, * log, * srcfilename; FILE * fout;
  500. /* Function: write a deltatext-node to fout.
  501.  * num points to the deltanumber, log to the logmessage, and
  502.  * sourcefile contains the text. Doubles up all SDELIMs in both the
  503.  * log and the text; Makes sure the log message ends in \n.
  504.  * returns false on error.
  505.  */
  506. {
  507.         register char * sp;
  508.     register int c;
  509.         register FILE * fin;
  510.  
  511.         VOID fprintf(fout,DELNUMFORM,num,Klog);
  512.         /* put log */
  513.         VOID putc(SDELIM,fout);
  514.         sp=log;
  515.         while (*sp) if (putc(*sp++,fout)==SDELIM) VOID putc(SDELIM,fout);
  516.         if (*(sp-1)!='\n') VOID putc('\n', fout); /*append \n if necessary*/
  517.         /* put text */
  518.         VOID fprintf(fout, "%c\n%s\n%c",SDELIM,Ktext,SDELIM);
  519.         if ((fin=fopen(srcfilename,"r"))==NULL) {
  520.                 error("Can't open source file %s",srcfilename);
  521.                 return false;
  522.         }
  523.         while ((c=fgetc(fin))!=EOF) {
  524.                 if (c==SDELIM) VOID putc(SDELIM,fout);   /*double up SDELIM*/
  525.                 VOID putc(c,fout);
  526.         }
  527.         VOID putc(SDELIM,fout); VOID putc('\n',fout);
  528.         VOID fclose(fin);
  529.         return true;
  530. }
  531.  
  532.  
  533.  
  534. #ifdef SYNTEST
  535.  
  536. main(argc,argv)
  537. int argc; char * argv[];
  538. {
  539.  
  540.         cmdid = "syntest";
  541.         if (argc<2) {
  542.                 VOID fputs("No input file\n",stderr);
  543.                 exit(-1);
  544.         }
  545.         if ((finptr=fopen(argv[1], "r")) == NULL) {
  546.                 faterror("Can't open input file %s\n",argv[1]);
  547.         }
  548.         Lexinit();
  549.         getadmin();
  550.         putadmin(stdout);
  551.  
  552.         gettree();
  553.         puttree(Head,stdout);
  554.  
  555.         getdesc(true);
  556.  
  557.         if (nextlex(),nexttok!=EOFILE) {
  558.                 fatserror("Syntax error");
  559.         }
  560.         exit(0);
  561. }
  562.  
  563.  
  564. cleanup(){}
  565. /*dummy*/
  566.  
  567.  
  568. #endif
  569.  
  570.