No empty .Rs/.Re
[netbsd-mini2440.git] / usr.bin / rcs / src / rcssyn.c
blob4de5c07f4b195066e9abf38fdff90a7c857b2880
1 /*
2 * RCS file input
3 */
4 #ifndef lint
5 static char rcsid[]= "$Id: rcssyn.c,v 1.1 1993/03/21 09:58:09 cgd Exp $ Purdue CS";
6 #endif
7 /*********************************************************************************
8 * Syntax Analysis.
9 * Keyword table
10 * Testprogram: define SYNDB
11 * Compatibility with Release 2: define COMPAT2
12 *********************************************************************************
15 /* Copyright (C) 1982, 1988, 1989 Walter Tichy
16 * All rights reserved.
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.
28 * Report all problems and direct all questions to:
29 * rcs-bugs@cs.purdue.edu
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
45 * Revision 4.5 88/11/08 12:00:37 narten
46 * changes from eggert@sm.unisys.com (Paul Eggert)
48 * Revision 4.5 88/08/09 19:13:21 eggert
49 * Allow cc -R; remove lint.
51 * Revision 4.4 87/12/18 11:46:16 narten
52 * more lint cleanups (Guy Harris)
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
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)
62 * Revision 1.2 87/03/27 14:22:40 jenkins
63 * Port to suns
65 * Revision 1.1 84/01/23 14:50:40 kcs
66 * Initial revision
68 * Revision 4.1 83/03/28 11:38:49 wft
69 * Added parsing and printing of default branch.
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.
75 * Revision 3.5 82/12/08 21:58:58 wft
76 * renamed Commentleader to Commleader.
78 * Revision 3.4 82/12/04 13:24:40 wft
79 * Added routine gettree(), which updates keeplock after reading the
80 * delta tree.
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.
86 * Revision 3.2 82/10/18 21:18:25 wft
87 * renamed putdeltatext to putdtext.
89 * Revision 3.1 82/10/11 19:45:11 wft
90 * made sure getc() returns into an integer.
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.
102 #define SYNDB
103 /* version SYNDB is for debugging the syntax analysis for RCS files.
104 * SYNDB performs additional error checks.
107 #define SYNTEST
108 /* version SYNTEST inputs a RCS file and then prints out its internal
109 * data structures.
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();
121 /* forward */
122 char * getkeyval();
124 /* keyword table */
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";
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;
161 getadmin()
162 /* Function: Reads an <admin> and initializes the globals
163 * AccessList, LastAccess, Symbols, LastSymbol,
164 * Locks, LastLock, StrictLocks, Head, Comment, TotalDeltas;
167 register char * id;
168 struct access * newaccess;
169 struct assoc * newassoc;
170 struct lock * newlock;
171 struct hshentry * delta;
173 Comment="";
174 AccessList=LastAccess=nil;
175 Symbols=LastSymbol=nil;
176 Locks=LastLock=nil;
177 Dbranch = Head = nil;
178 TotalDeltas=0;
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");
188 if (getkey(Kbranch)) { /* optional */
189 Dbranch=getnum();
190 if (!getlex(SEMI)) serror("Missing ';' after branch list");
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();
202 if (!getlex(SEMI)) serror("Missing ';' after %s",Ksuffix);
204 #endif
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;
217 if (!getlex(SEMI)) serror("Missing ';' after access list");
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;
237 if (!getlex(SEMI)) serror("Missing ';' after symbolic names");
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;
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);
268 if (getkey(Kcomment) && (nexttok==STRING)) {
269 VOID savestring(Commleader,COMMLENGTH);nextlex();
270 Comment=Commleader;
271 if (!getlex(SEMI)) serror("Missing ';' after %s",Kcomment);
277 getdelta()
278 /* Function: reads a delta block.
279 * returns false if the current block does not start with a number.
282 register struct hshentry * Delta, * num;
283 struct branchhead * LastBranch, * NewBranch;
285 if (!(Delta=getnum())) return false;
286 # ifdef SYNDB
287 if ((countnumflds(Delta->num)%2)!=0)
288 serror("Delta number required");
289 # endif
291 hshenter = false; /*Don't enter dates into hashtable*/
292 Delta->date = getkeyval(Kdate, NUM, false);
293 hshenter=true; /*reset hshenter for revision numbers.*/
295 Delta->author = getkeyval(Kauthor, ID, false);
297 Delta->state = getkeyval(Kstate, ID, true);
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;
315 if (!getlex(SEMI)) serror("Missing ';' after branches");
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);
331 gettree()
332 /* Function: Reads in the delta tree with getdelta(), then
333 * updates the lockedby fields.
335 { struct lock * currlock;
336 while (getdelta());
337 currlock=Locks;
338 while (currlock) {
339 currlock->delta->lockedby = currlock->login;
340 currlock = currlock->nextlock;
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.
353 if (!getkey(Kdesc) || (nexttok!=STRING)) fatserror("Missing descriptive text");
354 if (prdesc)
355 printstring(); /*echo string*/
356 else readstring(); /*skip string*/
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 ;.
375 register char * val;
377 if (!getkey(keyword)) {
378 fatserror("Missing %s", keyword);
380 if (nexttok==token) {
381 val = NextString;
382 nextlex();
383 } else {
384 if (!optional) {fatserror("Missing %s", keyword); }
385 else val = nil;
387 if (!getlex(SEMI)) serror("Missing ';' after %s",keyword);
388 return(val);
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.
400 { struct assoc * curassoc;
401 struct lock * curlock;
402 struct access * curaccess;
403 register char * sp;
405 VOID fputs(Khead,fout); VOID fputs(" ",fout);
406 if (Head) VOID fputs(Head->num,fout);
408 VOID fprintf(fout,";\n%s ",Kbranch);
409 if (Dbranch) VOID fputs(Dbranch->num,fout);
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;
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;
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;
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);
438 VOID fprintf(fout,"%c;\n\n",SDELIM);
444 putdelta(node,fout)
445 register struct hshentry * node;
446 register FILE * fout;
447 /* Function: prints a <delta> node to fout;
449 { struct branchhead * nextbranch;
451 if (node == nil) return;
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;
466 VOID fprintf(fout,";\n%s ",Knext);
467 if (node->next!=nil) VOID fputs(node->next->num,fout);
468 VOID fputs(";\n",fout);
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.
480 { struct branchhead * nextbranch;
482 if (root==nil) return;
484 if (root->selector !=DELETE)putdelta(root,fout);
485 /* selector DELETE means deleted; set by rcs -o */
487 puttree(root->next,fout);
489 nextbranch = root->branches;
490 while (nextbranch) {
491 puttree(nextbranch->hsh,fout);
492 nextbranch = nextbranch->nextbranch;
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.
507 register char * sp;
508 register int c;
509 register FILE * fin;
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;
523 while ((c=fgetc(fin))!=EOF) {
524 if (c==SDELIM) VOID putc(SDELIM,fout); /*double up SDELIM*/
525 VOID putc(c,fout);
527 VOID putc(SDELIM,fout); VOID putc('\n',fout);
528 VOID fclose(fin);
529 return true;
534 #ifdef SYNTEST
536 main(argc,argv)
537 int argc; char * argv[];
540 cmdid = "syntest";
541 if (argc<2) {
542 VOID fputs("No input file\n",stderr);
543 exit(-1);
545 if ((finptr=fopen(argv[1], "r")) == NULL) {
546 faterror("Can't open input file %s\n",argv[1]);
548 Lexinit();
549 getadmin();
550 putadmin(stdout);
552 gettree();
553 puttree(Head,stdout);
555 getdesc(true);
557 if (nextlex(),nexttok!=EOFILE) {
558 fatserror("Syntax error");
560 exit(0);
564 cleanup(){}
565 /*dummy*/
568 #endif