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