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