|
|
1.1 root 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: * All rights reserved.
17: *
18: * Redistribution and use in source and binary forms are permitted
19: * provided that the above copyright notice and this paragraph are
20: * duplicated in all such forms and that any documentation,
21: * advertising materials, and other materials related to such
22: * distribution and use acknowledge that the software was developed
23: * by Walter Tichy.
24: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
25: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
26: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27: *
28: * Report all problems and direct all questions to:
29: * [email protected]
30: *
31:
32:
33:
34:
35:
36:
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 [email protected] (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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.