page%swap@Sun.COM (Bob Page) (11/19/89)
Submitted-by: rsbx@cbmvax.commodore.com (Raymond S. Brand) Posting-number: Volume 89, Issue 224 Archive-name: unix/rcs.09 # 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/rcsclean.sh,v # rcs/rcs.rcsfiles/rcsedit.c,v # rcs/rcs.rcsfiles/rcsfcmp.c,v # rcs/rcs.rcsfiles/rcsfnms.c,v # This is archive 9 of a 14-part kit. # This archive created: Sun Nov 19 01:12:10 1989 if `test ! -d rcs` then mkdir rcs echo "mkdir rcs" fi if `test ! -d rcs/rcs.rcsfiles` then mkdir rcs/rcs.rcsfiles echo "mkdir rcs/rcs.rcsfiles" fi echo "extracting rcs/rcs.rcsfiles/rcsclean.sh,v" sed 's/^X//' << \SHAR_EOF > rcs/rcs.rcsfiles/rcsclean.sh,v Xhead 1.5; Xbranch 1.5.2; Xaccess ; Xsymbols amiga_rcs:1.5.2 cbmvax_source:1.5.1 uunet_june89_dist:1.5; Xlocks ; strict; Xcomment @# @; X X X1.5 Xdate 86.07.03.13.09.55; author jdl; state Exp; Xbranches 1.5.1.1 1.5.2.1; Xnext ; X X1.5.1.1 Xdate 89.08.11.01.42.19; author rsbx; state Exp; Xbranches ; Xnext ; X X1.5.2.1 Xdate 89.10.13.19.20.06; author rsbx; state Exp; Xbranches ; Xnext ; X X Xdesc X@RCS cleanup operation. X@ X X X X1.5 Xlog X@checked in with -k by rsbx at 89.08.10.16.18.40. X@ Xtext X@#! /bin/sh X# X# RCS cleanup operation. X# $Header: /arthur/src/local/bin/rcs/src/RCS/rcsclean.sh,v 1.5 86/07/03 13:09:55 jdl Exp $ X# X# This program removes working files which are copies of the latest X# revision on the default branch of the corresponding RCS files. X# For each file given, rcsclean performs a co operation for the latest X# revision on the default branch, and compares X# the result with the working file. If the two are identical, X# the working file is deleted. X# X# A typical application in a Makefile would be: X# clean:; rm *.o; rcsclean *.c *.o X# X# Limitation: This program doesn't work if given the name of X# an RCS file rather than the name of the working file. X XPATH=/usr/new/bin:/usr/local/bin:/bin:/usr/bin:/usr/ucb Xexport PATH Xprogname=$0 Xif [ $# = 0 ] ; then X echo "usage: $progname file ..." X echo "removes all working files that are checked in and are unchanged" X exit 0 Xfi XTMPFILE=/tmp/rcscl$$.tmp Xwhile test $# -gt 0 ; do X if test -f $1 ; then X co -p -q $1 > $TMPFILE X if [ $? = 0 ] ; then X cmp -s $1 $TMPFILE X if [ $? = 0 ] ; then X chmod +w $1; rm -f $1; rcs -u -q $1 X fi X fi X fi X shift Xdone Xrm -f $TMPFILE X@ X X X1.5.2.1 Xlog X@Start of Amiga RCS port branch. X@ Xtext X@d4 1 Xa4 1 X# $Header: /u/softeng/rsbx/rcs/amiga/RCS.cbmvax/rcsclean.sh,v 1.5.1.1 89/08/11 01:42:19 rsbx Exp Locker: rsbx $ X@ X X X1.5.1.1 Xlog X@Start of cbmvax RCS source branch. X@ Xtext X@d4 1 Xa4 1 X# $Header: /u/softeng/rsbx/rcs/rcs.uunet/src/RCS/rcsclean.sh,v 1.5 86/07/03 13:09:55 jdl Exp $ X@ SHAR_EOF echo "extracting rcs/rcs.rcsfiles/rcsedit.c,v" sed 's/^X//' << \SHAR_EOF > rcs/rcs.rcsfiles/rcsedit.c,v Xhead 4.8; Xbranch 4.8.2; Xaccess ; Xsymbols amiga_rcs:4.8.2 cbmvax_source:4.8.1 uunet_june89_dist:4.8; Xlocks ; strict; Xcomment @ * @; X X X4.8 Xdate 89.05.01.15.12.35; author narten; state Exp; Xbranches 4.8.1.1 4.8.2.1; Xnext ; X X4.8.1.1 Xdate 89.08.11.01.42.25; author rsbx; state Exp; Xbranches ; Xnext ; X X4.8.2.1 Xdate 89.10.13.19.18.24; author rsbx; state Exp; Xbranches ; Xnext 4.8.2.2; X X4.8.2.2 Xdate 89.10.15.15.44.09; author rsbx; state Exp; Xbranches ; Xnext 4.8.2.3; X X4.8.2.3 Xdate 89.10.16.19.07.14; author rsbx; state Exp; Xbranches ; Xnext 4.8.2.4; X X4.8.2.4 Xdate 89.10.16.23.42.40; author rsbx; state Exp; Xbranches ; Xnext ; X X Xdesc X@RCS stream editor. X@ X X X X4.8 Xlog X@checked in with -k by rsbx at 89.08.10.16.19.26. X@ Xtext X@/* X * RCS stream editor X */ X#ifndef lint Xstatic char rcsid[]= "$Id: rcsedit.c,v 4.8 89/05/01 15:12:35 narten Exp $ Purdue CS"; X#endif X/********************************************************************************** X * edits the input file according to a X * script from stdin, generated by diff -n X * performs keyword expansion 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: rcsedit.c,v $ X * Revision 4.8 89/05/01 15:12:35 narten X * changed copyright header to reflect current distribution rules X * X * Revision 4.7 88/11/08 13:54:14 narten X * misplaced semicolon caused infinite loop X * X * Revision 4.6 88/11/08 12:01:41 narten X * changes from eggert@@sm.unisys.com (Paul Eggert) X * X * Revision 4.6 88/08/09 19:12:45 eggert X * Shrink stdio code size; allow cc -R. X * X * Revision 4.5 87/12/18 11:38:46 narten X * Changes from the 43. version. Don't know the significance of the X * first change involving "rewind". Also, additional "lint" cleanup. X * (Guy Harris) X * X * Revision 4.4 87/10/18 10:32:21 narten X * Updating version numbers. Changes relative to version 1.1 actually X * relative to 4.1 X * X * Revision 1.4 87/09/24 13:59:29 narten X * Sources now pass through lint (if you ignore printf/sprintf/fprintf X * warnings) X * X * Revision 1.3 87/09/15 16:39:39 shepler X * added an initializatin of the variables editline and linecorr X * this will be done each time a file is processed. X * (there was an obscure bug where if co was used to retrieve multiple files X * it would dump) X * fix attributed to Roy Morris @@FileNet Corp ...!felix!roy X * X * Revision 1.2 87/03/27 14:22:17 jenkins X * Port to suns X * X * Revision 1.1 84/01/23 14:50:20 kcs X * Initial revision X * X * Revision 4.1 83/05/12 13:10:30 wft X * Added new markers Id and RCSfile; added locker to Header and Id. X * Overhauled expandline completely() (problem with $01234567890123456789@@). X * Moved trymatch() and marker table to rcskeys.c. X * X * Revision 3.7 83/05/12 13:04:39 wft X * Added retry to expandline to resume after failed match which ended in $. X * Fixed truncation problem for $19chars followed by@@@@. X * Log no longer expands full path of RCS file. X * X * Revision 3.6 83/05/11 16:06:30 wft X * added retry to expandline to resume after failed match which ended in $. X * Fixed truncation problem for $19chars followed by@@@@. X * X * Revision 3.5 82/12/04 13:20:56 wft X * Added expansion of keyword Locker. X * X * Revision 3.4 82/12/03 12:26:54 wft X * Added line number correction in case editing does not start at the X * beginning of the file. X * Changed keyword expansion to always print a space before closing KDELIM; X * Expansion for Header shortened. X * X * Revision 3.3 82/11/14 14:49:30 wft X * removed Suffix from keyword expansion. Replaced fclose with ffclose. X * keyreplace() gets log message from delta, not from curlogmsg. X * fixed expression overflow in while(c=putc(GETC.... X * checked nil printing. X * X * Revision 3.2 82/10/18 21:13:39 wft X * I added checks for write errors during the co process, and renamed X * expandstring() to xpandstring(). X * X * Revision 3.1 82/10/13 15:52:55 wft X * changed type of result of getc() from char to int. X * made keyword expansion loop in expandline() portable to machines X * without sign-extension. X */ X X X#include "rcsbase.h" X X Xextern FILE * fopen(); Xextern char * mktempfile(); Xextern char * bindex(); Xextern FILE * finptr, * frewrite; Xextern int rewriteflag; Xextern int nextc; Xextern char * RCSfilename, * workfilename; Xextern char * bindex(); Xextern char * getfullRCSname(); Xextern enum markers trymatch(); X X XFILE * fcopy, * fedit; /* result and edit file descriptors */ Xchar *resultfile; /* result file name */ Xchar * editfile; /* edit file name */ Xint editline; /*line counter in fedit; starts with 1, is always #lines+1 */ Xint linecorr; /*contains #adds - #deletes in each edit run. */ X /*used to correct editline in case file is not rewound after */ X /* applying one delta */ X Xiniteditfiles(dir) Xchar * dir; X/* Function: Initializes resultfile and editfile with temporary filenames X * in directory dir. Opens resultfile for reading and writing, with fcopy X * as file descriptor. fedit is set to nil. X */ X{ X editline = linecorr = 0; /* make sure we start from the beginning*/ X resultfile=mktempfile(dir,TMPFILE1); X editfile =mktempfile(dir,TMPFILE2); X fedit=nil; X if ((fcopy=fopen(resultfile,"w+"))==NULL) { X faterror("Can't open working file %s",resultfile); X } X} X X Xswapeditfiles(tostdout) X/* Function: swaps resultfile and editfile, assigns fedit=fcopy, X * rewinds fedit for reading, and opens resultfile for reading and X * writing, using fcopy. If tostdout, fcopy is set to stdout. X */ X{ char * tmpptr; X if(ferror(fcopy)) X faterror("write failed on %s -- file system full?",resultfile); X fedit=fcopy; X rewind(fedit); X editline = 1; linecorr=0; X tmpptr=editfile; editfile=resultfile; resultfile=tmpptr; X if (tostdout) X fcopy=stdout; X elsif ((fcopy=fopen(resultfile,"w+"))==NULL) { X faterror("Can't open working file %s",resultfile); X } X} X X Xfinishedit(delta) Xstruct hshentry * delta; X/* copy the rest of the edit file and close it (if it exists). X * if delta!=nil, perform keyword substitution at the same time. X */ X{ X register int c; X if (fedit!=nil) { X if (delta!=nil) { X while (expandline(fedit,fcopy,delta,false,false)) editline++; X } else { X while((c=getc(fedit))!=EOF) { X VOID putc(c,fcopy); X if (c=='\n') editline++; X } X } X ffclose(fedit); X } X} X X Xcopylines(line,delta) Xregister int line; struct hshentry * delta; X/* Function: copies input lines editline..line-1 from fedit to fcopy. X * If delta != nil, keyword expansion is done simultaneously. X * editline is updated. Rewinds a file only if necessary. X */ X{ X X if (editline>line) { X /* swap files */ X finishedit((struct hshentry *)nil); swapeditfiles(false); X /* assumes edit only during last pass, from the beginning*/ X } X while (editline<line) { X /*copy another line*/ X if (delta) X VOID expandline(fedit,fcopy,delta,false,false); X else X while (putc(getc(fedit),fcopy)!='\n'); X editline++; X } X} X X X Xxpandstring(delta) Xstruct hshentry * delta; X/* Function: Reads a string terminated by SDELIM from finptr and writes it X * to fcopy. Double SDELIM is replaced with single SDELIM. X * Keyword expansion is performed with data from delta. X * If rewriteflag==true, the string is also copied unchanged to frewrite. X * editline is updated. X */ X{ X editline=1; X while (expandline(finptr,fcopy,delta,true,rewriteflag)) editline++; X nextc='\n'; X} X X Xcopystring() X/* Function: copies a string terminated with a single SDELIM from finptr to X * fcopy, replacing all double SDELIM with a single SDELIM. X * If rewriteflag==true, the string also copied unchanged to frewrite. X * editline is set to (number of lines copied)+1. X * Assumption: next character read is first string character. X */ X{ register c; X register FILE *fin, *frew, *fcop; X register write; X X fin=finptr; frew=frewrite; fcop=fcopy; X write=rewriteflag; X editline=1; X while ((c=GETC(fin,frew,write)) != EOF) { X if ((c==SDELIM)&&((c=GETC(fin,frew,write)) != SDELIM)){ X /* end of string */ X nextc = c; X return; X } X VOID putc(c,fcop); X if (c=='\n') editline++; X } X nextc = c; X serror("Unterminated string"); X return; X} X X X X Xeditstring(delta) Xstruct hshentry * delta; X/* Function: reads an edit script from finptr and applies it to X * file fedit; the result is written to fcopy. X * If delta!=nil, keyword expansion is performed simultaneously. X * If frewrite==true, the edit script is also copied verbatim to frewrite. X * Assumes that all these files are open. X * If running out of lines in fedit, fedit and fcopy are swapped. X * resultfile and editfile are the names of the files that go with fcopy X * and fedit, respectively. X * Assumes the next input character from finptr is the first character of X * the edit script. Resets nextc on exit. X */ X{ X int ed; /* editor command */ X register int c; X register FILE *fin, *frew; X register int write, i; X int line, length; X X fin=finptr; frew=frewrite; X editline += linecorr; linecorr=0; /*correct line number*/ X write=rewriteflag; X for (;;) { X /* read next command and decode */ X /* assume next non-white character is command name*/ X while((ed=GETC(fin,frew,write))=='\n'|| X ed==' ' || ed=='\t'); X if (ed==SDELIM) break; X /* now attempt to read numbers. */ X /* fscanf causes trouble because of the required echoing */ X while ((c=GETC(fin,frew,write))==' '); /*skip spaces*/ X if (!('0'<=c && c<='9')) { X faterror("missing line number in edit script"); X break; X } X line= c -'0'; X while ('0'<=(c=GETC(fin,frew,write)) && c<='9') { X line = line*10 + c-'0'; X } X while (c==' ') c=GETC(fin,frew,write); 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,frew,write)) && c<='9') { X length = length*10 + c-'0'; X } X while(c!='\n'&&c!=EOF) c=GETC(fin,frew,write); /* skip to end of line */ X X switch (ed) { X case 'd': X copylines(line,delta); X /* skip over unwanted lines */ X for (i=length;i>0;i--) { X /*skip next line*/ X while ((c=getc(fedit))!='\n') X if (c==EOF) X faterror("EOF during edit"); X editline++; X } X linecorr -= length; X break; X case 'a': X copylines(line+1,delta); /*copy only; no delete*/ X for (i=length;i>0;i--) { X /*copy next line from script*/ X if (delta!=nil) X VOID expandline(fin,fcopy,delta,true,write); X else { X c = GETC(fin,frew,write); X while (putc(c,fcopy)!='\n'){ X if ((c==SDELIM)&&((c=GETC(fin,frew,write))!=SDELIM)){ X serror("Missing string delimiter in edit script"); X VOID putc(c,fcopy); X } X c = GETC(fin,frew,write); X } X } X } X linecorr += length; X break; X default: X faterror("unknown command in edit script: %c", ed); X break; X } X } X nextc=GETC(fin,frew,write); X} X X X X/* The rest is for keyword expansion */ X X X Xexpandline(in, out, delta,delimstuffed,write) Xregister FILE * in, * out; struct hshentry * delta; Xint delimstuffed, write; X/* Function: Reads a line from in and writes it to out. X * If delimstuffed==true, double SDELIM is replaced with single SDELIM. X * Keyword expansion is performed with data from delta. X * If write==true, the string is also copied unchanged to frewrite. X * Returns false if end-of-string or end-of-line is detected, true otherwise. X */ X{ X register c; X register FILE * frew; X register w, ds; X register char * tp; X char keystring[keylength+2]; X char keyval[keyvallength+2]; X enum markers matchresult; X X frew = frewrite; X w = write; X ds = delimstuffed; X c=GETC(in,frew,w); X for (;;) { X if (c==EOF) { X if(ds) { X error("unterminated string"); X nextc=c; X } X return(false); X } X X if (c==SDELIM && ds) { X if ((c=GETC(in,frew,w))!=SDELIM) { X /* end of string */ X nextc=c; X return false; X } X } X VOID putc(c,out); X X if (c=='\n') return true; /* end of line */ X X if (c==KDELIM) { X /* check for keyword */ X /* first, copy a long enough string into keystring */ X tp=keystring; X while (((c=GETC(in,frew,w))!=EOF) && (tp<keystring+keylength) && (c!='\n') X && (c!=SDELIM) && (c!=KDELIM) && (c!=VDELIM)) { X VOID putc(c,out); X *tp++ = c; X } X *tp++ = c; *tp = '\0'; X matchresult=trymatch(keystring,false); X if (matchresult==Nomatch) continue; X /* last c will be dealt with properly by continue*/ X X /* Now we have a keyword terminated with a K/VDELIM */ X if (c==VDELIM) { X /* try to find closing KDELIM, and replace value */ X tp=keyval; X while (((c=GETC(in,frew,w)) != EOF) X && (c!='\n') && (c!=KDELIM) && (tp<keyval+keyvallength)) { X *tp++ =c; X if (c==SDELIM && ds) { /*skip next SDELIM */ X c=GETC(in,frew,w); X /* Can't be at end of string. X /* always a \n before closing SDELIM */ X } X } X if (c!=KDELIM) { X /* couldn't find closing KDELIM -- give up */ X VOID putc(VDELIM,out); *tp='\0'; X VOID fputs(keyval,out); X continue; /* last c handled properly */ X } X } X /* now put out the new keyword value */ X keyreplace(matchresult,delta,out); X } X c=GETC(in,frew,w); X } /* end for */ X} X X X Xkeyreplace(marker,delta,out) Xenum markers marker; struct hshentry * delta; register FILE * out; X/* function: ouputs the keyword value(s) corresponding to marker. X * Attributes are derived from delta. X */ X{ X char * date; X register char * sp; X X date= delta->date; X X switch (marker) { X case Author: X VOID fprintf(out,"%c %s %c",VDELIM,delta->author,KDELIM); X break; X case Date: X VOID putc(VDELIM,out);VOID putc(' ',out); X VOID PRINTDATE(out,date);VOID putc(' ',out); X VOID PRINTTIME(out,date);VOID putc(' ',out);VOID putc(KDELIM,out); X break; X case Id: X case Header: X VOID putc(VDELIM,out); VOID putc(' ',out); X if (marker==Id) X VOID fputs(bindex(RCSfilename,'/'),out); X else VOID fputs(getfullRCSname(),out); X VOID fprintf(out," %s ", delta->num); X VOID PRINTDATE(out,date);VOID putc(' ',out);VOID PRINTTIME(out,date); X VOID fprintf(out, " %s %s ",delta->author,delta->state); X if (delta->lockedby!=nil) X VOID fprintf(out,"Locker: %s ",delta->lockedby); X VOID putc(KDELIM,out); X break; X case Locker: X VOID fprintf(out,"%c %s %c", VDELIM, X delta->lockedby==nil?"":delta->lockedby,KDELIM); X break; X case Log: X VOID fprintf(out, "%c\t%s %c\n%sRevision %s ", X VDELIM, bindex(RCSfilename,'/'), KDELIM, Comment, delta->num); X VOID PRINTDATE(out,date);VOID fputs(" ",out);VOID PRINTTIME(out,date); X VOID fprintf(out, " %s\n%s",delta->author,Comment); X /* do not include state here because it may change and is not updated*/ X sp = delta->log; X while (*sp) if (putc(*sp++,out)=='\n') VOID fputs(Comment,out); X /* Comment is the comment leader */ X break; X case RCSfile: X VOID fprintf(out,"%c %s %c",VDELIM,bindex(RCSfilename,'/'),KDELIM); X break; X case Revision: X VOID fprintf(out,"%c %s %c",VDELIM,delta->num,KDELIM); X break; X case Source: X VOID fprintf(out,"%c %s %c",VDELIM,getfullRCSname(),KDELIM); X break; X case State: X VOID fprintf(out,"%c %s %c",VDELIM,delta->state,KDELIM); X break; X case Nomatch: X VOID putc(KDELIM,out); X break; X } X} X X X@ X X X4.8.2.1 Xlog X@Start of Amiga RCS port branch. X@ Xtext X@d5 1 Xa5 5 X<<<<<<< rcsedit.c Xstatic char rcsid[]= "$Id: rcsedit.c,v 4.8.1.1 89/08/11 01:42:25 rsbx Exp Locker: rsbx $ Purdue CS"; X======= Xstatic char rcsid[]= "$Id: rcsedit.c,v 1.2 89/09/17 13:35:29 rick Exp $ Purdue CS"; X>>>>>>> 1.2 Xa40 11 X<<<<<<< rcsedit.c X * Revision 4.8.1.1 89/08/11 01:42:25 rsbx X * Start of cbmvax RCS source branch. X======= X * Revision 1.2 89/09/17 13:35:29 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<<<<<<< rcsedit.c Xa41 3 X * checked in with -k by rsbx at 89.08.10.16.19.26. X * X * Revision 4.8 89/05/01 15:12:35 narten Xa52 5 X======= X * Revision 1.2 88/09/03 15:09:56 rick X * Port to AmigaDos. All done with conditional compiles X * X>>>>>>> 1.2 Xa166 2 X if (fedit != NULL) X fclose(fedit); X@ X X X4.8.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: rcsedit.c,v 4.8.2.1 89/10/13 19:18:24 rsbx Exp Locker: rsbx $ Purdue CS"; Xd45 1 Xa45 3 X * Revision 4.8.2.1 89/10/13 19:18:24 rsbx X * Start of Amiga RCS port branch. X * Xd48 6 Xd55 1 Xd71 5 Xd457 1 Xa457 1 X GETC(in,frew,w); X@ X X X4.8.2.3 Xlog X@Changed file path handling to deal with Amiga file path sematics. X@ Xtext X@d5 1 Xa5 1 Xstatic char rcsid[]= "$Id: rcsedit.c,v 4.8.2.2 89/10/15 15:44:09 rsbx Exp $ Purdue CS"; Xa40 4 X * Revision 4.8.2.2 89/10/15 15:44: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 * Xd133 1 Xd138 1 Xd488 1 Xa488 1 X VOID fputs(fnamepart(RCSfilename),out); Xd503 1 Xa503 1 X VDELIM, fnamepart(RCSfilename), KDELIM, Comment, delta->num); Xd512 1 Xa512 1 X VOID fprintf(out,"%c %s %c",VDELIM,fnamepart(RCSfilename),KDELIM); X@ X X X4.8.2.4 Xlog X@Added function return type for fnamepart(). X@ Xtext X@d5 1 Xa5 1 Xstatic char rcsid[]= "$Id: rcsedit.c,v 4.8.2.3 89/10/16 19:07:14 rsbx Exp $ Purdue CS"; Xa40 3 X * Revision 4.8.2.3 89/10/16 19:07:14 rsbx X * Changed file path handling to deal with Amiga file path sematics. X * Xa135 1 Xextern char * fnamepart(); X@ X X X4.8.1.1 Xlog X@Start of cbmvax RCS source branch. X@ Xtext X@a41 3 X * checked in with -k by rsbx at 89.08.10.16.19.26. X * X * Revision 4.8 89/05/01 15:12:35 narten X@ SHAR_EOF echo "extracting rcs/rcs.rcsfiles/rcsfcmp.c,v" sed 's/^X//' << \SHAR_EOF > rcs/rcs.rcsfiles/rcsfcmp.c,v Xhead 4.5; Xbranch 4.5.2; Xaccess ; Xsymbols amiga_rcs:4.5.2 cbmvax_source:4.5.1 uunet_june89_dist:4.5; Xlocks ; strict; Xcomment @ * @; X X X4.5 Xdate 89.05.01.15.12.42; author narten; state Exp; Xbranches 4.5.1.1 4.5.2.1; Xnext ; X X4.5.1.1 Xdate 89.08.11.01.42.29; author rsbx; state Exp; Xbranches ; Xnext ; X X4.5.2.1 Xdate 89.10.13.19.18.28; author rsbx; state Exp; Xbranches ; Xnext 4.5.2.2; X X4.5.2.2 Xdate 89.10.15.15.44.13; author rsbx; state Exp; Xbranches ; Xnext ; X X Xdesc X@RCS file comparison. X@ X X X X4.5 Xlog X@checked in with -k by rsbx at 89.08.10.16.19.42. X@ Xtext X@/* X * RCS file comparison X */ X#ifndef lint Xstatic char rcsid[]= "$Id: rcsfcmp.c,v 4.5 89/05/01 15:12:42 narten Exp $ Purdue CS"; X#endif X/***************************************************************************** X * rcsfcmp() X * Testprogram: define FCMPTEST 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 X/* $Log: rcsfcmp.c,v $ X * Revision 4.5 89/05/01 15:12:42 narten X * changed copyright header to reflect current distribution rules X * X * Revision 4.4 88/11/08 12:01:33 narten X * changes from eggert@@sm.unisys.com (Paul Eggert) X * X * Revision 4.4 88/08/09 19:12:50 eggert X * Shrink stdio code size. X * X * Revision 4.3 87/12/18 11:40:02 narten X * lint cleanups (Guy Harris) X * X * Revision 4.2 87/10/18 10:33:06 narten X * updting version number. Changes relative to 1.1 actually relative to X * 4.1 X * X * Revision 1.2 87/03/27 14:22:19 jenkins X * Port to suns X * X * Revision 1.1 84/01/23 14:50:23 kcs X * Initial revision X * X * Revision 4.1 83/05/10 16:24:04 wft X * Marker matching now uses trymatch(). Marker pattern is now X * checked precisely. X * X * Revision 3.1 82/12/04 13:21:40 wft X * Initial revision. X * X */ X X/* X#define FCMPTEST X/* Testprogram; prints out whether two files are identical, X * except for keywords X */ X X#include "rcsbase.h" Xextern FILE * fopen(); Xextern enum markers trymatch(); /* check for keywords */ X X Xrcsfcmp(xfname,uxfname,delta) Xchar * xfname, *uxfname; struct hshentry *delta; X/* Function: compares the files xfname and uxfname. Returns true X * if xfname has the same contents as uxfname, while disregarding X * keyword values. For the LOG-keyword, rcsfcmp skips the log message X * given by the parameter delta in xfname. Thus, rcsfcmp returns true X * if xfname contains the same as uxfname, with the keywords expanded. X * Implementation: character-by-character comparison until $ is found. X * If a $ is found, read in the marker keywords; if they are real keywords X * and identical, read in keyword value. If value is terminated properly, X * disregard it and optionally skip log message; otherwise, compare value. X */ X{ X register int xc,uxc; X char xkeyword[keylength+2], uxkeyword[keylength+2]; X char xkeyval[keyvallength+1], uxkeyval[keyvallength+1]; X register FILE * xfp, * uxfp; X register char * tp; X int result; X enum markers match1,match2; X X if ((xfp=fopen(tp=xfname,"r"))==NULL || (uxfp=fopen(tp=uxfname,"r"))==NULL) { X faterror("Can't open %s\n", tp); X return false; X } X result=false; X xc=getc(xfp); uxc=getc(uxfp); X while( xc == uxc) { /* comparison loop */ X if (xc==EOF) { /* finished; everything is the same*/ X result=true; X break; X } X if ( xc!=KDELIM) { X /* get the next characters */ X xc=getc(xfp); uxc=getc(uxfp); X } else { X /* try to get both keywords */ X tp = xkeyword; X while( (xc=getc(xfp))!=EOF && (tp< xkeyword+keylength) && (xc!='\n') X && (xc!=KDELIM) && (xc!=VDELIM)) X *tp++ = xc; X *tp++ = xc; /* add closing K/VDELIM */ X *tp='\0'; X tp = uxkeyword; X while( (uxc=getc(uxfp))!=EOF && (tp< uxkeyword+keylength) && (uxc!='\n') X && (uxc!=KDELIM) && (uxc!=VDELIM)) X *tp++ = uxc; X *tp++ = xc; /* add closing K/VDELIM */ X *tp='\0'; X /* now we have 2 keywords, or something thal looks like it.*/ X match1=trymatch(xkeyword,false); X match2=trymatch(uxkeyword,false); X if (match1 != match2) break; /* not identical */ X#ifdef FCMPTEST X VOID printf("found potential keywords %s and %s\n",xkeyword,uxkeyword); X#endif X X if (match1 == Nomatch) { X /* not a keyword pattern, but could still be identical */ X if (strcmp(xkeyword,uxkeyword)==0) X continue; X else break; X } X#ifdef FCMPTEST X VOID printf("found common keyword %s\n",xkeyword); X#endif X tp=xkeyval; X if (xc==VDELIM) {/* get value */ X while (((xc=getc(xfp))!=KDELIM) && (xc!='\n') && (xc!=EOF) && X (tp<xkeyval+keyvallength)) X *tp++ = xc; X } X *tp = '\0'; /*xkeyval now filled with value; possibly empty*/ X tp=uxkeyval; X if (uxc==VDELIM) {/* get value */ X while (((uxc=getc(uxfp))!=KDELIM) && (uxc!='\n') && (uxc!=EOF) && X (tp<uxkeyval+keyvallength)) X *tp++ = uxc; X } X *tp = '\0'; /*uxkeyval now filled with value; possibly empty*/ X if (xc!=uxc) break; /* not the same */ X if (xc==KDELIM) { X xc=getc(xfp); uxc=getc(uxfp); /* skip closing KDELIM */ X /* if the keyword is LOG, also skip the log message in xfp*/ X if (match1==Log) { X /* first, compute the number of line feeds in log msg */ X int lncnt, ccnt; X lncnt=2; tp=delta->log; X while(*tp) if(*tp++=='\n') lncnt++; X while(xc!=EOF) { X if (xc=='\n') X if(--lncnt==0) break; X xc=getc(xfp); X } X /* skip last comment leader */ X /* Can't just skip another line here, because there may be */ X /* additional characters on the line (after the Log....$) */ X for (ccnt=strlen(Comment); ccnt>=0; lncnt--) { X xc=getc(xfp); X if(xc=='\n') break; X /* reads to the end of the comment leader or '\n', */ X /* whatever comes first. This is because some editors */ X /* strip off trailing blanks from a leader like " * ". */ X } X } X } else { X /* both end in the same character, but not a KDELIM */ X /* must compare string values.*/ X#ifdef FCMPTEST X VOID printf("non-terminated keywords %s, potentially different values\n",xkeyword); X#endif X if (strcmp(xkeyval,uxkeyval)!=0) break; /*different */ X xc=getc(xfp); uxc=getc(uxfp); /* skip closing char */ X } X } X } X VOID fclose(xfp); VOID fclose(uxfp); X return result; X} X X X X#ifdef FCMPTEST Xchar * RCSfilename, * workfilename; X Xchar * Comment; X Xmain(argc, argv) Xint argc; char *argv[]; X/* first argument: comment leader; 2nd: log message, 3rd: expanded file, X * 4th: unexpanded file X */ X{ struct hshentry delta; X X cmdid="rcsfcmp"; X Comment=argv[1]; X delta.log=argv[2]; X if (rcsfcmp(argv[3],argv[4],&delta)) X VOID printf("files are the same\n"); X else VOID printf("files are different\n"); X} X#endif X@ X X X4.5.2.1 Xlog X@Start of Amiga RCS port branch. X@ Xtext X@d5 1 Xa5 5 X<<<<<<< rcsfcmp.c Xstatic char rcsid[]= "$Id: rcsfcmp.c,v 4.5.1.1 89/08/11 01:42:29 rsbx Exp Locker: rsbx $ Purdue CS"; X======= Xstatic char rcsid[]= "$Id: rcsfcmp.c,v 1.2 89/09/17 13:42:09 rick Exp $ Purdue CS"; X>>>>>>> 1.2 Xa42 16 X<<<<<<< rcsfcmp.c X * Revision 4.5.1.1 89/08/11 01:42:29 rsbx X * Start of cbmvax RCS source branch. X * X * Revision 4.5 89/05/01 15:12:42 narten X * checked in with -k by rsbx at 89.08.10.16.19.42. X======= X * Revision 1.2 89/09/17 13:42:09 rick X * Port to AmigaDos done by Rick Schaeffer (ricks@@iscuva.iscs.com) X * All changes done with condition compile (#ifdef AMIGA). This X * version compiles correctly with Lattice C version 5.02 or later. X * X * Revision 1.1 89/09/17 13:04:37 rick X * Initial revision X>>>>>>> 1.2 X * X@ X X X4.5.2.2 Xlog X@Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS Xsources I have here (and are later than the ones Rick used). X@ Xtext X@d5 5 Xa9 1 Xstatic char rcsid[]= "$Id: rcsfcmp.c,v 4.5.2.1 89/10/13 19:18:28 rsbx Exp Locker: rsbx $ Purdue CS"; Xd47 1 Xa47 3 X * Revision 4.5.2.1 89/10/13 19:18:28 rsbx X * Start of Amiga RCS port branch. X * Xd53 5 Xd59 4 Xd202 1 Xa202 1 X for (ccnt=strlen(Comment); ccnt>=0;) { X@ X X X4.5.1.1 Xlog X@Start of cbmvax RCS source branch. X@ Xtext X@a43 3 X * checked in with -k by rsbx at 89.08.10.16.19.42. X * X * Revision 4.5 89/05/01 15:12:42 narten X@ SHAR_EOF echo "extracting rcs/rcs.rcsfiles/rcsfnms.c,v" sed 's/^X//' << \SHAR_EOF > rcs/rcs.rcsfiles/rcsfnms.c,v Xhead 4.8; Xbranch 4.8.2; Xaccess ; Xsymbols amiga_rcs:4.8.2 cbmvax_source:4.8.1 uunet_june89_dist:4.8; Xlocks ; strict; Xcomment @ * @; X X X4.8 Xdate 89.05.01.15.09.41; author narten; state Exp; Xbranches 4.8.1.1 4.8.2.1; Xnext ; X X4.8.1.1 Xdate 89.08.11.01.42.32; author rsbx; state Exp; Xbranches ; Xnext ; X X4.8.2.1 Xdate 89.10.13.19.18.32; author rsbx; state Exp; Xbranches ; Xnext 4.8.2.2; X X4.8.2.2 Xdate 89.10.15.15.44.18; author rsbx; state Exp; Xbranches ; Xnext 4.8.2.3; X X4.8.2.3 Xdate 89.10.15.18.27.52; author rsbx; state Exp; Xbranches ; Xnext 4.8.2.4; X X4.8.2.4 Xdate 89.10.16.19.07.19; author rsbx; state Exp; Xbranches ; Xnext 4.8.2.5; X X4.8.2.5 Xdate 89.10.16.23.54.04; author rsbx; state Exp; Xbranches ; Xnext 4.8.2.6; X X4.8.2.6 Xdate 89.10.17.16.17.29; author rsbx; state Exp; Xbranches ; Xnext 4.8.2.7; X X4.8.2.7 Xdate 89.10.17.18.38.55; author rsbx; state Exp; Xbranches ; Xnext 4.8.2.8; X X4.8.2.8 Xdate 89.10.30.13.44.29; author rsbx; state Exp; Xbranches ; Xnext 4.8.2.9; X X4.8.2.9 Xdate 89.10.30.13.53.10; author rsbx; state Exp; Xbranches ; Xnext 4.8.2.10; X X4.8.2.10 Xdate 89.11.01.14.43.14; author rsbx; state Exp; Xbranches ; Xnext 4.8.2.11; X X4.8.2.11 Xdate 89.11.05.18.03.59; author rsbx; state Exp; Xbranches ; Xnext ; X X Xdesc X@RCS file name handling. X@ X X X X4.8 Xlog X@checked in with -k by rsbx at 89.08.10.16.20.00. X@ Xtext X@/* X * RCS file name handling X */ X#ifndef lint X static char X rcsid[]= "$Id: rcsfnms.c,v 4.8 89/05/01 15:09:41 narten Exp $ Purdue CS"; X#endif X/**************************************************************************** X * creation and deletion of semaphorefile, X * creation of temporary filenames and cleanup() X * pairing of RCS file names and working file names. X * Testprogram: define PAIRTEST 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: rcsfnms.c,v $ X * Revision 4.8 89/05/01 15:09:41 narten X * changed getwd to not stat empty directories. X * X * Revision 4.7 88/11/08 12:01:22 narten X * changes from eggert@@sm.unisys.com (Paul Eggert) X * X * Revision 4.7 88/08/09 19:12:53 eggert X * Fix troff macro comment leader bug; add Prolog; allow cc -R; remove lint. X * X * Revision 4.6 87/12/18 11:40:23 narten X * additional file types added from 4.3 BSD version, and SPARC assembler X * comment character added. Also, more lint cleanups. (Guy Harris) X * X * Revision 4.5 87/10/18 10:34:16 narten X * Updating version numbers. Changes relative to 1.1 actually relative X * to verion 4.3 X * X * Revision 1.3 87/03/27 14:22:21 jenkins X * Port to suns X * X * Revision 1.2 85/06/26 07:34:28 svb X * Comment leader '% ' for '*.tex' files added. X * X * Revision 1.1 84/01/23 14:50:24 kcs X * Initial revision X * X * Revision 4.3 83/12/15 12:26:48 wft X * Added check for KDELIM in file names to pairfilenames(). X * X * Revision 4.2 83/12/02 22:47:45 wft X * Added csh, red, and sl file name suffixes. X * X * Revision 4.1 83/05/11 16:23:39 wft X * Added initialization of Dbranch to InitAdmin(). Canged pairfilenames(): X * 1. added copying of path from workfile to RCS file, if RCS file is omitted; X * 2. added getting the file status of RCS and working files; X * 3. added ignoring of directories. X * X * Revision 3.7 83/05/11 15:01:58 wft X * Added comtable[] which pairs file name suffixes with comment leaders; X * updated InitAdmin() accordingly. X * X * Revision 3.6 83/04/05 14:47:36 wft X * fixed Suffix in InitAdmin(). X * X * Revision 3.5 83/01/17 18:01:04 wft X * Added getwd() and rename(); these can be removed by defining X * V4_2BSD, since they are not needed in 4.2 bsd. X * Changed sys/param.h to sys/types.h. X * X * Revision 3.4 82/12/08 21:55:20 wft X * removed unused variable. X * X * Revision 3.3 82/11/28 20:31:37 wft X * Changed mktempfile() to store the generated file names. X * Changed getfullRCSname() to store the file and pathname, and to X * delete leading "../" and "./". X * X * Revision 3.2 82/11/12 14:29:40 wft X * changed pairfilenames() to handle file.sfx,v; also deleted checkpathnosfx(), X * checksuffix(), checkfullpath(). Semaphore name generation updated. X * mktempfile() now checks for nil path; freefilename initialized properly. X * Added Suffix .h to InitAdmin. Added testprogram PAIRTEST. X * Moved rmsema, trysema, trydiraccess, getfullRCSname from rcsutil.c to here. X * X * Revision 3.1 82/10/18 14:51:28 wft X * InitAdmin() now initializes StrictLocks=STRICT_LOCKING (def. in rcsbase.h). X * renamed checkpath() to checkfullpath(). X */ X X X#include "rcsbase.h" X#include <sys/types.h> X#include <sys/stat.h> X#include <sys/dir.h> X Xextern char * rindex(); Xextern char * mktemp(); Xextern FILE * fopen(); Xextern char * getwd(); /* get working directory; forward decl */ Xextern int stat(), fstat(); X Xextern FILE * finptr; /* RCS input file descriptor */ Xextern FILE * frewrite; /* New RCS file descriptor */ Xextern char * RCSfilename, * workfilename; /* filenames */ Xstruct stat RCSstat, workstat; /* file status for RCS file and working file */ Xint haveRCSstat, haveworkstat; /* indicators if status availalble */ X X Xchar tempfilename [NCPFN+10]; /* used for derived file names */ Xchar sub1filename [NCPPN]; /* used for files path/file.sfx,v */ Xchar sub2filename [NCPPN]; /* used for files path/RCS/file.sfx,v */ Xchar semafilename [NCPPN]; /* name of semaphore file */ Xint madesema; /* indicates whether a semaphore file has been set */ Xchar * tfnames[10]; /* temp. file names to be unlinked when finished */ Xint freefilename; /* index of next free file name in tfnames[] */ X X Xstruct compair { X char * suffix, * comlead; X}; X Xstruct compair comtable[] = { X/* comtable pairs each filename suffix with a comment leader. The comment */ X/* leader is placed before each line generated by the $Log keyword. This */ X/* table is used to guess the proper comment leader from the working file's */ X/* suffix during initial ci (see InitAdmin()). Comment leaders are needed */ X/* for languages without multiline comments; for others they are optional. */ X "c", " * ", /* C */ X "csh", "# ", /* shell */ X "e", "# ", /* efl */ X "f", "c ", /* fortran */ X "h", " * ", /* C-header */ X "l", " * ", /* lex NOTE: conflict between lex and franzlisp*/ X "mac", "; ", /* macro vms or dec-20 or pdp-11 macro */ X "me", ".\\\" ",/* me-macros t/nroff*/ X "mm", ".\\\" ",/* mm-macros t/nroff*/ X "ms", ".\\\" ",/* ms-macros t/nroff*/ X "p", " * ", /* pascal */ X "pl", "% ", /* prolog */ X "r", "# ", /* ratfor */ X "red", "% ", /* psl/rlisp */ X X#ifdef sparc X "s", "! ", /* assembler */ X#endif X#ifdef mc68000 X "s", "| ", /* assembler */ X#endif X#ifdef pdp11 X "s", "/ ", /* assembler */ X#endif X#ifdef vax X "s", "# ", /* assembler */ X#endif X X "sh", "# ", /* shell */ X "sl", "% ", /* psl */ X "red", "% ", /* psl/rlisp */ X "cl", ";;; ", /* common lisp */ X "ml", "; ", /* mocklisp */ X "el", "; ", /* gnulisp */ X "tex", "% ", /* tex */ X "y", " * ", /* yacc */ X "ye", " * ", /* yacc-efl */ X "yr", " * ", /* yacc-ratfor */ X "", "# ", /* default for empty suffix */ X nil, "" /* default for unknown suffix; must always be last */ X}; X X Xffclose(fptr) XFILE * fptr; X/* Function: checks ferror(fptr) and aborts the program if there were X * errors; otherwise closes fptr. X */ X{ if (ferror(fptr) || fclose(fptr)==EOF) X faterror("File read or write error; file system full?"); X} X X X Xint trysema(RCSname,makesema) Xchar * RCSname; int makesema; X/* Function: Checks whether a semaphore file exists for RCSname. If yes, X * returns false. If not, creates one if makesema==true and returns true X * if successful. If a semaphore file was created, madesema is set to true. X * The name of the semaphore file is put into variable semafilename. X */ X{ X register char * tp, *sp, *lp; X int fdesc; X X sp=RCSname; X lp = rindex(sp,'/'); X if (lp==0) { X semafilename[0]='.'; semafilename[1]='/'; X tp= &semafilename[2]; X } else { X /* copy path */ X tp=semafilename; X do *tp++ = *sp++; while (sp<=lp); X } X /*now insert `,' and append file name */ X *tp++ = ','; X lp = rindex(sp, RCSSEP); X while (sp<lp) *tp++ = *sp++; X *tp++ = ','; *tp++ = '\0'; /* will be the same length as RCSname*/ X X madesema = false; X if (access(semafilename, 0) == 0) { X error("RCS file %s is in use",RCSname); X return false; X } X if (makesema) { X if ((fdesc=creat(semafilename, 000)) == -1) { X error("Can't create semaphore file for RCS file %s",RCSname); X return false; X } else X VOID close(fdesc); X madesema=true; X } X return true; X} X X Xrmsema() X/* Function: delete the semaphore file if madeseam==true; X * sets madesema to false. X */ X{ X if (madesema) { X madesema=false; X if (unlink(semafilename) == -1) { X error("Can't find semaphore file %s",semafilename); X } X } X} X X X XInitCleanup() X{ freefilename = 0; /* initialize pointer */ X} X X Xcleanup() X/* Function: closes input file and rewrite file. X * Unlinks files in tfnames[], deletes semaphore file. X */ X{ X register int i; X X if (finptr!=NULL) VOID fclose(finptr); X if (frewrite!=NULL) VOID fclose(frewrite); X for (i=0; i<freefilename; i++) { X if (tfnames[i][0]!='\0') VOID unlink(tfnames[i]); X } X InitCleanup(); X rmsema(); X} X X Xchar * mktempfile(fullpath,filename) Xregister char * fullpath, * filename; X/* Function: Creates a unique filename using the process id and stores it X * into a free slot in tfnames. The filename consists of the path contained X * in fullpath concatenated with filename. filename should end in "XXXXXX". X * Because of storage in tfnames, cleanup() can unlink the file later. X * freefilename indicates the lowest unoccupied slot in tfnames. X * Returns a pointer to the filename created. X * Example use: mktempfile("/tmp/", somefilename) X */ X{ X register char * lastslash, *tp; X if ((tp=tfnames[freefilename])==nil) X tp=tfnames[freefilename] = talloc(NCPPN); X if (fullpath!=nil && (lastslash=rindex(fullpath,'/'))!=0) { X /* copy path */ X while (fullpath<=lastslash) *tp++ = *fullpath++; X } X while (*tp++ = *filename++); X return (mktemp(tfnames[freefilename++])); X} X X X X Xchar * bindex(sp,c) Xregister char * sp, c; X/* Function: Finds the last occurrence of character c in string sp X * and returns a pointer to the character just beyond it. If the X * character doesn't occur in the string, sp is returned. X */ X{ register char * r; X r = sp; X while (*sp) { X if (*sp++ == c) r=sp; X } X return r; X} X X X X X XInitAdmin() X/* function: initializes an admin node */ X{ register char * Suffix; X register int i; X X Head=Dbranch=nil; AccessList=nil; Symbols=nil; Locks=nil; X StrictLocks=STRICT_LOCKING; X X /* guess the comment leader from the suffix*/ X Suffix=bindex(workfilename, '.'); X if (Suffix==workfilename) Suffix= ""; /* empty suffix; will get default*/ X for (i=0;;i++) { X if (comtable[i].suffix==nil) { X Comment=comtable[i].comlead; /*default*/ X break; X } elsif (strcmp(Suffix,comtable[i].suffix)==0) { X Comment=comtable[i].comlead; /*default*/ X break; X } X } X Lexinit(); /* Note: if finptr==NULL, reads nothing; only initializes*/ X} X X X Xchar * findpairfile(argc, argv, fname) Xint argc; char * argv[], *fname; X/* Function: Given a filename fname, findpairfile scans argv for a pathname X * ending in fname. If found, returns a pointer to the pathname, and sets X * the corresponding pointer in argv to nil. Otherwise returns fname. X * argc indicates the number of entries in argv. Some of them may be nil. X */ X{ X register char * * next, * match; X register int count; X X for (next = argv, count = argc; count>0; next++,count--) { X if ((*next != nil) && strcmp(bindex(*next,'/'),fname)==0) { X /* bindex finds the beginning of the file name stem */ X match= *next; X *next=nil; X return match; X } X } X return fname; X} X X Xint pairfilenames(argc, argv, mustread, tostdout) Xint argc; char ** argv; int mustread, tostdout; X/* Function: Pairs the filenames pointed to by argv; argc indicates X * how many there are. X * Places a pointer to the RCS filename into RCSfilename, X * and a pointer to the name of the working file into workfilename. X * If both the workfilename and the RCS filename are given, and tostdout X * is true, a warning is printed. X * X * If the working file exists, places its status into workstat and X * sets haveworkstat to 0; otherwise, haveworkstat is set to -1; X * Similarly for the RCS file and the variables RCSstat and haveRCSstat. X * X * If the RCS file exists, it is opened for reading, the file pointer X * is placed into finptr, and the admin-node is read in; returns 1. X * If the RCS file does not exist and mustread==true, an error is printed X * and 0 returned. X * If the RCS file does not exist and mustread==false, the admin node X * is initialized to empty (Head, AccessList, Locks, Symbols, StrictLocks, Dbranch) X * and -1 returned. X * X * 0 is returned on all errors. Files that are directories are errors. X * Also calls InitCleanup(); X */ X{ X register char * sp, * tp; X char * lastsep, * purefname, * pureRCSname; X int opened, returncode; X char * RCS1; X char prefdir[NCPPN]; X X if (*argv == nil) return 0; /* already paired filename */ X if (rindex(*argv,KDELIM)!=0) { X /* KDELIM causes havoc in keyword expansion */ X error("RCS file name may not contain %c",KDELIM); X return 0; X } X InitCleanup(); X X /* first check suffix to see whether it is an RCS file or not */ X purefname=bindex(*argv, '/'); /* skip path */ X lastsep=rindex(purefname, RCSSEP); X if (lastsep!= 0 && *(lastsep+1)==RCSSUF && *(lastsep+2)=='\0') { X /* RCS file name given*/ X RCS1=(*argv); pureRCSname=purefname; X /* derive workfilename*/ X sp = purefname; tp=tempfilename; X while (sp<lastsep) *tp++ = *sp++; *tp='\0'; X /* try to find workfile name among arguments */ X workfilename=findpairfile(argc-1,argv+1,tempfilename); X if (strlen(pureRCSname)>NCPFN) { X error("RCS file name %s too long",RCS1); X return 0; X } X } else { X /* working file given; now try to find RCS file */ X workfilename= *argv; X /* derive RCS file name*/ X sp=purefname; tp=tempfilename; X while (*tp++ = *sp++); X *(tp-1)=RCSSEP; *tp++=RCSSUF; *tp++='\0'; X /* Try to find RCS file name among arguments*/ X RCS1=findpairfile(argc-1,argv+1,tempfilename); X pureRCSname=bindex(RCS1, '/'); X if (strlen(pureRCSname)>NCPFN) { X error("working file name %s too long",workfilename); X return 0; X } X } X /* now we have a (tentative) RCS filename in RCS1 and workfilename */ X /* First, get status of workfilename */ X haveworkstat=stat(workfilename, &workstat); X if ((haveworkstat==0) && ((workstat.st_mode & S_IFDIR) == S_IFDIR)) { X diagnose("Directory %s ignored",workfilename); X return 0; X } X /* Second, try to find the right RCS file */ X if (pureRCSname!=RCS1) { X /* a path for RCSfile is given; single RCS file to look for */ X finptr=fopen(RCSfilename=RCS1, "r"); X if (finptr!=NULL) { X returncode=1; X } else { /* could not open */ X if (access(RCSfilename,0)==0) { X error("Can't open existing %s", RCSfilename); X return 0; X } X if (mustread) { X error("Can't find %s", RCSfilename); X return 0; X } else { X /* initialize if not mustread */ X returncode = -1; X } X } X } else { X /* no path for RCS file name. Prefix it with path of work */ X /* file if RCS file omitted. Make a second name including */ X /* RCSDIR and try to open that one first. */ X sub1filename[0]=sub2filename[0]= '\0'; X if (RCS1==tempfilename) { X /* RCS file name not given; prepend work path */ X sp= *argv; tp= sub1filename; X while (sp<purefname) *tp++ = *sp ++; X *tp='\0'; X VOID strcpy(sub2filename,sub1filename); /* second one */ X } X VOID strcat(sub1filename,RCSDIR); X VOID strcpy(prefdir,sub1filename); /* preferred directory for RCS file*/ X VOID strcat(sub1filename,RCS1); VOID strcat(sub2filename,RCS1); X X X opened=( X ((finptr=fopen(RCSfilename=sub1filename, "r"))!=NULL) || X ((finptr=fopen(RCSfilename=sub2filename,"r"))!=NULL) ); X X if (opened) { X /* open succeeded */ X returncode=1; X } else { X /* open failed; may be read protected */ X if ((access(RCSfilename=sub1filename,0)==0) || X (access(RCSfilename=sub2filename,0)==0)) { X error("Can't open existing %s",RCSfilename); X return 0; X } X if (mustread) { X error("Can't find %s nor %s",sub1filename,sub2filename); X return 0; X } else { X /* initialize new file. Put into ./RCS if possible, strip off suffix*/ X RCSfilename= (access(prefdir,0)==0)?sub1filename:sub2filename; X returncode= -1; X } X } X } X X if (returncode == 1) { /* RCS file open */ X haveRCSstat=fstat(fileno(finptr),&RCSstat); X if ((haveRCSstat== 0) && ((RCSstat.st_mode & S_IFDIR) == S_IFDIR)) { X diagnose("Directory %s ignored",RCSfilename); X return 0; X } X Lexinit(); getadmin(); X } else { /* returncode == -1; RCS file nonexisting */ X haveRCSstat = -1; X InitAdmin(); X }; X X if (tostdout&& X !(RCS1==tempfilename||workfilename==tempfilename)) X /*The last term determines whether a pair of */ X /* file names was given in the argument list */ X warn("Option -p is set; ignoring output file %s",workfilename); X X return returncode; X} X X Xchar * getfullRCSname() X/* Function: returns a pointer to the full path name of the RCS file. X * Calls getwd(), but only once. X * removes leading "../" and "./". X */ X{ static char pathbuf[NCPPN]; X static char namebuf[NCPPN]; X static int pathlength; X X register char * realname, * lastpathchar; X register int dotdotcounter, realpathlength; X X if (*RCSfilename=='/') { X return(RCSfilename); X } else { X if (pathlength==0) { /*call curdir for the first time*/ X if (getwd(pathbuf)==NULL) X faterror("Can't build current directory path"); X pathlength=strlen(pathbuf); X if (!((pathlength==1) && (pathbuf[0]=='/'))) { X pathbuf[pathlength++]='/'; X /* Check needed because some getwd implementations */ X /* generate "/" for the root. */ X } X } X /*the following must be redone since RCSfilename may change*/ X /* find how many ../ to remvove from RCSfilename */ X dotdotcounter =0; X realname = RCSfilename; X while( realname[0]=='.' && X (realname[1]=='/'||(realname[1]=='.'&&realname[2]=='/'))){ X if (realname[1]=='/') { X /* drop leading ./ */ X realname += 2; X } else { X /* drop leading ../ and remember */ X dotdotcounter++; X realname += 3; X } X } X /* now remove dotdotcounter trailing directories from pathbuf*/ X lastpathchar=pathbuf + pathlength-1; X while (dotdotcounter>0 && lastpathchar>pathbuf) { X /* move pointer backwards over trailing directory */ X lastpathchar--; X if (*lastpathchar=='/') { X dotdotcounter--; X } X } X if (dotdotcounter>0) { X error("Can't generate full path name for RCS file"); X return RCSfilename; X } else { X /* build full path name */ X realpathlength=lastpathchar-pathbuf+1; X VOID strncpy(namebuf,pathbuf,realpathlength); X VOID strcpy(&namebuf[realpathlength],realname); X return(namebuf); X } X } X} X X X Xint trydiraccess(filename) Xchar * filename; X/* checks write permission in directory of filename and returns X * true if writable, false otherwise X */ X{ X char pathname[NCPPN]; X register char * tp, *sp, *lp; X lp = rindex(filename,'/'); X if (lp==0) { X /* check current directory */ X if (access(".",2)==0) X return true; X else { X error("Current directory not writable"); X return false; X } X } X /* copy path */ X sp=filename; X tp=pathname; X do *tp++ = *sp++; while (sp<=lp); X *tp='\0'; X if (access(pathname,2)==0) X return true; X else { X error("Directory %s not writable", pathname); X return false; X } X} X X X X#ifndef V4_2BSD X/* rename() and getwd() will be provided in bsd 4.2 */ X X Xint rename(from, to) Xchar * from, *to; X/* Function: renames a file with the name given by from to the name given by to. X * unlinks the to-file if it already exists. returns -1 on error, 0 otherwise. X */ X{ VOID unlink(to); /* no need to check return code; will be caught by link*/ X /* no harm done if file "to" does not exist */ X if (link(from,to)<0) return -1; X return(unlink(from)); X} X X X X#define dot "." X#define dotdot ".." X X X Xchar * getwd(name) Xchar * name; X/* Function: places full pathname of current working directory into name and X * returns name on success, NULL on failure. X * getwd is an adaptation of pwd. May not return to the current directory on X * failure. X */ X{ X FILE *file; X struct stat d, dd; X char buf[2]; /* to NUL-terminate dir.d_name */ X struct direct dir; X X int rdev, rino; X int off; X register i,j; X X name[off= 0] = '/'; X name[1] = '\0'; X buf[0] = '\0'; X if (stat("/", &d)<0) return NULL; X rdev = d.st_dev; X rino = d.st_ino; X for (;;) { X if (stat(dot, &d)<0) return NULL; X if (d.st_ino==rino && d.st_dev==rdev) { X if (name[off] == '/') name[off] = '\0'; X chdir(name); /*change back to current directory*/ X return name; X } X if ((file = fopen(dotdot,"r")) == NULL) return NULL; X if (fstat(fileno(file), &dd)<0) goto fail; X chdir(dotdot); X if(d.st_dev == dd.st_dev) { X if(d.st_ino == dd.st_ino) { X if (name[off] == '/') name[off] = '\0'; X chdir(name); /*change back to current directory*/ X VOID fclose(file); X return name; X } X do { X if (fread((char *)&dir, sizeof(dir), 1, file) !=1) X goto fail; X } while (dir.d_ino != d.st_ino); X } X else do { X if(fread((char *)&dir, sizeof(dir), 1, file) != 1) { X goto fail; X } X if (dir.d_ino == 0) X dd.st_ino = d.st_ino + 1; X else if (stat(dir.d_name, &dd) < 0) X goto fail; X } while(dd.st_ino != d.st_ino || dd.st_dev != d.st_dev); X VOID fclose(file); X X /* concatenate file name */ X i = -1; X while (dir.d_name[++i] != 0); X for(j=off+1; j>0; --j) X name[j+i+1] = name[j]; X off=i+off+1; X name[i+1] = '/'; X for(--i; i>=0; --i) X name[i+1] = dir.d_name[i]; X } /* end for */ X Xfail: VOID fclose(file); X return NULL; X} X X X#endif X X X#ifdef PAIRTEST X/* test program for pairfilenames() and getfullRCSname() */ Xchar * workfilename, *RCSfilename; Xextern int quietflag; X Xmain(argc, argv) Xint argc; char *argv[]; X{ X int result; X int initflag,tostdout; X quietflag=tostdout=initflag=false; X cmdid="pair"; X X while(--argc, ++argv, argc>=1 && ((*argv)[0] == '-')) { X switch ((*argv)[1]) { X X case 'p': tostdout=true; X break; X case 'i': initflag=true; X break; X case 'q': quietflag=true; X break; X default: error("unknown option: %s", *argv); X break; X } X } X X do { X RCSfilename=workfilename=nil; X result=pairfilenames(argc,argv,!initflag,tostdout); X if (result!=0) { X diagnose("RCSfile: %s; working file: %s",RCSfilename,workfilename); X diagnose("Full RCS file name: %s", getfullRCSname()); X } X switch (result) { X case 0: continue; /* already paired file */ X X case 1: if (initflag) { X error("RCS file %s exists already",RCSfilename); X } else { X diagnose("RCS file %s exists",RCSfilename); X } X VOID fclose(finptr); X break; X X case -1:diagnose("RCS file does not exist"); X break; X } X X } while (++argv, --argc>=1); X X} X#endif X@ X X X4.8.2.1 Xlog X@Start of Amiga RCS port branch. X@ Xtext X@d6 1 Xa6 5 X<<<<<<< rcsfnms.c X rcsid[]= "$Id: rcsfnms.c,v 4.8.1.1 89/08/11 01:42:32 rsbx Exp Locker: rsbx $ Purdue CS"; X======= X rcsid[]= "$Id: rcsfnms.c,v 1.2 89/09/17 13:35:38 rick Exp $ Purdue CS"; X>>>>>>> 1.2 Xa44 11 X<<<<<<< rcsfnms.c X * Revision 4.8.1.1 89/08/11 01:42:32 rsbx X * Start of cbmvax RCS source branch. X======= X * Revision 1.2 89/09/17 13:35:38 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<<<<<<< rcsfnms.c Xa45 3 X * checked in with -k by rsbx at 89.08.10.16.20.00. X * X * Revision 4.8 89/05/01 15:09:41 narten Xa53 8 X======= X * Revision 1.3 89/09/16 09:43:16 rick X * Modified AMIGA changes to work with Lattice C X * X * Revision 1.2 88/09/03 15:10:24 rick X * Port to AmigaDos. All done with conditional compiles X * X>>>>>>> 1.2 Xd115 2 Xa116 3 X#ifdef AMIGA X#include "stat.h" X#else Xa119 2 X#endif X#include "rcsbase.h" Xa120 2 Xextern int errno; X Xd201 1 Xa201 9 X{ X if (fptr == NULL) X return; X#ifdef AMIGA X if (ferror(fptr)) X warn("File read or write error %d; file system full?",errno); X fclose(fptr); X#else X if (ferror(fptr) || (fclose(fptr)==EOF)) Xa202 1 X#endif Xa220 3 X#ifdef AMIGA X tp = &semafilename[0]; X#else Xa222 1 X#endif Xa299 1 X<<<<<<< rcsfnms.c Xa301 14 X======= X lastfilename++; X if ((tp=tfnames[lastfilename])==nil) X tp=tfnames[lastfilename] = malloc(NCPPN); X#ifdef AMIGA X *tp = 0; X if (fullpath!=nil) { X if ((lastslash=rindex(fullpath,'/')) == NULL) X lastslash = rindex(fullpath,':'); X if (lastslash != NULL) X while (fullpath<=lastslash) *tp++ = *fullpath++; X } X#else X>>>>>>> 1.2 Xa305 1 X#endif Xa450 1 X#ifndef AMIGA Xa454 1 X#endif Xa516 1 X#ifndef AMIGA Xa521 1 X#endif Xa612 3 X#ifdef AMIGA X return true; X#else Xa618 1 X#endif Xd638 1 Xa638 1 X#ifndef AMIGA Xa648 1 X#endif Xa649 3 X#ifdef AMIGA X#include <libraries/dosextens.h> X#include <exec/memory.h> Xa650 3 Xextern struct Process *FindTask(); Xextern struct FileLock *ParentDir(), *Lock(); Xextern char *AllocMem(); Xa651 51 Xchar *followpath(lock,level) Xstruct FileLock *lock; Xint level; X{ X struct FileInfoBlock *fib; X struct FileLock *newlock; X static char pathbuf[NCPPN]; X X if (! lock) X return(pathbuf); X if (level == 0) X pathbuf[0] = 0; X fib = (struct FileInfoBlock *) AllocMem((long)sizeof(struct FileInfoBlock),MEMF_CLEAR); X if (fib == NULL) { X printf("followpath: Out of Memory\n"); X return(pathbuf); X } X newlock = ParentDir(lock); X followpath(newlock,1); X if (Examine(lock,fib)) { X if (fib->fib_FileName[0] > ' ') X strcat(pathbuf,fib->fib_FileName); X else X strcat(pathbuf,"RAM"); X if (newlock == NULL) X strcat(pathbuf,":"); X else X strcat(pathbuf,"/"); X } X UnLock(lock); X if (fib) X FreeMem(fib,(long) sizeof(struct FileInfoBlock)); X return(pathbuf); X} X Xchar *getwd(name) Xchar *name; X{ X struct FileLock *oldlock; X X oldlock = Lock("",ACCESS_READ); X if (oldlock == NULL) X return(NULL); X strcpy(name,followpath(oldlock,0)); X if (name[strlen(name)-1] == '/') X name[strlen(name)-1] = 0; X return(name); X} X X#else X Xa727 1 X#endif Xa782 33 X} X#endif X X#ifdef AMIGA Xchar *mktemp(template) Xchar *template; X{ X register char *cp; X register unsigned long val; X X cp = template; X cp += strlen(cp); X for (val = (unsigned long) FindTask(0L) ; ; ) X if (*--cp == 'X') { X *cp = val%10 + '0'; X val /= 10; X } else if (*cp != '.') X break; X X if (*++cp != 0) { X *cp = 'A'; X while (access(template, 0) == 0) { X if (*cp == 'Z') { X *template = 0; X break; X } X ++*cp; X } X } else { X if (access(template, 0) == 0) X *template = 0; X } X return template; X@ X X X4.8.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 rcsid[]= "$Id: rcsfnms.c,v 4.8.2.1 89/10/13 19:18:32 rsbx Exp Locker: rsbx $ Purdue CS"; Xd49 1 Xa49 3 X * Revision 4.8.2.1 89/10/13 19:18:32 rsbx X * Start of Amiga RCS port branch. X * Xd52 6 Xd59 1 Xd72 8 Xd276 1 Xa276 1 X *tp++ = ','; *tp = '\0'; /* will be the same length as RCSname*/ Xd344 1 Xd347 4 Xd360 1 Xd499 1 Xa499 1 X *(tp-1)=RCSSEP; *tp++=RCSSUF; *tp='\0'; Xa719 1 X#ifdef RICKS Xa774 10 X#else Xchar *getwd(char *name) X { X if (getcd(0, name) == 0) X { X return name; X } X return NULL; X } X#endif RICKS X@ X X X4.8.2.3 Xlog X@More changes to make Amiga port work. X@ Xtext X@d6 1 Xa6 1 X rcsid[]= "$Id: rcsfnms.c,v 4.8.2.2 89/10/15 15:44:18 rsbx Exp $ Purdue CS"; Xa44 4 X * Revision 4.8.2.2 89/10/15 15:44:18 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 * Xd245 1 Xa245 1 X tp = &semafilename[0]; Xa260 5 X#ifdef DEBUG X fprintf(stderr,"semafilename = %%%s%%\n", semafilename); X fflush(stderr); X#endif X Xd529 1 Xd549 1 Xa549 21 X struct stat pdirstat; X X if (stat(prefdir,&pdirstat)) X { X RCSfilename=sub2filename; X } X else X { X#ifdef AMIGA X if (pdirstat.st_type > 0) X#else X if ((pdirstat.st_mode & S_IFMT) != S_IFREG) X#endif X { X RCSfilename = sub1filename; X } X else X { X RCSfilename = sub2filename; X } X } X@ X X X4.8.2.4 Xlog X@Changed file path handling to deal with Amiga file path sematics. X@ Xtext X@d2 1 Xa2 1 X * RCS file name handling Xd6 1 Xa6 1 X rcsid[]= "$Id: rcsfnms.c,v 4.8.2.3 89/10/15 18:27:52 rsbx Exp $ Purdue CS"; Xd9 4 Xa12 4 X * creation and deletion of semaphorefile, X * creation of temporary filenames and cleanup() X * pairing of RCS file names and working file names. X * Testprogram: define PAIRTEST Xa44 3 X * Revision 4.8.2.3 89/10/15 18:27:52 rsbx X * More changes to make Amiga port work. X * Xd171 1 Xa171 1 X "c", " * ", /* C */ Xd173 5 Xa177 5 X "e", "# ", /* efl */ X "f", "c ", /* fortran */ X "h", " * ", /* C-header */ X "l", " * ", /* lex NOTE: conflict between lex and franzlisp*/ X "mac", "; ", /* macro vms or dec-20 or pdp-11 macro */ Xd181 1 Xa181 1 X "p", " * ", /* pascal */ Xd183 2 Xa184 2 X "r", "# ", /* ratfor */ X "red", "% ", /* psl/rlisp */ Xd187 1 Xa187 1 X "s", "! ", /* assembler */ Xd190 1 Xa190 1 X "s", "| ", /* assembler */ Xd193 1 Xa193 1 X "s", "/ ", /* assembler */ Xd196 1 Xa196 1 X "s", "# ", /* assembler */ Xa197 4 X#ifdef AMIGA X "asm", "* ", /* assembler */ X "i", "* ", /* assembler include */ X#endif Xd199 6 Xa204 6 X "sh", "# ", /* shell */ X "sl", "% ", /* psl */ X "red", "% ", /* psl/rlisp */ X "cl", ";;; ", /* common lisp */ X "ml", "; ", /* mocklisp */ X "el", "; ", /* gnulisp */ Xd206 5 Xa210 5 X "y", " * ", /* yacc */ X "ye", " * ", /* yacc-efl */ X "yr", " * ", /* yacc-ratfor */ X "", "# ", /* default for empty suffix */ X nil, "" /* default for unknown suffix; must always be last */ Xd227 2 Xa228 2 X if (ferror(fptr) || (fclose(fptr)==EOF)) X faterror("File read or write error; file system full?"); Xd242 2 Xa243 2 X register char * tp, *sp, *lp; X int fdesc; Xd245 3 Xa247 1 X sp=RCSname; Xa248 17 X if (lp = index(sp,':')) /* volume: ? */ X { X if (tp = rindex(lp,'/')) /* volume:path/ ? */ X { X lp = tp; X } X } X else X { X lp = rindex(sp,'/'); X } X#else X lp = rindex(sp,'/'); X#endif X X if (lp==0) { X#ifdef AMIGA Xd251 2 Xa252 2 X semafilename[0]='.'; semafilename[1]='/'; X tp= &semafilename[2]; Xd254 10 Xa263 10 X } else { X /* copy path */ X tp=semafilename; X do *tp++ = *sp++; while (sp<=lp); X } X /*now insert `,' and append file name */ X *tp++ = ','; X lp = rindex(sp, RCSSEP); X while (sp<lp) *tp++ = *sp++; X *tp++ = ','; *tp = '\0'; /* will be the same length as RCSname*/ Xd270 14 Xa283 14 X madesema = false; X if (access(semafilename, 0) == 0) { X error("RCS file %s is in use",RCSname); X return false; X } X if (makesema) { X if ((fdesc=creat(semafilename, 000)) == -1) { X error("Can't create semaphore file for RCS file %s",RCSname); X return false; X } X VOID close(fdesc); X madesema=true; X } X return true; Xd292 7 Xa298 7 X if (madesema) { X madesema=false; X if (unlink(semafilename) == -1) { X error("Can't find semaphore file %s",semafilename); X } X } X} Xd312 1 Xa312 1 X register int i; Xd314 7 Xa320 7 X if (finptr!=NULL) VOID fclose(finptr); X if (frewrite!=NULL) VOID fclose(frewrite); X for (i=0; i<freefilename; i++) { X if (tfnames[i][0]!='\0') VOID unlink(tfnames[i]); X } X InitCleanup(); X rmsema(); Xd335 3 Xa337 3 X register char * lastslash, *tp; X if ((tp=tfnames[freefilename])==nil) X tp=tfnames[freefilename] = talloc(NCPPN); Xd344 2 Xa345 2 X while (fullpath<=lastslash) *tp++ = *fullpath++; X } Xd347 4 Xa350 4 X if (fullpath!=nil && (lastslash=rindex(fullpath,'/'))!=0) { X /* copy path */ X while (fullpath<=lastslash) *tp++ = *fullpath++; X } Xd352 2 Xa353 2 X while (*tp++ = *filename++); X return (mktemp(tfnames[freefilename++])); Xd366 5 Xa370 5 X r = sp; X while (*sp) { X if (*sp++ == c) r=sp; X } X return r; Xa375 7 X#ifdef AMIGA Xchar * fnamepart(char *sp) X/* X * Function: Finds the filename part of a path. X */ X { X char *p1; Xa376 23 X if (p1 = bindex(sp,':')) /* volume: ? */ X { X return bindex(p1, '/'); X } X else X { X return bindex(sp,'/'); X } X X } X#else Xchar * fnamepart(char *sp) X/* X * Function: Finds the filename part of a path. X */ X { X return bindex(sp, '/'); X } X#endif X X X X Xd380 1 Xa380 1 X register int i; Xd382 2 Xa383 2 X Head=Dbranch=nil; AccessList=nil; Symbols=nil; Locks=nil; X StrictLocks=STRICT_LOCKING; Xd385 14 Xa398 14 X /* guess the comment leader from the suffix*/ X Suffix=bindex(workfilename, '.'); X if (Suffix==workfilename) Suffix= ""; /* empty suffix; will get default*/ X for (i=0;;i++) { X if (comtable[i].suffix==nil) { X Comment=comtable[i].comlead; /*default*/ X break; X } elsif (strcmp(Suffix,comtable[i].suffix)==0) { X Comment=comtable[i].comlead; /*default*/ X break; X } X } X Lexinit(); /* Note: if finptr==NULL, reads nothing; only initializes*/ X} Xd410 2 Xa411 2 X register char * * next, * match; X register int count; Xd413 10 Xa422 10 X for (next = argv, count = argc; count>0; next++,count--) { X if ((*next != nil) && strcmp(fnamepart(*next),fname)==0) { X /* fnamepart finds the beginning of the file name stem */ X match= *next; X *next=nil; X return match; X } X } X return fname; X} Xd450 4 Xa453 4 X register char * sp, * tp; X char * lastsep, * purefname, * pureRCSname; X int opened, returncode; X char * RCS1; Xd456 1 Xa456 1 X if (*argv == nil) return 0; /* already paired filename */ Xd462 1 Xa462 1 X InitCleanup(); Xd464 38 Xa501 38 X /* first check suffix to see whether it is an RCS file or not */ X purefname=fnamepart(*argv); /* skip path */ X lastsep=rindex(purefname, RCSSEP); X if (lastsep!= 0 && *(lastsep+1)==RCSSUF && *(lastsep+2)=='\0') { X /* RCS file name given*/ X RCS1=(*argv); pureRCSname=purefname; X /* derive workfilename*/ X sp = purefname; tp=tempfilename; X while (sp<lastsep) *tp++ = *sp++; *tp='\0'; X /* try to find workfile name among arguments */ X workfilename=findpairfile(argc-1,argv+1,tempfilename); X if (strlen(pureRCSname)>NCPFN) { X error("RCS file name %s too long",RCS1); X return 0; X } X } else { X /* working file given; now try to find RCS file */ X workfilename= *argv; X /* derive RCS file name*/ X sp=purefname; tp=tempfilename; X while (*tp++ = *sp++); X *(tp-1)=RCSSEP; *tp++=RCSSUF; *tp='\0'; X /* Try to find RCS file name among arguments*/ X RCS1=findpairfile(argc-1,argv+1,tempfilename); X pureRCSname=fnamepart(RCS1); X if (strlen(pureRCSname)>NCPFN) { X error("working file name %s too long",workfilename); X return 0; X } X } X /* now we have a (tentative) RCS filename in RCS1 and workfilename */ X /* First, get status of workfilename */ X haveworkstat=stat(workfilename, &workstat); X#ifdef TODO X if ((haveworkstat==0) && ((workstat.st_mode & S_IFDIR) == S_IFDIR)) { X diagnose("Directory %s ignored",workfilename); X return 0; X } Xd503 20 Xa522 20 X /* Second, try to find the right RCS file */ X if (pureRCSname!=RCS1) { X /* a path for RCSfile is given; single RCS file to look for */ X finptr=fopen(RCSfilename=RCS1, "r"); X if (finptr!=NULL) { X returncode=1; X } else { /* could not open */ X if (access(RCSfilename,0)==0) { X error("Can't open existing %s", RCSfilename); X return 0; X } X if (mustread) { X error("Can't find %s", RCSfilename); X return 0; X } else { X /* initialize if not mustread */ X returncode = -1; X } X } X } else { Xd538 1 Xa538 1 X opened=( Xd542 5 Xa546 5 X if (opened) { X /* open succeeded */ X returncode=1; X } else { X /* open failed; may be read protected */ Xd549 4 Xa552 4 X error("Can't open existing %s",RCSfilename); X return 0; X } X if (mustread) { Xd554 3 Xa556 3 X return 0; X } else { X /* initialize new file. Put into ./RCS if possible, strip off suffix*/ Xd559 2 Xa560 1 X if (stat(prefdir,&pdirstat)) { Xd562 3 Xa564 1 X } else { Xd566 1 Xa566 1 X if (pdirstat.st_type > 0) { Xd568 1 Xa568 1 X if ((pdirstat.st_mode & S_IFMT) != S_IFREG) { Xd570 1 Xd572 3 Xa574 1 X } else { Xd576 1 Xd578 4 Xa581 5 X } X returncode= -1; X } X } X } Xd583 7 Xa589 7 X if (returncode == 1) { /* RCS file open */ X#ifdef TODO X haveRCSstat=fstat(fileno(finptr),&RCSstat); X if ((haveRCSstat== 0) && ((RCSstat.st_mode & S_IFDIR) == S_IFDIR)) { X diagnose("Directory %s ignored",RCSfilename); X return 0; X } Xd591 5 Xa595 5 X Lexinit(); getadmin(); X } else { /* returncode == -1; RCS file nonexisting */ X haveRCSstat = -1; X InitAdmin(); X }; Xd597 5 Xa601 5 X if (tostdout&& X !(RCS1==tempfilename||workfilename==tempfilename)) X /*The last term determines whether a pair of */ X /* file names was given in the argument list */ X warn("Option -p is set; ignoring output file %s",workfilename); Xd603 1 Xa603 1 X return returncode; Xd613 2 Xa614 2 X static char namebuf[NCPPN]; X static int pathlength; Xd616 2 Xa617 2 X register char * realname, * lastpathchar; X register int dotdotcounter, realpathlength; Xd619 49 Xa667 49 X if (*RCSfilename=='/') { X return(RCSfilename); X } else { X if (pathlength==0) { /*call curdir for the first time*/ X if (getwd(pathbuf)==NULL) X faterror("Can't build current directory path"); X pathlength=strlen(pathbuf); X if (!((pathlength==1) && (pathbuf[0]=='/'))) { X pathbuf[pathlength++]='/'; X /* Check needed because some getwd implementations */ X /* generate "/" for the root. */ X } X } X /*the following must be redone since RCSfilename may change*/ X /* find how many ../ to remvove from RCSfilename */ X dotdotcounter =0; X realname = RCSfilename; X while( realname[0]=='.' && X (realname[1]=='/'||(realname[1]=='.'&&realname[2]=='/'))){ X if (realname[1]=='/') { X /* drop leading ./ */ X realname += 2; X } else { X /* drop leading ../ and remember */ X dotdotcounter++; X realname += 3; X } X } X /* now remove dotdotcounter trailing directories from pathbuf*/ X lastpathchar=pathbuf + pathlength-1; X while (dotdotcounter>0 && lastpathchar>pathbuf) { X /* move pointer backwards over trailing directory */ X lastpathchar--; X if (*lastpathchar=='/') { X dotdotcounter--; X } X } X if (dotdotcounter>0) { X error("Can't generate full path name for RCS file"); X return RCSfilename; X } else { X /* build full path name */ X realpathlength=lastpathchar-pathbuf+1; X VOID strncpy(namebuf,pathbuf,realpathlength); X VOID strcpy(&namebuf[realpathlength],realname); X return(namebuf); X } X } X} Xd677 5 Xa681 5 X char pathname[NCPPN]; X register char * tp, *sp, *lp; X lp = rindex(filename,'/'); X if (lp==0) { X /* check current directory */ Xd683 1 Xa683 1 X return true; Xd685 6 Xa690 6 X if (access(".",2)==0) X return true; X else { X error("Current directory not writable"); X return false; X } Xd692 12 Xa703 12 X } X /* copy path */ X sp=filename; X tp=pathname; X do *tp++ = *sp++; while (sp<=lp); X *tp='\0'; X if (access(pathname,2)==0) X return true; X else { X error("Directory %s not writable", pathname); X return false; X } Xd718 3 Xa720 3 X /* no harm done if file "to" does not exist */ X if (link(from,to)<0) return -1; X return(unlink(from)); Xd807 4 Xa810 4 X FILE *file; X struct stat d, dd; X char buf[2]; /* to NUL-terminate dir.d_name */ X struct direct dir; Xd812 3 Xa814 3 X int rdev, rino; X int off; X register i,j; Xd816 38 Xa853 38 X name[off= 0] = '/'; X name[1] = '\0'; X buf[0] = '\0'; X if (stat("/", &d)<0) return NULL; X rdev = d.st_dev; X rino = d.st_ino; X for (;;) { X if (stat(dot, &d)<0) return NULL; X if (d.st_ino==rino && d.st_dev==rdev) { X if (name[off] == '/') name[off] = '\0'; X chdir(name); /*change back to current directory*/ X return name; X } X if ((file = fopen(dotdot,"r")) == NULL) return NULL; X if (fstat(fileno(file), &dd)<0) goto fail; X chdir(dotdot); X if(d.st_dev == dd.st_dev) { X if(d.st_ino == dd.st_ino) { X if (name[off] == '/') name[off] = '\0'; X chdir(name); /*change back to current directory*/ X VOID fclose(file); X return name; X } X do { X if (fread((char *)&dir, sizeof(dir), 1, file) !=1) X goto fail; X } while (dir.d_ino != d.st_ino); X } X else do { X if(fread((char *)&dir, sizeof(dir), 1, file) != 1) { X goto fail; X } X if (dir.d_ino == 0) X dd.st_ino = d.st_ino + 1; X else if (stat(dir.d_name, &dd) < 0) X goto fail; X } while(dd.st_ino != d.st_ino || dd.st_dev != d.st_dev); X VOID fclose(file); Xd855 10 Xa864 10 X /* concatenate file name */ X i = -1; X while (dir.d_name[++i] != 0); X for(j=off+1; j>0; --j) X name[j+i+1] = name[j]; X off=i+off+1; X name[i+1] = '/'; X for(--i; i>=0; --i) X name[i+1] = dir.d_name[i]; X } /* end for */ Xd867 1 Xa867 1 X return NULL; Xd883 4 Xa886 4 X int result; X int initflag,tostdout; X quietflag=tostdout=initflag=false; X cmdid="pair"; Xd888 2 Xa889 2 X while(--argc, ++argv, argc>=1 && ((*argv)[0] == '-')) { X switch ((*argv)[1]) { Xd891 10 Xa900 10 X case 'p': tostdout=true; X break; X case 'i': initflag=true; X break; X case 'q': quietflag=true; X break; X default: error("unknown option: %s", *argv); X break; X } X } Xd902 9 Xa910 9 X do { X RCSfilename=workfilename=nil; X result=pairfilenames(argc,argv,!initflag,tostdout); X if (result!=0) { X diagnose("RCSfile: %s; working file: %s",RCSfilename,workfilename); X diagnose("Full RCS file name: %s", getfullRCSname()); X } X switch (result) { X case 0: continue; /* already paired file */ Xd912 7 Xa918 7 X case 1: if (initflag) { X error("RCS file %s exists already",RCSfilename); X } else { X diagnose("RCS file %s exists",RCSfilename); X } X VOID fclose(finptr); X break; Xd920 3 Xa922 3 X case -1:diagnose("RCS file does not exist"); X break; X } Xd924 1 Xa924 1 X } while (++argv, --argc>=1); X@ X X X4.8.2.5 Xlog X@Removed some debugging code. X@ Xtext X@d6 1 Xa6 1 X rcsid[]= "$Id: rcsfnms.c,v 4.8.2.4 89/10/16 19:07:19 rsbx Exp $ Purdue CS"; Xa44 3 X * Revision 4.8.2.4 89/10/16 19:07:19 rsbx X * Changed file path handling to deal with Amiga file path sematics. X * Xd286 5 X@ X X X4.8.2.6 Xlog X@Fix to fnamepart(). X@ Xtext X@d6 1 Xa6 1 X rcsid[]= "$Id: rcsfnms.c,v 4.8.2.5 89/10/16 23:54:04 rsbx Exp $ Purdue CS"; Xa44 3 X * Revision 4.8.2.5 89/10/16 23:54:04 rsbx X * Removed some debugging code. X * Xd404 1 Xa404 1 X if (p1 = strchr(sp,':')) /* volume: ? */ Xa405 1 X p1++; X@ X X X4.8.2.7 Xlog X@getfullRCSname() fixed up. X@ Xtext X@a152 3 X#ifdef AMIGA Xchar * getfullRCSname(); X#endif Xa654 1 X#ifndef AMIGA Xa715 1 X#endif Xd770 71 X@ X X X4.8.2.8 Xlog X@mktemp() changed to use hex digits instead of decimal digits in temp Xfile name. X@ Xtext X@d6 1 Xa6 1 X rcsid[]= "$Id: rcsfnms.c,v 4.8.2.7 89/10/17 18:38:55 rsbx Exp $ Purdue CS"; Xa44 3 X * Revision 4.8.2.7 89/10/17 18:38:55 rsbx X * getfullRCSname() fixed up. X * Xd912 5 Xa916 1 Xstatic char *hex = "0123456789abcdef"; Xa917 5 Xchar *mktemp(char *template) X { X char *cp; X unsigned long val; X Xa920 1 X { Xd922 3 Xa924 7 X *cp = hex[val%16]; X val /= 16; X } X else X { X if (*cp != '.') X { Xa925 2 X } X } Xd927 1 Xa927 2 X if (*++cp != 0) X { Xd929 2 Xa930 4 X while (access(template, 0) == 0) X { X if (*cp == 'Z') X { Xd933 1 Xa933 1 X } Xa934 1 X } Xd936 1 Xa936 2 X else X { Xa937 1 X { Xd939 1 Xa939 2 X } X } Xd941 1 Xa941 1 X } X@ X X X4.8.2.9 Xlog X@Previous changes to mktemp() had syntax errors. X@ Xtext X@d6 1 Xa6 1 X rcsid[]= "$Id: rcsfnms.c,v 4.8.2.8 89/10/30 13:44:29 rsbx Exp $ Purdue CS"; Xa44 4 X * Revision 4.8.2.8 89/10/30 13:44:29 rsbx X * mktemp() changed to use hex digits instead of decimal digits in temp X * file name. X * Xd926 1 Xa926 2 X if (*--cp == 'X') X { Xd929 4 Xa932 2 X } X else Xd934 1 Xa934 4 X if (*cp != '.') X { X break; X } X@ X X X4.8.2.10 Xlog X@Changes to make the delete bit to track the write bit. Made protection Xbit manipulation less insane. X@ Xtext X@d6 1 Xa6 1 X rcsid[]= "$Id: rcsfnms.c,v 4.8.2.9 89/10/30 13:53:10 rsbx Exp $ Purdue CS"; Xa44 3 X * Revision 4.8.2.9 89/10/30 13:53:10 rsbx X * Previous changes to mktemp() had syntax errors. X * Xa641 1 X haveRCSstat=stat(RCSfilename,&RCSstat); Xd643 1 X@ X X X4.8.2.11 Xlog X@Added support for RCS_link files to be used as a poor O/S's symbolic link. X@ Xtext X@d6 1 Xa6 1 X rcsid[]= "$Id: rcsfnms.c,v 4.8.2.10 89/11/01 14:43:14 rsbx Exp $ Purdue CS"; Xa44 4 X * Revision 4.8.2.10 89/11/01 14:43:14 rsbx X * Changes to make the delete bit to track the write bit. Made protection X * bit manipulation less insane. X * Xa176 3 X#ifdef LINK Xchar sub3filename [NCPPN]; /* used for files path/RCS/file.sfx,v */ X#endif /* LINK */ Xa521 3 X#ifdef LINK X char prefdir2[NCPPN]; X#endif /* LINK */ Xa592 13 X#ifdef LINK X FILE *symbolic_link_file = NULL; X sub3filename[0]='\0'; X if ( access( "RCS_link", 0 ) == 0 ) X symbolic_link_file = fopen( "RCS_link", "r" ); X if ( symbolic_link_file ){ X int sl; X fgets( sub3filename, NCPPN, symbolic_link_file ); X fclose( symbolic_link_file ); X sl = strlen(sub3filename); X sub3filename[sl?sl-1:0] = '\0'; X } X#endif /* LINK */ Xa601 5 X#ifdef LINK X prefdir2[0] = '\0'; X if ( sub3filename[0] ) X VOID strcpy(prefdir2,sub3filename); /* preferred directory for RCS file*/ X#endif /* LINK */ Xd603 1 Xa603 5 X VOID strcat(sub1filename,RCS1); X VOID strcat(sub2filename,RCS1); X#ifdef LINK X VOID strcat(sub3filename,RCS1); X#endif /* LINK */ Xa604 1 X Xd607 1 Xa607 6 X#ifdef LINK X ((finptr=fopen(RCSfilename=sub2filename, "r"))!=NULL) || X (sub3filename[0] && ((finptr=fopen(RCSfilename=sub3filename, "r"))!=NULL))); X#else X ((finptr=fopen(RCSfilename=sub2filename, "r"))!=NULL) ); X#endif /* LINK */ Xa614 4 X#ifdef LINK X (access(RCSfilename=sub2filename,0)==0) || X (sub3filename[0] && (access(RCSfilename=sub3filename,0)==0))){ X#else Xa615 1 X#endif /* LINK */ Xa619 6 X#ifdef LINK X if ( sub3filename[0] ) X error("Can't find %s, %s nor %s",sub1filename,sub2filename,sub3filename); X else X error("Can't find %s nor %s",sub1filename,sub2filename); X#else Xa620 1 X#endif /* LINK */ Xa625 19 X#ifdef LINK X#ifdef AMIGA X if (!stat(prefdir, &pdirstat) && (pdirstat.st_type > 0)) { X#else X if (!stat(prefdir, &pdirstat) && ((pdirstat.st_mode & S_IFMT) != S_IFREG)) { X#endif X RCSfilename = sub1filename; X } else { X#ifdef AMIGA X if (!stat(prefdir2, &pdirstat) && (pdirstat.st_type > 0)) { X#else X if (!stat(prefdir2, &pdirstat) && ((pdirstat.st_mode & S_IFMT) != S_IFREG)) { X#endif X RCSfilename = sub3filename; X } else { X RCSfilename = sub2filename; X } X } X#else Xa638 1 X#endif /* LINK */ X@ X X X4.8.1.1 Xlog X@Start of cbmvax RCS source branch. X@ Xtext X@a45 3 X * checked in with -k by rsbx at 89.08.10.16.20.00. X * X * Revision 4.8 89/05/01 15:09:41 narten X@ SHAR_EOF echo "End of archive 9 (of 14)" # if you want to concatenate archives, remove anything after this line exit