386BSD 0.1 development
authorWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Wed, 16 Aug 1989 04:40:34 +0000 (20:40 -0800)
committerWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Wed, 16 Aug 1989 04:40:34 +0000 (20:40 -0800)
Work on file usr/src/usr.bin/rcs/src/rcssyn.c

Co-Authored-By: Lynne Greer Jolitz <ljolitz@cardio.ucsf.edu>
Synthesized-from: 386BSD-0.1

usr/src/usr.bin/rcs/src/rcssyn.c [new file with mode: 0644]

diff --git a/usr/src/usr.bin/rcs/src/rcssyn.c b/usr/src/usr.bin/rcs/src/rcssyn.c
new file mode 100644 (file)
index 0000000..c317a60
--- /dev/null
@@ -0,0 +1,569 @@
+/*
+ *                     RCS file input
+ */
+#ifndef lint
+static char rcsid[]= "$Id: rcssyn.c,v 4.6 89/05/01 15:13:32 narten Exp $ Purdue CS";
+#endif
+/*********************************************************************************
+ *                       Syntax Analysis.
+ *                       Keyword table
+ *                       Testprogram: define SYNDB
+ *                       Compatibility with Release 2: define COMPAT2
+ *********************************************************************************
+ */
+
+/* Copyright (C) 1982, 1988, 1989 Walter Tichy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Walter Tichy.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Report all problems and direct all questions to:
+ *   rcs-bugs@cs.purdue.edu
+ * 
+
+
+
+
+
+
+
+*/
+
+
+/* $Log:       rcssyn.c,v $
+ * Revision 4.6  89/05/01  15:13:32  narten
+ * changed copyright header to reflect current distribution rules
+ * 
+ * Revision 4.5  88/11/08  12:00:37  narten
+ * changes from  eggert@sm.unisys.com (Paul Eggert)
+ * 
+ * Revision 4.5  88/08/09  19:13:21  eggert
+ * Allow cc -R; remove lint.
+ * 
+ * Revision 4.4  87/12/18  11:46:16  narten
+ * more lint cleanups (Guy Harris)
+ * 
+ * Revision 4.3  87/10/18  10:39:36  narten
+ * Updating version numbers. Changes relative to 1.1 actually relative to
+ * 4.1
+ * 
+ * Revision 1.3  87/09/24  14:00:49  narten
+ * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
+ * warnings)
+ * 
+ * Revision 1.2  87/03/27  14:22:40  jenkins
+ * Port to suns
+ * 
+ * Revision 1.1  84/01/23  14:50:40  kcs
+ * Initial revision
+ * 
+ * Revision 4.1  83/03/28  11:38:49  wft
+ * Added parsing and printing of default branch.
+ * 
+ * Revision 3.6  83/01/15  17:46:50  wft
+ * Changed readdelta() to initialize selector and log-pointer.
+ * Changed puttree to check for selector==DELETE; putdtext() uses DELNUMFORM.
+ *
+ * Revision 3.5  82/12/08  21:58:58  wft
+ * renamed Commentleader to Commleader.
+ *
+ * Revision 3.4  82/12/04  13:24:40  wft
+ * Added routine gettree(), which updates keeplock after reading the
+ * delta tree.
+ *
+ * Revision 3.3  82/11/28  21:30:11  wft
+ * Reading and printing of Suffix removed; version COMPAT2 skips the
+ * Suffix for files of release 2 format. Fixed problems with printing nil.
+ *
+ * Revision 3.2  82/10/18  21:18:25  wft
+ * renamed putdeltatext to putdtext.
+ *
+ * Revision 3.1  82/10/11  19:45:11  wft
+ * made sure getc() returns into an integer.
+ */
+
+
+
+/*
+#define COMPAT2
+/* version COMPAT2 reads files of the format of release 2 and 3, but
+ * generates files of release 3 format. Need not be defined if no
+ * old RCS files generated with release 2 exist.
+ */
+/*
+#define SYNDB
+/* version SYNDB is for debugging the syntax analysis for RCS files.
+ * SYNDB performs additional error checks.
+ */
+/*
+#define SYNTEST
+/* version SYNTEST inputs a RCS file and then prints out its internal
+ * data structures.
+*/
+
+#include "rcsbase.h"
+extern FILE * finptr;        /*RCS input file*/
+extern char * getid();
+extern struct hshentry * getnum();
+extern int    getkey();
+extern int    getlex();
+extern        readstring();
+extern        savestring();
+
+/* forward */
+char * getkeyval();
+
+/* keyword table */
+
+char Kaccess[]   = "access";
+char Kauthor[]   = "author";
+char Kbranch[]   = "branch";
+char Kbranches[] = "branches";
+char Kcomment[]  = "comment";
+char Kdate[]     = "date";
+char Kdesc[]     = "desc";
+char Khead[]     = "head";
+char Klocks[]    = "locks";
+char Klog[]      = "log";
+char Knext[]     = "next";
+char Kstate[]    = "state";
+char Kstrict[]   = "strict";
+#ifdef COMPAT2
+char Ksuffix[]   = "suffix";
+#endif
+char Ksymbols[]  = "symbols";
+char Ktext[]     = "text";
+
+#define COMMLENGTH 20
+char              Commleader[COMMLENGTH];
+char            * Comment;
+struct access   * AccessList;
+struct access   * LastAccess;
+struct assoc    * Symbols;
+struct assoc    * LastSymbol;
+struct lock     * Locks;
+struct lock     * LastLock;
+int               StrictLocks;
+struct hshentry * Head;
+struct hshentry * Dbranch;
+int               TotalDeltas;
+
+
+
+getadmin()
+/* Function: Reads an <admin> and initializes the globals
+ * AccessList, LastAccess, Symbols, LastSymbol,
+ * Locks, LastLock, StrictLocks, Head, Comment, TotalDeltas;
+ */
+{
+        register char   * id;
+        struct access   * newaccess;
+        struct assoc    * newassoc;
+        struct lock     * newlock;
+        struct hshentry * delta;
+
+        Comment="";
+        AccessList=LastAccess=nil;
+        Symbols=LastSymbol=nil;
+        Locks=LastLock=nil;
+        Dbranch = Head = nil;
+        TotalDeltas=0;
+
+        if (!getkey(Khead)) fatserror("Missing head");
+        Head=getnum();
+#       ifdef SYNDB
+        if (Head&&((countnumflds(Head->num)%2)!=0))
+                serror("Delta number required for head");
+#       endif
+        if (!getlex(SEMI)) serror("Missing ';' after head");
+
+        if (getkey(Kbranch)) { /* optional */
+                Dbranch=getnum();
+                if (!getlex(SEMI)) serror("Missing ';' after branch list");
+        }
+
+
+#ifdef COMPAT2
+        /* read suffix. Only in release 2 format */
+        if (getkey(Ksuffix)) {
+                if (nexttok==STRING) {
+                        readstring(); nextlex(); /*through away the suffix*/
+                } elsif(nexttok==ID) {
+                        nextlex();
+                }
+                if (!getlex(SEMI)) serror("Missing ';' after %s",Ksuffix);
+        }
+#endif
+
+        if (!getkey(Kaccess)) fatserror("Missing access list");
+        while (id=getid()) {
+                newaccess = (struct access *)talloc(sizeof(struct access));
+                newaccess->login = id;
+                newaccess->nextaccess = nil;
+                if (AccessList == nil) {
+                        AccessList=LastAccess=newaccess;
+                } else {
+                        LastAccess=LastAccess->nextaccess=newaccess;
+                }
+        }
+        if (!getlex(SEMI)) serror("Missing ';' after access list");
+
+        if (!getkey(Ksymbols)) fatserror("Missing symbols");
+        while (id = getid()) {
+                if (!getlex(COLON))
+                        serror("Missing ':' in symbolic name definition");
+                if (!(delta=getnum())) {
+                        serror("Missing number in symbolic name definition");
+                } else { /*add new pair to association list*/
+                        newassoc=(struct assoc *)talloc(sizeof(struct assoc));
+                        newassoc->symbol=id;
+                        newassoc->delta=delta;
+                        newassoc->nextassoc=nil;
+                        if (Symbols == nil) {
+                                Symbols=LastSymbol=newassoc;
+                        } else {
+                                LastSymbol=LastSymbol->nextassoc=newassoc;
+                        }
+                }
+        }
+        if (!getlex(SEMI)) serror("Missing ';' after symbolic names");
+
+        if (!getkey(Klocks)) serror("Missing locks");
+        while (id = getid()) {
+                if (!getlex(COLON))
+                        serror("Missing ':' in lock");
+                if (!(delta=getnum())) {
+                        serror("Missing number in lock");
+                } else { /*add new pair to lock list*/
+#                       ifdef SYNDB
+                        if ((countnumflds(delta->num)%2)!=0)
+                                serror("Delta number required for lock");
+#                       endif
+                        newlock=(struct lock *)talloc(sizeof(struct lock));
+                        newlock->login=id;
+                        newlock->delta=delta;
+                        newlock->nextlock=nil;
+                        if (Locks == nil) {
+                                Locks=LastLock=newlock;
+                        } else {
+                                LastLock=LastLock->nextlock=newlock;
+                        }
+                }
+        }
+        if (!getlex(SEMI)) serror("Missing ';' after locks");
+        if (!getkey(Kstrict)) {
+                StrictLocks = false;
+        } else {
+                StrictLocks = true;
+                if (!getlex(SEMI)) serror("Missing ';' after keyword %s",Kstrict);
+        }
+        if (getkey(Kcomment) && (nexttok==STRING)) {
+                VOID savestring(Commleader,COMMLENGTH);nextlex();
+                Comment=Commleader;
+                if (!getlex(SEMI)) serror("Missing ';' after %s",Kcomment);
+        }
+}
+
+
+
+getdelta()
+/* Function: reads a delta block.
+ * returns false if the current block does not start with a number.
+ */
+{
+        register struct hshentry * Delta, * num;
+        struct branchhead * LastBranch, * NewBranch;
+
+        if (!(Delta=getnum())) return false;
+#       ifdef SYNDB
+        if ((countnumflds(Delta->num)%2)!=0)
+                serror("Delta number required");
+#       endif
+
+        hshenter = false; /*Don't enter dates into hashtable*/
+        Delta->date = getkeyval(Kdate, NUM, false);
+        hshenter=true;    /*reset hshenter for revision numbers.*/
+
+        Delta->author = getkeyval(Kauthor, ID, false);
+
+        Delta->state = getkeyval(Kstate, ID, true);
+
+        if (!getkey(Kbranches)) fatserror("Missing branches");
+        Delta->branches = LastBranch=nil;
+        while (num=getnum()) {
+#               ifdef SYNDB
+                if ((countnumflds(num->num)%2)!=0)
+                        serror("Delta number required");
+#               endif
+                NewBranch = (struct branchhead *)talloc(sizeof(struct branchhead));
+                NewBranch->hsh = num;
+                NewBranch->nextbranch = nil;
+                if (LastBranch == nil) {
+                        Delta->branches=LastBranch=NewBranch;
+                } else {
+                        LastBranch=LastBranch->nextbranch=NewBranch;
+                }
+        }
+        if (!getlex(SEMI)) serror("Missing ';' after branches");
+
+        if (!getkey(Knext)) fatserror("Missing next");
+        Delta->next=num=getnum();
+#       ifdef SYNDB
+        if (num&&((countnumflds(num->num)%2)!=0))
+                serror("Delta number required");
+#       endif
+        if (!getlex(SEMI)) serror("Missing ';' after next");
+        Delta->log=Delta->lockedby = nil;
+        Delta->selector = '\0';
+        TotalDeltas++;
+        return (true);
+}
+
+
+gettree()
+/* Function: Reads in the delta tree with getdelta(), then
+ * updates the lockedby fields.
+ */
+{       struct lock * currlock;
+        while (getdelta());
+        currlock=Locks;
+        while (currlock) {
+                currlock->delta->lockedby = currlock->login;
+                currlock = currlock->nextlock;
+        }
+}
+
+
+getdesc(prdesc)
+int  prdesc;
+/* Function: read in descriptive text
+ * nexttok is not advanced afterwards.
+ * if prdesc==true, the text is printed to stdout.
+ */
+{
+
+        if (!getkey(Kdesc) || (nexttok!=STRING)) fatserror("Missing descriptive text");
+        if (prdesc)
+                printstring();  /*echo string*/
+        else    readstring();   /*skip string*/
+}
+
+
+
+
+
+
+char * getkeyval(keyword, token, optional)
+enum tokens token; char * keyword; int optional;
+/* reads a pair of the form
+ * <keyword> <token> ;
+ * where token is one of <id> or <num>. optional indicates whether
+ * <token> is optional. A pointer to
+ * the acutal character string of <id> or <num) is returned.
+ * Getkeyval terminates the program on missing keyword or token, continues
+ * on missing ;.
+ */
+{
+        register char * val;
+
+        if (!getkey(keyword)) {
+                fatserror("Missing %s", keyword);
+        }
+        if (nexttok==token) {
+                val = NextString;
+                nextlex();
+        } else {
+                if (!optional) {fatserror("Missing %s", keyword); }
+                else val = nil;
+        }
+        if (!getlex(SEMI)) serror("Missing ';' after %s",keyword);
+        return(val);
+}
+
+
+
+
+putadmin(fout)
+register FILE * fout;
+/* Function: Print the <admin> node read with getadmin() to file fout.
+ * Assumption: Variables AccessList, Symbols, Locks, StrictLocks,
+ * and Head have been set.
+ */
+{       struct assoc  * curassoc;
+        struct lock   * curlock;
+        struct access * curaccess;
+        register char * sp;
+
+        VOID fputs(Khead,fout); VOID fputs("     ",fout);
+        if (Head) VOID fputs(Head->num,fout);
+
+        VOID fprintf(fout,";\n%s   ",Kbranch);
+        if (Dbranch) VOID fputs(Dbranch->num,fout);
+
+        VOID fprintf(fout,";\n%s  ",Kaccess);
+        curaccess = AccessList;
+        if (curaccess==nil) VOID putc(' ',fout);
+        while (curaccess) {
+               VOID putc(' ',fout);
+               VOID fputs(curaccess->login,fout);
+               curaccess = curaccess->nextaccess;
+        }
+        VOID fprintf(fout,";\n%s ",Ksymbols);
+        curassoc = Symbols;
+        if (curassoc==nil) VOID putc(' ',fout);
+        while (curassoc) {
+               VOID fprintf(fout," %s:%s",curassoc->symbol, curassoc->delta->num);
+               curassoc = curassoc->nextassoc;
+        }
+        VOID fprintf(fout,";\n%s   ",Klocks);
+        curlock = Locks;
+        if (curlock==nil) VOID putc(' ',fout);
+        while (curlock) {
+               VOID fprintf(fout," %s:%s",curlock->login, curlock->delta->num);
+               curlock = curlock->nextlock;
+        }
+        if (StrictLocks) VOID fprintf(fout,"; %s",Kstrict);
+        VOID fprintf(fout,";\n%s  %c",Kcomment,SDELIM);
+        if((sp=Comment)!=nil) {
+               while (*sp) if (putc(*sp++,fout)==SDELIM) VOID putc(SDELIM,fout);
+        }
+        VOID fprintf(fout,"%c;\n\n",SDELIM);
+}
+
+
+
+
+putdelta(node,fout)
+register struct hshentry * node;
+register FILE * fout;
+/* Function: prints a <delta> node to fout;
+ */
+{      struct branchhead * nextbranch;
+
+        if (node == nil) return;
+
+        VOID fprintf(fout,"\n%s\n",node->num);
+        VOID fprintf(fout,"%s     %s;  %s %s;  %s ",
+                Kdate,node->date,Kauthor,node->author,Kstate);
+        if (node->state!=nil) VOID fputs(node->state,fout);
+        VOID fputs(";\nbranches",fout);
+        nextbranch = node->branches;
+        if (nextbranch==nil) VOID putc(' ',fout);
+        while (nextbranch) {
+               VOID putc(' ',fout);
+               VOID fputs(nextbranch->hsh->num,fout);
+               nextbranch = nextbranch->nextbranch;
+        }
+
+        VOID fprintf(fout,";\n%s     ",Knext);
+        if (node->next!=nil) VOID fputs(node->next->num,fout);
+        VOID fputs(";\n",fout);
+
+}
+
+
+
+
+puttree(root,fout)
+struct hshentry * root;
+register FILE * fout;
+/* Function: prints the delta tree in preorder to fout, starting with root.
+ */
+{       struct branchhead * nextbranch;
+
+        if (root==nil) return;
+
+        if (root->selector !=DELETE)putdelta(root,fout);
+        /* selector DELETE means deleted; set by rcs -o */
+
+        puttree(root->next,fout);
+
+        nextbranch = root->branches;
+        while (nextbranch) {
+             puttree(nextbranch->hsh,fout);
+             nextbranch = nextbranch->nextbranch;
+        }
+}
+
+
+
+int putdtext(num,log,srcfilename,fout)
+char * num, * log, * srcfilename; FILE * fout;
+/* Function: write a deltatext-node to fout.
+ * num points to the deltanumber, log to the logmessage, and
+ * sourcefile contains the text. Doubles up all SDELIMs in both the
+ * log and the text; Makes sure the log message ends in \n.
+ * returns false on error.
+ */
+{
+        register char * sp;
+       register int c;
+        register FILE * fin;
+
+        VOID fprintf(fout,DELNUMFORM,num,Klog);
+        /* put log */
+        VOID putc(SDELIM,fout);
+        sp=log;
+        while (*sp) if (putc(*sp++,fout)==SDELIM) VOID putc(SDELIM,fout);
+        if (*(sp-1)!='\n') VOID putc('\n', fout); /*append \n if necessary*/
+        /* put text */
+        VOID fprintf(fout, "%c\n%s\n%c",SDELIM,Ktext,SDELIM);
+        if ((fin=fopen(srcfilename,"r"))==NULL) {
+                error("Can't open source file %s",srcfilename);
+                return false;
+        }
+        while ((c=fgetc(fin))!=EOF) {
+                if (c==SDELIM) VOID putc(SDELIM,fout);   /*double up SDELIM*/
+                VOID putc(c,fout);
+        }
+        VOID putc(SDELIM,fout); VOID putc('\n',fout);
+        VOID fclose(fin);
+        return true;
+}
+
+
+
+#ifdef SYNTEST
+
+main(argc,argv)
+int argc; char * argv[];
+{
+
+        cmdid = "syntest";
+        if (argc<2) {
+                VOID fputs("No input file\n",stderr);
+                exit(-1);
+        }
+        if ((finptr=fopen(argv[1], "r")) == NULL) {
+                faterror("Can't open input file %s\n",argv[1]);
+        }
+        Lexinit();
+        getadmin();
+        putadmin(stdout);
+
+        gettree();
+        puttree(Head,stdout);
+
+        getdesc(true);
+
+        if (nextlex(),nexttok!=EOFILE) {
+                fatserror("Syntax error");
+        }
+        exit(0);
+}
+
+
+cleanup(){}
+/*dummy*/
+
+
+#endif
+