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