|
|
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.