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