5 static char rcsid
[]= "$Id: rcssyn.c,v 1.1 1993/03/21 09:58:09 cgd Exp $ Purdue CS";
7 /*********************************************************************************
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
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
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
58 * Revision 1.3 87/09/24 14:00:49 narten
59 * Sources now pass through lint (if you ignore printf/sprintf/fprintf
62 * Revision 1.2 87/03/27 14:22:40 jenkins
65 * Revision 1.1 84/01/23 14:50:40 kcs
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
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.
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.
103 /* version SYNDB is for debugging the syntax analysis for RCS files.
104 * SYNDB performs additional error checks.
108 /* version SYNTEST inputs a RCS file and then prints out its internal
113 extern FILE * finptr
; /*RCS input file*/
114 extern char * getid();
115 extern struct hshentry
* getnum();
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";
136 char Knext
[] = "next";
137 char Kstate
[] = "state";
138 char Kstrict
[] = "strict";
140 char Ksuffix
[] = "suffix";
142 char Ksymbols
[] = "symbols";
143 char Ktext
[] = "text";
145 #define COMMLENGTH 20
146 char Commleader
[COMMLENGTH
];
148 struct access
* AccessList
;
149 struct access
* LastAccess
;
150 struct assoc
* Symbols
;
151 struct assoc
* LastSymbol
;
153 struct lock
* LastLock
;
155 struct hshentry
* Head
;
156 struct hshentry
* Dbranch
;
162 /* Function: Reads an <admin> and initializes the globals
163 * AccessList, LastAccess, Symbols, LastSymbol,
164 * Locks, LastLock, StrictLocks, Head, Comment, TotalDeltas;
168 struct access
* newaccess
;
169 struct assoc
* newassoc
;
170 struct lock
* newlock
;
171 struct hshentry
* delta
;
174 AccessList
=LastAccess
=nil
;
175 Symbols
=LastSymbol
=nil
;
177 Dbranch
= Head
= nil
;
180 if (!getkey(Khead
)) fatserror("Missing head");
183 if (Head
&&((countnumflds(Head
->num
)%2)!=0))
184 serror("Delta number required for head");
186 if (!getlex(SEMI
)) serror("Missing ';' after head");
188 if (getkey(Kbranch
)) { /* optional */
190 if (!getlex(SEMI
)) serror("Missing ';' after branch list");
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
) {
202 if (!getlex(SEMI
)) serror("Missing ';' after %s",Ksuffix
);
206 if (!getkey(Kaccess
)) fatserror("Missing access list");
208 newaccess
= (struct access
*)talloc(sizeof(struct access
));
209 newaccess
->login
= id
;
210 newaccess
->nextaccess
= nil
;
211 if (AccessList
== nil
) {
212 AccessList
=LastAccess
=newaccess
;
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()) {
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
));
228 newassoc
->delta
=delta
;
229 newassoc
->nextassoc
=nil
;
230 if (Symbols
== nil
) {
231 Symbols
=LastSymbol
=newassoc
;
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()) {
242 serror("Missing ':' in lock");
243 if (!(delta
=getnum())) {
244 serror("Missing number in lock");
245 } else { /*add new pair to lock list*/
247 if ((countnumflds(delta
->num
)%2)!=0)
248 serror("Delta number required for lock");
250 newlock
=(struct lock
*)talloc(sizeof(struct lock
));
252 newlock
->delta
=delta
;
253 newlock
->nextlock
=nil
;
255 Locks
=LastLock
=newlock
;
257 LastLock
=LastLock
->nextlock
=newlock
;
261 if (!getlex(SEMI
)) serror("Missing ';' after locks");
262 if (!getkey(Kstrict
)) {
266 if (!getlex(SEMI
)) serror("Missing ';' after keyword %s",Kstrict
);
268 if (getkey(Kcomment
) && (nexttok
==STRING
)) {
269 VOID
savestring(Commleader
,COMMLENGTH
);nextlex();
271 if (!getlex(SEMI
)) serror("Missing ';' after %s",Kcomment
);
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;
287 if ((countnumflds(Delta
->num
)%2)!=0)
288 serror("Delta number required");
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()) {
303 if ((countnumflds(num
->num
)%2)!=0)
304 serror("Delta number required");
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
;
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();
320 if (num
&&((countnumflds(num
->num
)%2)!=0))
321 serror("Delta number required");
323 if (!getlex(SEMI
)) serror("Missing ';' after next");
324 Delta
->log
=Delta
->lockedby
= nil
;
325 Delta
->selector
= '\0';
332 /* Function: Reads in the delta tree with getdelta(), then
333 * updates the lockedby fields.
335 { struct lock
* currlock
;
339 currlock
->delta
->lockedby
= currlock
->login
;
340 currlock
= currlock
->nextlock
;
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");
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
377 if (!getkey(keyword
)) {
378 fatserror("Missing %s", keyword
);
380 if (nexttok
==token
) {
384 if (!optional
) {fatserror("Missing %s", keyword
); }
387 if (!getlex(SEMI
)) serror("Missing ';' after %s",keyword
);
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
;
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
);
416 VOID
fputs(curaccess
->login
,fout
);
417 curaccess
= curaccess
->nextaccess
;
419 VOID
fprintf(fout
,";\n%s ",Ksymbols
);
421 if (curassoc
==nil
) VOID
putc(' ',fout
);
423 VOID
fprintf(fout
," %s:%s",curassoc
->symbol
, curassoc
->delta
->num
);
424 curassoc
= curassoc
->nextassoc
;
426 VOID
fprintf(fout
,";\n%s ",Klocks
);
428 if (curlock
==nil
) VOID
putc(' ',fout
);
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
);
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
);
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
);
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
;
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.
511 VOID
fprintf(fout
,DELNUMFORM
,num
,Klog
);
513 VOID
putc(SDELIM
,fout
);
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*/
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
);
523 while ((c
=fgetc(fin
))!=EOF
) {
524 if (c
==SDELIM
) VOID
putc(SDELIM
,fout
); /*double up SDELIM*/
527 VOID
putc(SDELIM
,fout
); VOID
putc('\n',fout
);
537 int argc
; char * argv
[];
542 VOID
fputs("No input file\n",stderr
);
545 if ((finptr
=fopen(argv
[1], "r")) == NULL
) {
546 faterror("Can't open input file %s\n",argv
[1]);
553 puttree(Head
,stdout
);
557 if (nextlex(),nexttok
!=EOFILE
) {
558 fatserror("Syntax error");