From 5e0f5a2237e55356497c82114b4e4106507d5180 Mon Sep 17 00:00:00 2001 From: CSRG Date: Thu, 18 Feb 1988 00:16:57 -0800 Subject: [PATCH] BSD 4_3_Tahoe development Work on file usr/src/new/rcs/src/rcsedit.c Work on file usr/src/new/rcs/src/rcsfnms.c Work on file usr/src/new/rcs/src/rcsdiff.c Synthesized-from: CSRG/cd2/4.3tahoe --- usr/src/new/rcs/src/rcsdiff.c | 261 ++++++++++++ usr/src/new/rcs/src/rcsedit.c | 483 +++++++++++++++++++++ usr/src/new/rcs/src/rcsfnms.c | 762 ++++++++++++++++++++++++++++++++++ 3 files changed, 1506 insertions(+) create mode 100644 usr/src/new/rcs/src/rcsdiff.c create mode 100644 usr/src/new/rcs/src/rcsedit.c create mode 100644 usr/src/new/rcs/src/rcsfnms.c diff --git a/usr/src/new/rcs/src/rcsdiff.c b/usr/src/new/rcs/src/rcsdiff.c new file mode 100644 index 0000000000..63350bea71 --- /dev/null +++ b/usr/src/new/rcs/src/rcsdiff.c @@ -0,0 +1,261 @@ +/* + * RCS rcsdiff operation + */ +#ifndef lint +static char rcsid[]= +"$Header: /usr/src/new/rcs/src/RCS/rcsdiff.c,v 3.9 88/02/18 11:55:57 bostic Exp $ Purdue CS"; +#endif +/***************************************************************************** + * generate difference between RCS revisions + ***************************************************************************** + * + * Copyright (C) 1982 by Walter F. Tichy + * Purdue University + * Computer Science Department + * West Lafayette, IN 47907 + * + * All rights reserved. No part of this software may be sold or distributed + * in any form or by any means without the prior written permission of the + * author. + * Report problems and direct all inquiries to Tichy@purdue (ARPA net). + */ + + +/* $Log: rcsdiff.c,v $ + * Revision 3.9 88/02/18 11:55:57 bostic + * replaced with version 4 + * + * Revision 4.4 87/12/18 11:37:46 narten + * changes Jay Lepreau made in the 4.3 BSD version, to add support for + * "-i", "-w", and "-t" flags and to permit flags to be bundled together, + * merged in. + * + * Revision 4.3 87/10/18 10:31:42 narten + * Updating version numbers. Changes relative to 1.1 actually + * relative to 4.1 + * + * Revision 1.3 87/09/24 13:59:21 narten + * Sources now pass through lint (if you ignore printf/sprintf/fprintf + * warnings) + * + * Revision 1.2 87/03/27 14:22:15 jenkins + * Port to suns + * + * Revision 1.1 84/01/23 14:50:18 kcs + * Initial revision + * + * Revision 4.1 83/05/03 22:13:19 wft + * Added default branch, option -q, exit status like diff. + * Added fterror() to replace faterror(). + * + * Revision 3.6 83/01/15 17:52:40 wft + * Expanded mainprogram to handle multiple RCS files. + * + * Revision 3.5 83/01/06 09:33:45 wft + * Fixed passing of -c (context) option to diff. + * + * Revision 3.4 82/12/24 15:28:38 wft + * Added call to catchsig(). + * + * Revision 3.3 82/12/10 16:08:17 wft + * Corrected checking of return code from diff; improved error msgs. + * + * Revision 3.2 82/12/04 13:20:09 wft + * replaced getdelta() with gettree(). Changed diagnostics. + * + * Revision 3.1 82/11/28 19:25:04 wft + * Initial revision. + * + */ +#include +#include "rcsbase.h" +#define ERRCODE 2 /*error code for exit status */ +#ifndef lint +static char rcsbaseid[] = RCSBASE; +#endif + +extern int cleanup(); /* cleanup after signals */ +extern char * mktempfile(); /*temporary file name generator */ +extern int fterror(); /*forward for special fatal error func. */ +extern struct hshentry * genrevs(); /*generate delta numbers */ +extern int nerror; /*counter for errors */ +extern int quietflag; /*suppresses diagnostics */ +extern FILE * finptr; /* RCS input file */ + +char *RCSfilename; +char *workfilename; +char * temp1file, * temp2file; + +char bops[10] = "-"; +char otherops[10] = "-"; + +main (argc, argv) +int argc; char **argv; +{ + char * cmdusage; + char command[NCPPN+revlength+40]; + int revnums; /* counter for revision numbers given */ + char * rev1, * rev2; /* revision numbers from command line */ + char numericrev[revlength]; /* holds expanded revision number */ + char * xrev1, * xrev2; /* expanded revision numbers */ + struct hshentry * gendeltas[hshsize];/*stores deltas to be generated*/ + struct hshentry * target; + char * boption, * otheroption; + int exit_stats; + int filecounter; + char *argp; + register c; + + catchints(); + otheroption = otherops + 1; + boption = bops + 1; + cmdid = "rcsdiff"; + cmdusage = "command format:\n rcsdiff [-biwt] [-q] [-cefhn] [-rrev1] [-rrev2] file"; + filecounter=revnums=0; + while (--argc,++argv, argc>=1 && ((*argv)[0] == '-')) { + argp = &((*argv)[1]); + while (c = *argp++) switch (c) { + case 'r': + if (*argp!='\0') { + if (revnums==0) { + rev1= argp; revnums=1; + } elif (revnums==1) { + rev2= argp; revnums=2; + } else { + fterror("too many revision numbers"); + } + } /* do nothing for empty -r */ + argp += strlen(argp); + break; + case 'b': + case 'i': + case 'w': + case 't': + *boption++ = c; + break; + case 'q': + quietflag=true; + break; + case 'c': + case 'e': + case 'f': + case 'h': + case 'n': + if (otheroption == otherops + 1) { + *otheroption++ = c; + if (c == 'c' && isdigit(*argp)) { + while (isdigit(*argp)) + *otheroption++ = *argp++; + if (*argp) + faterror("-c: bad count"); + argp = ""; + } + } else { + fterror("Options c,e,f,h,n are mutually exclusive"); + } + break; + default: + fterror("unknown option: %s\n%s", *argv,cmdusage); + }; + } /* end of option processing */ + + if (boption != bops + 1) { + *boption = ' '; + boption = bops; + } + if (otheroption != otherops + 1) { + *otheroption = ' '; + otheroption = otherops; + } + if (argc<1) fterror("No input file\n%s",cmdusage); + + /* now handle all filenames */ + do { + finptr=NULL; + + if (pairfilenames(argc,argv,true,false)!=1) continue; + if (++filecounter>1) + diagnose("==================================================================="); + diagnose("RCS file: %s",RCSfilename); + if (revnums<2 && !(access(workfilename,4)==0)) { + error("Can't open %s",workfilename); + continue; + } + if (!trysema(RCSfilename,false)) continue; /* give up */ + + + gettree(); /* reads in the delta tree */ + + if (Head==nil) { + error("no revisions present"); + continue; + } + if (revnums==0) + rev1=Dbranch!=nil?Dbranch->num:Head->num; /* default rev1 */ + + if (!expandsym(rev1,numericrev)) continue; + if (!(target=genrevs(numericrev,(char *)nil,(char *)nil,(char *)nil,gendeltas))) continue; + xrev1=target->num; + + if (revnums==2) { + if (!expandsym(rev2,numericrev)) continue; + if (!(target=genrevs(numericrev,(char *)nil,(char *)nil,(char *)nil,gendeltas))) continue; + xrev2=target->num; + } + + + temp1file=mktempfile("/tmp/",TMPFILE1); + diagnose("retrieving revision %s",xrev1); + VOID sprintf(command,"%s/co -q -p%s %s > %s\n", + TARGETDIR,xrev1,RCSfilename,temp1file); + if (system(command)){ + error("co failed"); + continue; + } + if (revnums<=1) { + temp2file=workfilename; + diagnose("diff %s%s-r%s %s",boption,otheroption,xrev1,workfilename); + } else { + temp2file=mktempfile("/tmp/",TMPFILE2); + diagnose("retrieving revision %s",xrev2); + VOID sprintf(command,"%s/co -q -p%s %s > %s\n", + TARGETDIR,xrev2,RCSfilename,temp2file); + if (system(command)){ + error("co failed"); + continue; + } + diagnose("diff %s%s-r%s -r%s",boption,otheroption,xrev1,xrev2); + } + VOID sprintf(command,"%s %s%s%s %s\n",DIFF,boption, + otheroption, temp1file, temp2file); + exit_stats = system (command); + if (exit_stats != 0 && exit_stats != (1 << BYTESIZ)) { + error ("diff failed"); + continue; + } + } while (cleanup(), + ++argv, --argc >=1); + + + if (nerror>0) { + exit(ERRCODE); + } else { + exit(exit_stats>>BYTESIZ); + /* return exit status from diff */ + } + +} + + +/*VARARGS3*/ +fterror(e, e1, e2) +char * e, * e1, * e2; +/* prints error message and terminates program with ERRCODE */ +{ nerror++; + VOID fprintf(stderr,"%s error: ",cmdid); + VOID fprintf(stderr,e, e1, e2); + VOID fprintf(stderr,"\n%s aborted\n",cmdid); + VOID cleanup(); + exit(ERRCODE); +} + diff --git a/usr/src/new/rcs/src/rcsedit.c b/usr/src/new/rcs/src/rcsedit.c new file mode 100644 index 0000000000..6029c4cc3f --- /dev/null +++ b/usr/src/new/rcs/src/rcsedit.c @@ -0,0 +1,483 @@ +/* + * RCS stream editor + */ +#ifndef lint +static char rcsid[]= "$Id: rcsedit.c,v 3.9 88/02/18 11:56:51 bostic Exp $ Purdue CS"; +#endif +/********************************************************************************** + * edits the input file according to a + * script from stdin, generated by diff -n + * performs keyword expansion + ********************************************************************************** + * + * Copyright (C) 1982 by Walter F. Tichy + * Purdue University + * Computer Science Department + * West Lafayette, IN 47907 + * + * All rights reserved. No part of this software may be sold or distributed + * in any form or by any means without the prior written permission of the + * author. + * Report problems and direct all inquiries to Tichy@purdue (ARPA net). + */ + + +/* $Log: rcsedit.c,v $ + * Revision 3.9 88/02/18 11:56:51 bostic + * replaced with version 4 + * + * Revision 4.5 87/12/18 11:38:46 narten + * Changes from the 43. version. Don't know the significance of the + * first change involving "rewind". Also, additional "lint" cleanup. + * (Guy Harris) + * + * Revision 4.4 87/10/18 10:32:21 narten + * Updating version numbers. Changes relative to version 1.1 actually + * relative to 4.1 + * + * Revision 1.4 87/09/24 13:59:29 narten + * Sources now pass through lint (if you ignore printf/sprintf/fprintf + * warnings) + * + * Revision 1.3 87/09/15 16:39:39 shepler + * added an initializatin of the variables editline and linecorr + * this will be done each time a file is processed. + * (there was an obscure bug where if co was used to retrieve multiple files + * it would dump) + * fix attributed to Roy Morris @FileNet Corp ...!felix!roy + * + * Revision 1.2 87/03/27 14:22:17 jenkins + * Port to suns + * + * Revision 1.1 84/01/23 14:50:20 kcs + * Initial revision + * + * Revision 4.1 83/05/12 13:10:30 wft + * Added new markers Id and RCSfile; added locker to Header and Id. + * Overhauled expandline completely() (problem with $01234567890123456789@). + * Moved trymatch() and marker table to rcskeys.c. + * + * Revision 3.7 83/05/12 13:04:39 wft + * Added retry to expandline to resume after failed match which ended in $. + * Fixed truncation problem for $19chars followed by@@. + * Log no longer expands full path of RCS file. + * + * Revision 3.6 83/05/11 16:06:30 wft + * added retry to expandline to resume after failed match which ended in $. + * Fixed truncation problem for $19chars followed by@@. + * + * Revision 3.5 82/12/04 13:20:56 wft + * Added expansion of keyword Locker. + * + * Revision 3.4 82/12/03 12:26:54 wft + * Added line number correction in case editing does not start at the + * beginning of the file. + * Changed keyword expansion to always print a space before closing KDELIM; + * Expansion for Header shortened. + * + * Revision 3.3 82/11/14 14:49:30 wft + * removed Suffix from keyword expansion. Replaced fclose with ffclose. + * keyreplace() gets log message from delta, not from curlogmsg. + * fixed expression overflow in while(c=putc(GETC.... + * checked nil printing. + * + * Revision 3.2 82/10/18 21:13:39 wft + * I added checks for write errors during the co process, and renamed + * expandstring() to xpandstring(). + * + * Revision 3.1 82/10/13 15:52:55 wft + * changed type of result of getc() from char to int. + * made keyword expansion loop in expandline() portable to machines + * without sign-extension. + */ + + +#include "rcsbase.h" + + +extern FILE * fopen(); +extern char * mktempfile(); +extern char * bindex(); +extern FILE * finptr, * frewrite; +extern int rewriteflag; +extern int nextc; +extern char * RCSfilename, * workfilename; +extern char * bindex(); +extern char * getfullRCSname(); +extern enum markers trymatch(); + + +FILE * fcopy, * fedit; /* result and edit file descriptors */ +char *resultfile = nil; /* result file name */ +char * editfile = nil; /* edit file name */ +int editline; /*line counter in fedit; starts with 1, is always #lines+1 */ +int linecorr; /*contains #adds - #deletes in each edit run. */ + /*used to correct editline in case file is not rewound after */ + /* applying one delta */ + +initeditfiles(dir) +char * dir; +/* Function: Initializes resultfile and editfile with temporary filenames + * in directory dir. Opens resultfile for reading and writing, with fcopy + * as file descriptor. fedit is set to nil. + */ +{ + editline = linecorr = 0; /* make sure we start from the beginning*/ + resultfile=mktempfile(dir,TMPFILE1); + editfile =mktempfile(dir,TMPFILE2); + fedit=nil; + if ((fcopy=fopen(resultfile,"w+"))==NULL) { + faterror("Can't open working file %s",resultfile); + } +} + + +swapeditfiles(tostdout) +/* Function: swaps resultfile and editfile, assigns fedit=fcopy, + * rewinds fedit for reading, and opens resultfile for reading and + * writing, using fcopy. If tostdout, fcopy is set to stdout. + */ +{ char * tmpptr; + if(ferror(fcopy)) + faterror("write failed on %s -- file system full?",resultfile); + fedit=fcopy; + rewind(fedit); + editline = 1; linecorr=0; + tmpptr=editfile; editfile=resultfile; resultfile=tmpptr; + if (tostdout) + fcopy=stdout; + elsif ((fcopy=fopen(resultfile,"w+"))==NULL) { + faterror("Can't open working file %s",resultfile); + } +} + + +finishedit(delta) +struct hshentry * delta; +/* copy the rest of the edit file and close it (if it exists). + * if delta!=nil, perform keyword substitution at the same time. + */ +{ + register int c; + if (fedit!=nil) { + if (delta!=nil) { + while (expandline(fedit,fcopy,delta,false,false)) editline++; + } else { + while((c=getc(fedit))!=EOF) { + VOID putc(c,fcopy); + if (c=='\n') editline++; + } + } + ffclose(fedit); + } +} + + +copylines(line,delta) +register int line; struct hshentry * delta; +/* Function: copies input lines editline..line-1 from fedit to fcopy. + * If delta != nil, keyword expansion is done simultaneously. + * editline is updated. Rewinds a file only if necessary. + */ +{ + + if (editline>line) { + /* swap files */ + finishedit((struct hshentry *)nil); swapeditfiles(false); + /* assumes edit only during last pass, from the beginning*/ + } + while (editline0;i--) { + /*skip next line*/ + while ((c=getc(fedit))!='\n'); + if (c==EOF) + faterror("EOF during edit"); + editline++; + } + linecorr -= length; + break; + case 'a': + copylines(line+1,delta); /*copy only; no delete*/ + for (i=length;i>0;i--) { + /*copy next line from script*/ + if (delta!=nil) + VOID expandline(finptr,fcopy,delta,true,write); + else { + c = GETC(finptr,frewrite,write); + while (putc(c,fcopy)!='\n'){ + if ((c==SDELIM)&&((c=GETC(finptr,frewrite,write))!=SDELIM)){ + serror("Missing string delimiter in edit script"); + VOID putc(c,fcopy); + } + c = GETC(finptr,frewrite,write); + } + } + } + linecorr += length; + break; + default: + faterror("unknown command in edit script: %c", ed); + break; + } + } + nextc=GETC(finptr,frewrite,write); +} + + + +/* The rest if for keyword expansion */ + + + +expandline(in, out, delta,delimstuffed,write) +FILE * in, * out; struct hshentry * delta; +register int delimstuffed, write; +/* Function: Reads a line from in and writes it to out. + * If delimstuffed==true, double SDELIM is replaced with single SDELIM. + * Keyword expansion is performed with data from delta. + * If write==true, the string is also copied unchanged to frewrite. + * Returns false if end-of-string or end-of-line is detected, true otherwise. + */ +{ + register c; + register char * tp; + char keystring[keylength+2]; + char keyval[keyvallength+2]; + enum markers matchresult; + + c=GETC(in,frewrite,write); + for (;;) { + if (c==EOF) { + if(delimstuffed) { + error("unterminated string"); + nextc=c; + } + return(false); + } + + if (c==SDELIM && delimstuffed) { + if ((c=GETC(in,frewrite,write))!=SDELIM) { + /* end of string */ + nextc=c; + return false; + } + } + VOID putc(c,out); + + if (c=='\n') return true; /* end of line */ + + if (c==KDELIM) { + /* check for keyword */ + /* first, copy a long enough string into keystring */ + tp=keystring; + while (((c=GETC(in,frewrite,write))!=EOF) && (tpdate; + + switch (marker) { + case Author: + VOID fprintf(out,"%c %s %c",VDELIM,delta->author,KDELIM); + break; + case Date: + VOID putc(VDELIM,out);VOID putc(' ',out); + VOID PRINTDATE(out,date);VOID putc(' ',out); + VOID PRINTTIME(out,date);VOID putc(' ',out);VOID putc(KDELIM,out); + break; + case Id: + case Header: + VOID putc(VDELIM,out); VOID putc(' ',out); + if (marker==Id) + VOID fputs(bindex(RCSfilename,'/'),out); + else VOID fputs(getfullRCSname(),out); + VOID fprintf(out," %s ", delta->num); + VOID PRINTDATE(out,date);VOID putc(' ',out);VOID PRINTTIME(out,date); + VOID fprintf(out, " %s %s ",delta->author,delta->state); + if (delta->lockedby!=nil) + VOID fprintf(out,"Locker: %s ",delta->lockedby); + VOID putc(KDELIM,out); + break; + case Locker: + VOID fprintf(out,"%c %s %c", VDELIM, + delta->lockedby==nil?"":delta->lockedby,KDELIM); + break; + case Log: + VOID fprintf(out, "%c\t%s %c\n%sRevision %s ", + VDELIM, bindex(RCSfilename,'/'), KDELIM, Comment, delta->num); + VOID PRINTDATE(out,date);VOID fputs(" ",out);VOID PRINTTIME(out,date); + VOID fprintf(out, " %s\n%s",delta->author,Comment); + /* do not include state here because it may change and is not updated*/ + sp = delta->log; + while (*sp) if (putc(*sp++,out)=='\n') VOID fputs(Comment,out); + /* Comment is the comment leader */ + break; + case RCSfile: + VOID fprintf(out,"%c %s %c",VDELIM,bindex(RCSfilename,'/'),KDELIM); + break; + case Revision: + VOID fprintf(out,"%c %s %c",VDELIM,delta->num,KDELIM); + break; + case Source: + VOID fprintf(out,"%c %s %c",VDELIM,getfullRCSname(),KDELIM); + break; + case State: + VOID fprintf(out,"%c %s %c",VDELIM,delta->state,KDELIM); + break; + case Nomatch: + VOID putc(KDELIM,out); + break; + } +} + + diff --git a/usr/src/new/rcs/src/rcsfnms.c b/usr/src/new/rcs/src/rcsfnms.c new file mode 100644 index 0000000000..19b6e13d33 --- /dev/null +++ b/usr/src/new/rcs/src/rcsfnms.c @@ -0,0 +1,762 @@ +/* + * RCS file name handling + */ +#ifndef lint + static char + rcsid[]= "$Id: rcsfnms.c,v 3.10 88/02/18 11:57:27 bostic Exp $ Purdue CS"; +#endif +/**************************************************************************** + * creation and deletion of semaphorefile, + * creation of temporary filenames and cleanup() + * pairing of RCS file names and working file names. + * Testprogram: define PAIRTEST + **************************************************************************** + * + * Copyright (C) 1982 by Walter F. Tichy + * Purdue University + * Computer Science Department + * West Lafayette, IN 47907 + * + * All rights reserved. No part of this software may be sold or distributed + * in any form or by any means without the prior written permission of the + * author. + * Report problems and direct all inquiries to Tichy@purdue (ARPA net). + */ + + +/* $Log: rcsfnms.c,v $ + * Revision 3.10 88/02/18 11:57:27 bostic + * replaced with version 4 + * + * Revision 4.6 87/12/18 11:40:23 narten + * additional file types added from 4.3 BSD version, and SPARC assembler + * comment character added. Also, more lint cleanups. (Guy Harris) + * + * Revision 4.5 87/10/18 10:34:16 narten + * Updating version numbers. Changes relative to 1.1 actually relative + * to verion 4.3 + * + * Revision 1.3 87/03/27 14:22:21 jenkins + * Port to suns + * + * Revision 1.2 85/06/26 07:34:28 svb + * Comment leader '% ' for '*.tex' files added. + * + * Revision 1.1 84/01/23 14:50:24 kcs + * Initial revision + * + * Revision 4.3 83/12/15 12:26:48 wft + * Added check for KDELIM in file names to pairfilenames(). + * + * Revision 4.2 83/12/02 22:47:45 wft + * Added csh, red, and sl file name suffixes. + * + * Revision 4.1 83/05/11 16:23:39 wft + * Added initialization of Dbranch to InitAdmin(). Canged pairfilenames(): + * 1. added copying of path from workfile to RCS file, if RCS file is omitted; + * 2. added getting the file status of RCS and working files; + * 3. added ignoring of directories. + * + * Revision 3.7 83/05/11 15:01:58 wft + * Added comtable[] which pairs file name suffixes with comment leaders; + * updated InitAdmin() accordingly. + * + * Revision 3.6 83/04/05 14:47:36 wft + * fixed Suffix in InitAdmin(). + * + * Revision 3.5 83/01/17 18:01:04 wft + * Added getwd() and rename(); these can be removed by defining + * V4_2BSD, since they are not needed in 4.2 bsd. + * Changed sys/param.h to sys/types.h. + * + * Revision 3.4 82/12/08 21:55:20 wft + * removed unused variable. + * + * Revision 3.3 82/11/28 20:31:37 wft + * Changed mktempfile() to store the generated file names. + * Changed getfullRCSname() to store the file and pathname, and to + * delete leading "../" and "./". + * + * Revision 3.2 82/11/12 14:29:40 wft + * changed pairfilenames() to handle file.sfx,v; also deleted checkpathnosfx(), + * checksuffix(), checkfullpath(). Semaphore name generation updated. + * mktempfile() now checks for nil path; lastfilename initialized properly. + * Added Suffix .h to InitAdmin. Added testprogram PAIRTEST. + * Moved rmsema, trysema, trydiraccess, getfullRCSname from rcsutil.c to here. + * + * Revision 3.1 82/10/18 14:51:28 wft + * InitAdmin() now initializes StrictLocks=STRICT_LOCKING (def. in rcsbase.h). + * renamed checkpath() to checkfullpath(). + */ + + +#include "rcsbase.h" +#include +#include +#include + +extern char * rindex(); +extern char * mktemp(); +extern char * malloc(); +extern FILE * fopen(); +extern char * getwd(); /* get working directory; forward decl */ +extern int stat(), fstat(); + +extern FILE * finptr; /* RCS input file descriptor */ +extern FILE * frewrite; /* New RCS file descriptor */ +extern char * RCSfilename, * workfilename; /* filenames */ +struct stat RCSstat, workstat; /* file status for RCS file and working file */ +int haveRCSstat, haveworkstat; /* indicators if status availalble */ + + +char tempfilename [NCPFN+10]; /* used for derived file names */ +char sub1filename [NCPPN]; /* used for files path/file.sfx,v */ +char sub2filename [NCPPN]; /* used for files path/RCS/file.sfx,v */ +char semafilename [NCPPN]; /* name of semaphore file */ +int madesema; /* indicates whether a semaphore file has been set */ +char * tfnames[10] = /* temp. file names to be unlinked when finished */ + {nil,nil,nil,nil,nil,nil,nil,nil,nil,nil}; +int lastfilename = -1;/* index of last file name in tfnames[] */ + + +struct compair { + char * suffix, * comlead; +}; + +struct compair comtable[] = { +/* comtable pairs each filename suffix with a comment leader. The comment */ +/* leader is placed before each line generated by the $Log keyword. This */ +/* table is used to guess the proper comment leader from the working file's */ +/* suffix during initial ci (see InitAdmin()). Comment leaders are needed */ +/* for languages without multiline comments; for others they are optional. */ + "c", " * ", /* C */ + "csh", "# ", /* shell */ + "e", "# ", /* efl */ + "f", "c ", /* fortran */ + "h", " * ", /* C-header */ + "l", " * ", /* lex NOTE: conflict between lex and franzlisp*/ + "mac", "; ", /* macro vms or dec-20 or pdp-11 macro */ + "me", "\\\" ", /* me-macros t/nroff*/ + "mm", "\\\" ", /* mm-macros t/nroff*/ + "ms", "\\\" ", /* ms-macros t/nroff*/ + "p", " * ", /* pascal */ + "r", "# ", /* ratfor */ + "red", "% ", /* psl/rlisp */ + +#ifdef sparc + "s", "! ", /* assembler */ +#endif +#ifdef mc68000 + "s", "| ", /* assembler */ +#endif +#ifdef pdp11 + "s", "/ ", /* assembler */ +#endif +#ifdef vax + "s", "# ", /* assembler */ +#endif + + "sh", "# ", /* shell */ + "sl", "% ", /* psl */ + "red", "% ", /* psl/rlisp */ + "cl", ";;; ", /* common lisp */ + "ml", "; ", /* mocklisp */ + "el", "; ", /* gnulisp */ + "tex", "% ", /* tex */ + "y", " * ", /* yacc */ + "ye", " * ", /* yacc-efl */ + "yr", " * ", /* yacc-ratfor */ + "", "# ", /* default for empty suffix */ + nil, "" /* default for unknown suffix; must always be last */ +}; + + +ffclose(fptr) +FILE * fptr; +/* Function: checks ferror(fptr) and aborts the program if there were + * errors; otherwise closes fptr. + */ +{ if (ferror(fptr) || fclose(fptr)==EOF) + faterror("File read or write error; file system full?"); +} + + + +int trysema(RCSfilename,makesema) +char * RCSfilename; int makesema; +/* Function: Checks whether a semaphore file exists for RCSfilename. If yes, + * returns false. If not, creates one if makesema==true and returns true + * if successful. If a semaphore file was created, madesema is set to true. + * The name of the semaphore file is put into variable semafilename. + */ +{ + register char * tp, *sp, *lp; + int fdesc; + + sp=RCSfilename; + lp = rindex(sp,'/'); + if (lp==0) { + semafilename[0]='.'; semafilename[1]='/'; + tp= &semafilename[2]; + } else { + /* copy path */ + tp=semafilename; + do *tp++ = *sp++; while (sp<=lp); + } + /*now insert `,' and append file name */ + *tp++ = ','; + lp = rindex(sp, RCSSEP); + while (sp0; next++,count--) { + if ((*next != nil) && strcmp(bindex(*next,'/'),fname)==0) { + /* bindex finds the beginning of the file name stem */ + match= *next; + *next=nil; + return match; + } + } + return fname; +} + + +int pairfilenames(argc, argv, mustread, tostdout) +int argc; char ** argv; int mustread, tostdout; +/* Function: Pairs the filenames pointed to by argv; argc indicates + * how many there are. + * Places a pointer to the RCS filename into RCSfilename, + * and a pointer to the name of the working file into workfilename. + * If both the workfilename and the RCS filename are given, and tostdout + * is true, a warning is printed. + * + * If the working file exists, places its status into workstat and + * sets haveworkstat to 0; otherwise, haveworkstat is set to -1; + * Similarly for the RCS file and the variables RCSstat and haveRCSstat. + * + * If the RCS file exists, it is opened for reading, the file pointer + * is placed into finptr, and the admin-node is read in; returns 1. + * If the RCS file does not exist and mustread==true, an error is printed + * and 0 returned. + * If the RCS file does not exist and mustread==false, the admin node + * is initialized to empty (Head, AccessList, Locks, Symbols, StrictLocks, Dbranch) + * and -1 returned. + * + * 0 is returned on all errors. Files that are directories are errors. + * Also calls InitCleanup(); + */ +{ + register char * sp, * tp; + char * lastsep, * purefname, * pureRCSname; + int opened, returncode; + char * RCS1; + char prefdir[NCPPN]; + + if (*argv == nil) return 0; /* already paired filename */ + if (rindex(*argv,KDELIM)!=0) { + /* KDELIM causes havoc in keyword expansion */ + error("RCS file name may not contain %c",KDELIM); + return 0; + } + InitCleanup(); + + /* first check suffix to see whether it is an RCS file or not */ + purefname=bindex(*argv, '/'); /* skip path */ + lastsep=rindex(purefname, RCSSEP); + if (lastsep!= 0 && *(lastsep+1)==RCSSUF && *(lastsep+2)=='\0') { + /* RCS file name given*/ + RCS1=(*argv); pureRCSname=purefname; + /* derive workfilename*/ + sp = purefname; tp=tempfilename; + while (spNCPFN) { + error("RCS file name %s too long",RCS1); + return 0; + } + } else { + /* working file given; now try to find RCS file */ + workfilename= *argv; + /* derive RCS file name*/ + sp=purefname; tp=tempfilename; + while (*tp++ = *sp++); + *(tp-1)=RCSSEP; *tp++=RCSSUF; *tp++='\0'; + /* Try to find RCS file name among arguments*/ + RCS1=findpairfile(argc-1,argv+1,tempfilename); + pureRCSname=bindex(RCS1, '/'); + if (strlen(pureRCSname)>NCPFN) { + error("working file name %s too long",workfilename); + return 0; + } + } + /* now we have a (tentative) RCS filename in RCS1 and workfilename */ + /* First, get status of workfilename */ + haveworkstat=stat(workfilename, &workstat); + if ((haveworkstat==0) && ((workstat.st_mode & S_IFDIR) == S_IFDIR)) { + diagnose("Directory %s ignored",workfilename); + return 0; + } + /* Second, try to find the right RCS file */ + if (pureRCSname!=RCS1) { + /* a path for RCSfile is given; single RCS file to look for */ + finptr=fopen(RCSfilename=RCS1, "r"); + if (finptr!=NULL) { + returncode=1; + } else { /* could not open */ + if (access(RCSfilename,0)==0) { + error("Can't open existing %s", RCSfilename); + return 0; + } + if (mustread) { + error("Can't find %s", RCSfilename); + return 0; + } else { + /* initialize if not mustread */ + returncode = -1; + } + } + } else { + /* no path for RCS file name. Prefix it with path of work */ + /* file if RCS file omitted. Make a second name including */ + /* RCSDIR and try to open that one first. */ + sub1filename[0]=sub2filename[0]= '\0'; + if (RCS1==tempfilename) { + /* RCS file name not given; prepend work path */ + sp= *argv; tp= sub1filename; + while (sp0 && lastpathchar>pathbuf) { + /* move pointer backwards over trailing directory */ + lastpathchar--; + if (*lastpathchar=='/') { + dotdotcounter--; + } + } + if (dotdotcounter>0) { + error("Can't generate full path name for RCS file"); + return RCSfilename; + } else { + /* build full path name */ + realpathlength=lastpathchar-pathbuf+1; + VOID strncpy(namebuf,pathbuf,realpathlength); + VOID strcpy(&namebuf[realpathlength],realname); + return(namebuf); + } + } +} + + + +int trydiraccess(filename) +char * filename; +/* checks write permission in directory of filename and returns + * true if writable, false otherwise + */ +{ + char pathname[NCPPN]; + register char * tp, *sp, *lp; + lp = rindex(filename,'/'); + if (lp==0) { + /* check current directory */ + if (access(".",2)==0) + return true; + else { + error("Current directory not writable"); + return false; + } + } + /* copy path */ + sp=filename; + tp=pathname; + do *tp++ = *sp++; while (sp<=lp); + *tp='\0'; + if (access(pathname,2)==0) + return true; + else { + error("Directory %s not writable", pathname); + return false; + } +} + + + +#ifndef V4_2BSD +/* rename() and getwd() will be provided in bsd 4.2 */ + + +int rename(from, to) +char * from, *to; +/* Function: renames a file with the name given by from to the name given by to. + * unlinks the to-file if it already exists. returns -1 on error, 0 otherwise. + */ +{ VOID unlink(to); /* no need to check return code; will be caught by link*/ + /* no harm done if file "to" does not exist */ + if (link(from,to)<0) return -1; + return(unlink(from)); +} + + + +#define dot "." +#define dotdot ".." + + + +char * getwd(name) +char * name; +/* Function: places full pathname of current working directory into name and + * returns name on success, NULL on failure. + * getwd is an adaptation of pwd. May not return to the current directory on + * failure. + */ +{ + FILE *file; + struct stat d, dd; + char buf[2]; /* to NUL-terminate dir.d_name */ + struct direct dir; + + int rdev, rino; + int off; + register i,j; + + name[off= 0] = '/'; + name[1] = '\0'; + buf[0] = '\0'; + stat("/", &d); + rdev = d.st_dev; + rino = d.st_ino; + for (;;) { + if (stat(dot, &d)<0) return NULL; + if (d.st_ino==rino && d.st_dev==rdev) { + if (name[off] == '/') name[off] = '\0'; + chdir(name); /*change back to current directory*/ + return name; + } + if ((file = fopen(dotdot,"r")) == NULL) return NULL; + if (fstat(fileno(file), &dd)<0) goto fail; + chdir(dotdot); + if(d.st_dev == dd.st_dev) { + if(d.st_ino == dd.st_ino) { + if (name[off] == '/') name[off] = '\0'; + chdir(name); /*change back to current directory*/ + VOID fclose(file); + return name; + } + do { + if (fread((char *)&dir, sizeof(dir), 1, file) !=1) + goto fail; + } while (dir.d_ino != d.st_ino); + } + else do { + if(fread((char *)&dir, sizeof(dir), 1, file) != 1) { + goto fail; + } + stat(dir.d_name, &dd); + } while(dd.st_ino != d.st_ino || dd.st_dev != d.st_dev); + VOID fclose(file); + + /* concatenate file name */ + i = -1; + while (dir.d_name[++i] != 0); + for(j=off+1; j>0; --j) + name[j+i+1] = name[j]; + off=i+off+1; + name[i+1] = '/'; + for(--i; i>=0; --i) + name[i+1] = dir.d_name[i]; + } /* end for */ + +fail: VOID fclose(file); + return NULL; +} + + +#endif + + +#ifdef PAIRTEST +/* test program for pairfilenames() and getfullRCSname() */ +char * workfilename, *RCSfilename; +extern int quietflag; + +main(argc, argv) +int argc; char *argv[]; +{ + int result; + int initflag,tostdout; + quietflag=tostdout=initflag=false; + cmdid="pair"; + + while(--argc, ++argv, argc>=1 && ((*argv)[0] == '-')) { + switch ((*argv)[1]) { + + case 'p': tostdout=true; + break; + case 'i': initflag=true; + break; + case 'q': quietflag=true; + break; + default: error("unknown option: %s", *argv); + break; + } + } + + do { + RCSfilename=workfilename=nil; + result=pairfilenames(argc,argv,!initflag,tostdout); + if (result!=0) { + diagnose("RCSfile: %s; working file: %s",RCSfilename,workfilename); + diagnose("Full RCS file name: %s", getfullRCSname()); + } + switch (result) { + case 0: continue; /* already paired file */ + + case 1: if (initflag) { + error("RCS file %s exists already",RCSfilename); + } else { + diagnose("RCS file %s exists",RCSfilename); + } + VOID fclose(finptr); + break; + + case -1:diagnose("RCS file does not exist"); + break; + } + + } while (++argv, --argc>=1); + +} +#endif -- 2.20.1