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