page%swap@Sun.COM (Bob Page) (11/19/89)
Submitted-by: rsbx@cbmvax.commodore.com (Raymond S. Brand) Posting-number: Volume 89, Issue 226 Archive-name: unix/rcs.11 # 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/rcssyn.c,v # rcs/rcs.rcsfiles/rcsutil.c,v # rcs/rcs.rcsfiles/rlog.c,v # This is archive 11 of a 14-part kit. # This archive created: Sun Nov 19 01:12:11 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/rcssyn.c,v" sed 's/^X//' << \SHAR_EOF > rcs/rcs.rcsfiles/rcssyn.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.32; author narten; state Exp; Xbranches 4.6.1.1 4.6.2.1; Xnext ; X X4.6.1.1 Xdate 89.08.11.01.43.06; author rsbx; state Exp; Xbranches ; Xnext ; X X4.6.2.1 Xdate 89.10.13.19.19.15; author rsbx; state Exp; Xbranches ; Xnext 4.6.2.2; X X4.6.2.2 Xdate 89.10.15.15.45.04; 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.23.06. X@ Xtext X@/* X * RCS file input X */ X#ifndef lint Xstatic char rcsid[]= "$Id: rcssyn.c,v 4.6 89/05/01 15:13:32 narten Exp $ Purdue CS"; X#endif X/********************************************************************************* X * Syntax Analysis. X * Keyword table X * Testprogram: define SYNDB X * Compatibility with Release 2: define COMPAT2 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/* $Log: rcssyn.c,v $ X * Revision 4.6 89/05/01 15:13:32 narten X * changed copyright header to reflect current distribution rules X * X * Revision 4.5 88/11/08 12:00:37 narten X * changes from eggert@@sm.unisys.com (Paul Eggert) X * X * Revision 4.5 88/08/09 19:13:21 eggert X * Allow cc -R; remove lint. X * X * Revision 4.4 87/12/18 11:46:16 narten X * more lint cleanups (Guy Harris) X * X * Revision 4.3 87/10/18 10:39:36 narten X * Updating version numbers. Changes relative to 1.1 actually relative to X * 4.1 X * X * Revision 1.3 87/09/24 14:00:49 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:40 jenkins X * Port to suns X * X * Revision 1.1 84/01/23 14:50:40 kcs X * Initial revision X * X * Revision 4.1 83/03/28 11:38:49 wft X * Added parsing and printing of default branch. X * X * Revision 3.6 83/01/15 17:46:50 wft X * Changed readdelta() to initialize selector and log-pointer. X * Changed puttree to check for selector==DELETE; putdtext() uses DELNUMFORM. X * X * Revision 3.5 82/12/08 21:58:58 wft X * renamed Commentleader to Commleader. X * X * Revision 3.4 82/12/04 13:24:40 wft X * Added routine gettree(), which updates keeplock after reading the X * delta tree. X * X * Revision 3.3 82/11/28 21:30:11 wft X * Reading and printing of Suffix removed; version COMPAT2 skips the X * Suffix for files of release 2 format. Fixed problems with printing nil. X * X * Revision 3.2 82/10/18 21:18:25 wft X * renamed putdeltatext to putdtext. X * X * Revision 3.1 82/10/11 19:45:11 wft X * made sure getc() returns into an integer. X */ X X X X/* X#define COMPAT2 X/* version COMPAT2 reads files of the format of release 2 and 3, but X * generates files of release 3 format. Need not be defined if no X * old RCS files generated with release 2 exist. X */ X/* X#define SYNDB X/* version SYNDB is for debugging the syntax analysis for RCS files. X * SYNDB performs additional error checks. X */ X/* X#define SYNTEST X/* version SYNTEST inputs a RCS file and then prints out its internal X * data structures. X*/ X X#include "rcsbase.h" Xextern FILE * finptr; /*RCS input file*/ Xextern char * getid(); Xextern struct hshentry * getnum(); Xextern int getkey(); Xextern int getlex(); Xextern readstring(); Xextern savestring(); X X/* forward */ Xchar * getkeyval(); X X/* keyword table */ X Xchar Kaccess[] = "access"; Xchar Kauthor[] = "author"; Xchar Kbranch[] = "branch"; Xchar Kbranches[] = "branches"; Xchar Kcomment[] = "comment"; Xchar Kdate[] = "date"; Xchar Kdesc[] = "desc"; Xchar Khead[] = "head"; Xchar Klocks[] = "locks"; Xchar Klog[] = "log"; Xchar Knext[] = "next"; Xchar Kstate[] = "state"; Xchar Kstrict[] = "strict"; X#ifdef COMPAT2 Xchar Ksuffix[] = "suffix"; X#endif Xchar Ksymbols[] = "symbols"; Xchar Ktext[] = "text"; X X#define COMMLENGTH 20 Xchar Commleader[COMMLENGTH]; Xchar * Comment; Xstruct access * AccessList; Xstruct access * LastAccess; Xstruct assoc * Symbols; Xstruct assoc * LastSymbol; Xstruct lock * Locks; Xstruct lock * LastLock; Xint StrictLocks; Xstruct hshentry * Head; Xstruct hshentry * Dbranch; Xint TotalDeltas; X X X Xgetadmin() X/* Function: Reads an <admin> and initializes the globals X * AccessList, LastAccess, Symbols, LastSymbol, X * Locks, LastLock, StrictLocks, Head, Comment, TotalDeltas; X */ X{ X register char * id; X struct access * newaccess; X struct assoc * newassoc; X struct lock * newlock; X struct hshentry * delta; X X Comment=""; X AccessList=LastAccess=nil; X Symbols=LastSymbol=nil; X Locks=LastLock=nil; X Dbranch = Head = nil; X TotalDeltas=0; X X if (!getkey(Khead)) fatserror("Missing head"); X Head=getnum(); X# ifdef SYNDB X if (Head&&((countnumflds(Head->num)%2)!=0)) X serror("Delta number required for head"); X# endif X if (!getlex(SEMI)) serror("Missing ';' after head"); X X if (getkey(Kbranch)) { /* optional */ X Dbranch=getnum(); X if (!getlex(SEMI)) serror("Missing ';' after branch list"); X } X X X#ifdef COMPAT2 X /* read suffix. Only in release 2 format */ X if (getkey(Ksuffix)) { X if (nexttok==STRING) { X readstring(); nextlex(); /*through away the suffix*/ X } elsif(nexttok==ID) { X nextlex(); X } X if (!getlex(SEMI)) serror("Missing ';' after %s",Ksuffix); X } X#endif X X if (!getkey(Kaccess)) fatserror("Missing access list"); X while (id=getid()) { X newaccess = (struct access *)talloc(sizeof(struct access)); X newaccess->login = id; X newaccess->nextaccess = nil; X if (AccessList == nil) { X AccessList=LastAccess=newaccess; X } else { X LastAccess=LastAccess->nextaccess=newaccess; X } X } X if (!getlex(SEMI)) serror("Missing ';' after access list"); X X if (!getkey(Ksymbols)) fatserror("Missing symbols"); X while (id = getid()) { X if (!getlex(COLON)) X serror("Missing ':' in symbolic name definition"); X if (!(delta=getnum())) { X serror("Missing number in symbolic name definition"); X } else { /*add new pair to association list*/ X newassoc=(struct assoc *)talloc(sizeof(struct assoc)); X newassoc->symbol=id; X newassoc->delta=delta; X newassoc->nextassoc=nil; X if (Symbols == nil) { X Symbols=LastSymbol=newassoc; X } else { X LastSymbol=LastSymbol->nextassoc=newassoc; X } X } X } X if (!getlex(SEMI)) serror("Missing ';' after symbolic names"); X X if (!getkey(Klocks)) serror("Missing locks"); X while (id = getid()) { X if (!getlex(COLON)) X serror("Missing ':' in lock"); X if (!(delta=getnum())) { X serror("Missing number in lock"); X } else { /*add new pair to lock list*/ X# ifdef SYNDB X if ((countnumflds(delta->num)%2)!=0) X serror("Delta number required for lock"); X# endif X newlock=(struct lock *)talloc(sizeof(struct lock)); X newlock->login=id; X newlock->delta=delta; X newlock->nextlock=nil; X if (Locks == nil) { X Locks=LastLock=newlock; X } else { X LastLock=LastLock->nextlock=newlock; X } X } X } X if (!getlex(SEMI)) serror("Missing ';' after locks"); X if (!getkey(Kstrict)) { X StrictLocks = false; X } else { X StrictLocks = true; X if (!getlex(SEMI)) serror("Missing ';' after keyword %s",Kstrict); X } X if (getkey(Kcomment) && (nexttok==STRING)) { X VOID savestring(Commleader,COMMLENGTH);nextlex(); X Comment=Commleader; X if (!getlex(SEMI)) serror("Missing ';' after %s",Kcomment); X } X} X X X Xgetdelta() X/* Function: reads a delta block. X * returns false if the current block does not start with a number. X */ X{ X register struct hshentry * Delta, * num; X struct branchhead * LastBranch, * NewBranch; X X if (!(Delta=getnum())) return false; X# ifdef SYNDB X if ((countnumflds(Delta->num)%2)!=0) X serror("Delta number required"); X# endif X X hshenter = false; /*Don't enter dates into hashtable*/ X Delta->date = getkeyval(Kdate, NUM, false); X hshenter=true; /*reset hshenter for revision numbers.*/ X X Delta->author = getkeyval(Kauthor, ID, false); X X Delta->state = getkeyval(Kstate, ID, true); X X if (!getkey(Kbranches)) fatserror("Missing branches"); X Delta->branches = LastBranch=nil; X while (num=getnum()) { X# ifdef SYNDB X if ((countnumflds(num->num)%2)!=0) X serror("Delta number required"); X# endif X NewBranch = (struct branchhead *)talloc(sizeof(struct branchhead)); X NewBranch->hsh = num; X NewBranch->nextbranch = nil; X if (LastBranch == nil) { X Delta->branches=LastBranch=NewBranch; X } else { X LastBranch=LastBranch->nextbranch=NewBranch; X } X } X if (!getlex(SEMI)) serror("Missing ';' after branches"); X X if (!getkey(Knext)) fatserror("Missing next"); X Delta->next=num=getnum(); X# ifdef SYNDB X if (num&&((countnumflds(num->num)%2)!=0)) X serror("Delta number required"); X# endif X if (!getlex(SEMI)) serror("Missing ';' after next"); X Delta->log=Delta->lockedby = nil; X Delta->selector = '\0'; X TotalDeltas++; X return (true); X} X X Xgettree() X/* Function: Reads in the delta tree with getdelta(), then X * updates the lockedby fields. X */ X{ struct lock * currlock; X while (getdelta()); X currlock=Locks; X while (currlock) { X currlock->delta->lockedby = currlock->login; X currlock = currlock->nextlock; X } X} X X Xgetdesc(prdesc) Xint prdesc; X/* Function: read in descriptive text X * nexttok is not advanced afterwards. X * if prdesc==true, the text is printed to stdout. X */ X{ X X if (!getkey(Kdesc) || (nexttok!=STRING)) fatserror("Missing descriptive text"); X if (prdesc) X printstring(); /*echo string*/ X else readstring(); /*skip string*/ X} X X X X X X Xchar * getkeyval(keyword, token, optional) Xenum tokens token; char * keyword; int optional; X/* reads a pair of the form X * <keyword> <token> ; X * where token is one of <id> or <num>. optional indicates whether X * <token> is optional. A pointer to X * the acutal character string of <id> or <num) is returned. X * Getkeyval terminates the program on missing keyword or token, continues X * on missing ;. X */ X{ X register char * val; X X if (!getkey(keyword)) { X fatserror("Missing %s", keyword); X } X if (nexttok==token) { X val = NextString; X nextlex(); X } else { X if (!optional) {fatserror("Missing %s", keyword); } X else val = nil; X } X if (!getlex(SEMI)) serror("Missing ';' after %s",keyword); X return(val); X} X X X X Xputadmin(fout) Xregister FILE * fout; X/* Function: Print the <admin> node read with getadmin() to file fout. X * Assumption: Variables AccessList, Symbols, Locks, StrictLocks, X * and Head have been set. X */ X{ struct assoc * curassoc; X struct lock * curlock; X struct access * curaccess; X register char * sp; X X VOID fputs(Khead,fout); VOID fputs(" ",fout); X if (Head) VOID fputs(Head->num,fout); X X VOID fprintf(fout,";\n%s ",Kbranch); X if (Dbranch) VOID fputs(Dbranch->num,fout); X X VOID fprintf(fout,";\n%s ",Kaccess); X curaccess = AccessList; X if (curaccess==nil) VOID putc(' ',fout); X while (curaccess) { X VOID putc(' ',fout); X VOID fputs(curaccess->login,fout); X curaccess = curaccess->nextaccess; X } X VOID fprintf(fout,";\n%s ",Ksymbols); X curassoc = Symbols; X if (curassoc==nil) VOID putc(' ',fout); X while (curassoc) { X VOID fprintf(fout," %s:%s",curassoc->symbol, curassoc->delta->num); X curassoc = curassoc->nextassoc; X } X VOID fprintf(fout,";\n%s ",Klocks); X curlock = Locks; X if (curlock==nil) VOID putc(' ',fout); X while (curlock) { X VOID fprintf(fout," %s:%s",curlock->login, curlock->delta->num); X curlock = curlock->nextlock; X } X if (StrictLocks) VOID fprintf(fout,"; %s",Kstrict); X VOID fprintf(fout,";\n%s %c",Kcomment,SDELIM); X if((sp=Comment)!=nil) { X while (*sp) if (putc(*sp++,fout)==SDELIM) VOID putc(SDELIM,fout); X } X VOID fprintf(fout,"%c;\n\n",SDELIM); X} X X X X Xputdelta(node,fout) Xregister struct hshentry * node; Xregister FILE * fout; X/* Function: prints a <delta> node to fout; X */ X{ struct branchhead * nextbranch; X X if (node == nil) return; X X VOID fprintf(fout,"\n%s\n",node->num); X VOID fprintf(fout,"%s %s; %s %s; %s ", X Kdate,node->date,Kauthor,node->author,Kstate); X if (node->state!=nil) VOID fputs(node->state,fout); X VOID fputs(";\nbranches",fout); X nextbranch = node->branches; X if (nextbranch==nil) VOID putc(' ',fout); X while (nextbranch) { X VOID putc(' ',fout); X VOID fputs(nextbranch->hsh->num,fout); X nextbranch = nextbranch->nextbranch; X } X X VOID fprintf(fout,";\n%s ",Knext); X if (node->next!=nil) VOID fputs(node->next->num,fout); X VOID fputs(";\n",fout); X X} X X X X Xputtree(root,fout) Xstruct hshentry * root; Xregister FILE * fout; X/* Function: prints the delta tree in preorder to fout, starting with root. X */ X{ struct branchhead * nextbranch; X X if (root==nil) return; X X if (root->selector !=DELETE)putdelta(root,fout); X /* selector DELETE means deleted; set by rcs -o */ X X puttree(root->next,fout); X X nextbranch = root->branches; X while (nextbranch) { X puttree(nextbranch->hsh,fout); X nextbranch = nextbranch->nextbranch; X } X} X X X Xint putdtext(num,log,srcfilename,fout) Xchar * num, * log, * srcfilename; FILE * fout; X/* Function: write a deltatext-node to fout. X * num points to the deltanumber, log to the logmessage, and X * sourcefile contains the text. Doubles up all SDELIMs in both the X * log and the text; Makes sure the log message ends in \n. X * returns false on error. X */ X{ X register char * sp; X register int c; X register FILE * fin; X X VOID fprintf(fout,DELNUMFORM,num,Klog); X /* put log */ X VOID putc(SDELIM,fout); X sp=log; X while (*sp) if (putc(*sp++,fout)==SDELIM) VOID putc(SDELIM,fout); X if (*(sp-1)!='\n') VOID putc('\n', fout); /*append \n if necessary*/ X /* put text */ X VOID fprintf(fout, "%c\n%s\n%c",SDELIM,Ktext,SDELIM); X if ((fin=fopen(srcfilename,"r"))==NULL) { X error("Can't open source file %s",srcfilename); X return false; X } X while ((c=fgetc(fin))!=EOF) { X if (c==SDELIM) VOID putc(SDELIM,fout); /*double up SDELIM*/ X VOID putc(c,fout); X } X VOID putc(SDELIM,fout); VOID putc('\n',fout); X VOID fclose(fin); X return true; X} X X X X#ifdef SYNTEST X Xmain(argc,argv) Xint argc; char * argv[]; X{ X X cmdid = "syntest"; 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 putadmin(stdout); X X gettree(); X puttree(Head,stdout); X X getdesc(true); X X if (nextlex(),nexttok!=EOFILE) { X fatserror("Syntax error"); X } X exit(0); X} X X Xcleanup(){} X/*dummy*/ X X X#endif X X@ X X X4.6.2.1 Xlog X@Start of Amiga RCS port branch. X@ Xtext X@d5 1 Xa5 5 X<<<<<<< rcssyn.c Xstatic char rcsid[]= "$Id: rcssyn.c,v 4.6.1.1 89/08/11 01:43:06 rsbx Exp Locker: rsbx $ Purdue CS"; X======= Xstatic char rcsid[]= "$Id: rcssyn.c,v 1.2 89/09/17 13:36:37 rick Exp $ Purdue CS"; X>>>>>>> 1.2 Xa41 16 X<<<<<<< rcssyn.c X * Revision 4.6.1.1 89/08/11 01:43:06 rsbx X * Start of cbmvax RCS source branch. X * X * Revision 4.6 89/05/01 15:13:32 narten X * checked in with -k by rsbx at 89.08.10.16.23.06. X======= X * Revision 1.2 89/09/17 13:36:37 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:39 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: rcssyn.c,v 4.6.2.1 89/10/13 19:19:15 rsbx Exp Locker: rsbx $ Purdue CS"; Xd46 1 Xa46 3 X * Revision 4.6.2.1 89/10/13 19:19:15 rsbx X * Start of Amiga RCS port branch. X * Xd52 9 X@ X X X4.6.1.1 Xlog X@Start of cbmvax RCS source branch. X@ Xtext X@a42 3 X * checked in with -k by rsbx at 89.08.10.16.23.06. X * X * Revision 4.6 89/05/01 15:13:32 narten X@ SHAR_EOF echo "extracting rcs/rcs.rcsfiles/rcsutil.c,v" sed 's/^X//' << \SHAR_EOF > rcs/rcs.rcsfiles/rcsutil.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.40; author narten; state Exp; Xbranches 4.6.1.1 4.6.2.1; Xnext ; X X4.6.1.1 Xdate 89.08.11.01.43.12; author rsbx; state Exp; Xbranches ; Xnext 4.6.1.2; X X4.6.1.2 Xdate 89.08.11.02.17.29; author rsbx; state Exp; Xbranches ; Xnext 4.6.1.3; X X4.6.1.3 Xdate 89.10.16.15.08.36; author rsbx; state Exp; Xbranches ; Xnext ; X X4.6.2.1 Xdate 89.10.13.19.19.20; author rsbx; state Exp; Xbranches ; Xnext 4.6.2.2; X X4.6.2.2 Xdate 89.10.15.15.45.09; author rsbx; state Exp; Xbranches ; Xnext 4.6.2.3; X X4.6.2.3 Xdate 89.10.15.18.27.58; author rsbx; state Exp; Xbranches ; Xnext 4.6.2.4; X X4.6.2.4 Xdate 89.10.16.19.01.15; author rsbx; state Exp; Xbranches ; Xnext 4.6.2.5; X X4.6.2.5 Xdate 89.10.16.19.07.28; author rsbx; state Exp; Xbranches ; Xnext 4.6.2.6; X X4.6.2.6 Xdate 89.10.16.23.54.57; author rsbx; state Exp; Xbranches ; Xnext 4.6.2.7; X X4.6.2.7 Xdate 89.10.17.15.04.39; author rsbx; state Exp; Xbranches ; Xnext 4.6.2.8; X X4.6.2.8 Xdate 89.10.18.10.54.09; author rsbx; state Exp; Xbranches ; Xnext ; X X Xdesc X@RCS utilities. X@ X X X4.6 Xlog X@checked in with -k by rsbx at 89.08.10.16.23.16. X@ Xtext X@/* X * RCS utilities X */ X#ifndef lint Xstatic char rcsid[]= "$Id: rcsutil.c,v 4.6 89/05/01 15:13:40 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: rcsutil.c,v $ X * Revision 4.6 89/05/01 15:13:40 narten X * changed copyright header to reflect current distribution rules X * X * Revision 4.5 88/11/08 16:01:02 narten X * corrected use of varargs routines X * X * Revision 4.4 88/11/08 12:00:28 narten X * changes from eggert@@sm.unisys.com (Paul Eggert) X * X * Revision 4.4 88/08/09 19:13:24 eggert X * Check for memory exhaustion. X * Permit signal handlers to yield either 'void' or 'int'; fix oldSIGINT botch. X * Use execv(), not system(); yield exit status like diff(1)'s. X * X * Revision 4.3 87/10/18 10:40:22 narten X * Updating version numbers. Changes relative to 1.1 actually X * relative to 4.1 X * X * Revision 1.3 87/09/24 14:01:01 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:43 jenkins X * Port to suns X * X * Revision 1.1 84/01/23 14:50:43 kcs X * Initial revision X * X * Revision 4.1 83/05/10 15:53:13 wft X * Added getcaller() and findlock(). X * Changed catchints() to check SIGINT for SIG_IGN before setting up the signal X * (needed for background jobs in older shells). Added restoreints(). X * Removed printing of full RCS path from logcommand(). X * X * Revision 3.8 83/02/15 15:41:49 wft X * Added routine fastcopy() to copy remainder of a file in blocks. X * X * Revision 3.7 82/12/24 15:25:19 wft X * added catchints(), ignoreints() for catching and ingnoring interrupts; X * fixed catchsig(). X * X * Revision 3.6 82/12/08 21:52:05 wft X * Using DATEFORM to format dates. X * X * Revision 3.5 82/12/04 18:20:49 wft X * Replaced SNOOPDIR with SNOOPFILE; changed addlock() to update X * lockedby-field. X * X * Revision 3.4 82/12/03 17:17:43 wft X * Added check to addlock() ensuring only one lock per person. X * Addlock also returns a pointer to the lock created. Deleted fancydate(). X * X * Revision 3.3 82/11/27 12:24:37 wft X * moved rmsema(), trysema(), trydiraccess(), getfullRCSname() to rcsfnms.c. X * Introduced macro SNOOP so that snoop can be placed in directory other than X * TARGETDIR. Changed %02d to %.2d for compatibility reasons. X * X * Revision 3.2 82/10/18 21:15:11 wft X * added function getfullRCSname(). X * X * Revision 3.1 82/10/13 16:17:37 wft X * Cleanup message is now suppressed in quiet mode. X */ X X X X X#include <sys/types.h> X#include <sys/stat.h> X#include <signal.h> X#include "rcsbase.h" X#include <pwd.h> X#include <varargs.h> X X#if defined(USG) || defined(V4_2BSD) X#include <fcntl.h> X#endif X X#ifndef V4_2BSD X#define vfork fork X#endif X Xextern char * bindex(); Xextern FILE * finptr; Xextern char * RCSfilename; Xextern char * getlogin(); Xextern struct passwd *getpwuid(); Xextern char * malloc(); X X Xchar * talloc(size) Xunsigned size; X{ X char * p; X if (!(p = malloc(size))) { X faterror("out of memory"); X } X return p; X} X X X Xchar * getcaller() X/* Function: gets the callers login from his uid. X * If the uid is root, tries to get the true login with getlogin(). X */ X{ char * name; X int uid; X uid=getuid(); X if (uid==0) { X /* super user; try getlogin() to distinguish */ X name = getlogin(); X if (name!=nil && *name!='\0') X return name; X } X return(getpwuid(uid)->pw_name); X} X X X Xstruct hshentry * findlock(who,delete) Xchar * who; int delete; X/* Finds the first lock held by who and returns a pointer X * to the locked delta; also removes the lock if delete==true. X * Returns nil if there is no lock held by who. X */ X{ X register struct lock * next, * trail; X struct lock dummy; X X dummy.nextlock=next=Locks; X trail = &dummy; X while (next!=nil) { X if(strcmp(who,next->login)==0) break; /*found a lock*/ X trail=next; X next=next->nextlock; X } X if (next!=nil) { X /* found one */ X if (delete) { X /* delete it */ X trail->nextlock=next->nextlock; X Locks=dummy.nextlock; X next->delta->lockedby=nil; /* reset locked-by */ X } X return next->delta; X } else return nil; X} X X X X X X X Xstruct lock * addlock(delta,who) Xstruct hshentry * delta; char * who; X/* Given a delta, addlock checks whether X * the delta is locked by somebody other than who. X * If so, an error message is printed, and false returned. X * If the delta is not reserved at all, a lock for it is added, X * and a pointer for the lock returned. X */ X{ X struct lock * next; X X next=Locks; X while (next!=nil) { X if (cmpnum(delta->num,next->delta->num)==0) { X if (strcmp(who,next->login)==0) X return next; X /* lock exists already */ X else { X error("revision %s already locked by %s", X delta->num, next->login); X return false; X } X } else { X if (strcmp(who,next->login)==0) { X error("you already locked %s; only one lock allowed per person.", X next->delta->num); X return false; X } else { X next=next->nextlock; X } X } X } X /* not found; set up new lockblock */ X next= (struct lock *) talloc(sizeof (struct lock)); X delta->lockedby=next->login=who; X next->delta= delta; X next->nextlock=Locks; X Locks=next; X return next; X} X X X Xint addsymbol(delta,name,rebind) Xstruct hshentry * delta; char * name; int rebind; X/* Function: adds a new symbolic name and associates it with node delta. X * If name already exists and rebind is true, the name is associated X * with the new delta; otherwise, an error message is printed and X * false returned. Returns true it successful. X */ X{ register struct assoc * next; X next=Symbols; X while (next!=nil) { X if (strcmp(name,next->symbol)==0) { X if (rebind) { X next->delta=delta; X return true; X } else { X error("symbolic name %s already bound to %s", X name,next->delta->num); X return false; X } X } else next = next->nextassoc; X } X /* not found; insert new pair. */ X next = (struct assoc *) talloc(sizeof(struct assoc)); X next->symbol=name; X next->delta=delta; X next->nextassoc=Symbols; X Symbols = next; X return true; X} X X X X Xint checkaccesslist(who) Xchar * who; X/* function: Returns true if who is the superuser, the owner of the X * file, the access list is empty, or who is on the access list. X * Prints an error message and returns false otherwise. X */ X{ X register struct access * next; X struct stat statbuf; X X if ((AccessList==nil) || (strcmp(who,"root")==0)) X return true; X X next=AccessList; X do { X if (strcmp(who,next->login)==0) X return true; X next=next->nextaccess; X } while (next!=nil); X X VOID fstat(fileno(finptr),&statbuf); /* get owner of file */ X if (getuid() == statbuf.st_uid) return true; X X error("User %s not on the access list",who); X return false; X} X X Xstatic SIGNAL_TYPE catchsig(s) X{ X ignoreints(); X diagnose("\nRCS: cleaning up\n"); X VOID cleanup(); X exit(2); X#ifdef lint X catchsig(s); X#endif X} X Xstatic sig[] = {SIGINT,SIGHUP,SIGQUIT,SIGPIPE,SIGTERM}; X#define SIGS (sizeof(sig)/sizeof(*sig)) Xstatic SIGNAL_TYPE (*catcher[SIGS])(); X X void catchints() X { X register i; X for (i=SIGS; 0<=--i; ) X catcher[i] = X signal(sig[i],SIG_IGN) == SIG_IGN ? SIG_IGN : catchsig; X restoreints(); X } X X void ignoreints() X { X register i; X for (i=SIGS; 0<=--i; ) X VOID signal(sig[i], SIG_IGN); X } X Xvoid restoreints() X{ X register i; X for (i=SIGS; 0<=--i; ) X if (catcher[i] != SIG_IGN) X VOID signal(sig[i], catcher[i]); X} X Xfastcopy(inf,outf) XFILE * inf, * outf; X/* Function: copies the remainder of file inf to outf. First copies the X * rest that is in the IO-buffer of inf character by character, and then X * copies the remainder in blocks. X */ X{ char buf[BUFSIZ]; X register int rcount, wcount; X X /* write the rest of the buffer to outf */ X while ((--inf->_cnt)>=0) { X VOID putc(*inf->_ptr++&0377,outf); X } X if (fflush(outf) == EOF) { X writeerror(); X } X X /*now read the rest of the file in blocks*/ X while ((rcount=read(fileno(inf),buf,BUFSIZ))>0) { X wcount=write(fileno(outf),buf,rcount); X if (wcount!=rcount) { X writeerror(); X } X } X} X X X X X X X#ifdef SNOOPFILE X X#include "time.h" Xextern struct tm* localtime(); Xextern long time(); X Xlogcommand(commandname,delta, sequence,login) Xchar* commandname; struct hshentry * delta, * sequence[];char * login; X/* Function: start a process to write the file that X * logs the RCS command. X * Each line in the log file contains the following information: X * operation, revision(r), backward deltas applied(b), forward deltas applied(f), X * total deltas present(t), creation date of delta(d), date of operation(o), X * login of caller, RCS file name. X */ X{ X char logline[200]; X char curdate[datelength]; X char *inoutargs[5]; X register int i, backward, forward; X long clock; X struct tm * tm; X X clock=time((long *)0); X tm=localtime(&clock); X X VOID sprintf(curdate,DATEFORM, X tm->tm_year, tm->tm_mon+1, tm->tm_mday, X tm->tm_hour, tm->tm_min, tm->tm_sec); X X i= backward=forward=0; X while(sequence[i]!=nil) { /* count deltas to be applied*/ X if (countnumflds(sequence[i]->num) == 2) X backward++; /* reverse delta */ X else forward++; /* branch delta */ X i++; X } X VOID sprintf(logline,"%s %10sr %3db %3df %3dt %sc %so %s %s", X commandname,delta->num,backward,forward,TotalDeltas,delta->date, X curdate,login,bindex(getfullRCSname(),'/')); X inoutargs[0] = nil; X inoutargs[1] = nil; X inoutargs[2] = SNOOP; X inoutargs[3] = logline; X inoutargs[4] = nil; X VOID run_back(inoutargs); X} X#endif X X Xstatic int fdreopen(fd, file, flags, mode) X char *file; X{ X int newfd; X VOID close(fd); X newfd = flags==-1 ? creat(file,mode) : open(file,flags,mode); X if (newfd < 0 || newfd == fd) X return newfd; X#ifdef F_DUPFD X fd = fcntl(newfd, F_DUPFD, fd); X#else X fd = dup2(newfd, fd); X#endif X VOID close(newfd); X return fd; X} X Xstatic void tryopen(fd,file,flags) X char *file; X{ X if (file && fdreopen(fd,file,flags,0600) != fd) { X VOID write(fileno(stderr), file, strlen(file)); X VOID write(fileno(stderr), ": cannot open\n", 14); X _exit(2); X } X} X X/* X/* Run in the background a command specified by the strings in 'inoutargs'. X/* inoutargs[0], if nonnil, is the name of the input file. X/* inoutargs[1], if nonnil, is the name of the output file. X/* inoutargs[2..] form the command to be run in the background. X/*/ Xstatic int run_back(inoutargs) X register char **inoutargs; X{ X int pid; X if (fflush(stdout) == EOF || fflush(stderr) == EOF) X return -1; X if (!(pid = vfork())) { X tryopen(fileno(stdin), inoutargs[0], 0); X tryopen(fileno(stdout), inoutargs[1], -1); X VOID execv(inoutargs[2], &inoutargs[2]); X inoutargs[1] = "/bin/sh"; X VOID execv(inoutargs[1], &inoutargs[1]); X VOID write(fileno(stderr), "/bin/sh: not found\n", 19); X _exit(2); X } X return pid; X} X X#define CARGSMAX 20 X/* X/* Run a command. X/* The first two arguments are the input and output files (if nonnil); X/* the rest specify the command and its arguments. X/*/ Xint run(va_alist) X va_dcl X{ X va_list ap; X int pid, wstatus, w; X char *rgargs[CARGSMAX]; X register i = 0; X va_start(ap); X rgargs[0] = va_arg(ap, char *); X rgargs[1] = va_arg(ap, char *); X for (i =2; i< CARGSMAX; i++) { X rgargs[i] = va_arg(ap, char *); X if (rgargs[i] == NULL) X break; X } X va_end(ap); X pid = run_back(rgargs); X if (pid < 0) X return pid; X for (;;) X if ((w = wait(&wstatus)) < 0) X return w; X else if (w == pid) X return wstatus; X} X@ X X X4.6.2.1 Xlog X@Start of Amiga RCS port branch. X@ Xtext X@d5 1 Xa5 5 X<<<<<<< rcsutil.c Xstatic char rcsid[]= "$Id: rcsutil.c,v 4.6.1.2 89/08/11 02:17:29 rsbx Exp Locker: rsbx $ Purdue CS"; X======= Xstatic char rcsid[]= "$Id: rcsutil.c,v 1.2 89/09/17 13:36:49 rick Exp $ Purdue CS"; X>>>>>>> 1.2 Xa36 14 X<<<<<<< rcsutil.c X * Revision 4.6.1.2 89/08/11 02:17:29 rsbx X * Changed catchints() to compile on cbmvax. X======= X * Revision 1.2 89/09/17 13:36:49 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<<<<<<< rcsutil.c X * Revision 4.6.1.1 89/08/11 01:43:12 rsbx X * Start of cbmvax RCS source branch. X * Xa37 3 X * checked in with -k by rsbx at 89.08.10.16.23.16. X * X * Revision 4.6 89/05/01 15:13:40 narten Xa50 11 X======= X * Revision 1.4 89/09/16 09:43:48 rick X * Modified AMIGA changes to work with Lattice C X * X * Revision 1.3 88/09/03 17:16:22 rick X * Make fastcopy really fast for AmigaDos X * X * Revision 1.2 88/09/03 15:12:57 rick X * Port to AmigaDos. All done with conditional compiles X * X>>>>>>> 1.2 Xd103 1 Xa103 1 X#ifndef AMIGA Xd107 1 Xa108 1 X<<<<<<< rcsutil.c Xa113 7 X======= X#else X#include "stat.h" X#include <signal.h> X#endif X#include "rcsbase.h" X>>>>>>> 1.2 Xa125 8 X<<<<<<< rcsutil.c X======= X#ifdef AMIGA Xshort oldSIGINT; X#else Xint (*oldSIGINT)(); /* saves the original value for SIGINT */ X#endif X>>>>>>> 1.2 Xa126 1 X<<<<<<< rcsutil.c Xa135 6 X======= X#ifdef AMIGA Xchar *getcaller() X{ X char *getenv(); X>>>>>>> 1.2 Xa136 1 X<<<<<<< rcsutil.c Xa138 5 X======= X return(getenv("LOGNAME")); X} X#else X>>>>>>> 1.2 Xa153 1 X#endif Xd156 1 Xa287 3 X#ifdef AMIGA X return true; X#else Xa292 1 X#endif Xa294 1 X<<<<<<< rcsutil.c Xa298 31 X======= X#ifdef AMIGA X Xcatchsig() X{ X diagnose("\nRCS: cleaning up\n"); X VOID cleanup(); X exit(1); X} X Xvoid catchints() X{ X signal(SIGINT,catchsig); X} X Xvoid ignoreints() X{ X signal(SIGINT,SIG_IGN); X} X Xvoid restoreints() X{ X signal(SIGINT,catchsig); X} X X#else X Xcatchsig(sig) X{ X VOID signal(sig, SIG_IGN); X>>>>>>> 1.2 Xd315 2 Xa316 4 X if (signal(sig[i],SIG_IGN) == SIG_IGN) X catcher[i] = SIG_IGN; X else X catcher[i] = catchsig; Xa333 1 X#endif Xa334 1 X<<<<<<< rcsutil.c Xa335 27 X======= X#ifdef AMIGA X#define AMIGABUF (4 *1024) Xfastcopy(inf,outf) XFILE *inf,*outf; X{ X static char buf[AMIGABUF]; X register int rcount, wcount; X int infd,outfd; X X while (inf->_rcnt--) X putc(*inf->_ptr++,outf); X fflush(outf); X infd = fileno(inf); X outfd = fileno(outf); X X while ((rcount = read(infd,buf,AMIGABUF)) > 0) { X if (rcount) { X wcount = write(outfd,buf,rcount); X if (wcount!=rcount) X faterror("write error"); X } X } X} X#else Xfastcopy(inf,outf) X>>>>>>> 1.2 Xa359 4 X<<<<<<< rcsutil.c X======= X#endif X>>>>>>> 1.2 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: rcsutil.c,v 4.6.2.1 89/10/13 19:19:20 rsbx Exp Locker: rsbx $ Purdue CS"; Xd41 1 Xa41 3 X * Revision 4.6.2.1 89/10/13 19:19:20 rsbx X * Start of Amiga RCS port branch. X * Xd44 6 Xd51 1 Xd72 11 Xd140 2 Xd146 1 Xa146 1 X Xa150 1 X Xd152 1 Xa153 6 X#ifdef STDARGS X#include <stdarg.h> X#else X#include <varargs.h> X#endif X Xd165 2 Xd168 1 Xa168 2 Xextern int run_back(char **inoutargs); X/* short oldSIGINT; */ Xd172 1 Xd174 1 Xd184 1 Xa184 2 X X Xd189 6 Xd198 1 Xa335 1 X#ifndef AMIGA Xd337 1 Xa337 1 X#endif Xd359 6 Xd367 1 Xa367 1 Xstatic SIGNAL_TYPE catchsig() Xd391 1 Xa391 1 Xstatic SIGNAL_TYPE catchsig(s) Xd393 2 Xa394 1 X ignoreints(); Xd407 1 Xa407 1 Xvoid catchints() Xd418 1 Xa418 1 Xvoid ignoreints() Xd434 3 Xd462 1 Xd487 2 Xd490 1 Xd546 1 Xa546 1 X#ifndef AMIGA Xa596 1 X#endif Xa598 1 X#ifdef STDARGS Xd600 4 Xa603 34 X * Run a command. X * The first two arguments are the input and output files (if nonnil); X * the rest specify the command and its arguments. X */ Xint run(char *arg0, char *arg1, ...) X{ X va_list ap; X int pid, wstatus, w; X char *rgargs[CARGSMAX]; X register i; X va_start(ap, arg1); X rgargs[0] = arg0; X rgargs[1] = arg1; X for (i =2; i< CARGSMAX; i++) { X rgargs[i] = va_arg(ap, char *); X if (rgargs[i] == NULL) X break; X } X va_end(ap); X pid = run_back(rgargs); X if (pid < 0) X return pid; X for (;;) X if ((w = wait(&wstatus)) < 0) X return w; X else if (w == pid) X return wstatus; X} X#else X/* X * Run a command. X * The first two arguments are the input and output files (if nonnil); X * the rest specify the command and its arguments. X */ Xa628 1 X#endif X@ X X X4.6.2.3 Xlog X@More changes to make Amiga port work. X@ Xtext X@d5 1 Xa5 1 Xstatic char rcsid[]= "$Id: rcsutil.c,v 4.6.2.2 89/10/15 15:45:09 rsbx Exp $ Purdue CS"; Xa36 4 X * Revision 4.6.2.2 89/10/15 15:45:09 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 * Xa167 2 Xchar *getenv(); Xstatic char *unknownname = "Unknown"; Xd170 2 Xa171 8 X char *name; X name = getenv("LOGNAME"); X X if ((name == NULL) || (*name == '\0')) X { X return unknownname; X } X return name; X@ X X X4.6.2.4 Xlog X@run() moved from rcsutil.c to amiga.c and made to work. X@ Xtext X@d5 1 Xa5 1 Xstatic char rcsid[]= "$Id: rcsutil.c,v 4.6.1.3 89/10/16 15:08:36 rsbx Exp $ Purdue CS"; Xa36 3 X * Revision 4.6.2.3 89/10/15 18:27:58 rsbx X * More changes to make Amiga port work. X * Xd153 6 Xd571 1 Xa634 1 X#endif X@ X X X4.6.2.5 Xlog X@Changed file path handling to deal with Amiga file path sematics. X@ Xtext X@a36 3 X * Revision 4.6.1.3 89/10/16 15:08:36 rsbx X * run() move from rcsutil.c to amiga.c and made to work. X * Xd122 1 Xa122 4 X#ifdef AMIGA X#include "stat.h" X#include <signal.h> X#else Xd132 3 Xd149 1 Xd430 3 Xa432 3 X if (wcount!=rcount) X faterror("write error"); X } Xd507 1 Xa507 1 X curdate,login,fnamepart(getfullRCSname())); X@ X X X4.6.2.6 Xlog X@Changes to getcaller(). X@ Xtext X@d5 1 Xa5 1 Xstatic char rcsid[]= "$Id: rcsutil.c,v 4.6.2.5 89/10/16 19:07:28 rsbx Exp $ Purdue CS"; Xa36 3 X * Revision 4.6.2.5 89/10/16 19:07:28 rsbx X * Changed file path handling to deal with Amiga file path sematics. X * Xa140 1 X#include <ctype.h> Xd176 1 Xa176 2 X char *sp; X char c; Xd178 3 Xa180 18 X sp = name = getenv("LOGNAME"); X X#ifdef TODO X/* check for ethernet user/hostname */ X#endif X X if (sp) { X while ((c = *sp) && (isascii(c))) { X switch (ctab[c]) { X case IDCHAR: X case LETTER: X case DIGIT: X sp++; X continue; X default: X *sp = '\0'; X break; X } Xa181 5 X } X X if ((name == NULL) || (*name == '\0')) { X return unknownname; X } X@ X X X4.6.2.7 Xlog X@Yet more changes to getcaller(). X@ Xtext X@d5 1 Xa5 1 Xstatic char rcsid[]= "$Id: rcsutil.c,v 4.6.2.6 89/10/16 23:54:57 rsbx Exp $ Purdue CS"; Xa36 3 X * Revision 4.6.2.6 89/10/16 23:54:57 rsbx X * Changes to getcaller(). X * Xd183 1 Xa183 3 X if (!(name = getenv("LOGNAME"))) { X return unknownname; X } Xd188 13 Xa200 11 X sp =name; X while ((c = *sp) && (isascii(c))) { X switch (ctab[c]) { X case IDCHAR: X case LETTER: X case DIGIT: X sp++; X continue; X default: X *sp = '\0'; X break; Xd204 1 Xa204 3 X X if (*name == '\0') { X free(name); Xd207 1 Xa207 5 X X sp = talloc(sp-name+1); X strcpy(sp, name); X free(name); X return sp; X@ X X X4.6.2.8 Xlog X@LOGNAME changed to USERNAME. Still need to check the Ameristar software Xfor username. X@ Xtext X@d5 1 Xa5 1 Xstatic char rcsid[]= "$Id: rcsutil.c,v 4.6.2.7 89/10/17 15:04:39 rsbx Exp $ Purdue CS"; Xa36 3 X * Revision 4.6.2.7 89/10/17 15:04:39 rsbx X * Yet more changes to getcaller(). X * Xd186 1 Xa186 1 X if (!(name = getenv("USERNAME"))) { X@ X X X4.6.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.23.16. X * X * Revision 4.6 89/05/01 15:13:40 narten X@ X X X4.6.1.2 Xlog X@Changed catchints() to compile on cbmvax. X@ Xtext X@d5 1 Xa5 1 Xstatic char rcsid[]= "$Id: rcsutil.c,v 4.6.1.1 89/08/11 01:43:12 rsbx Exp Locker: rsbx $ Purdue CS"; Xa36 3 X * Revision 4.6.1.1 89/08/11 01:43:12 rsbx X * Start of cbmvax RCS source branch. X * Xd318 2 Xa319 4 X if (signal(sig[i],SIG_IGN) == SIG_IGN) X catcher[i] = SIG_IGN; X else X catcher[i] = catchsig; X@ X X X4.6.1.3 Xlog X@run() move from rcsutil.c to amiga.c and made to work. X@ Xtext X@d5 1 Xa5 1 Xstatic char rcsid[]= "$Id: rcsutil.c,v 4.6.2.3 89/10/15 18:27:58 rsbx Exp $ Purdue CS"; Xa36 13 X * Revision 4.6.2.3 89/10/15 18:27:58 rsbx X * More changes to make Amiga port work. X * X * Revision 4.6.2.2 89/10/15 15:45:09 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 * X * Revision 4.6.2.1 89/10/13 19:19:20 rsbx X * Start of Amiga RCS port branch. X * X * Revision 4.6.1.2 89/08/11 02:17:29 rsbx X * Changed catchints() to compile on cbmvax. X * Xd109 1 Xa109 1 X#ifndef AMIGA Xd113 1 Xd115 1 Xa120 13 X#else X#include "stat.h" X#include <signal.h> X#endif X X#include "rcsbase.h" X X#ifdef STDARGS X#include <stdarg.h> X#else X#include <varargs.h> X#endif X Xa143 7 X#ifdef AMIGA Xchar *getenv(); Xstatic char *unknownname = "Unknown"; Xchar *getcaller() X{ X char *name; X name = getenv("LOGNAME"); Xa144 7 X if ((name == NULL) || (*name == '\0')) X { X return unknownname; X } X return name; X} X#else Xa159 1 X#endif Xd162 1 Xa281 1 X#ifndef AMIGA Xd283 1 Xa283 1 X#endif Xa293 3 X#ifdef AMIGA X return true; X#else Xa298 1 X#endif Xa300 1 X#ifdef AMIGA Xa301 24 Xstatic SIGNAL_TYPE catchsig() X{ X diagnose("\nRCS: cleaning up\n"); X VOID cleanup(); X exit(1); X} X Xvoid catchints() X{ X signal(SIGINT,catchsig); X} X Xvoid ignoreints() X{ X signal(SIGINT,SIG_IGN); X} X Xvoid restoreints() X{ X signal(SIGINT,catchsig); X} X X#else X Xd317 1 Xa317 1 Xvoid catchints() Xd328 1 Xa328 1 Xvoid ignoreints() Xa341 1 X#endif Xa342 2 X#ifdef AMIGA X#define AMIGABUF (4 *1024) Xa343 22 XFILE *inf,*outf; X{ X static char buf[AMIGABUF]; X register int rcount, wcount; X int infd,outfd; X X while (inf->_rcnt--) X putc(*inf->_ptr++,outf); X fflush(outf); X infd = fileno(inf); X outfd = fileno(outf); X X while ((rcount = read(infd,buf,AMIGABUF)) > 0) { X if (rcount) { X wcount = write(outfd,buf,rcount); X if (wcount!=rcount) X faterror("write error"); X } X } X} X#else Xfastcopy(inf,outf) Xa367 1 X#endif Xd423 1 Xa423 1 X#ifndef AMIGA Xa475 1 X#ifdef STDARGS Xd477 4 Xa480 34 X * Run a command. X * The first two arguments are the input and output files (if nonnil); X * the rest specify the command and its arguments. X */ Xint run(char *arg0, char *arg1, ...) X{ X va_list ap; X int pid, wstatus, w; X char *rgargs[CARGSMAX]; X register i; X va_start(ap, arg1); X rgargs[0] = arg0; X rgargs[1] = arg1; X for (i =2; i< CARGSMAX; i++) { X rgargs[i] = va_arg(ap, char *); X if (rgargs[i] == NULL) X break; X } X va_end(ap); X pid = run_back(rgargs); X if (pid < 0) X return pid; X for (;;) X if ((w = wait(&wstatus)) < 0) X return w; X else if (w == pid) X return wstatus; X} X#else X/* X * Run a command. X * The first two arguments are the input and output files (if nonnil); X * the rest specify the command and its arguments. X */ Xa505 2 X#endif X#endif X@ SHAR_EOF echo "extracting rcs/rcs.rcsfiles/rlog.c,v" sed 's/^X//' << \SHAR_EOF > rcs/rcs.rcsfiles/rlog.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.13.48; author narten; state Exp; Xbranches 4.7.1.1 4.7.2.1; Xnext ; X X4.7.1.1 Xdate 89.08.11.01.43.14; author rsbx; state Exp; Xbranches ; Xnext ; X X4.7.2.1 Xdate 89.10.13.19.19.26; author rsbx; state Exp; Xbranches ; Xnext 4.7.2.2; X X4.7.2.2 Xdate 89.10.15.15.45.14; author rsbx; state Exp; Xbranches ; Xnext ; X X Xdesc X@RLOG operation. X@ X X X X4.7 Xlog X@checked in with -k by rsbx at 89.08.10.16.23.28. X@ Xtext X@/* X * RLOG operation X */ X#ifndef lint Xstatic char rcsid[]= X"$Header: /usr/src/local/bin/rcs/src/RCS/rlog.c,v 4.7 89/05/01 15:13:48 narten Exp $ Purdue CS"; X#endif X/***************************************************************************** X * print contents of RCS files 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 X/* $Log: rlog.c,v $ X * Revision 4.7 89/05/01 15:13:48 narten X * changed copyright header to reflect current distribution rules X * X * Revision 4.6 88/11/08 11:59:40 narten X * changes from eggert@@sm.unisys.com (Paul Eggert) X * X * Revision 4.6 88/08/09 19:13:28 eggert X * Check for memory exhaustion; don't access freed storage. X * Shrink stdio code size; remove lint. X * X * Revision 4.5 87/12/18 11:46:38 narten X * more lint cleanups (Guy Harris) X * X * Revision 4.4 87/10/18 10:41:12 narten X * Updating version numbers X * Changes relative to 1.1 actually relative to 4.2 X * X * Revision 1.3 87/09/24 14:01:10 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:45 jenkins X * Port to suns X * X * Revision 1.1 84/01/23 14:50:45 kcs X * Initial revision X * X * Revision 4.2 83/12/05 09:18:09 wft X * changed rewriteflag to external. X * X * Revision 4.1 83/05/11 16:16:55 wft X * Added -b, updated getnumericrev() accordingly. X * Replaced getpwuid() with getcaller(). X * X * Revision 3.7 83/05/11 14:24:13 wft X * Added options -L and -R; X * Fixed selection bug with -l on multiple files. X * Fixed error on dates of the form -d'>date' (rewrote getdatepair()). X * X * Revision 3.6 82/12/24 15:57:53 wft X * shortened output format. X * X * Revision 3.5 82/12/08 21:45:26 wft X * removed call to checkaccesslist(); used DATEFORM to format all dates; X * removed unused variables. X * X * Revision 3.4 82/12/04 13:26:25 wft X * Replaced getdelta() with gettree(); removed updating of field lockedby. X * X * Revision 3.3 82/12/03 14:08:20 wft X * Replaced getlogin with getpwuid(), %02d with %.2d, fancydate with PRINTDATE. X * Fixed printing of nil, removed printing of Suffix, X * added shortcut if no revisions are printed, disambiguated struct members. X * X * Revision 3.2 82/10/18 21:09:06 wft X * call to curdir replaced with getfullRCSname(), X * fixed call to getlogin(), cosmetic changes on output, X * changed conflicting long identifiers. X * X * Revision 3.1 82/10/13 16:07:56 wft X * fixed type of variables receiving from getc() (char -> int). X */ X X X X#include "time.h" X#include "rcsbase.h" X#ifndef lint Xstatic char rcsbaseid[] = RCSBASE; X#endif X Xextern char * partialno(); Xextern char * getcaller(); /*get login of caller */ Xextern free(); Xextern int countnumflds(); Xextern int compartial(); Xextern int expandsym(); /*get numeric name of a revision */ Xextern int nextc; /*next input character */ Xextern char Klog[]; Xextern char Ktext[]; Xextern int partime(); Xextern long maketime(); /*convert parsed time to unix time. */ Xextern struct tm * localtime(); /*convert unixtime into a tm-structure */ Xextern int pairfilenames(); Xextern struct hshentry * getnum(); Xextern FILE * finptr; /* RCS input file */ Xextern FILE * frewrite; /* new RCS file */ Xextern int rewriteflag; /* indicates whether input should be */ X /* echoed to frewrite */ Xextern int nerror; /* error counter */ X Xchar * RCSfilename, * workfilename; X Xchar * caller; /* caller's login; */ Xint descflag, selectflag, selectop; /* option to print access list, symbolic */ X /* names, descriptive text, locks and */ X /* Head */ Xint onlylockflag; /* option to print only files */ X /* with locks */ Xint onlyRCSflag; /* option to print only RCS file name */ Xint lockflag; /* whether locker option is set */ Xint revno; /* number of revision chosen */ X Xstruct lockers { /* lockers in locker option; stored */ X char * login; /* lockerlist */ X struct lockers * lockerlink; X } ; X Xstruct stateattri { /* states in state option; stored in */ X char * status; /* statelist */ X struct stateattri * nextstate; X } ; X Xstruct authors { /* login names in author option; */ X char * login; /* stored in authorlist */ X struct authors * nextauthor; X } ; X Xstruct Revpairs{ /* revision or branch range in -r */ X int numfld; /* option; stored in revlist */ X char * strtrev; X char * endrev; X struct Revpairs * rnext; X } ; X Xstruct Datepairs{ /* date range in -d option; stored in */ X char strtdate[datelength]; /* duelst and datelist */ X char enddate[datelength]; X struct Datepairs * dnext; X }; X Xchar Dotstring[200]; /* string of numeric revision name */ Xchar * Nextdotstring; /* next available place of Dotstring */ Xstruct Datepairs * datelist, * duelst; Xstruct Revpairs * revlist, * Revlst; Xint branchflag; /* set on -b */ Xstruct lockers * lockerlist; Xstruct stateattri * statelist; Xstruct authors * authorlist; X X X Xmain (argc, argv) Xint argc; Xchar * argv[]; X{ X struct Datepairs * currdate; X struct assoc * curassoc; X struct access * curaccess; X struct lock * currlock; X char * cmdusage; X X cmdusage = "command format:\nrlog -L -R -h -t -b -ddates -l[lockers] -rrevisions -sstates -w[logins] file ..."; X cmdid = "rlog"; X descflag = selectflag = true; X lockflag = onlylockflag = selectop = false; X onlyRCSflag = false; X lockerlist = nil; X authorlist = nil; X statelist = nil; X Revlst = revlist = nil; X branchflag= false; X duelst = datelist = nil; X caller=getcaller(); X X while (--argc,++argv, argc>=1 && ((*argv)[0] == '-')) { X switch ((*argv)[1]) { X X case 'L': X onlylockflag = true; X break; X X case 'R': X onlyRCSflag =true; X break; X X case 'l': X selectop = true; X lockflag = true; X getlocker( (*argv)+2 ); X break; X X case 'b': X selectop = true; X branchflag = true; X break; X X case 'r': X selectop = true; X getrevpairs( (*argv)+2 ); X break; X X case 'd': X selectop = true; X getdatepair( (*argv)+2 ); X break; X X case 's': X selectop = true; X getstate( (*argv)+2); X break; X X case 'w': X selectop = true; X getauthor( (*argv)+2); X break; X X case 'h': X if ( ! selectflag ) warn("option -t overrides -h"); X else descflag = false; X break; X X case 't': X selectflag = false; X if ( ! descflag ) warn("option -t overrides -h"); X descflag = true; X break; X X default: X faterror("unknown option: %s\n%s", *argv,cmdusage); X X }; X } /* end of option processing */ X X if (argc<1) faterror("No input file\n%s",cmdusage); X X X /* now handle all filenames */ X do { X rewriteflag=false; X finptr=frewrite=nil; X X X if (!pairfilenames(argc, argv, true,false)) continue; X X /* now RCSfilename contains the name of the RCS file, and finptr X * the file descriptor. Workfilename contains the name of the X * working file. X */ X X if ( !trysema(RCSfilename, false)) goto loopend; /* give up */ X X /* do nothing if -L is given and there are no locks*/ X if ( onlylockflag && Locks == nil ) goto loopend; X X if ( onlyRCSflag ) { X VOID fprintf(stdout, "%s\n", RCSfilename); X goto loopend; X } X /* print RCS filename , working filename and optional X administrative information */ X VOID fprintf(stdout, "\nRCS file: %s; ",RCSfilename); X /* could use getfullRCSname() here, but that is very slow */ X VOID fprintf(stdout, "Working file: %s\n", workfilename); X VOID fprintf(stdout, "head: %s\n", Head==nil?"":Head->num); X VOID fprintf(stdout, "branch: %s\n", Dbranch==nil?"":Dbranch->num); X X VOID fputs("locks: ", stdout); /* print locker list */ X currlock = Locks; X while( currlock ) { X VOID fprintf(stdout," %s: %s;", currlock->login, X currlock->delta->num); X currlock = currlock->nextlock; X } X if ( StrictLocks ) X VOID fputs(Locks==nil?" ; strict":" strict",stdout); X X VOID fputs("\naccess list: ", stdout); /* print access list */ X curaccess = AccessList; X while(curaccess) { X VOID fputs(" ",stdout); X VOID fputs(curaccess->login, stdout); X curaccess = curaccess->nextaccess; X } X X VOID fputs("\nsymbolic names:", stdout); /* print symbolic names */ X curassoc = Symbols; X while( curassoc ) { X VOID fprintf(stdout, " %s: %s;",curassoc->symbol, X curassoc->delta->num); X curassoc = curassoc->nextassoc; X } X X VOID fprintf(stdout,"\ncomment leader: \"%s\"\n",Comment); X X gettree(); X VOID fprintf(stdout, "total revisions: %d; ", TotalDeltas); X if ( Head == nil || !selectflag || !descflag) { X VOID putc('\n',stdout); X if (descflag) VOID fputs("description:\n", stdout); X getdesc(descflag); X VOID fputs("=============================================================================\n",stdout); X goto loopend; X } X X X /* keep only those locks given by -l */ X if (lockflag) X trunclocks(); X getnumericrev(); /* get numeric revision or branch names */ X revno = 0; X X exttree(Head); X X /* get most recently date of the dates pointed by duelst */ X currdate = duelst; X while( currdate) { X recentdate(Head, currdate); X currdate = currdate->dnext; X } X X extdate(Head); X X /* reinitialize the date specification list */ X currdate = duelst; X while(currdate) { X VOID sprintf(currdate->strtdate,DATEFORM,0,0,0,0,0,0); X currdate = currdate->dnext; X } X X if ( selectop || ( selectflag && descflag) ) X VOID fprintf(stdout, "selected revisions: %d", revno); X VOID putc('\n', stdout); X if (descflag) VOID fputs("description:\n", stdout); X getdesc(descflag); X while( (nexttok != EOFILE) && readdeltalog()); X if (selectflag && descflag && revno) { X putrunk(); X putree(Head); X if (nextlex(), nexttok != EOFILE) X fatserror("syntax error; expecting EOF"); X } X VOID fputs("=============================================================================\n",stdout); X loopend: X VOID fclose(finptr); X } while( ++argv, --argc >= 1); X exit(nerror!=0); X} X X X Xputrunk() X/* function: print revisions chosen, which are in trunk */ X X{ X struct hshentry * ptr, * pre; X X if (Head == nil) return; /* empty tree */ X X pre = Head; X ptr = Head->next; X while( ptr ) { X putadelta(pre,ptr,true); X pre = ptr; X ptr = ptr->next; X } X putadelta(pre,ptr,true); X} X X X Xputree(root) Xstruct hshentry *root; X/* function: print delta tree( not include trunck) in reversed calender X order on each branch */ X X{ X if ( root == nil ) return; X X putree(root->next); X X putforest(root->branches); X} X X X X Xputforest(branchroot) Xstruct branchhead * branchroot; X/* function: print branches that has the same direct ancestor */ X{ X X if ( branchroot == nil ) return; X X putforest(branchroot->nextbranch); X X putabranch(branchroot->hsh); X putree(branchroot->hsh); X} X X X X Xputabranch(root) Xstruct hshentry *root; X/* function : print one branch */ X X{ X X if ( root == nil) return; X X putabranch(root->next); X X putadelta(root, root, false); X} X X X X X Xputadelta(node,editscript,trunk) Xregister struct hshentry * node; Xregister struct hshentry * editscript; Xint trunk; X/* function: print delta node if node->selector is 's'. */ X/* editscript indicates where the editscript is stored */ X/* trunk indicated whether this node is in trunk */ X{ X struct branchhead * newbranch; X char * branchnum, branch[40]; X X if ( ( node == nil) || ( node->selector == 'u')) X return; X X VOID fprintf(stdout,"----------------------------\n"); X VOID fprintf(stdout, "revision %s ",node->num); X if ( node->lockedby ) X VOID fprintf(stdout, "locked by: %s; ", node->lockedby); X VOID putc('\n', stdout); X X VOID fputs("date: ",stdout); X VOID PRINTDATE(stdout,node->date); VOID putc(' ',stdout); X VOID PRINTTIME(stdout,node->date); X VOID fprintf(stdout, "; author: %s; ", node->author); X VOID fprintf(stdout, "state: %s; ", node->state); X X if ( editscript ) X if(trunk) X VOID fprintf(stdout,"lines added/del: %d/%d", X editscript->deletelns, editscript->insertlns); X else X VOID fprintf(stdout,"lines added/del: %d/%d", X editscript->insertlns, editscript->deletelns); X X VOID putc('\n', stdout); X X branchnum = & (branch[0]); X newbranch = node->branches; X if ( newbranch ) { X VOID fputs("branches: ", stdout); X while( newbranch ) { X getbranchno(newbranch->hsh->num, branchnum); X VOID fprintf(stdout, "%s; ", branchnum); X newbranch = newbranch->nextbranch; X } X VOID putc('\n', stdout); X } X X VOID fputs(node->log,stdout); X} X X X X X Xreaddeltalog() X/* Function : get the log message and skip the text of a deltatext node. X * Return false if current block does not start with a number. X * Assumes the current lexeme is not yet in nexttok; does not X * advance nexttok. X */ X{ X register struct hshentry * Delta; X X nextlex(); X if ( !(Delta = getnum() )) return(false); X if ( ! getkey(Klog) || ( nexttok != STRING ) ) X fatserror("Missing log entry"); X Delta->log = talloc(logsize); X VOID savestring(Delta->log, logsize); X nextlex(); X if ( ! getkey(Ktext) || (nexttok != STRING) ) X fatserror("Missing delta text"); X Delta->insertlns = Delta->deletelns = 0; X if ( Delta != Head) X getscript(Delta); X else X readstring(); X return true; X} X X X Xgetscript(Delta) Xstruct hshentry * Delta; X/* function: read edit script of Delta and count how many lines added */ X/* and deleted in the script */ X X{ X int ed; /* editor command */ X register FILE * fin; X register int c; X register int i; X int length; X X fin = finptr; X while( (ed = getc(fin)) != EOF) { X /* assume first none white character is command name */ X while( ed == '\n' || ed == ' ' || ed == '\t') X ed = getc(fin); X if (ed == SDELIM) break; /* script text is ended */ X while( ( c = getc(fin)) == ' ' ); /* skip blank */ X if ( ! ('0' <= c && c <= '9')) { X faterror("Missing line number in edit script"); X break; X } X while( '0' <= (c = getc(fin)) && c <= '9' ) ; X X while( c == ' ')c = getc(fin); /* skip blanks */ X if ( !('0' <= c && c <= '9' ) ) { X faterror("Incorrect range in edit script"); X break; X } X length = c - '0'; X while( '0' <= (c = getc(fin)) && c <= '9' ) X length = length * 10 + c - '0'; X while( c != '\n' && c != EOF) c = getc(fin); X switch (ed) { X case 'd' : X Delta->deletelns += length; X break; X X case 'a' : X /* skip scripted lines */ X for ( i=length; i > 0 && c != EOF; i--){ X while( (c=getc(fin)) != '\n' && c != EOF); X Delta->insertlns++; X } X break; X X default: X faterror("Unknown command in edit script: %c", ed); X break; X } X } X nextc = getc(fin); X} X X X X X X X Xexttree(root) Xstruct hshentry *root; X/* function: select revisions , starting with root */ X X{ X struct branchhead * newbranch; X X if (root == nil) return; X X extractdelta(root); X exttree(root->next); X X newbranch = root->branches; X while( newbranch ) { X exttree(newbranch->hsh); X newbranch = newbranch->nextbranch; X } X} X X X X Xgetlocker(argv) Xchar * argv; X/* function : get the login names of lockers from command line */ X/* and store in lockerlist. */ X X{ X register char c; X struct lockers * newlocker; X argv--; X while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || X c == '\n' || c == ';') ; X if ( c == '\0') { X lockerlist=nil; X return; X } X X while( c != '\0' ) { X newlocker = ( struct lockers *)talloc( sizeof(struct lockers) ); X newlocker->lockerlink = lockerlist; X newlocker->login = argv; X lockerlist = newlocker; X while ( ( c = (*++argv)) != ',' && c != '\0' && c != ' ' X && c != '\t' && c != '\n' && c != ';') ; X *argv = '\0'; X if ( c == '\0' ) return; X while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || X c == '\n' || c == ';') ; X } X} X X X Xgetauthor(argv) Xchar *argv; X/* function: get the author's name form command line */ X/* and store in aauthorlist */ X X{ X register c; X struct authors * newauthor; X X argv--; X while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || X c == '\n' || c == ';') ; X if ( c == '\0' ) { X authorlist = (struct authors *)talloc(sizeof(struct authors)); X authorlist->login = caller; X authorlist->nextauthor = nil; X return; X } X X while( c != '\0' ) { X newauthor = (struct authors *)talloc(sizeof(struct authors)); X newauthor->nextauthor = authorlist; X newauthor->login = argv; X authorlist = newauthor; X while( ( c = *++argv) != ',' && c != '\0' && c != ' ' X && c != '\t' && c != '\n' && c != ';') ; X * argv = '\0'; X if ( c == '\0') return; X while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || X c == '\n' || c == ';') ; X } X} X X X X Xgetstate(argv) Xchar * argv; X/* function : get the states of revisions from command line */ X/* and store in statelist */ X X{ X register char c; X struct stateattri *newstate; X X argv--; X while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || X c == '\n' || c == ';') ; X if ( c == '\0'){ X warn(" Missing state attributes after -s options"); X return; X } X X while( c != '\0' ) { X newstate = (struct stateattri *)talloc(sizeof(struct stateattri)); X newstate->nextstate = statelist; X newstate->status = argv; X statelist = newstate; X while( (c = (*++argv)) != ',' && c != '\0' && c != ' ' X && c != '\t' && c != '\n' && c != ';') ; X *argv = '\0'; X if ( c == '\0' ) return; X while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || X c == '\n' || c == ';') ; X } X} X X X Xtrunclocks() X/* Function: Truncate the list of locks to those that are held by the */ X/* id's on lockerlist. Do not truncate if lockerlist empty. */ X X{ X struct lockers * plocker; X struct lock * plocked, * nextlocked; X X if ( (lockerlist == nil) || (Locks == nil)) return; X X /* shorten Locks to those contained in lockerlist */ X plocked = Locks; X Locks = nil; X while( plocked != nil) { X plocker = lockerlist; X while((plocker != nil) && ( strcmp(plocker->login, plocked->login)!=0)) X plocker = plocker->lockerlink; X nextlocked = plocked->nextlock; X if ( plocker != nil) { X plocked->nextlock = Locks; X Locks = plocked; X } X plocked = nextlocked; X } X} X X X Xrecentdate(root, pd) Xstruct hshentry * root; Xstruct Datepairs * pd; X/* function: Finds the delta that is closest to the cutoff date given by */ X/* pd among the revisions selected by exttree. */ X/* Successively narrows down the interfal given by pd, */ X/* and sets the strtdate of pd to the date of the selected delta */ X{ X struct branchhead * newbranch; X X if ( root == nil) return; X if ( root->selector == 's') { X if ( cmpnum(root->date, pd->strtdate) >= 0 && X cmpnum(root->date, pd->enddate) <= 0) X VOID strcpy(pd->strtdate, root->date); X } X X recentdate(root->next, pd); X newbranch = root->branches; X while( newbranch) { X recentdate(newbranch->hsh, pd); X newbranch = newbranch->nextbranch; X } X} X X X X X X Xextdate(root) Xstruct hshentry * root; X/* function: select revisions which are in the date range specified */ X/* in duelst and datelist, start at root */ X X{ X struct branchhead * newbranch; X struct Datepairs * pdate; X X if ( root == nil) return; X X if ( datelist || duelst) { X pdate = datelist; X while( pdate ) { X if ( (pdate->strtdate)[0] == '\0' || cmpnum(root->date,pdate->strtdate) >= 0){ X if ((pdate->enddate)[0] == '\0' || cmpnum(pdate->enddate,root->date) >= 0) X break; X } X pdate = pdate->dnext; X } X if ( pdate == nil) { X pdate = duelst; X while(pdate) { X if ( cmpnum(root->date, pdate->strtdate) == 0) X break; X pdate = pdate->dnext; X } X } X if ( pdate == nil) X root->selector = 'u'; X } X if (root->selector == 's') revno++; X X extdate(root->next); X X newbranch = root->branches; X while( newbranch ) { X extdate(newbranch->hsh); X newbranch = newbranch->nextbranch; X } X} X X X Xextractdelta(pdelta) Xstruct hshentry * pdelta; X/* function: compare information of pdelta to the authorlst, lockerlist, */ X/* statelist, revlist and mark 's' on selector if pdelta is */ X/* selected; otherwise, mark 'u' */ X X{ X struct lock * plock; X struct stateattri * pstate; X struct authors * pauthor; X struct Revpairs * prevision; X int length; X X pdelta->selector = 's'; X if ( authorlist ) { /* certain author's revisions wanted only */ X pauthor = authorlist; X while((pauthor != nil) && ( strcmp(pauthor->login, pdelta->author)!=0)) X pauthor = pauthor->nextauthor; X if ( pauthor == nil ) { X pdelta->selector = 'u'; X return; X } X } X if ( statelist ) { /* revisions with certain state wanted */ X pstate = statelist; X while((pstate != nil) && (strcmp(pstate->status, pdelta->state)!=0)) X pstate = pstate->nextstate; X if ( pstate == nil ) { X pdelta->selector = 'u'; X return; X } X } X if ( lockflag ) { /* locked revisions */ X plock = Locks; X while( plock && (plock->delta != pdelta)) X plock = plock->nextlock; X if (plock == nil ) { X pdelta->selector = 'u'; X return; X } X } X if ( Revlst ) { /* revisions or branches selected */ X X prevision = Revlst; X while( prevision != nil ) { X length = prevision->numfld; X if ( length % 2 == 1) { /* a branch number */ X if ( countnumflds(pdelta->num) ==(length+1)) X if ( (compartial(pdelta->num, prevision->strtrev,length) >= 0)&& X (compartial(prevision->endrev, pdelta->num, length) >= 0) ) X break; X } X else if ( countnumflds(pdelta->num ) == length) /* a revision */ X if ( (compartial(pdelta->num, prevision->strtrev, length) >= 0) && X (compartial(prevision->endrev, pdelta->num, length) >= 0) ) X break; X prevision = prevision->rnext; X } X if (prevision == nil) { X pdelta->selector = 'u'; X return; X } X } X} X X X Xchar * procdate(target, source) Xchar * target, * source; X/* Function: Parses a free-format date in target, converts it X * into RCS internal format, and stores the result into source. X * Returns target on success, nil otherwise. X */ X{ X long unixtime; X struct tm parseddate, *ftm; X X if ( partime(source, &parseddate) == 0) { X error("Can't parse date/time: %s", source); X *target= '\0'; X return nil; X } X if ( (unixtime = maketime(&parseddate)) == 0L) { X error("Inconsistent date/time: %s", source); X *target='\0'; X return nil; X } X ftm = localtime(&unixtime); X VOID sprintf(target,DATEFORM, X ftm->tm_year,ftm->tm_mon+1,ftm->tm_mday,ftm->tm_hour,ftm->tm_min,ftm->tm_sec); X return target; X} X X X Xgetdatepair(argv) X char * argv; X/* function: get time range from command line and store in datelist if */ X/* a time range specified or in duelst if a time spot specified */ X X{ X register char c; X struct Datepairs * nextdate; X char * rawdate; X int switchflag; X X argv--; X while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || X c == '\n' || c == ';') ; X if ( c == '\0' ) { X warn("Missing date/time after -d"); X return; X } X X while( c != '\0' ) { X switchflag = false; X nextdate = (struct Datepairs *) talloc(sizeof(struct Datepairs)); X if ( c == '<' ) { /* case: -d <date */ X c = *++argv; X (nextdate->strtdate)[0] = '\0'; X } elsif (c == '>') { /* case: -d >date */ X c = *++argv; X (nextdate->enddate)[0] = '\0'; X switchflag = true; X } else { X rawdate = argv; X while( c != '<' && c != '>' && c != ';' && c != '\0') X c = *++argv; X *argv = '\0'; X if ( c == '>' ) switchflag=true; X if (procdate(switchflag?nextdate->enddate:nextdate->strtdate, X rawdate)==nil) continue; X if ( c == ';' || c == '\0') { /* case: -d date */ X VOID strcpy(nextdate->enddate,nextdate->strtdate); X VOID sprintf(nextdate->strtdate,DATEFORM,0,0,0,0,0,0); X nextdate->dnext = duelst; X duelst = nextdate; X goto end; X } else { X /* case: -d date< or -d date>; see switchflag */ X while ( (c= *++argv) == ' ' || c=='\t' || c=='\n'); X if ( c == ';' || c == '\0') { X /* second date missing */ X if (switchflag) X *nextdate->strtdate= '\0'; X else X *nextdate->enddate= '\0'; X nextdate->dnext = datelist; X datelist = nextdate; X goto end; X } X } X } X rawdate = argv; X while( c != '>' && c != '<' && c != ';' && c != '\0') X c = *++argv; X *argv = '\0'; X if (procdate(switchflag?nextdate->strtdate:nextdate->enddate, X rawdate)==nil) continue; X nextdate->dnext = datelist; X datelist = nextdate; X end: X/* X VOID printf("startdate: %s; enddate: %s;\n", nextdate->strtdate,nextdate->enddate); X*/ X if ( c == '\0') return; X while( (c = *++argv) == ';' || c == ' ' || c == '\t' || c =='\n'); X } X} X X X X X Xgetnumericrev() X/* function: get the numeric name of revisions which stored in revlist */ X/* and then stored the numeric names in Revlst */ X/* if branchflag, also add default branch */ X X{ X struct Revpairs * ptr, *pt; X int flag; X char *temprev; X X /* free the previous numeric revision list */ X pt = Revlst; X while( pt) { X ptr = pt->rnext; X free((char *)pt); X pt = ptr; X } X Nextdotstring = &Dotstring[0]; /* reset buffer */ X X X Revlst = nil; X ptr = revlist; X while( ptr ) { X pt = (struct Revpairs *) talloc(sizeof(struct Revpairs)); X if ( ptr->numfld == 1 ){ /* case: -r rev */ X if ( (flag = expandsym(ptr->strtrev, Nextdotstring)) == true ) { X pt->numfld = countnumflds(Nextdotstring); X pt->strtrev = pt->endrev = Nextdotstring; X while( *Nextdotstring++ != '\0' ) ; X } X } X else if( ptr->numfld == 2){ /* case: -r rev- */ X if ( (flag = expandsym(ptr->strtrev, Nextdotstring)) == true) { X pt->numfld = countnumflds(Nextdotstring); X pt->strtrev = Nextdotstring; X while( *Nextdotstring++ != '\0' ) ; X pt->endrev = Nextdotstring; X if ( pt->numfld > 2) choptail(pt->strtrev); X * Nextdotstring++ = '\0'; X } X } X else if(ptr->numfld == 3) { /* case: -r -rev */ X if ( (flag = expandsym(ptr->endrev, Nextdotstring)) == true) { X pt->endrev = Nextdotstring; X while( *Nextdotstring++ != '\0' ) ; X pt->numfld = countnumflds(pt->endrev); X pt->strtrev = Nextdotstring; X if ( pt->numfld == 2) X *Nextdotstring++ = '1'; X else X choptail(pt->endrev); X *Nextdotstring++ = '.'; X *Nextdotstring++ = '1'; X *Nextdotstring++ = '\0'; X } X } X else { /* case: -r rev1-rev2 */ X if ( (flag = expandsym(ptr->strtrev, Nextdotstring)) == true ) { X pt->strtrev = Nextdotstring; X while( *Nextdotstring++ != '\0' ) ; X if ( ( flag = expandsym(ptr->endrev, Nextdotstring)) == true) { X pt->numfld = countnumflds(pt->strtrev); X pt->endrev = Nextdotstring; X while( *Nextdotstring++ != '\0' ) ; X if((flag = checkrevpair(pt->strtrev, pt->endrev)) == true) X /* switch pt->strtrev with pt->endrev, if pt->strtrev > pt->endre */ X if (compartial(pt->strtrev, pt->endrev, pt->numfld) > 0 ) { X temprev = pt->strtrev; X pt->strtrev = pt->endrev; X pt->endrev = temprev; X } X } X } X } X X if ( flag ){ X pt->rnext = Revlst; X Revlst = pt; X } X else X free((char *)pt); X ptr = ptr->rnext; X } X /* Now take care of branchflag */ X if (branchflag) { X flag =true; X pt = (struct Revpairs *) talloc(sizeof(struct Revpairs)); X if (Dbranch) { X pt->strtrev = pt->endrev = Dbranch->num; X } elsif (Head!=nil) { X pt->strtrev = pt->endrev = /* branch number of head */ X partialno(Nextdotstring,Head->num,1); X while( *Nextdotstring++ != '\0' ) ; X } else flag = false; X if (flag) { /* prepend new node */ X pt->rnext=Revlst; Revlst=pt; X pt->numfld = countnumflds(pt->strtrev); X } X } X X} X X X Xcheckrevpair(num1,num2) Xchar *num1, *num2; X/* function: check whether num1, num2 are legal pair,i.e. X only the last field are different and have same number of X feilds( if length <= 2, may be different if first field) */ X X{ X int length; X X if ( (length = countnumflds(num1)) != countnumflds(num2) ) { X error(" Invalid branch or revision pair %s : %s", num1, num2); X return false; X } X if ( length > 2 ) X if (compartial(num1, num2, length-1) != 0) { X error("Invalid branch or revision pair %s : %s", num1, num2); X return false; X } X X return true; X} X X X Xgetrevpairs(argv) Xregister char * argv; X/* function: get revision or branch range from command line, and */ X/* store in revlist */ X X{ X register char c; X struct Revpairs * nextrevpair; X int flag; X X argv--; X while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || X c == '\n' || c == ';') ; X if ( c == '\0' ) { X warn(" Missing revision or branch number after -r"); X return; X } X X while( c != '\0') { X while( c == ',' || c == ' ' || c == '\t' || X c == '\n' || c == ';') c = *++argv; X if (c == '\0') return; X nextrevpair = (struct Revpairs *) talloc(sizeof(struct Revpairs)); X nextrevpair->rnext = revlist; X revlist = nextrevpair; X nextrevpair->numfld = nil; X nextrevpair->strtrev = nil; X nextrevpair->endrev = nil; X flag = false; X if ( c == '<' || c == '-' ) { /* case: -r -rev or -r <rev */ X flag = true; X while( (c =(*++argv)) == ' ' || c == '\t' || c =='\n') ; X } X else { X nextrevpair->strtrev = argv; X /* get a revision or branch name */ X while( c != ',' && c != ';' && c != ' ' && c != '\0' && c != '-' X && c != '\t' && c != '\n' && c != '<') c = *++argv; X X *argv = '\0'; X X if ( c != '<' && c != '-') { /* case: rev */ X nextrevpair->numfld = 1; X continue; X } X X if ( (c =(*++argv)) == ',' || c == '\0' || c == ' ' X || c == '\t' || c == '\n' || c == ';') {/* case: rev_ */ X nextrevpair->numfld = 2; X continue; X } X } X nextrevpair->endrev = argv; X while( c != ',' && c != ' ' && c != '\0' && c != '\t' && c != '<' X && c != '\n' && c != '-' && c != ';') c = *++argv; X X * argv = '\0'; X if ( c == '<'){ X error("separator expected near %s", nextrevpair->endrev); X while( (c = *++argv) != ',' && c != ' ' && c != '\0' && X c != '\t' && c != '\n' && c != ';' ) ; X revlist = nextrevpair->rnext; X continue; X } X else { X if (flag) /* case: -rev */ X nextrevpair->numfld = 3; X X else /* rev1-rev2 appears */ X nextrevpair->numfld = 4; X } X } X} X X X Xchoptail(strhead) Xchar * strhead; X/* function : chop off the last field of a branch or a revision number */ X X{ X char *pt, *sp; X X for(pt = Nextdotstring-1; pt != strhead && *pt != '.'; pt--) ; X for(sp = strhead; sp < pt; sp++) *Nextdotstring++ = *sp; X} X X@ X X X4.7.2.1 Xlog X@Start of Amiga RCS port branch. X@ Xtext X@d6 1 Xa6 5 X<<<<<<< rlog.c X"$Header: /u/softeng/rsbx/rcs/amiga/RCS.cbmvax/rlog.c,v 4.7.1.1 89/08/11 01:43:14 rsbx Exp Locker: rsbx $ Purdue CS"; X======= X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rlog.c,v 1.2 89/09/17 13:36:54 rick Exp $ Purdue CS"; X>>>>>>> 1.2 Xa41 16 X<<<<<<< rlog.c X * Revision 4.7.1.1 89/08/11 01:43:14 rsbx X * Start of cbmvax RCS source branch. X * X * Revision 4.7 89/05/01 15:13:48 narten X * checked in with -k by rsbx at 89.08.10.16.23.28. X======= X * Revision 1.2 89/09/17 13:36:54 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:13:12 rick X * Port to AmigaDos. All done with conditional compiles X>>>>>>> 1.2 X * 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@d6 5 Xa10 1 X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rlog.c,v 4.7.2.1 89/10/13 19:19:26 rsbx Exp Locker: rsbx $ Purdue CS"; Xd46 1 Xa46 3 X * Revision 4.7.2.1 89/10/13 19:19:26 rsbx X * Start of Amiga RCS port branch. X * Xd52 9 X@ X X X4.7.1.1 Xlog X@Start of cbmvax RCS source branch. X@ Xtext X@d6 1 Xa6 1 X"$Header: /u/softeng/rsbx/rcs/rcs.uunet/src/RCS/rlog.c,v 4.7 89/05/01 15:13:48 narten Exp $ Purdue CS"; Xa41 3 X * Revision 4.7 89/05/01 15:13:48 narten X * checked in with -k by rsbx at 89.08.10.16.23.28. X * X@ SHAR_EOF echo "End of archive 11 (of 14)" # if you want to concatenate archives, remove anything after this line exit