[comp.sources.amiga] v89i225: rcs - revision control system, Part10/14

page%swap@Sun.COM (Bob Page) (11/19/89)

Submitted-by: rsbx@cbmvax.commodore.com (Raymond S. Brand)
Posting-number: Volume 89, Issue 225
Archive-name: unix/rcs.10

# This is a shell archive.
# Remove anything above and including the cut line.
# Then run the rest of the file through 'sh'.
# Unpacked files will be owned by you and have default permissions.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: SHell ARchive
# Run the following text through 'sh' to create:
#	rcs/rcs.rcsfiles/rcsgen.c,v
#	rcs/rcs.rcsfiles/rcskeep.c,v
#	rcs/rcs.rcsfiles/rcskeys.c,v
#	rcs/rcs.rcsfiles/rcslex.c,v
#	rcs/rcs.rcsfiles/rcsrev.c,v
# This is archive 10 of a 14-part kit.
# This archive created: Sun Nov 19 01:12:10 1989
if `test ! -d rcs`
then
  mkdir rcs
  echo "mkdir rcs"
fi
if `test ! -d rcs/rcs.rcsfiles`
then
  mkdir rcs/rcs.rcsfiles
  echo "mkdir rcs/rcs.rcsfiles"
fi
echo "extracting rcs/rcs.rcsfiles/rcsgen.c,v"
sed 's/^X//' << \SHAR_EOF > rcs/rcs.rcsfiles/rcsgen.c,v
Xhead     4.7;
Xbranch   4.7.2;
Xaccess   ;
Xsymbols  amiga_rcs:4.7.2 cbmvax_source:4.7.1 uunet_june89_dist:4.7;
Xlocks    ; strict;
Xcomment  @ * @;
X
X
X4.7
Xdate     89.05.01.15.12.49;  author narten;  state Exp;
Xbranches 4.7.1.1 4.7.2.1;
Xnext     ;
X
X4.7.1.1
Xdate     89.08.11.01.42.41;  author rsbx;  state Exp;
Xbranches ;
Xnext     ;
X
X4.7.2.1
Xdate     89.10.13.19.18.42;  author rsbx;  state Exp;
Xbranches ;
Xnext     4.7.2.2;
X
X4.7.2.2
Xdate     89.10.15.15.44.33;  author rsbx;  state Exp;
Xbranches ;
Xnext     4.7.2.3;
X
X4.7.2.3
Xdate     89.11.09.21.29.00;  author rsbx;  state Exp;
Xbranches ;
Xnext     ;
X
X
Xdesc
X@RCS revision generation.
X@
X
X
X
X4.7
Xlog
X@checked in with -k by rsbx at 89.08.10.16.21.17.
X@
Xtext
X@/*
X *                     RCS revision generation
X */
X#ifndef lint
Xstatic char rcsid[]= "$Id: rcsgen.c,v 4.7 89/05/01 15:12:49 narten Exp $ Purdue CS";
X#endif
X
X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by Walter Tichy.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X * Report all problems and direct all questions to:
X *   rcs-bugs@@cs.purdue.edu
X * 
X
X
X
X
X
X
X
X*/
X
X
X
X/* $Log:	rcsgen.c,v $
X * Revision 4.7  89/05/01  15:12:49  narten
X * changed copyright header to reflect current distribution rules
X * 
X * Revision 4.6  88/11/08  12:01:13  narten
X * changes from  eggert@@sm.unisys.com (Paul Eggert)
X * 
X * Revision 4.6  88/08/28  14:59:10  eggert
X * Shrink stdio code size; allow cc -R; remove lint; isatty() -> ttystdin()
X * 
X * Revision 4.5  87/12/18  11:43:25  narten
X * additional lint cleanups, and a bug fix from the 4.3BSD version that
X * keeps "ci" from sticking a '\377' into the description if you run it
X * with a zero-length file as the description. (Guy Harris)
X * 
X * Revision 4.4  87/10/18  10:35:10  narten
X * Updating version numbers. Changes relative to 1.1 actually relative to
X * 4.2
X * 
X * Revision 1.3  87/09/24  13:59:51  narten
X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
X * warnings)
X * 
X * Revision 1.2  87/03/27  14:22:27  jenkins
X * Port to suns
X * 
X * Revision 1.1  84/01/23  14:50:28  kcs
X * Initial revision
X * 
X * Revision 4.2  83/12/02  23:01:39  wft
X * merged 4.1 and 3.3.1.1 (clearerr(stdin)).
X * 
X * Revision 4.1  83/05/10  16:03:33  wft
X * Changed putamin() to abort if trying to reread redirected stdin.
X * Fixed getdesc() to output a prompt on initial newline.
X * 
X * Revision 3.3.1.1  83/10/19  04:21:51  lepreau
X * Added clearerr(stdin) for re-reading description from stdin.
X * 
X * Revision 3.3  82/11/28  21:36:49  wft
X * 4.2 prerelease
X * 
X * Revision 3.3  82/11/28  21:36:49  wft
X * Replaced ferror() followed by fclose() with ffclose().
X * Putdesc() now suppresses the prompts if stdin
X * is not a terminal. A pointer to the current log message is now
X * inserted into the corresponding delta, rather than leaving it in a
X * global variable.
X *
X * Revision 3.2  82/10/18  21:11:26  wft
X * I added checks for write errors during editing, and improved
X * the prompt on putdesc().
X *
X * Revision 3.1  82/10/13  15:55:09  wft
X * corrected type of variables assigned to by getc (char --> int)
X */
X
X
X
X
X#include "rcsbase.h"
X
Xextern struct hshentry * getnum();
Xextern FILE * fopen();
Xextern savestring();
Xextern editstring();
X
Xextern int nextc;          /* next character from lexical analyzer          */
Xextern char Ktext[];       /* keywords from syntax analyzer                 */
Xextern char Klog[];        /* Keyword "log"                                 */
Xextern char Kdesc[];       /* Keyword for description                       */
Xextern FILE * frewrite;    /* new RCS file                                  */
Xextern FILE * fcopy;       /* result file during editing                    */
Xextern char * resultfile;  /* file name for fcopy                           */
Xextern int    rewriteflag; /* indicates whether to rewrite the input file   */
X
X
Xchar    curlogmsg[logsize]; /* buffer for current log message                */
X
Xenum stringwork {copy, edit, expand, edit_expand };
X/* parameter to scandeltatext() */
X
X
X
X
Xchar * buildrevision(deltas, target, dir, expandflag)
Xstruct hshentry ** deltas, * target;
Xchar * dir; int expandflag;
X/* Function: Generates the revision given by target
X * by retrieving all deltas given by parameter deltas and combining them.
X * If dir==nil, the revision is printed on the standard output,
X * otherwise written into a temporary file in directory dir.
X * if expandflag==true, keyword expansion is performed.
X * returns false on errors, the name of the file with the revision otherwise.
X *
X * Algorithm: Copy inital revision unchanged. Then edit all revisions but
X * the last one into it, alternating input and output files (resultfile and
X * editfile). The last revision is then edited in, performing simultaneous
X * keyword substitution (this saves one extra pass).
X * All this simplifies if only one revision needs to be generated,
X * or no keyword expansion is necessary, or if output goes to stdout.
X */
X{
X        int i;
X
X        if (deltas[0]==target) {
X                /* only latest revision to generate */
X                if (dir==nil) {/* print directly to stdout */
X                        fcopy=stdout;
X                        scandeltatext(target,expand);
X                        return(char *) true;
X                } else {
X                        initeditfiles(dir);
X                        scandeltatext(target,expandflag?expand:copy);
X                        ffclose(fcopy);
X                        return(resultfile);
X                }
X        } else {
X                /* several revisions to generate */
X                initeditfiles(dir?dir:"/tmp/");
X                /* write initial revision into fcopy, no keyword expansion */
X                scandeltatext(deltas[0],copy);
X                i = 1;
X                while (deltas[i+1] != nil) {
X                        /* do all deltas except last one */
X                        scandeltatext(deltas[i++],edit);
X                }
X                if (!expandflag) {
X                        /* no keyword expansion; only invoked from ci */
X                        scandeltatext(deltas[i],edit);
X                        finishedit((struct hshentry *)nil);
X                        ffclose(fcopy);
X                } else {
X                        /* perform keyword expansion*/
X                        /* first, get to beginning of file*/
X                        finishedit((struct hshentry *)nil); swapeditfiles(dir==nil);
X                        scandeltatext(deltas[i],edit_expand);
X                        finishedit(deltas[i]);
X                        if (dir!=nil) ffclose(fcopy);
X                }
X                return(resultfile); /*doesn't matter for dir==nil*/
X        }
X}
X
X
X
Xscandeltatext(delta,func)
Xstruct hshentry * delta; enum stringwork func;
X/* Function: Scans delta text nodes up to and including the one given
X * by delta. For the one given by delta, the log message is saved into
X * curlogmsg and the text is processed according to parameter func.
X * Assumes the initial lexeme must be read in first.
X * Does not advance nexttok after it is finished.
X */
X{       struct hshentry * nextdelta;
X
X        do {
X                nextlex();
X                if (!(nextdelta=getnum())) {
X                        fatserror("Can't find delta for revision %s", delta->num);
X                }
X                if (!getkey(Klog) || nexttok!=STRING)
X                        serror("Missing log entry");
X                elsif (delta==nextdelta) {
X                        VOID savestring(curlogmsg,logsize);
X                        delta->log=curlogmsg;
X                } else {readstring();
X                        delta->log= "";
X                }
X                nextlex();
X                if (!getkey(Ktext) || nexttok!=STRING)
X                        fatserror("Missing delta text");
X
X                if(delta==nextdelta)
X                        /* got the one we're looking for */
X                        switch (func) {
X                        case copy:      copystring();
X                                        break;
X                        case expand:    xpandstring(delta);
X                                        break;
X                        case edit:      editstring((struct hshentry *)nil);
X                                        break;
X                        case edit_expand: editstring(delta);
X                                        break;
X                        }
X                else    readstring(); /* skip over it */
X
X        } while (delta!=nextdelta);
X}
X
X
Xint stdinread; /* stdinread>0 if redirected stdin has been read once */
X
Xint ttystdin()
X{
X	static int initialized, istty;
X	if (!initialized) {
X		istty = isatty(fileno(stdin));
X		initialized = 1;
X	}
X	return istty;
X}
X
Xputdesc(initflag,textflag,textfile,quietflag)
Xint initflag,textflag; char * textfile; int quietflag;
X/* Function: puts the descriptive text into file frewrite.
X * if !initflag && !textflag, the text is copied from the old description.
X * Otherwise, if the textfile!=nil, the text is read from that
X * file, or from stdin, if textfile==nil.
X * Increments stdinread if text is read from redirected stdin.
X * if initflag&&quietflag&&!textflag, an empty text is inserted.
X * if !initflag, the old descriptive text is discarded.
X */
X{       register FILE * txt; register int c, old1, old2;
X	register FILE * frew;
X#ifdef lint
X	if (quietflag ==  0) initflag = quietflag; /* silencelint */
X#endif
X
X	frew = frewrite;
X        if (!initflag && !textflag) {
X                /* copy old description */
X                VOID fprintf(frew,"\n\n%s%c",Kdesc,nextc);
X                rewriteflag=true; getdesc(false);
X        } else {
X                /* get new description */
X               if (!initflag) {
X                        /*skip old description*/
X                        rewriteflag=false; getdesc(false);
X                }
X                VOID fprintf(frew,"\n\n%s\n%c",Kdesc,SDELIM);
X                if (textfile) {
X                        old1='\n';
X                        /* copy textfile */
X                        if ((txt=fopen(textfile,"r"))!=NULL) {
X                                while ((c=getc(txt))!=EOF) {
X                                        if (c==SDELIM) VOID putc(c,frew); /*double up*/
X                                        VOID putc(c,frew);
X                                        old1=c;
X                                }
X                                if (old1!='\n') VOID putc('\n',frew);
X                                VOID fclose(txt);
X				VOID putc(SDELIM,frew);
X				VOID fputs("\n\n", frew);
X				return;
X                        } else {
X                                error("Can't open file %s with description",textfile);
X                                if (!ttystdin()) return;
X                                /* otherwise, get description from terminal */
X                        }
X                }
X                /* read text from stdin */
X                if (ttystdin()) {
X                    VOID fputs("enter description, terminated with ^D or '.':\n",stderr);
X                    VOID fputs("NOTE: This is NOT the log message!\n>> ",stderr);
X		    if (feof(stdin))
X		            clearerr(stdin);
X                } else {  /* redirected stdin */
X                    if (stdinread>0)
X                        faterror("Can't reread redirected stdin for description; use -t<file>");
X                    stdinread++;
X                }
X                c = '\0'; old2= '\n';
X                if ((old1=getchar())==EOF) {
X                        if (ttystdin()) {
X                             VOID putc('\n',stderr);
X                             clearerr(stdin);
X			}
X		} else {
X		     if (old1=='\n' && ttystdin())
X			 VOID fputs(">> ",stderr);
X		     for (;;) {
X                            c=getchar();
X                            if (c==EOF) {
X                                    if (ttystdin()) {
X                                            VOID putc('\n',stderr);
X                                            clearerr(stdin);
X				    }
X                                    VOID putc(old1,frew);
X                                    if (old1!='\n') VOID putc('\n',frew);
X                                    break;
X                            }
X                            if (c=='\n' && old1=='.' && old2=='\n') {
X                                    break;
X                            }
X                            if (c=='\n' && ttystdin()) VOID fputs(">> ",stderr);
X			    if(old1==SDELIM) VOID putc(old1,frew); /* double up*/
X			    VOID putc(old1,frew);
X                            old2=old1;
X                            old1=c;
X                    } /* end for */
X		}
X		VOID putc(SDELIM,frew); VOID fputs("\n\n",frew);
X        }
X}
X@
X
X
X4.7.2.1
Xlog
X@Start of Amiga RCS port branch.
X@
Xtext
X@d5 1
Xa5 5
X<<<<<<< rcsgen.c
Xstatic char rcsid[]= "$Id: rcsgen.c,v 4.7.1.1 89/08/11 01:42:41 rsbx Exp Locker: rsbx $ Purdue CS";
X=======
Xstatic char rcsid[]= "$Id: rcsgen.c,v 1.2 89/09/17 13:35:51 rick Exp $ Purdue CS";
X>>>>>>> 1.2
Xa35 11
X<<<<<<< rcsgen.c
X * Revision 4.7.1.1  89/08/11  01:42:41  rsbx
X * Start of cbmvax RCS source branch.
X=======
X * Revision 1.2  89/09/17  13:35:51  rick
X * Port to AmigaDos done by Rick Schaeffer (ricks@@iscuva.iscs.com)
X * All changes done with conditional compile (#ifdef AMIGA).  This version
X * compiles correctly with Lattice C version 5.02 or later.
X>>>>>>> 1.2
X * 
X<<<<<<< rcsgen.c
Xa36 3
X * checked in with -k by rsbx at 89.08.10.16.21.17.
X * 
X * Revision 4.7  89/05/01  15:12:49  narten
Xa44 8
X=======
X * Revision 1.3  89/09/16  09:43:28  rick
X * Modified AMIGA changes to work with Lattice C
X * 
X * Revision 1.2  88/09/03  15:10:56  rick
X * Port to AmigaDos.  All done with conditional compiles
X * 
X>>>>>>> 1.2
Xa111 1
X<<<<<<< rcsgen.c
Xa112 4
X=======
Xchar    curlogmsg[logsize] /* buffer for current log message                */
X        ="";
X>>>>>>> 1.2
Xa153 3
X#ifdef AMIGA
X                initeditfiles(dir?dir:"t:");
X#else
Xa154 1
X#endif
Xa289 3
X#ifdef AMIGA
X		    fflush(stderr);
X#endif
Xa303 1
X<<<<<<< rcsgen.c
Xa304 3
X=======
X		     if (old1=='\n' && isatty(fileno(stdin))) {
X>>>>>>> 1.2
Xa305 4
X#ifdef AMIGA
X			 fflush(stderr);
X#endif
X			 }
Xa319 1
X<<<<<<< rcsgen.c
Xa322 10
X=======
X                            if (c=='\n' && isatty(fileno(stdin))) {
X                            	VOID fputs(">> ",stderr);
X#ifdef AMIGA
X				fflush(stderr);
X#endif
X				}
X                            if(old1==SDELIM) VOID putc(old1,frewrite); /* double up*/
X                            VOID putc(old1,frewrite);
X>>>>>>> 1.2
X@
X
X
X4.7.2.2
Xlog
X@Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS
Xsources I have here (and are later than the ones Rick used).
X@
Xtext
X@d5 5
Xa9 1
Xstatic char rcsid[]= "$Id: rcsgen.c,v 4.7.2.1 89/10/13 19:18:42 rsbx Exp Locker: rsbx $ Purdue CS";
Xd40 1
Xa40 3
X * Revision 4.7.2.1  89/10/13  19:18:42  rsbx
X * Start of Amiga RCS port branch.
X * 
Xd43 6
Xd50 1
Xd63 8
Xd138 3
Xd143 1
Xd335 1
Xa335 1
X                old2= '\n';
Xd342 3
Xd346 1
Xd366 5
Xd379 1
X@
X
X
X4.7.2.3
Xlog
X@Changed "^D" to "^\".
X@
Xtext
X@d5 1
Xa5 1
Xstatic char rcsid[]= "$Id: rcsgen.c,v 4.7.2.2 89/10/15 15:44:33 rsbx Exp Locker: rsbx $ Purdue CS";
Xa35 4
X * Revision 4.7.2.2  89/10/15  15:44:33  rsbx
X * Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS
X * sources I have here (and are later than the ones Rick used).
X * 
Xa301 3
X#ifdef AMIGA
X                    VOID fputs("enter description, terminated with ^\\ or '.':\n",stderr);
X#else
Xa302 1
X#endif
X@
X
X
X4.7.1.1
Xlog
X@Start of cbmvax RCS source branch.
X@
Xtext
X@a36 3
X * checked in with -k by rsbx at 89.08.10.16.21.17.
X * 
X * Revision 4.7  89/05/01  15:12:49  narten
X@
SHAR_EOF
echo "extracting rcs/rcs.rcsfiles/rcskeep.c,v"
sed 's/^X//' << \SHAR_EOF > rcs/rcs.rcsfiles/rcskeep.c,v
Xhead     4.6;
Xbranch   4.6.2;
Xaccess   ;
Xsymbols  amiga_rcs:4.6.2 cbmvax_source:4.6.1 uunet_june89_dist:4.6;
Xlocks    ; strict;
Xcomment  @ * @;
X
X
X4.6
Xdate     89.05.01.15.12.56;  author narten;  state Exp;
Xbranches 4.6.1.1 4.6.2.1;
Xnext     ;
X
X4.6.1.1
Xdate     89.08.11.01.42.46;  author rsbx;  state Exp;
Xbranches ;
Xnext     ;
X
X4.6.2.1
Xdate     89.10.13.19.18.47;  author rsbx;  state Exp;
Xbranches ;
Xnext     4.6.2.2;
X
X4.6.2.2
Xdate     89.10.15.15.44.38;  author rsbx;  state Exp;
Xbranches ;
Xnext     ;
X
X
Xdesc
X@RCS keyword extraction.
X@
X
X
X
X4.6
Xlog
X@checked in with -k by rsbx at 89.08.10.16.21.35.
X@
Xtext
X@/*
X *                     RCS keyword extraction
X */
X#ifndef lint
Xstatic char rcsid[]= "$Id: rcskeep.c,v 4.6 89/05/01 15:12:56 narten Exp $ Purdue CS";
X#endif
X/*****************************************************************************
X *                       main routine: getoldkeys()
X *                       Testprogram: define KEEPTEST
X *****************************************************************************
X */
X
X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by Walter Tichy.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X * Report all problems and direct all questions to:
X *   rcs-bugs@@cs.purdue.edu
X * 
X
X
X
X
X
X
X
X*/
X
X
X
X/* $Log:	rcskeep.c,v $
X * Revision 4.6  89/05/01  15:12:56  narten
X * changed copyright header to reflect current distribution rules
X * 
X * Revision 4.5  88/11/08  12:01:05  narten
X * changes from  eggert@@sm.unisys.com (Paul Eggert)
X * 
X * Revision 4.5  88/08/09  19:13:03  eggert
X * Remove lint and speed up by making FILE *fp local, not global.
X * 
X * Revision 4.4  87/12/18  11:44:21  narten
X * more lint cleanups (Guy Harris)
X * 
X * Revision 4.3  87/10/18  10:35:50  narten
X * Updating version numbers. Changes relative to 1.1 actually relative
X * to 4.1
X * 
X * Revision 1.3  87/09/24  14:00:00  narten
X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
X * warnings)
X * 
X * Revision 1.2  87/03/27  14:22:29  jenkins
X * Port to suns
X * 
X * Revision 1.1  84/01/23  14:50:30  kcs
X * Initial revision
X * 
X * Revision 4.1  83/05/10  16:26:44  wft
X * Added new markers Id and RCSfile; extraction added.
X * Marker matching with trymatch().
X * 
X * Revision 3.2  82/12/24  12:08:26  wft
X * added missing #endif.
X *
X * Revision 3.1  82/12/04  13:22:41  wft
X * Initial revision.
X *
X */
X
X/*
X#define KEEPTEST
X/* Testprogram; prints out the keyword values found. */
X
X#include  "rcsbase.h"
Xextern char * checkid();
Xextern FILE * fopen();
Xstatic int getval();
Xextern enum markers trymatch();
X
X#define IDLENGTH 30
Xchar prevauthor[IDLENGTH];
Xchar prevdate[datelength];
Xchar prevRCS[NCPFN];
Xchar prevrev[revlength];
Xchar prevsource[NCPPN];
Xchar prevstate [IDLENGTH];
Xchar prevlocker[IDLENGTH];
Xchar dummy[IDLENGTH];
X
Xgetoldkeys(fname)
Xchar * fname;
X/* Function: Tries to read keyword values for author, date,
X * revision number, RCS file, (both with and without path),
X * state, and workfilename out of the file fname.
X * The results are placed into
X * prevauthor, prevdate, prevRCS, prevrev, prevsource, prevstate.
X * Aborts immediately if it finds an error and returns false.
X * If it returns true, it doesn't mean that any of the
X * values were found; instead, check to see whether the corresponding arrays
X * contain the empty string.
X */
X{
X    register FILE *fp;
X    register int c;
X    char keyword[keylength+2];
X    register char * tp;
X    enum markers mresult;
X
X    /* initialize to empty */
X    prevauthor[0]=prevsource[0]=prevstate[0]=prevdate[0]=prevrev[0]= '\0';
X
X    if ( (fp = fopen(fname, "r") ) == NULL ) {
X       error("Can't open %s\n", fname);
X       return false;
X    }
X    while( (c=getc(fp)) != EOF) {
X        if ( c==KDELIM) {
X            /* try to get keyword */
X            tp = keyword;
X	    while( (c=getc(fp))!=EOF && (tp< keyword+keylength) && (c!='\n')
X		   && (c!=KDELIM) && (c!=VDELIM))
X		  *tp++ = c;
X
X            if (c==KDELIM) {VOID ungetc(c,fp);continue;}
X            if (c!=VDELIM) continue;
X	    *tp++ = c;
X            *tp='\0';
X            while ((c=getc(fp))==' '||c=='\t'); /* skip blanks */
X            VOID ungetc(c,fp); /* needed for getval */
X
X	    switch (mresult=trymatch(keyword,true)) {
X            case Author:
X		if (getval(fp,prevauthor,IDLENGTH,true))
X                    if (!checkid(prevauthor, '\0')) goto errexit;
X                break;
X            case Date:
X		if (!getprevdate(fp,true)) goto errexit;
X                break;
X            case Header:
X            case Id:
X		if (mresult==Header) {
X		    if (!getval(fp,prevsource,NCPPN,true)) break; /*unexpanded*/
X		} else {
X		    if (!getval(fp,prevRCS,NCPFN,true))    break; /*unexpanded*/
X		}
X		if (!getval(fp,prevrev,revlength,false)) goto errexit;
X		if (!checknum(prevrev,-1)) {
X		    error("Bad revision number");
X		    goto errexit;
X		}
X		if (!getprevdate(fp,false)) goto errexit;
X		if (!getval(fp,prevauthor,IDLENGTH,false)) goto errexit;
X		if (!checkid(prevauthor, '\0')) goto errexit;
X		if (!getval(fp,prevstate,IDLENGTH,false)) goto errexit;
X		if (!checkid(prevstate, '\0')) goto errexit;
X		VOID getval(fp, dummy, IDLENGTH, true);    /* optional locker*/
X		VOID getval(fp, prevlocker,IDLENGTH,true); /* optional locker*/
X                break;
X            case Locker:
X                VOID getval(fp,prevlocker,IDLENGTH,true);
X		if (!checkid(prevlocker, '\0')) goto errexit;
X                break;
X            case Log:
X		VOID getval(fp,prevRCS,NCPPN,true);
X                break;
X            case RCSfile:
X                VOID getval(fp,prevRCS,NCPFN,true);
X                break;
X            case Revision:
X                if (getval(fp,prevrev,revlength,true))
X                    if (!checknum(prevrev,-1)) {
X                        error("Bad revision number");
X                        goto errexit;
X                    }
X                break;
X            case Source:
X                VOID getval(fp,prevsource,NCPPN,true);
X                break;
X            case State:
X                if (getval(fp,prevstate,IDLENGTH,true))
X                    if (!checkid(prevstate, '\0')) goto errexit;
X                break;
X            default:
X               continue;
X            }
X            if (getc(fp)!=KDELIM)
X                warn("Closing %c missing on keyword",KDELIM);
X            if (prevauthor[0]!='\0'&&prevrev[0]!='\0'&&prevstate[0]!='\0'&&
X                prevdate[0]!='\0' &&
X		 ((prevsource[0]!='\0')||(prevRCS[0]!='\0'))){
X                /* done; prevlocker is irrelevant */
X                break;
X           }
X        }
X    }
X    VOID fclose(fp);
X    return true;
X
Xerrexit:
X    prevauthor[0]=prevsource[0]=prevstate[0]=prevdate[0]=prevrev[0]= '\0';
X    VOID fclose(fp); return false;
X}
X
X
Xstatic int getval(fp,target,maxchars,optional)
Xregister FILE *fp;
Xchar * target; int maxchars, optional;
X/* Function: Places a keyword value into target, but not more
X * than maxchars characters. Prints an error if optional==false
X * and there is no keyword. Returns true if one is found, false otherwise.
X */
X{   register char * tp;
X    register int c;
X
X    tp=target;
X    c=getc(fp);
X    if (c==KDELIM) {
X        if (!optional)
X            error("Missing keyword value");
X        VOID ungetc(c,fp);
X        return false;
X    } else {
X        while (!(c==' '||c=='\n'||c=='\t'||c==KDELIM||c==EOF)) {
X            if (tp-target>=maxchars-1) {
X                error("keyword value too long");
X                return false;
X            } else {
X                *tp++ =c;
X                c=getc(fp);
X            }
X        }
X        *tp= '\0';
X#       ifdef KEEPTEST
X        VOID printf("getval: %s\n",target);
X#       endif
X        while(c==' '||c=='\t') c=getc(fp); /* skip trailing blanks */
X    }
X    VOID ungetc(c,fp);
X    return true;
X}
X
X
Xint getprevdate(fp,optional)
XFILE *fp;
Xint optional;
X/* Function: reads a date prevdate; checks format
X * If there is not date and optional==false, an error is printed.
X * Returns false on error, true otherwise.
X */
X{   char prevday[10];
X    char prevtime[10];
X
X    prevday[0]=prevtime[0]='\0';
X    if (!getval(fp,prevday,9,optional)) return optional;
X    if (!getval(fp,prevtime,9,false)) return false;
X    /*process date */
X    prevday[2]=prevday[5]=prevday[8]=prevtime[2]=prevtime[5]='.';
X    prevday[9]='\0';
X    VOID strcpy(prevdate,prevday);
X    VOID strcat(prevdate,prevtime);
X    if (!checknum(prevdate,5)) {
X            error("Bad date: %s",prevdate);
X            prevdate[0]='\0';
X            return false;
X    }
X    return true;
X}
X
Xint checknum(sp,fields)
Xregister char * sp; int fields;
X{    register int dotcount;
X     if (sp==nil||*sp=='\0') return true;
X     dotcount=0;
X     while(*sp) {
X        if (*sp=='.') dotcount++;
X        elsif (ctab[*sp]!=DIGIT) return false;
X        sp++;
X     }
X     if (fields >= 0 && dotcount!=fields) return false;
X     return true;
X}
X
X
X
X#ifdef KEEPTEST
Xchar * RCSfilename, * workfilename;
X
Xmain(argc, argv)
Xint  argc; char  *argv[];
X{
X	cmdid="keeptest";
X        while (*(++argv)) {
X                if (getoldkeys(*argv))
X                VOID printf("%s:  revision: %s, date: %s, author: %s, state: %s\n",
X                        *argv, prevrev, prevdate, prevauthor,prevstate);
X		VOID printf("Source: %s, RCSfile: %s\n",prevsource,prevRCS);
X	}
X	exit(0);
X}
X#endif
X@
X
X
X4.6.2.1
Xlog
X@Start of Amiga RCS port branch.
X@
Xtext
X@d5 1
Xa5 5
X<<<<<<< rcskeep.c
Xstatic char rcsid[]= "$Id: rcskeep.c,v 4.6.1.1 89/08/11 01:42:46 rsbx Exp Locker: rsbx $ Purdue CS";
X=======
Xstatic char rcsid[]= "$Id: rcskeep.c,v 1.2 89/09/17 13:35:58 rick Exp $ Purdue CS";
X>>>>>>> 1.2
Xa40 16
X<<<<<<< rcskeep.c
X * Revision 4.6.1.1  89/08/11  01:42:46  rsbx
X * Start of cbmvax RCS source branch.
X * 
X * Revision 4.6  89/05/01  15:12:56  narten
X * checked in with -k by rsbx at 89.08.10.16.21.35.
X=======
X * Revision 1.2  89/09/17  13:35:58  rick
X * Port to AmigaDos done by Rick Schaeffer (ricks@@iscuva.iscs.com)
X * All changes done with conditional compile (#ifdef AMIGA).  This version
X * compiles correctly with Lattice C version 5.02 or later.
X * 
X * Revision 1.2  88/09/03  15:11:14  rick
X * Port to AmigaDos.  All done with conditional compiles
X>>>>>>> 1.2
X * 
X@
X
X
X4.6.2.2
Xlog
X@Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS
Xsources I have here (and are later than the ones Rick used).
X@
Xtext
X@d5 5
Xa9 1
Xstatic char rcsid[]= "$Id: rcskeep.c,v 4.6.2.1 89/10/13 19:18:47 rsbx Exp Locker: rsbx $ Purdue CS";
Xd45 1
Xa45 3
X * Revision 4.6.2.1  89/10/13  19:18:47  rsbx
X * Start of Amiga RCS port branch.
X * 
Xd51 9
X@
X
X
X4.6.1.1
Xlog
X@Start of cbmvax RCS source branch.
X@
Xtext
X@a41 3
X * checked in with -k by rsbx at 89.08.10.16.21.35.
X * 
X * Revision 4.6  89/05/01  15:12:56  narten
X@
SHAR_EOF
echo "extracting rcs/rcs.rcsfiles/rcskeys.c,v"
sed 's/^X//' << \SHAR_EOF > rcs/rcs.rcsfiles/rcskeys.c,v
Xhead     4.3;
Xbranch   4.3.2;
Xaccess   ;
Xsymbols  amiga_rcs:4.3.2 cbmvax_source:4.3.1 uunet_june89_dist:4.3;
Xlocks    ; strict;
Xcomment  @ * @;
X
X
X4.3
Xdate     89.05.01.15.13.02;  author narten;  state Exp;
Xbranches 4.3.1.1 4.3.2.1;
Xnext     ;
X
X4.3.1.1
Xdate     89.08.11.01.42.49;  author rsbx;  state Exp;
Xbranches ;
Xnext     ;
X
X4.3.2.1
Xdate     89.10.13.19.18.51;  author rsbx;  state Exp;
Xbranches ;
Xnext     4.3.2.2;
X
X4.3.2.2
Xdate     89.10.15.15.44.42;  author rsbx;  state Exp;
Xbranches ;
Xnext     ;
X
X
Xdesc
X@RCS keyword table and match operation.
X@
X
X
X
X4.3
Xlog
X@checked in with -k by rsbx at 89.08.10.16.22.01.
X@
Xtext
X@/*
X *                     RCS keyword table and match operation
X */
X#ifndef lint
Xstatic char rcsid[]= "$Id: rcskeys.c,v 4.3 89/05/01 15:13:02 narten Exp $ Purdue CS";
X#endif
X
X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by Walter Tichy.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X * Report all problems and direct all questions to:
X *   rcs-bugs@@cs.purdue.edu
X * 
X
X
X
X
X
X
X
X*/
X
X
X
X/* $Log:	rcskeys.c,v $
X * Revision 4.3  89/05/01  15:13:02  narten
X * changed copyright header to reflect current distribution rules
X * 
X * Revision 4.2  87/10/18  10:36:33  narten
X * Updating version numbers. Changes relative to 1.1 actuallyt
X * relative to 4.1
X * 
X * Revision 1.2  87/09/24  14:00:10  narten
X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
X * warnings)
X * 
X * Revision 1.1  84/01/23  14:50:32  kcs
X * Initial revision
X * 
X * Revision 4.1  83/05/04  10:06:53  wft
X * Initial revision.
X * 
X */
X
X
X#include "rcsbase.h"
X
X
X
Xstruct { char * keyword; enum markers marker;} markertable[] =
X        {{AUTHOR,   Author  },
X         {DATE,     Date    },
X         {HEADER,   Header  },
X         {IDH,      Id      },
X         {LOCKER,   Locker  },
X         {LOG,      Log     },
X         {RCSFILE,  RCSfile },
X         {REVISION, Revision},
X         {SOURCE,   Source  },
X         {STATE,    State   },
X         {nil,      Nomatch }};
X
X
X
Xenum markers trymatch(string,onlyvdelim)
Xchar * string;
X/* function: Checks whether string starts with a keyword followed
X * by a KDELIM or a VDELIM. If onlyvdelim==true, only a VDELIM
X * may follow the keyword.
X * If successful, returns the appropriate marker, otherwise Nomatch.
X */
X{
X        register int j;
X	register char * p, * s;
X        for (j=0; markertable[j].keyword!=nil; j++ ) {
X		/* try next keyword */
X		p = markertable[j].keyword; s = string;
X		while (*p!='\0' && *s!='\0' && *p == *s) {
X			p++; s++;
X		}
X		if (*p != '\0') continue; /* no match */
X		if ((*s == VDELIM) || (!onlyvdelim && (*s == KDELIM)))
X			return(markertable[j].marker);
X        }
X        return(Nomatch);
X}
X
X@
X
X
X4.3.2.1
Xlog
X@Start of Amiga RCS port branch.
X@
Xtext
X@d5 1
Xa5 5
X<<<<<<< rcskeys.c
Xstatic char rcsid[]= "$Id: rcskeys.c,v 4.3.1.1 89/08/11 01:42:49 rsbx Exp Locker: rsbx $ Purdue CS";
X=======
Xstatic char rcsid[]= "$Id: rcskeys.c,v 1.2 89/09/17 13:36:05 rick Exp $ Purdue CS";
X>>>>>>> 1.2
Xa35 4
X<<<<<<< rcskeys.c
X * Revision 4.3.1.1  89/08/11  01:42:49  rsbx
X * Start of cbmvax RCS source branch.
X * 
Xa36 3
X * checked in with -k by rsbx at 89.08.10.16.22.01.
X * 
X * Revision 4.3  89/05/01  15:13:02  narten
Xa37 9
X=======
X * Revision 1.2  89/09/17  13:36:05  rick
X * Port to AmigaDos done by Rick Schaeffer (ricks@@iscuva.iscs.com)
X * All changes done with conditional compile (#ifdef AMIGA).  This version
X * compiles correctly with Lattice C version 5.02 or later.
X * 
X * Revision 1.2  88/09/03  15:11:32  rick
X * Port to AmigaDos.  All done with conditional compiles
X>>>>>>> 1.2
X@
X
X
X4.3.2.2
Xlog
X@Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS
Xsources I have here (and are later than the ones Rick used).
X@
Xtext
X@d5 5
Xa9 1
Xstatic char rcsid[]= "$Id: rcskeys.c,v 4.3.2.1 89/10/13 19:18:51 rsbx Exp Locker: rsbx $ Purdue CS";
Xd40 1
Xa40 3
X * Revision 4.3.2.1  89/10/13  19:18:51  rsbx
X * Start of Amiga RCS port branch.
X * 
Xd49 9
X@
X
X
X4.3.1.1
Xlog
X@Start of cbmvax RCS source branch.
X@
Xtext
X@a36 3
X * checked in with -k by rsbx at 89.08.10.16.22.01.
X * 
X * Revision 4.3  89/05/01  15:13:02  narten
X@
SHAR_EOF
echo "extracting rcs/rcs.rcsfiles/rcslex.c,v"
sed 's/^X//' << \SHAR_EOF > rcs/rcs.rcsfiles/rcslex.c,v
Xhead     4.6;
Xbranch   4.6.2;
Xaccess   ;
Xsymbols  amiga_rcs:4.6.2 cbmvax_source:4.6.1 uunet_june89_dist:4.6;
Xlocks    ; strict;
Xcomment  @ * @;
X
X
X4.6
Xdate     89.05.01.15.13.07;  author narten;  state Exp;
Xbranches 4.6.1.1 4.6.2.1;
Xnext     ;
X
X4.6.1.1
Xdate     89.08.11.01.42.52;  author rsbx;  state Exp;
Xbranches ;
Xnext     ;
X
X4.6.2.1
Xdate     89.10.13.19.18.54;  author rsbx;  state Exp;
Xbranches ;
Xnext     4.6.2.2;
X
X4.6.2.2
Xdate     89.10.15.15.44.48;  author rsbx;  state Exp;
Xbranches ;
Xnext     ;
X
X
Xdesc
X@RCS file input.
X@
X
X
X
X4.6
Xlog
X@checked in with -k by rsbx at 89.08.10.16.22.16.
X@
Xtext
X@/*
X *                     RCS file input
X */
X#ifndef lint
Xstatic char rcsid[]= "$Id: rcslex.c,v 4.6 89/05/01 15:13:07 narten Exp $ Purdue CS";
X#endif
X/*********************************************************************************
X *                     Lexical Analysis.
X *                     Character mapping table,
X *                     hashtable, Lexinit, nextlex, getlex, getkey,
X *                     getid, getnum, readstring, printstring, savestring,
X *                     checkid, serror, fatserror, error, faterror, warn, diagnose
X *                     fflsbuf, puts, fprintf
X *                     Testprogram: define LEXDB
X *********************************************************************************
X */
X
X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by Walter Tichy.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X * Report all problems and direct all questions to:
X *   rcs-bugs@@cs.purdue.edu
X * 
X
X
X
X
X
X
X
X*/
X
X
X
X/* $Log:	rcslex.c,v $
X * Revision 4.6  89/05/01  15:13:07  narten
X * changed copyright header to reflect current distribution rules
X * 
X * Revision 4.5  88/11/08  12:00:54  narten
X * changes from  eggert@@sm.unisys.com (Paul Eggert)
X * 
X * Revision 4.5  88/08/28  15:01:12  eggert
X * Don't loop when writing error messages to a full filesystem.
X * Flush stderr/stdout when mixing output.
X * Yield exit status compatible with diff(1).
X * Shrink stdio code size; allow cc -R; remove lint.
X * 
X * Revision 4.4  87/12/18  11:44:47  narten
X * fixed to use "varargs" in "fprintf"; this is required if it is to
X * work on a SPARC machine such as a Sun-4
X * 
X * Revision 4.3  87/10/18  10:37:18  narten
X * Updating version numbers. Changes relative to 1.1 actually relative
X * to version 4.1
X * 
X * Revision 1.3  87/09/24  14:00:17  narten
X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
X * warnings)
X * 
X * Revision 1.2  87/03/27  14:22:33  jenkins
X * Port to suns
X * 
X * Revision 1.1  84/01/23  14:50:33  kcs
X * Initial revision
X * 
X * Revision 4.1  83/03/25  18:12:51  wft
X * Only changed $Header to $Id.
X * 
X * Revision 3.3  82/12/10  16:22:37  wft
X * Improved error messages, changed exit status on error to 1.
X *
X * Revision 3.2  82/11/28  21:27:10  wft
X * Renamed ctab to map and included EOFILE; ctab is now a macro in rcsbase.h.
X * Added fflsbuf(), fputs(), and fprintf(), which abort the RCS operations
X * properly in case there is an IO-error (e.g., file system full).
X *
X * Revision 3.1  82/10/11  19:43:56  wft
X * removed unused label out:;
X * made sure all calls to getc() return into an integer, not a char.
X */
X
X
X/*
X#define LEXDB
X/* version LEXDB is for testing the lexical analyzer. The testprogram
X * reads a stream of lexemes, enters the revision numbers into the
X * hashtable, and prints the recognized tokens. Keywords are recognized
X * as identifiers.
X */
X
X
X
X#include "rcsbase.h"
X#include <varargs.h>
X
X
X
X/* character mapping table */
Xenum tokens map[] = {
X        EOFILE,         /* this will end up at ctab[-1] */
X        UNKN,   INSERT, UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,
X        UNKN,   SPACE,  NEWLN,  UNKN,   SPACE,  UNKN,   UNKN,   UNKN,
X        UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,
X        UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,
X        SPACE,  EXCLA,  DQUOTE, HASH,   DOLLAR, PERCNT, AMPER,  SQUOTE,
X        LPARN,  RPARN,  TIMES,  PLUS,   COMMA,  MINUS,  PERIOD, DIVIDE,
X        DIGIT,  DIGIT,  DIGIT,  DIGIT,  DIGIT,  DIGIT,  DIGIT,  DIGIT,
X        DIGIT,  DIGIT,  COLON,  SEMI,   LESS,   EQUAL,  GREAT,  QUEST,
X        AT,     LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
X        LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
X        LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
X        LETTER, LETTER, LETTER, LBRACK, BACKSL, RBRACK, UPARR,  UNDER,
X        ACCENT, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
X        LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
X        LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
X        LETTER, LETTER, LETTER, LBRACE, BAR,    RBRACE, TILDE,  UNKN
X};
X
X
X
X
Xstruct hshentry * nexthsh;  /*pointer to next hashtable-entry, set by lookup*/
X
Xenum tokens     nexttok;    /*next token, set by nextlex                    */
X
Xint             hshenter;   /*if true, next suitable lexeme will be entered */
X                            /*into the symbol table. Handle with care.      */
Xint             nextc;      /*next input character, initialized by Lexinit  */
X
Xint             eof;        /*end-of-file indicator, set to >0 on end of file*/
Xint             line;       /*current line-number of input                  */
Xint             nerror;     /*counter for errors                            */
Xint             nwarn;      /*counter for warnings                          */
Xchar *          cmdid;      /*command identification for error messages     */
Xint             quietflag;  /*indicates quiet mode                          */
XFILE *          finptr;     /*input file descriptor                         */
X
XFILE *          frewrite;   /*file descriptor for echoing input             */
X
Xint             rewriteflag;/*indicates whether to echo to frewrite         */
X
Xchar            StringTab[strtsize]; /* string table and heap               */
X
Xchar *          NextString;         /*pointer to next identifier in StringTab*/
Xchar *          Topchar;            /*pointer to next free byte in StringTab*/
X                                    /*set by nextlex, lookup                */
Xstruct hshentry hshtab[hshsize];    /*hashtable                             */
X
X
X
X
X
Xlookup() {
X
X/* Function: Looks up the character string pointed to by NextString in the
X * hashtable. If the string is not present, a new entry for it is created.
X * If the string is present, TopChar is moved back to save the space for
X * the string, and NextString is set to point to the original string.
X * In any case, the address of the corresponding hashtable entry is placed
X * into nexthsh.
X * Algorithm: Quadratic hash, covering all entries.
X * Assumptions: NextString points at the first character of the string.
X * Topchar points at the first empty byte after the string.
X */
X
X        register int     ihash;      /* index into hashtable */
X        register char    * sp, * np;
X        int              c, delta, final, FirstScan; /*loop control*/
X
X        /* calculate hash code */
X        sp = NextString;
X        ihash = 0;
X        while (*sp) ihash += *sp++;
X
X        /* set up first search loop (c=0,step=1,until (hshsiz-1)/2 */
X        c=0;delta=1;final=(hshsize-1)/2;
X        FirstScan=true;   /*first loop */
X
X        for (;;) {
X                ihash = (ihash+c)%hshsize;   /*next index*/
X
X                if (hshtab[ihash].num == nil) {
X                        /*empty slot found*/
X                        hshtab[ihash].num = NextString;
X                        nexthsh= &hshtab[ihash];/*save hashtable address*/
X#                       ifdef LEXDB
X                        VOID printf("\nEntered: %s at %d ",nexthsh->num, ihash);
X#                       endif
X                        return;
X                }
X                /* compare strings */
X                sp=NextString;np=hshtab[ihash].num;
X                while (*sp == *np++) {
X                        if (*sp == 0) {
X                                /* match found */
X                                nexthsh= &hshtab[ihash];
X                                Topchar = NextString;
X                                NextString = nexthsh->num;
X                                return;
X                        } else sp++;
X                }
X
X                /* neither empty slot nor string found */
X                /* calculate next index and repeat */
X                if (c != final)
X                        c += delta;
X                else {
X                        if (FirstScan) {
X                                /*set up second sweep*/
X                                delta = -1; final = 1; FirstScan= false;
X                        } else {
X                                fatserror("Hashtable overflow");
X                        }
X                }
X        }
X};
X
X
X
X
X
X
XLexinit()
X/* Function: Initialization of lexical analyzer:
X * initializes the hastable,
X * initializes nextc, nexttok if finptr != NULL
X */
X{       register int            c;
X
X        for (c=hshsize-1; c>=0; c--) {
X                hshtab[c].num = nil;
X        }
X
X        hshenter=true; eof=0; line=1; nerror=0; nwarn=0;
X        NextString=nil; Topchar = &StringTab[0];
X        if (finptr) {
X                nextc = GETC(finptr,frewrite,rewriteflag); /*initial character*/
X                nextlex();            /*initial token*/
X        } else {
X                nextc = '\0';
X                nexttok=EOFILE;
X        }
X}
X
X
X
X
X
X
X
Xnextlex()
X
X/* Function: Reads the next token and sets nexttok to the next token code.
X * Only if the hshenter==true, a revision number is entered into the
X * hashtable and a pointer to it is placed into nexthsh.
X * This is useful for avoiding that dates are placed into the hashtable.
X * For ID's and NUM's, NextString is set to the character string in the
X * string table. Assumption: nextc contains the next character.
X */
X{       register c;
X	register FILE * fin, * frew;
X        register char * sp;
X        register enum tokens d;
X
X        if (eof) {
X                nexttok=EOFILE;
X                return;
X        }
X	fin=finptr; frew=frewrite;
Xloop:
X        switch(nexttok=ctab[nextc]) {
X
X        case UNKN:
X        case IDCHAR:
X        case PERIOD:
X                serror("unknown Character: %c",nextc);
X                nextc=GETC(fin,frew,rewriteflag);
X                goto loop;
X
X        case NEWLN:
X                line++;
X#               ifdef LEXDB
X                VOID putchar('\n');
X#               endif
X                /* Note: falls into next case */
X
X        case SPACE:
X                nextc=GETC(fin,frew,rewriteflag);
X                goto loop;
X
X        case EOFILE:
X                eof++;
X                nexttok=EOFILE;
X                return;
X
X        case DIGIT:
X                NextString = sp = Topchar;
X                *sp++ = nextc;
X                while ((d=ctab[c=GETC(fin,frew,rewriteflag)])==DIGIT ||
X                        d==PERIOD) {
X                        *sp++ = c;         /* 1.2. and 1.2 are different */
X                }
X                *sp++ = '\0';
X                if (sp >= StringTab+strtsize) {
X                        /*may have written outside stringtable already*/
X                        fatserror("Stringtable overflow");
X                }
X                Topchar = sp;
X                nextc = c;
X                if (hshenter == true)
X                        lookup();      /* lookup updates NextString, Topchar*/
X                nexttok = NUM;
X                return;
X
X
X        case LETTER:
X                NextString = sp = Topchar;
X                *sp++ = nextc;
X                while ((d=ctab[c=GETC(fin,frew,rewriteflag)])==LETTER ||
X                        d==DIGIT || d==IDCHAR) {
X                        *sp++ = c;
X                }
X                *sp++ = '\0';
X                if (sp >= StringTab+strtsize) {
X                        /*may have written outside stringtable already*/
X                        fatserror("Stringtable overflow");
X                }
X                Topchar = sp;
X                nextc = c;
X                nexttok = ID;  /* may be ID or keyword */
X                return;
X
X        case SBEGIN: /* long string */
X                nexttok = STRING;
X                /* note: only the initial SBEGIN has been read*/
X                /* read the string, and reset nextc afterwards*/
X                return;
X
X        default:
X                nextc=GETC(fin,frew,rewriteflag);
X                return;
X        }
X}
X
X
Xint getlex(token)
Xenum tokens token;
X/* Function: Checks if nexttok is the same as token. If so,
X * advances the input by calling nextlex and returns true.
X * otherwise returns false.
X * Doesn't work for strings and keywords; loses the character string for ids.
X */
X{
X        if (nexttok==token) {
X                nextlex();
X                return(true);
X        } else  return(false);
X}
X
Xint getkey (key)
Xchar * key;
X/* Function: If the current token is a keyword identical to key,
X * getkey advances the input by calling nextlex and returns true;
X * otherwise returns false.
X */
X{
X        register char *s1,*s2;
X
X        if (nexttok==ID) {
X                s1=key; s2=NextString;
X                while(*s1 == *s2++)
X                     if (*s1++ == '\0') {
X                         /* match found */
X                         Topchar = NextString; /*reset Topchar */
X                         nextlex();
X                         return(true);
X                     }
X        }
X        return(false);
X}
X
X
X
Xchar * getid()
X/* Function: Checks if nexttok is an identifier. If so,
X * advances the input by calling nextlex and returns a pointer
X * to the identifier; otherwise returns nil.
X * Treats keywords as identifiers.
X */
X{
X        register char * name;
X        if (nexttok==ID) {
X                name = NextString;
X                nextlex();
X                return name;
X        } else  return nil;
X}
X
X
Xstruct hshentry * getnum()
X/* Function: Checks if nexttok is a number. If so,
X * advances the input by calling nextlex and returns a pointer
X * to the hashtable entry. Otherwise returns nil.
X * Doesn't work if hshenter is false.
X */
X{
X        register struct hshentry * num;
X        if (nexttok==NUM) {
X                num=nexthsh;
X                nextlex();
X                return num;
X        } else  return nil;
X}
X
X
Xreadstring()
X/* skip over characters until terminating single SDELIM        */
X/* if rewriteflag==true, copy every character read to frewrite.*/
X/* Does not advance nextlex at the end.                        */
X{       register c;
X	register FILE * fin,  * frew;
X	fin=finptr; frew=frewrite;
X        if (rewriteflag) {
X                /* copy string verbatim to frewrite */
X                while ((c=getc(fin)) != EOF) {
X			VOID putc(c,frew);
X                        if (c==SDELIM) {
X                                if ((c=getc(fin)) == EOF || putc(c,frew) != SDELIM) {
X                                        /* end of string */
X                                        nextc=c;
X                                        return;
X                                }
X                        }
X                }
X        } else {
X                /* skip string */
X                while ((c=getc(fin)) != EOF) {
X                        if (c==SDELIM) {
X                                if ((c=getc(fin)) != SDELIM) {
X                                        /* end of string */
X                                        nextc=c;
X                                        return;
X                                }
X                        }
X                }
X        }
X        nextc = c;
X        error("Unterminated string");
X}
X
X
Xprintstring()
X/* Function: copy a string to stdout, until terminated with a single SDELIM.
X * Does not advance nextlex at the end.
X */
X{
X        register c;
X	register FILE * fin;
X	fin=finptr;
X	while ((c=getc(fin)) != EOF) {
X                if (c==SDELIM) {
X			if ((c=getc(fin)) != SDELIM) {
X                                /* end of string */
X                                nextc=c;
X                                return;
X                        }
X                }
X                VOID putchar(c);
X        }
X        nextc = c;
X        error("Unterminated string");
X}
X
X
X
Xsavestring(target,length)
Xchar * target; int length;
X/* copies a string terminated with SDELIM from file finptr to buffer target,
X * but not more than length bytes. If the string is longer than length,
X * the extra characters are skipped. The string may be empty, in which
X * case a '\0' is placed into target.
X * Double SDELIM is replaced with SDELIM.
X * If rewriteflag==true, the string is also copied unchanged to frewrite.
X * Returns the length of the saved string.
X * Does not advance nextlex at the end.
X */
X{
X        register c;
X	register FILE * fin, * frew;
X        register char * tp, * max;
X
X	fin=finptr; frew=frewrite;
X        tp=target; max= target+length; /*max is one too large*/
X        while ((c=GETC(fin,frew,rewriteflag))!=EOF) {
X		*tp++ =c;
X                if (c== SDELIM) {
X                        if ((c=GETC(fin,frew,rewriteflag))!=SDELIM) {
X                                /* end of string */
X                                *(tp-1)='\0';
X                                nextc=c;
X                                return;
X                        }
X                }
X                if (tp >= max) {
X                        /* overflow */
X                        error("string buffer overflow -- truncating string");
X                        target[length-1]='\0';
X                        /* skip rest of string */
X                        while ((c=GETC(fin,frew,rewriteflag))!=EOF) {
X                                if ((c==SDELIM) && ((c=GETC(fin,frew,rewriteflag))!=SDELIM)) {
X                                        /* end of string */
X                                        nextc=c;
X                                        return;
X                                }
X                        }
X                        nextc = c;
X                        error("Can't find %c to terminate string before end of file",SDELIM);
X                        return;
X                }
X        }
X        nextc = c;
X        error("Can't find %c to terminate string before end of file",SDELIM);
X}
X
X
Xchar  *checkid(id, delim)
Xchar    *id, delim;
X/*   Function:  check whether the string starting at id is an   */
X/*              identifier and return a pointer to the last char*/
X/*              of the identifer. White space, delim and '\0'   */
X/*              are legal delimeters. Aborts the program if not */
X/*              a legal identifier. Useful for checking commands*/
X{
X        register enum  tokens  d;
X        register char    *temp;
X        register char    c,tc;
X
X        temp = id;
X        if ( ctab[*id] == LETTER ) {
X            while( (d=ctab[c=(*++id)]) == LETTER || d==DIGIT || d==IDCHAR) ;
X            if ( c!=' ' && c!='\t' && c!='\n' && c!='\0' && c!=delim) {
X                /* append \0 to end of id before error message */
X                tc = c;
X                while( (c=(*++id))!=' ' && c!='\t' && c!='\n' && c!='\0' && c!=delim) ;
X                *id = '\0';
X                faterror("Invalid character %c in identifier %s",tc,temp);
X                return nil ;
X            } else
X                return id;
X        } else {
X            /* append \0 to end of id before error message */
X            while( (c=(*++id))!=' ' && c!='\t' && c!='\n' && c!='\0' && c!=delim) ;
X            *id = '\0';
X            faterror("Identifier %s does not start with letter",temp);
X            return nil;
X        }
X}
X
Xwriteerror()
X{
X	static looping;
X	if (looping)
X		exit(2);
X	looping = 1;
X	faterror("write error");
X}
X
Xnlflush(iop)
Xregister FILE * iop;
X{
X	if (putc('\n',iop)==EOF || fflush(iop)==EOF)
X                writeerror();
X}
X
X
X/*VARARGS1*/
Xserror(e,e1,e2,e3,e4,e5)
Xchar * e, * e1, * e2, * e3, * e4, * e5;
X/* non-fatal syntax error */
X{       nerror++;
X        VOID fprintf(stderr,"%s error, line %d: ", cmdid, line);
X        VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
X        nlflush(stderr);
X}
X
X/*VARARGS1*/
Xerror(e,e1,e2,e3,e4,e5)
Xchar * e, * e1, * e2, * e3, * e4, * e5;
X/* non-fatal error */
X{       nerror++;
X        VOID fprintf(stderr,"%s error: ",cmdid);
X        VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
X        nlflush(stderr);
X}
X
X/*VARARGS1*/
Xfatserror(e,e1,e2,e3,e4,e5)
Xchar * e, * e1, * e2, * e3, * e4, * e5;
X/* fatal syntax error */
X{       nerror++;
X        VOID fprintf(stderr,"%s error, line %d: ", cmdid,line);
X        VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
X        VOID fprintf(stderr,"\n%s aborted\n",cmdid);
X        VOID cleanup();
X        exit(2);
X}
X
X/*VARARGS1*/
Xfaterror(e,e1,e2,e3,e4,e5)
Xchar * e, * e1, * e2, * e3, * e4, * e5;
X/* fatal error, terminates program after cleanup */
X{       nerror++;
X        VOID fprintf(stderr,"%s error: ",cmdid);
X        VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
X        VOID fprintf(stderr,"\n%s aborted\n",cmdid);
X        VOID cleanup();
X        exit(2);
X}
X
X/*VARARGS1*/
Xwarn(e,e1,e2,e3,e4,e5)
Xchar * e, * e1, * e2, * e3, * e4, * e5;
X/* prints a warning message */
X{       nwarn++;
X        VOID fprintf(stderr,"%s warning: ",cmdid);
X        VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
X        nlflush(stderr);
X}
X
X
X/*VARARGS1*/
Xdiagnose(e,e1,e2,e3,e4,e5)
Xchar * e, * e1, * e2, * e3, * e4, * e5;
X/* prints a diagnostic message */
X{
X        if (!quietflag) {
X                VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
X                nlflush(stderr);
X        }
X}
X
X
X
Xfflsbuf(c, iop)
Xunsigned c; register FILE * iop;
X/* Function: Flush iop.
X * Same routine as _flsbuf in stdio, but aborts program on error.
X */
X{       register result;
X        if ((result=_flsbuf(c,iop))==EOF)
X                writeerror();
X        return result;
X}
X
X
Xfputs(s, iop)
Xregister char *s;
Xregister FILE *iop;
X/* Function: Put string s on file iop, abort on error.
X * Same as puts in stdio, but with different putc macro.
X */
X{
X	register r;
X	register c;
X
X	while (c = *s++)
X		r = putc(c, iop);
X	return(r);
X}
X
X
X
Xfprintf(iop, fmt, va_alist)
XFILE *iop;
Xchar *fmt;
Xva_dcl
X/* Function: formatted output. Same as fprintf in stdio,
X * but aborts program on error
X */
X{
X	register int value;
X	va_list ap;
X
X	va_start(ap);
X#ifdef VFPRINTF
X	VOID vfprintf(iop, fmt, ap);
X#else
X	_doprnt(fmt, ap, iop);
X#endif
X        if (ferror(iop)) {
X		writeerror();
X                value = EOF;
X        } else value = 0;
X	va_end(ap);
X	return value;
X}
X
X
X
X#ifdef LEXDB
X/* test program reading a stream of lexems and printing the tokens.
X */
X
X
X
Xmain(argc,argv)
Xint argc; char * argv[];
X{
X        cmdid="lextest";
X        if (argc<2) {
X                VOID fputs("No input file\n",stderr);
X                exit(1);
X        }
X        if ((finptr=fopen(argv[1], "r")) == NULL) {
X                faterror("Can't open input file %s\n",argv[1]);
X        }
X        Lexinit();
X        rewriteflag=false;
X        while (nexttok != EOFILE) {
X        switch (nexttok) {
X
X        case ID:
X                VOID printf("ID: %s",NextString);
X                break;
X
X        case NUM:
X                if (hshenter==true)
X                   VOID printf("NUM: %s, index: %d",nexthsh->num, nexthsh-hshtab);
X                else
X                   VOID printf("NUM, unentered: %s",NextString);
X                hshenter = !hshenter; /*alternate between dates and numbers*/
X                break;
X
X        case COLON:
X                VOID printf("COLON"); break;
X
X        case SEMI:
X                VOID printf("SEMI"); break;
X
X        case STRING:
X                readstring();
X                VOID printf("STRING"); break;
X
X        case UNKN:
X                VOID printf("UNKN"); break;
X
X        default:
X                VOID printf("DEFAULT"); break;
X        }
X        VOID printf(" | ");
X        nextlex();
X        }
X        VOID printf("\nEnd of lexical analyzer test\n");
X}
X
Xcleanup()
X/* dummy */
X{}
X
X
X#endif
X@
X
X
X4.6.2.1
Xlog
X@Start of Amiga RCS port branch.
X@
Xtext
X@d5 1
Xa5 5
X<<<<<<< rcslex.c
Xstatic char rcsid[]= "$Id: rcslex.c,v 4.6.1.1 89/08/11 01:42:52 rsbx Exp Locker: rsbx $ Purdue CS";
X=======
Xstatic char rcsid[]= "$Id: rcslex.c,v 1.2 89/09/17 13:36:11 rick Exp $ Purdue CS";
X>>>>>>> 1.2
Xa45 11
X<<<<<<< rcslex.c
X * Revision 4.6.1.1  89/08/11  01:42:52  rsbx
X * Start of cbmvax RCS source branch.
X=======
X * Revision 1.2  89/09/17  13:36:11  rick
X * Port to AmigaDos done by Rick Schaeffer (ricks@@iscuva.iscs.com)
X * All changes done with conditional compile (#ifdef AMIGA).  This version
X * compiles correctly with Lattice C version 5.02 or later.
X>>>>>>> 1.2
X * 
X<<<<<<< rcslex.c
Xa46 3
X * checked in with -k by rsbx at 89.08.10.16.22.16.
X * 
X * Revision 4.6  89/05/01  15:13:07  narten
Xa57 5
X=======
X * Revision 1.2  88/09/03  15:11:38  rick
X * Port to AmigaDos.  All done with conditional compiles
X * 
X>>>>>>> 1.2
Xa103 1
X#ifndef AMIGA
Xa104 1
X#endif
Xd226 1
Xa226 1
X}
Xa647 1
X<<<<<<< rcslex.c
Xa648 4
X=======
X                VOID putc('\n',stderr);
X                fflush(stderr);
X>>>>>>> 1.2
Xd653 1
Xa653 1
X#ifndef AMIGA
Xd682 1
Xd707 1
Xa707 1
X#endif
X@
X
X
X4.6.2.2
Xlog
X@Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS
Xsources I have here (and are later than the ones Rick used).
X@
Xtext
X@d5 5
Xa9 1
Xstatic char rcsid[]= "$Id: rcslex.c,v 4.6.2.1 89/10/13 19:18:54 rsbx Exp Locker: rsbx $ Purdue CS";
Xd50 1
Xa50 3
X * Revision 4.6.2.1  89/10/13  19:18:54  rsbx
X * Start of Amiga RCS port branch.
X * 
Xd53 6
Xd60 1
Xd76 5
Xd673 1
Xd675 4
X@
X
X
X4.6.1.1
Xlog
X@Start of cbmvax RCS source branch.
X@
Xtext
X@a46 3
X * checked in with -k by rsbx at 89.08.10.16.22.16.
X * 
X * Revision 4.6  89/05/01  15:13:07  narten
X@
SHAR_EOF
echo "extracting rcs/rcs.rcsfiles/rcsrev.c,v"
sed 's/^X//' << \SHAR_EOF > rcs/rcs.rcsfiles/rcsrev.c,v
Xhead     4.5;
Xbranch   4.5.2;
Xaccess   ;
Xsymbols  amiga_rcs:4.5.2 cbmvax_source:4.5.1 uunet_june89_dist:4.5;
Xlocks    ; strict;
Xcomment  @ * @;
X
X
X4.5
Xdate     89.05.01.15.13.22;  author narten;  state Exp;
Xbranches 4.5.1.1 4.5.2.1;
Xnext     ;
X
X4.5.1.1
Xdate     89.08.11.01.42.59;  author rsbx;  state Exp;
Xbranches ;
Xnext     4.5.1.2;
X
X4.5.1.2
Xdate     89.08.11.03.07.56;  author rsbx;  state Exp;
Xbranches ;
Xnext     ;
X
X4.5.2.1
Xdate     89.10.13.19.19.08;  author rsbx;  state Exp;
Xbranches ;
Xnext     4.5.2.2;
X
X4.5.2.2
Xdate     89.10.15.15.44.58;  author rsbx;  state Exp;
Xbranches ;
Xnext     ;
X
X
Xdesc
X@RCS revision number handling.
X@
X
X
X
X4.5
Xlog
X@checked in with -k by rsbx at 89.08.10.16.22.50.
X@
Xtext
X@/*
X *                     RCS revision number handling
X */
X#ifndef lint
Xstatic char rcsid[]= "$Id: rcsrev.c,v 4.5 89/05/01 15:13:22 narten Exp $ Purdue CS";
X#endif
X
X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by Walter Tichy.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X * Report all problems and direct all questions to:
X *   rcs-bugs@@cs.purdue.edu
X * 
X
X
X
X
X
X
X
X*/
X
X
X
X
X/* $Log:	rcsrev.c,v $
X * Revision 4.5  89/05/01  15:13:22  narten
X * changed copyright header to reflect current distribution rules
X * 
X * Revision 4.4  87/12/18  11:45:22  narten
X * more lint cleanups. Also, the NOTREACHED comment is no longer necessary, 
X * since there's now a return value there with a value. (Guy Harris)
X * 
X * Revision 4.3  87/10/18  10:38:42  narten
X * Updating version numbers. Changes relative to version 1.1 actually 
X * relative to 4.1
X * 
X * Revision 1.3  87/09/24  14:00:37  narten
X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
X * warnings)
X * 
X * Revision 1.2  87/03/27  14:22:37  jenkins
X * Port to suns
X * 
X * Revision 1.1  84/01/23  14:50:37  kcs
X * Initial revision
X * 
X * Revision 4.1  83/03/25  21:10:45  wft
X * Only changed $Header to $Id.
X * 
X * Revision 3.4  82/12/04  13:24:08  wft
X * Replaced getdelta() with gettree().
X *
X * Revision 3.3  82/11/28  21:33:15  wft
X * fixed compartial() and compnum() for nil-parameters; fixed nils
X * in error messages. Testprogram output shortenend.
X *
X * Revision 3.2  82/10/18  21:19:47  wft
X * renamed compnum->cmpnum, compnumfld->cmpnumfld,
X * numericrevno->numricrevno.
X *
X * Revision 3.1  82/10/11  19:46:09  wft
X * changed expandsym() to check for source==nil; returns zero length string
X * in that case.
X */
X
X
X
X/*
X#define REVTEST
X/* version REVTEST is for testing the routines that generate a sequence
X * of delta numbers needed to regenerate a given delta.
X */
X
X#include "rcsbase.h"
X
Xextern FILE * finptr;   /* RCS input file */
Xextern char * getid();
Xextern struct hshentry * getnum();
Xextern int    getkey();
Xextern int    getlex();
X
Xextern char * getkeyval();
Xstruct hshentry * genbranch(); /* forward */
X
X
X
Xint countnumflds(s)
Xchar * s;
X/* Given a pointer s to a dotted number (date or revision number),
X * countnumflds returns the number of digitfields in s.
X */
X{       register char * sp;
X        register int    count;
X        if ((sp=s)==nil) return(0);
X        if (*sp == '\0') return(0);
X        count = 1;
X        while (*sp) {
X                if (*sp++ == '.') count++;
X        }
X        if (*(--sp) == '.') count--; /*trailing periods don't count*/
X        return(count);
X}
X
Xgetbranchno(revno,branchno)
Xchar * revno, * branchno;
X/* Given a non-nil revision number revno, getbranchno copies the number of the branch
X * on which revno is into branchnumber. If revno itself is a branch number,
X * it is copied unchanged.
X */
X{
X        register int i, numflds;
X        register char * tp, * sp;
X
X        numflds=countnumflds(revno);
X        if (numflds%2 == 1)
X                VOID strcpy(branchno,revno);
X        else {
X                sp=revno; tp=branchno;
X                for (i=1;i<numflds;i++) {
X                        while(*sp!='.') *tp++ = *sp++;
X                        *tp++ = *sp++;
X                }
X                *(tp-1)='\0';
X        }
X}
X
X
X
Xint cmpnum(num1, num2)
Xchar * num1, * num2;
X/* compares the two dotted numbers num1 and num2 lexicographically
X * by field. Individual fields are compared numerically.
X * returns <0, 0, >0 if num1<num2, num1==num2, and num1>num2, resp.
X * omitted fields are assumed to be higher than the existing ones.
X*/
X{
X        register char * s1, *s2;
X        register int n1, n2;
X
X        s1=num1==nil?"":num1;
X        s2=num2==nil?"":num2;
X
X        do {
X                n1 = 0;
X                while (('0' <= *s1) && (*s1 <= '9')) {
X                        n1 = n1*10 + (*s1 - '0');
X                        s1++;
X                }
X                /* skip '.' */
X                if (*s1=='.') s1++;
X
X                n2 = 0;
X                while (('0' <= *s2) && (*s2 <= '9')) {
X                        n2 = n2*10 + (*s2 - '0');
X                        s2++;
X                }
X                /* skip '.' */
X                if (*s2=='.') s2++;
X
X        } while ((n1==n2) && (*s1!='\0') && (*s2!='\0'));
X
X        if (((*s1=='\0') && (*s2=='\0')) || (n1!=n2))
X                return (n1 - n2);
X        /*now n1==n2 and one of s1 or s2 is shorter*/
X        /*give precedence to shorter one*/
X        if (*s1=='\0') return 1;
X        else           return -1;
X
X}
X
X
X
Xint cmpnumfld(num1, num2, fld)
Xchar * num1, * num2; int fld;
X/* compares the two dotted numbers at field fld and returns
X * num1[fld]-num2[fld]. Assumes that num1 and num2 have at least fld fields.
X*/
X{
X        register char * s1, *s2;
X        register int n1, n2;
X
X        s1=num1; n1=fld-1;
X        /* skip fld-1 fields */
X        while (n1) {
X                while(*s1 != '.') s1++;
X                n1--; s1++;
X        }
X        s2 = num2; n2=fld-1;
X        while (n2) {
X                while(*s2 != '.') s2++;
X                n2--; s2++;
X        }
X        /* Don't put the above into a single loop! */
X        /* Now s1 and s2 point to the beginning of the respective fields */
X        /* compute numerical value and compare */
X        n1 = 0;
X        while (('0' <= *s1) && (*s1 <= '9')) {
X                n1 = n1*10 + (*s1 - '0');
X                s1++;
X        }
X        n2 = 0;
X        while (('0' <= *s2) && (*s2 <= '9')) {
X                n2 = n2*10 + (*s2 - '0');
X                s2++;
X        }
X        return (n1 - n2);
X}
X
X
Xint compartial(num1, num2, length)
Xchar    * num1;
Xchar    * num2;
Xint     length;
X
X/*   compare the first "length" fields of two dot numbers;
X     the omitted field is considered to be larger than any number  */
X/*   restriction:  at least one number has length or more fields   */
X
X{
X        register        char    *s1, *s2;
X        register        int     n1, n2;
X
X
X        s1 = num1;      s2 = num2;
X        if ( s1==nil || *s1 == '\0' ) return 1;
X        if ( s2==nil || *s2 == '\0' ) return -1;
X
X        do {
X            n1 = 0;
X            while( ('0' <= *s1) && (*s1 <= '9') ) {
X                n1 = n1 * 10 + (*s1 - '0') ;
X                s1++;
X            }
X            if ( *s1 == '.' ) s1++;    /*  skip .   */
X
X            n2 = 0;
X            while( ( '0' <= *s2) && ( *s2 <= '9' ) ) {
X                   n2 = n2 * 10 + ( *s2 - '0' ) ;
X                s2++;
X            }
X            if (*s2 == '.') s2++;
X        }   while(  ( n1 == n2) && ((--length) != 0) &&
X                    ( *s1 != '\0') && (*s2 != '\0')  );
X
X        if ( (n1 != n2) || (length == 0) ){
X                return(n1-n2);   }
X
X        if ( *s1 == '\0' ) return 1;
X        if ( *s2 == '\0' ) return -1;
X	VOID fprintf(stderr, "RCS Internal error, routine: compartial\n");
X	return(0);
X}
X
X
X
Xincnum(onum,nnum)
Xchar * onum, *nnum;
X/* increments the last field of revision number onum by one and
X * places the result into nnum
X */
X{
X        register char * sp, *tp;
X        register int i;
X
X        sp = onum; tp = nnum;
X        for (i=countnumflds(onum)-1; i>0; i--) {
X                while (*sp != '.') *tp++ = *sp++;
X                *tp++ = *sp++;  /* copy dot also */
X        }
X        VOID sprintf(tp,"%d",atoi(sp)+1);
X}
X
X
Xchar * partialno(rev1,rev2,length)
Xchar * rev1, * rev2; register int length;
X/* Function: Copies length fields of revision number rev2 into rev1.
X * returns rev1.
X */
X{       register char * r1,* r2;
X
X        r1=rev1; r2=rev2;
X        while (length) {
X                while(*r2 != '.' && *r2!='\0') *r1++ = *r2++;
X                *r1++ = *r2++;
X                length--;
X        }
X        /* eliminate last '.'*/
X        *(r1-1)='\0';
X        return rev1;
X}
X
X
X
Xchar * getancestor(r1, r2, r3)
Xchar * r1, *r2, *r3;
X/* function: finds the common ancestor of r1 and r2 and
X * places it into r3.
X * returns r3 if successful, false otherwise.
X * works reliably only if r1 and r2 are not branch numbers.
X */
X{       int l1, l2, l3;
X        char t1[revlength], t2[revlength];
X
X        l1=countnumflds(r1); l2=countnumflds(r2);
X        if ((l1<=2 && l2<=2)||(cmpnum(r1,r2)==0)) {
X                /* on main trunk or identical */
X                error("Common ancestor of %s and %s undefined.", r1, r2);
X                return false;
X        }
X
X        l3=0;
X        while ((cmpnumfld(r1, r2, l3+1)==0) && (cmpnumfld(r1, r2, l3+2)==0)){
X                l3=l3+2;
X        }
X        /* This will terminate since r1 and r2 are not the same; see above*/
X        if (l3==0) {
X                /* no common prefix. Common ancestor on main trunk. */
X                VOID partialno(t1,r1,l1>2?2:l1); VOID partialno(t2,r2,l2>2?2:l2);
X                if (cmpnum(t1,t2)<0)
X                        VOID strcpy(r3,t1);
X                else    VOID strcpy(r3,t2);
X                if ((cmpnum(r3,r1)==0)||(cmpnum(r3,r2)==0)) {
X                        error("Ancestor for %s and %s undefined.",r1,r2);
X                        return false;
X                }
X                return r3;
X        } else {
X               if (cmpnumfld(r1,r2,l3+1)==0) {
X                        error("Ancestor for %s and %s undefined.",r1,r2);
X                        return false;
X                }
X                return(partialno(r3,r1,l3));
X        }
X}
X
X
X
X
Xstruct hshentry * genrevs(revno,date,author,state,store)
Xchar * revno, * date, * author, * state;
Xstruct hshentry * * store;
X/* Function: finds the deltas needed for reconstructing the
X * revision given by revno, date, author, and state, and stores pointers
X * to these deltas into an array whose starting address is given by store.
X * The last pointer stored is nil. The last delta (target delta) is returned.
X * If the proper delta could not be found, nil is returned.
X */
X{
X        int length;
X        register struct hshentry * next;
X        int result;
X        char * branchnum;
X        char t[revlength];
X
X        if (Head == nil) {
X                error("RCSfile empty.");
X                return nil;
X        }
X
X        length = countnumflds(revno);
X        next=Head;
X
X        if (length >= 1) {
X                /* at least one field; find branch exactly */
X                while ((next!=nil) &&
X                       ((result=cmpnumfld(revno,next->num,1))<0)) {
X                        /*puts(next->num);*/
X                        *store++ = next;
X                        next = next->next;
X                }
X
X                if (next==nil) {error("Branch number %s too low.",partialno(t,revno,1));return nil;}
X                if (result>0)  {error("Branch number %s not present.",partialno(t,revno,1));return nil;}
X        }
X        if (length<=1){
X                /* pick latest one on given branch */
X                branchnum = next->num; /* works even for empty revno*/
X                while ((next!=nil) &&
X                       (cmpnumfld(branchnum,next->num,1)==0) &&
X                       !(
X                        (date==nil?1:(cmpnum(date,next->date)>=0)) &&
X                        (author==nil?1:(strcmp(author,next->author)==0)) &&
X                        (state ==nil?1:(strcmp(state, next->state) ==0))
X                        )
X                       )
X                {       /*puts(next->num);*/
X                        *store ++ = next;
X                        next=next->next;
X                }
X                if ((next==nil) ||
X                    (cmpnumfld(branchnum,next->num,1)!=0))/*overshot*/ {
X                        error("Cannot find revision on branch %s with a date before %s, author %s, and state %s.",
X                                length==0?partialno(t,branchnum,1):revno,date==nil?"<now>":date,
X                                author==nil?"<any>":author, state==nil?"<any>":state);
X                        return nil;
X                } else {
X                        /*puts(next->num);*/
X                        *store++ = next;
X                }
X                *store = nil;
X                return next;
X        }
X
X        /* length >=2 */
X        /* find revision; may go low if length==2*/
X        while ((next!=nil) &&
X               ((result =cmpnumfld(revno,next->num,2)) <0) &&
X               (cmpnumfld(revno,next->num,1)==0) ) {
X                /*puts(next->num);*/
X                *store++ = next;
X                next = next->next;
X        }
X
X        if ((next==nil) || (cmpnumfld(revno,next->num,1)!=0)) {
X                error("Revision number %s too low.",partialno(t,revno,2));
X                return nil;
X        }
X        if ((length>2) && (result!=0)) {
X                error("Revision %s not present.",partialno(t,revno,2));
X                return nil;
X        }
X
X        /* print last one */
X        /*puts(next->num);*/
X        *store++ = next;
X
X        if (length>2)
X                return genbranch(next,revno,length,date,author,state,store);
X        else { /* length == 2*/
X                if ((date!=nil) && (cmpnum(date,next->date)<0)){
X                        error("Revision %s has date %s.",next->num, next->date);
X                        return nil;
X                }
X                if ((author!=nil)&&(strcmp(author,next->author)!=0)) {
X                        error("Revision %s has author %s.",next->num,next->author);
X                        return nil;
X                }
X                if ((state!=nil)&&(strcmp(state,next->state)!=0)) {
X                        error("Revision %s has state %s.",next->num,
X                               next->state==nil?"<empty>":next->state);
X                        return nil;
X                }
X                *store=nil;
X                return next;
X        }
X}
X
X
X
X
Xstruct hshentry * genbranch(bpoint, revno, length,date,author,state,store)
Xstruct hshentry * bpoint;
Xchar * revno; int length;
Xchar * date, * author, * state;
Xstruct hshentry ** store;
X/* Function: given a branchpoint, a revision number, date, author, and state,
X * genbranch finds the deltas necessary to reconstruct the given revision
X * from the branch point on.
X * Pointers to the found deltas are stored in an array beginning with store.
X * revno must be on a side branch.
X * return nil on error
X */
X{
X        int field;
X        register struct hshentry * next, * trail;
X        register struct branchhead * bhead;
X        int result;
X        char t[revlength];
X
X        bhead = bpoint->branches;
X
X        for (field=3; field<=length; field=field+2) {
X
X                if (bhead==nil) {error("No side branches present for %s.",partialno(t,revno,field-1));return nil;}
X
X                /*find branch head*/
X                /*branches are arranged in increasing order*/
X                while ((bhead!=nil) &&
X                       ((result=cmpnumfld(revno,bhead->hsh->num,field))>0)) {
X                        bhead = bhead->nextbranch;
X                }
X
X                if (bhead==nil) {error("Branch number %s too high.",partialno(t,revno,field));return nil;}
X                if (result<0)   {error("Branch number %s not present.",partialno(t,revno,field));return nil;}
X
X                next = bhead->hsh;
X                if (length==field) {
X                        /* pick latest one on that branch */
X                        trail=nil;
X                        do { if ((date==nil?1:(cmpnum(date,next->date)>=0)) &&
X                                 (author==nil?1:(strcmp(author,next->author)==0)) &&
X                                 (state ==nil?1:(strcmp(state, next->state) ==0))
X                             ) trail = next;
X                             next=next->next;
X                        } while (next!=nil);
X
X                        if (trail==nil) {
X                             error("Cannot find revision on branch %s with a date before %s, author %s, and state %s.",
X                                        revno, date==nil?"<now>":date,
X                                        author==nil?"<any>":author, state==nil?"<any>":state);
X                             return nil;
X                        } else { /* print up to last one suitable */
X                             next = bhead->hsh;
X                             while (next!=trail) {
X                                  /*puts(next->num);*/
X                                  *store++ = next;
X                                  next=next->next;
X                             }
X                             /*puts(next->num);*/
X                             *store++ = next;
X                        }
X                        *store = nil;
X                        return next;
X                }
X
X                /* length > field */
X                /* find revision */
X                /* check low */
X                if (cmpnumfld(revno,next->num,field+1)<0) {
X                        error("Revision number %s too low.",partialno(t,revno,field+1));
X                        return(nil);
X                }
X                do {    /*puts(next->num);*/
X                        *store++ = next;
X                        trail = next;
X                        next = next->next;
X                } while ((next!=nil) &&
X                       (cmpnumfld(revno,next->num,field+1) >=0));
X
X                if ((length>field+1) &&  /*need exact hit */
X                    (cmpnumfld(revno,trail->num,field+1) !=0)){
X                        error("Revision %s not present.",partialno(t,revno,field+1));
X                        return(nil);
X                }
X                if (length == field+1) {
X                        if ((date!=nil) && (cmpnum(date,trail->date)<0)){
X                                error("Revision %s has date %s.",trail->num, trail->date);
X                                return nil;
X                        }
X                        if ((author!=nil)&&(strcmp(author,trail->author)!=0)) {
X                                error("Revision %s has author %s.",trail->num,trail->author);
X                                return nil;
X                        }
X                        if ((state!=nil)&&(strcmp(state,trail->state)!=0)) {
X                                error("Revision %s has state %s.",trail->num,
X                                       trail->state==nil?"<empty>":trail->state);
X                                return nil;
X                        }
X                }
X                bhead = trail->branches;
X
X        }
X        * store = nil;
X        return trail;
X}
X
X
Xchar * lookupsym(id)
Xchar * id;
X/* Function: looks up id in the list of symbolic names starting
X * with pointer SYMBOLS, and returns a pointer to the corresponding
X * revision number. Returns nil if not present.
X */
X{
X        register struct assoc * next;
X        next = Symbols;
X        while (next!=nil) {
X                if (strcmp(id, next->symbol)==0)
X                        return(next->delta->num);
X                else    next=next->nextassoc;
X        }
X        return nil;
X}
X
Xint expandsym(source, target)
Xchar * source, * target;
X/* Function: Source points to a revision number. Expandsym copies
X * the number to target, but replaces all symbolic fields in the
X * source number with their numeric values.
X * A trailing '.' is omitted; leading zeroes are compressed.
X * returns false on error;
X */
X{       register char * sp, * tp, *bp;
X        char symbuf[30];
X        register enum tokens d;
X
X        sp = source; tp=target;
X        if (sp == nil) { /*accept nil pointer as a legal value*/
X                *tp='\0';
X                return true;
X        }
X
X        while (*sp != '\0') {
X                if (ctab[*sp] == DIGIT) {
X                        if (*sp=='0') {
X                                /* skip leading zeroes */
X                                sp++;
X                                while(*sp == '0') sp++;
X                                if (*sp=='\0' || *sp=='.') *tp++ = '0'; /*single zero*/
X                        }
X                        while(ctab[*sp] == DIGIT) *tp++ = *sp++;
X                        if ((*sp == '\0') || ((*sp=='.')&&(*(sp+1)=='\0'))) {
X                                *tp='\0'; return true;
X                        }
X                        if (*sp == '.') *tp++ = *sp++;
X                        else {
X                            error("Improper revision number: %s",source);
X                            *tp = '\0';
X                            return false;
X                        }
X                } elsif (ctab[*sp] == LETTER) {
X                        bp = symbuf;
X                        do {    *bp++ = *sp++;
X                        } while(((d=ctab[*sp])==LETTER) || (d==DIGIT) ||
X                              (d==IDCHAR));
X                        *bp= '\0';
X                        bp=lookupsym(symbuf);
X                        if (bp==nil) {
X                                error("Symbolic number %s is undefined.",symbuf);
X                                *tp='\0';
X                                return false;
X                        } else { /* copy number */
X                                while (*tp++ = *bp++); /* copies the trailing \0*/
X                        }
X                        if ((*sp == '\0') || ((*sp=='.')&&(*(sp+1)=='\0')))
X                                return true;
X                        if (*sp == '.')  {
X                                *(tp-1) = *sp++;
X                        } else {
X                                error("Improper revision number: %s",source);
X                                return false;
X                        }
X                }else {
X                        error("Improper revision number: %s", source);
X                        *tp = '\0';
X                        return false;
X                }
X        }
X        *tp = '\0';
X        return true;
X}
X
X
X
X#ifdef REVTEST
X
Xmain(argc,argv)
Xint argc; char * argv[];
X{
X        char symrevno[revlength];       /* used for input of revision numbers */
X        char numricrevno[revlength];
X        char author[20];
X        char state[20];
X        char date[20];
X        struct hshentry * gendeltas[hshsize/2];
X        struct hshentry * target;
X        int i;
X
X        cmdid = "revtest";
X        if (argc<2) {
X                VOID fputs("No input file\n",stderr);
X                exit(-1);
X        }
X        if ((finptr=fopen(argv[1], "r")) == NULL) {
X                faterror("Can't open input file %s\n",argv[1]);
X        }
X        Lexinit();
X        getadmin();
X
X        gettree();
X
X        getdesc(false);
X
X        do {
X                /* all output goes to stderr, to have diagnostics and       */
X                /* errors in sequence.                                      */
X                VOID fprintf(stderr,"\nEnter revision number or <return> or '.': ");
X                if(gets(symrevno)==NULL) break;
X                if (*symrevno == '.') break;
X                VOID fprintf(stderr,"%s;\n",symrevno);
X                expandsym(symrevno,numricrevno);
X                VOID fprintf(stderr,"expanded number: %s; ",numricrevno);
X                VOID fprintf(stderr,"Date: ");
X                gets(date); VOID fprintf(stderr,"%s; ",date);
X                VOID fprintf(stderr,"Author: ");
X                gets(author);VOID fprintf(stderr,"%s; ",author);
X                VOID fprintf(stderr,"State: ");
X                gets(state); VOID fprintf(stderr, "%s;\n", state);
X                target=genrevs(numricrevno,*date=='\0'?(char *)nil:date, *author=='\0'?(char *)nil:author,
X                              *state=='\0'?(char *)nil:state,gendeltas);
X                if (target!=nil) {
X                        i=0;
X                        while (gendeltas[i]!=nil) {
X                                VOID fprintf(stderr,"%s\n",gendeltas[i++]->num);
X                        }
X                }
X        } while (true);
X        VOID fprintf(stderr,"done\n");
X
X}
X
Xcleanup(){}
X/*dummy*/
X
X#endif REVTEST
X@
X
X
X4.5.2.1
Xlog
X@Start of Amiga RCS port branch.
X@
Xtext
X@d5 1
Xa5 5
X<<<<<<< rcsrev.c
Xstatic char rcsid[]= "$Id: rcsrev.c,v 4.5.1.2 89/08/11 03:07:56 rsbx Exp Locker: rsbx $ Purdue CS";
X=======
Xstatic char rcsid[]= "$Id: rcsrev.c,v 1.2 89/09/17 13:36:25 rick Exp $ Purdue CS";
X>>>>>>> 1.2
Xa36 17
X<<<<<<< rcsrev.c
X * Revision 4.5.1.2  89/08/11  03:07:56  rsbx
X * Added eggert's 88/08/28 15:03:00 change to remove possibility of an internal
X * error and (same change) removed lint.
X * 
X * Revision 4.5.1.1  89/08/11  01:42:59  rsbx
X * Start of cbmvax RCS source branch.
X=======
X * Revision 1.2  89/09/17  13:36:25  rick
X * Port to AmigaDos done by Rick Schaeffer (ricks@@iscuva.iscs.com)
X * All changes done with conditional compile (#ifdef AMIGA).  This version
X * compiles correctly with Lattice C version 5.02 or later.
X * 
X * Revision 1.2  88/09/03  15:12:14  rick
X * Port to AmigaDos.  All done with conditional compiles
X>>>>>>> 1.2
X * 
Xa37 3
X * checked in with -k by rsbx at 89.08.10.16.22.50.
X * 
X * Revision 4.5  89/05/01  15:13:22  narten
Xd88 4
Xd93 1
Xd108 1
Xa108 1
X        do {
Xd110 1
Xa110 1
X        } while (*sp);
Xd239 1
Xa239 1
X        for (;;) {
Xd253 2
Xd256 7
Xa262 5
X	    if ( n1 != n2 ) return n1-n2;
X	    if ( --length == 0 ) return 0;
X	    if ( *s1 == '\0' ) return 1;
X	    if ( *s2 == '\0' ) return -1;
X	}
X@
X
X
X4.5.2.2
Xlog
X@Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS
Xsources I have here (and are later than the ones Rick used).
X@
Xtext
X@d5 5
Xa9 1
Xstatic char rcsid[]= "$Id: rcsrev.c,v 4.5.2.1 89/10/13 19:19:08 rsbx Exp Locker: rsbx $ Purdue CS";
Xd41 1
Xa41 3
X * Revision 4.5.2.1  89/10/13  19:19:08  rsbx
X * Start of Amiga RCS port branch.
X * 
Xd48 9
X@
X
X
X4.5.1.1
Xlog
X@Start of cbmvax RCS source branch.
X@
Xtext
X@a37 3
X * checked in with -k by rsbx at 89.08.10.16.22.50.
X * 
X * Revision 4.5  89/05/01  15:13:22  narten
X@
X
X
X4.5.1.2
Xlog
X@Added eggert's 88/08/28 15:03:00 change to remove possibility of an internal
Xerror and (same change) removed lint.
X@
Xtext
X@d5 1
Xa5 1
Xstatic char rcsid[]= "$Id: rcsrev.c,v 4.5.1.1 89/08/11 01:42:59 rsbx Exp Locker: rsbx $ Purdue CS";
Xa36 3
X * Revision 4.5.1.1  89/08/11  01:42:59  rsbx
X * Start of cbmvax RCS source branch.
X * 
Xd91 4
Xd96 1
Xd111 1
Xa111 1
X        do {
Xd113 1
Xa113 1
X        } while (*sp);
Xd242 1
Xa242 1
X        for (;;) {
Xd256 2
Xd259 7
Xa265 5
X	    if ( n1 != n2 ) return n1-n2;
X	    if ( --length == 0 ) return 0;
X	    if ( *s1 == '\0' ) return 1;
X	    if ( *s2 == '\0' ) return -1;
X	}
X@
SHAR_EOF
echo "End of archive 10 (of 14)"
# if you want to concatenate archives, remove anything after this line
exit