head 5.8; branch 5.8.2; access; symbols HWGRCSP11F:5.8.2.15 HWGRCSP10F:5.8.2.15 HWGRCSP9:5.8.2.15 HWGRCSP8F:5.8.2.14 HWGRCSP7F:5.8.2.9 HWGRCSP6F:5.8.2.5 HWGRCSP5F:5.8.2.2 HWGRCSp3:5.8.2.1 HWGRCSp4:5.8.2.2 HWGRCS_Fish:5.8.1 HWGRCS:5.8.1; locks; strict; comment @ * @; 5.8 date 91.09.24.00.28.40; author eggert; state Exp; branches 5.8.1.1 5.8.2.1; next ; 5.8.1.1 date 93.01.18.14.38.26; author heinz; state Exp; branches; next 5.8.1.2; 5.8.1.2 date 93.01.18.18.15.39; author heinz; state Exp; branches; next 5.8.1.3; 5.8.1.3 date 93.04.13.19.51.54; author heinz; state Exp; branches; next ; 5.8.2.1 date 93.04.14.19.11.32; author heinz; state Exp; branches; next 5.8.2.2; 5.8.2.2 date 93.06.13.09.36.39; author heinz; state Exp; branches; next 5.8.2.3; 5.8.2.3 date 93.12.04.11.07.25; author heinz; state Exp; branches; next 5.8.2.4; 5.8.2.4 date 93.12.18.16.12.22; author heinz; state Exp; branches; next 5.8.2.5; 5.8.2.5 date 93.12.18.16.20.08; author heinz; state Exp; branches; next 5.8.2.6; 5.8.2.6 date 94.01.07.22.26.37; author heinz; state Exp; branches; next 5.8.2.7; 5.8.2.7 date 94.01.19.17.07.59; author heinz; state Exp; branches; next 5.8.2.8; 5.8.2.8 date 94.01.19.17.31.19; author heinz; state Exp; branches; next 5.8.2.9; 5.8.2.9 date 94.01.22.12.42.08; author heinz; state Exp; branches; next 5.8.2.10; 5.8.2.10 date 94.02.10.17.25.54; author heinz; state Exp; branches; next 5.8.2.11; 5.8.2.11 date 94.02.11.19.51.33; author heinz; state Exp; branches; next 5.8.2.12; 5.8.2.12 date 94.02.12.19.20.21; author heinz; state Exp; branches; next 5.8.2.13; 5.8.2.13 date 94.03.14.09.21.04; author heinz; state Exp; branches; next 5.8.2.14; 5.8.2.14 date 94.03.14.10.20.14; author heinz; state Exp; branches; next 5.8.2.15; 5.8.2.15 date 94.03.31.16.48.30; author heinz; state Exp; branches; next ; desc @Checked in with -k 16.jan.93 HWG @ 5.8 log @checked in with -k by heinz at 1993/01/17 01:53:17 @ text @/* * RCS file name handling */ /**************************************************************************** * creation and deletion of /tmp temporaries * pairing of RCS file names and working file names. * Testprogram: define PAIRTEST **************************************************************************** */ /* Copyright (C) 1982, 1988, 1989 Walter Tichy Copyright 1990, 1991 by Paul Eggert Distributed under license by the Free Software Foundation, Inc. This file is part of RCS. RCS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. RCS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with RCS; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. Report problems and direct all questions to: rcs-bugs@@cs.purdue.edu */ /* $Log: rcsfnms.c,v $ * Revision 5.8 1991/09/24 00:28:40 eggert * Don't export bindex(). * * Revision 5.7 1991/08/19 03:13:55 eggert * Fix messages when rcswriteopen fails. * Look in $TMP and $TEMP if $TMPDIR isn't set. Tune. * * Revision 5.6 1991/04/21 11:58:23 eggert * Fix errno bugs. Add -x, RCSINIT, MS-DOS support. * * Revision 5.5 1991/02/26 17:48:38 eggert * Fix setuid bug. Support new link behavior. * Define more portable getcwd(). * * Revision 5.4 1990/11/01 05:03:43 eggert * Permit arbitrary data in comment leaders. * * Revision 5.3 1990/09/14 22:56:16 hammer * added more filename extensions and their comment leaders * * Revision 5.2 1990/09/04 08:02:23 eggert * Fix typo when !RCSSEP. * * Revision 5.1 1990/08/29 07:13:59 eggert * Work around buggy compilers with defective argument promotion. * * Revision 5.0 1990/08/22 08:12:50 eggert * Ignore signals when manipulating the semaphore file. * Modernize list of file name extensions. * Permit paths of arbitrary length. Beware file names beginning with "-". * Remove compile-time limits; use malloc instead. * Permit dates past 1999/12/31. Make lock and temp files faster and safer. * Ansify and Posixate. * Don't use access(). Fix test for non-regular files. Tune. * * Revision 4.8 89/05/01 15:09:41 narten * changed getwd to not stat empty directories. * * Revision 4.7 88/08/09 19:12:53 eggert * Fix troff macro comment leader bug; add Prolog; allow cc -R; remove lint. * * 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 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; freefilename 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" libId(fnmsId, "$Id: rcsfnms.c,v 5.8 1991/09/24 00:28:40 eggert Exp $") char const *RCSfilename; char *workfilename; FILE *workstdout; struct stat RCSstat; char const *suffixes; static char const rcsdir[] = "RCS"; #define rcsdirlen (sizeof(rcsdir)-1) static struct buf RCSbuf, RCSb; static int RCSerrno; /* Temp file names to be unlinked when done, if they are not nil. */ #define TEMPNAMES 5 /* must be at least DIRTEMPNAMES (see rcsedit.c) */ static char *volatile tfnames[TEMPNAMES]; struct compair { char const *suffix, *comlead; }; static struct compair const 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. */ "a", "-- ", /* Ada */ "ada", "-- ", "asm", ";; ", /* assembler (MS-DOS) */ "bat", ":: ", /* batch (MS-DOS) */ "c", " * ", /* C */ "c++", "// ", /* C++ in all its infinite guises */ "cc", "// ", "cpp", "// ", "cxx", "// ", "cl", ";;; ", /* Common Lisp */ "cmd", ":: ", /* command (OS/2) */ "cmf", "c ", /* CM Fortran */ "cs", " * ", /* C* */ "el", "; ", /* Emacs Lisp */ "f", "c ", /* Fortran */ "for", "c ", "h", " * ", /* C-header */ "hpp", "// ", /* C++ header */ "hxx", "// ", "l", " * ", /* lex NOTE: conflict between lex and franzlisp */ "lisp",";;; ", /* Lucid Lisp */ "lsp", ";; ", /* Microsoft Lisp */ "mac", ";; ", /* macro (DEC-10, MS-DOS, PDP-11, VMS, etc) */ "me", ".\\\" ",/* me-macros t/nroff*/ "ml", "; ", /* mocklisp */ "mm", ".\\\" ",/* mm-macros t/nroff*/ "ms", ".\\\" ",/* ms-macros t/nroff*/ "p", " * ", /* Pascal */ "pas", " * ", "pl", "% ", /* Prolog */ "tex", "% ", /* TeX */ "y", " * ", /* yacc */ nil, "# " /* default for unknown suffix; must always be last */ }; #if has_mktemp static char const * tmp() /* Yield the name of the tmp directory. */ { static char const *s; if (!s && !(s = cgetenv("TMPDIR")) /* Unix tradition */ && !(s = cgetenv("TMP")) /* DOS tradition */ && !(s = cgetenv("TEMP")) /* another DOS tradition */ ) s = TMPDIR; return s; } #endif char const * maketemp(n) int n; /* Create a unique filename using n and the process id and store it * into the nth slot in tfnames. * Because of storage in tfnames, tempunlink() can unlink the file later. * Returns a pointer to the filename created. */ { char *p; char const *t = tfnames[n]; if (t) return t; catchints(); { # if has_mktemp char const *tp = tmp(); p = testalloc(strlen(tp) + 10); VOID sprintf(p, "%s%cT%cXXXXXX", tp, SLASH, '0'+n); if (!mktemp(p) || !*p) faterror("can't make temporary file name `%s%cT%cXXXXXX'", tp, SLASH, '0'+n ); # else static char tfnamebuf[TEMPNAMES][L_tmpnam]; p = tfnamebuf[n]; if (!tmpnam(p) || !*p) # ifdef P_tmpdir faterror("can't make temporary file name `%s...'",P_tmpdir); # else faterror("can't make temporary file name"); # endif # endif } tfnames[n] = p; return p; } void tempunlink() /* Clean up maketemp() files. May be invoked by signal handler. */ { register int i; register char *p; for (i = TEMPNAMES; 0 <= --i; ) if ((p = tfnames[i])) { VOID unlink(p); /* * We would tfree(p) here, * but this might dump core if we're handing a signal. * We're about to exit anyway, so we won't bother. */ tfnames[i] = 0; } } static char const * bindex(sp,ch) register char const *sp; int ch; /* Function: Finds the last occurrence of character c in string sp * and returns a pointer to the character just beyond it. If the * character doesn't occur in the string, sp is returned. */ { register char const c=ch, *r; r = sp; while (*sp) { if (*sp++ == c) r=sp; } return r; } static int suffix_matches(suffix, pattern) register char const *suffix, *pattern; { register int c; if (!pattern) return true; for (;;) switch (*suffix++ - (c = *pattern++)) { case 0: if (!c) return true; break; case 'A'-'a': if (ctab[c] == Letter) break; /* fall into */ default: return false; } } static void InitAdmin() /* function: initializes an admin node */ { register char const *Suffix; register int i; Head=nil; Dbranch=nil; AccessList=nil; Symbols=nil; Locks=nil; StrictLocks=STRICT_LOCKING; /* guess the comment leader from the suffix*/ Suffix=bindex(workfilename, '.'); if (Suffix==workfilename) Suffix= ""; /* empty suffix; will get default*/ for (i=0; !suffix_matches(Suffix,comtable[i].suffix); i++) ; Comment.string = comtable[i].comlead; Comment.size = strlen(comtable[i].comlead); Lexinit(); /* note: if !finptr, reads nothing; only initializes */ } #if defined(_POSIX_NO_TRUNC) && _POSIX_NO_TRUNC!=-1 # define LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED 0 #else # define LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED 1 #endif #if LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED #ifdef NAME_MAX # define filenametoolong(path) (NAME_MAX < strlen(basename(path))) #else static int filenametoolong(path) char *path; /* Yield true if the last file name in PATH is too long. */ { static unsigned long dot_namemax; register size_t namelen; register char *base; register unsigned long namemax; base = path + dirlen(path); namelen = strlen(base); if (namelen <= _POSIX_NAME_MAX) /* fast check for shorties */ return false; if (base != path) { *--base = 0; namemax = pathconf(path, _PC_NAME_MAX); *base = SLASH; } else { /* Cache the results for the working directory, for speed. */ if (!dot_namemax) dot_namemax = pathconf(".", _PC_NAME_MAX); namemax = dot_namemax; } /* If pathconf() yielded -1, namemax is now ULONG_MAX. */ return namemaxsize < size) { if (b->size) tfree(b->string); else b->size = sizeof(malloc_type); while (b->size < size) b->size <<= 1; b->string = tnalloc(char, b->size); } } void bufrealloc(b, size) register struct buf *b; size_t size; /* like bufalloc, except *B's old contents, if any, are preserved */ { if (b->size < size) { if (!b->size) bufalloc(b, size); else { while ((b->size <<= 1) < size) ; b->string = trealloc(char, b->string, b->size); } } } void bufautoend(b) struct buf *b; /* Free an auto buffer at block exit. */ { if (b->size) tfree(b->string); } struct cbuf bufremember(b, s) struct buf *b; size_t s; /* * Free the buffer B with used size S. * Yield a cbuf with identical contents. * The cbuf will be reclaimed when this input file is finished. */ { struct cbuf cb; if ((cb.size = s)) cb.string = fremember(trealloc(char, b->string, s)); else { bufautoend(b); /* not really auto */ cb.string = ""; } return cb; } char * bufenlarge(b, alim) register struct buf *b; char const **alim; /* Make *B larger. Set *ALIM to its new limit, and yield the relocated value * of its old limit. */ { size_t s = b->size; bufrealloc(b, s + 1); *alim = b->string + b->size; return b->string + s; } void bufscat(b, s) struct buf *b; char const *s; /* Concatenate S to B's end. */ { size_t blen = b->string ? strlen(b->string) : 0; bufrealloc(b, blen+strlen(s)+1); VOID strcpy(b->string+blen, s); } void bufscpy(b, s) struct buf *b; char const *s; /* Copy S into B. */ { bufalloc(b, strlen(s)+1); VOID strcpy(b->string, s); } char const * basename(p) char const *p; /* Yield the address of the base filename of the pathname P. */ { register char const *b = p, *q = p; for (;;) switch (*q++) { case SLASHes: b = q; break; case 0: return b; } } size_t dirlen(p) char const *p; /* Yield the length of P's directory, including its trailing SLASH. */ { return basename(p) - p; } static size_t suffixlen(x) char const *x; /* Yield the length of X, an RCS filename suffix. */ { register char const *p; p = x; for (;;) switch (*p) { case 0: case SLASHes: return p - x; default: ++p; continue; } } char const * rcssuffix(name) char const *name; /* Yield the suffix of NAME if it is an RCS filename, 0 otherwise. */ { char const *x, *p, *nz; size_t dl, nl, xl; nl = strlen(name); nz = name + nl; x = suffixes; do { if ((xl = suffixlen(x))) { if (xl <= nl && memcmp(p = nz-xl, x, xl) == 0) return p; } else { dl = dirlen(name); if ( rcsdirlen < dl && !memcmp(p = name+(dl-=rcsdirlen+1), rcsdir, rcsdirlen) && (!dl || isSLASH(*--p)) ) return nz; } x += xl; } while (*x++); return 0; } /*ARGSUSED*/ RILE * rcsreadopen(RCSname, status, mustread) struct buf *RCSname; struct stat *status; int mustread; /* Open RCSNAME for reading and yield its FILE* descriptor. * If successful, set *STATUS to its status. * Pass this routine to pairfilenames() for read-only access to the file. */ { return Iopen(RCSname->string, FOPEN_R, status); } static int finopen(rcsopen, mustread) RILE *(*rcsopen)P((struct buf*,struct stat*,int)); int mustread; /* * Use RCSOPEN to open an RCS file; MUSTREAD is set if the file must be read. * Set finptr to the result and yield true if successful. * RCSb holds the file's name. * Set RCSbuf to the best RCS name found so far, and RCSerrno to its errno. * Yield true if successful or if an unusual failure. */ { int interesting, preferold; /* * We prefer an old name to that of a nonexisting new RCS file, * unless we tried locking the old name and failed. */ preferold = RCSbuf.string[0] && (mustread||frewrite); finptr = (*rcsopen)(&RCSb, &RCSstat, mustread); interesting = finptr || errno!=ENOENT; if (interesting || !preferold) { /* Use the new name. */ RCSerrno = errno; bufscpy(&RCSbuf, RCSb.string); } return interesting; } static int fin2open(d, dlen, base, baselen, x, xlen, rcsopen, mustread) char const *d, *base, *x; size_t dlen, baselen, xlen; RILE *(*rcsopen)P((struct buf*,struct stat*,int)); int mustread; /* * D is a directory name with length DLEN (including trailing slash). * BASE is a filename with length BASELEN. * X is an RCS filename suffix with length XLEN. * Use RCSOPEN to open an RCS file; MUSTREAD is set if the file must be read. * Yield true if successful. * Try dRCS/basex first; if that fails and x is nonempty, try dbasex. * Put these potential names in RCSb. * Set RCSbuf to the best RCS name found so far, and RCSerrno to its errno. * Yield true if successful or if an unusual failure. */ { register char *p; bufalloc(&RCSb, dlen + rcsdirlen + 1 + baselen + xlen + 1); /* Try dRCS/basex. */ VOID memcpy(p = RCSb.string, d, dlen); VOID memcpy(p += dlen, rcsdir, rcsdirlen); p += rcsdirlen; *p++ = SLASH; VOID memcpy(p, base, baselen); VOID memcpy(p += baselen, x, xlen); p[xlen] = 0; if (xlen) { if (finopen(rcsopen, mustread)) return true; /* Try dbasex. */ /* Start from scratch, because finopen() may have changed RCSb. */ VOID memcpy(p = RCSb.string, d, dlen); VOID memcpy(p += dlen, base, baselen); VOID memcpy(p += baselen, x, xlen); p[xlen] = 0; } return finopen(rcsopen, mustread); } int pairfilenames(argc, argv, rcsopen, mustread, quiet) int argc; char **argv; RILE *(*rcsopen)P((struct buf*,struct stat*,int)); int mustread, quiet; /* 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 workstdout * is set, a warning is printed. * * If the RCS file exists, places its status into RCSstat. * * If the RCS file exists, it is RCSOPENed 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, * print an error unless QUIET and return 0. * Otherwise, initialize the admin node and return -1. * * 0 is returned on all errors, e.g. files that are not regular files. */ { static struct buf tempbuf; register char *p, *arg, *RCS1; char const *purefname, *pureRCSname, *x; int paired; size_t arglen, dlen, baselen, xlen; if (!(arg = *argv)) return 0; /* already paired filename */ if (*arg == '-') { error("%s option is ignored after file names", arg); return 0; } purefname = basename(arg); /* Allocate buffer temporary to hold the default paired file name. */ p = arg; for (;;) { switch (*p++) { /* Beware characters that cause havoc with ci -k. */ case KDELIM: error("RCS file name `%s' contains %c", arg, KDELIM); return 0; case ' ': case '\n': case '\t': error("RCS file name `%s' contains white space", arg); return 0; default: continue; case 0: break; } break; } paired = false; /* first check suffix to see whether it is an RCS file or not */ if ((x = rcssuffix(arg))) { /* RCS file name given*/ RCS1 = arg; pureRCSname = purefname; baselen = x - purefname; if ( 1 < argc && !rcssuffix(workfilename = p = argv[1]) && baselen <= (arglen = strlen(p)) && ((p+=arglen-baselen) == workfilename || isSLASH(p[-1])) && memcmp(purefname, p, baselen) == 0 ) { argv[1] = 0; paired = true; } else { bufscpy(&tempbuf, purefname); workfilename = p = tempbuf.string; p[baselen] = 0; } } else { /* working file given; now try to find RCS file */ workfilename = arg; baselen = p - purefname - 1; /* derive RCS file name*/ if ( 1 < argc && (x = rcssuffix(RCS1 = argv[1])) && baselen <= x - RCS1 && ((pureRCSname=x-baselen)==RCS1 || isSLASH(pureRCSname[-1])) && memcmp(purefname, pureRCSname, baselen) == 0 ) { argv[1] = 0; paired = true; } else pureRCSname = RCS1 = 0; } /* now we have a (tentative) RCS filename in RCS1 and workfilename */ /* Second, try to find the right RCS file */ if (pureRCSname!=RCS1) { /* a path for RCSfile is given; single RCS file to look for */ bufscpy(&RCSbuf, RCS1); finptr = (*rcsopen)(&RCSbuf, &RCSstat, mustread); RCSerrno = errno; } else { bufscpy(&RCSbuf, ""); if (RCS1) /* RCS file name was given without path. */ VOID fin2open(arg, (size_t)0, pureRCSname, baselen, x, strlen(x), rcsopen, mustread ); else { /* No RCS file name was given. */ /* Try each suffix in turn. */ dlen = purefname-arg; x = suffixes; while (! fin2open(arg, dlen, purefname, baselen, x, xlen=suffixlen(x), rcsopen, mustread )) { x += xlen; if (!*x++) break; } } } RCSfilename = p = RCSbuf.string; if (finptr) { if (!S_ISREG(RCSstat.st_mode)) { error("%s isn't a regular file -- ignored", p); return 0; } Lexinit(); getadmin(); } else { if (RCSerrno!=ENOENT || mustread || !frewrite) { if (RCSerrno == EEXIST) error("RCS file %s is in use", p); else if (!quiet || RCSerrno!=ENOENT) enerror(RCSerrno, p); return 0; } InitAdmin(); }; # if LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED if (filenametoolong(p)) { error("RCS file name %s is too long", p); return 0; } # ifndef NAME_MAX /* * Check workfilename too, even though it cannot be longer, * because it may reside on a different filesystem. */ if (filenametoolong(workfilename)) { error("working file name %s is too long", workfilename); return 0; } # endif # endif if (paired && workstdout) warn("Option -p is set; ignoring output file %s",workfilename); prevkeys = false; return finptr ? 1 : -1; } char const * getfullRCSname() /* Function: returns a pointer to the full path name of the RCS file. * Gets the working directory's name at most once. * Removes leading "../" and "./". */ { static char const *wdptr; static struct buf rcsbuf, wdbuf; static size_t pathlength; register char const *realname; register size_t parentdirlength; register unsigned dotdotcounter; register char *d; register char const *wd; if (ROOTPATH(RCSfilename)) { return(RCSfilename); } else { if (!(wd = wdptr)) { /* Get working directory for the first time. */ if (!(d = cgetenv("PWD"))) { bufalloc(&wdbuf, SIZEABLE_PATH + 1); # if !has_getcwd && has_getwd d = getwd(wdbuf.string); # else while ( !(d = getcwd(wdbuf.string, wdbuf.size)) && errno==ERANGE ) bufalloc(&wdbuf, wdbuf.size<<1); # endif if (!d) efaterror("working directory"); } parentdirlength = strlen(d); while (parentdirlength && isSLASH(d[parentdirlength-1])) { d[--parentdirlength] = 0; /* Check needed because some getwd implementations */ /* generate "/" for the root. */ } wdptr = wd = d; pathlength = parentdirlength; } /*the following must be redone since RCSfilename may change*/ /* Find how many `../'s to remove from RCSfilename. */ dotdotcounter =0; realname = RCSfilename; while (realname[0]=='.') { if (isSLASH(realname[1])) { /* drop leading ./ */ realname += 2; } else if (realname[1]=='.' && isSLASH(realname[2])) { /* drop leading ../ and remember */ dotdotcounter++; realname += 3; } else break; } /* Now remove dotdotcounter trailing directories from wd. */ parentdirlength = pathlength; while (dotdotcounter && parentdirlength) { /* move pointer backwards over trailing directory */ if (isSLASH(wd[--parentdirlength])) { dotdotcounter--; } } /* build full path name */ bufalloc(&rcsbuf, parentdirlength+strlen(realname)+2); d = rcsbuf.string; VOID memcpy(d, wd, parentdirlength); d += parentdirlength; *d++ = SLASH; VOID strcpy(d, realname); return rcsbuf.string; } } #ifndef isSLASH int isSLASH(c) int c; { switch (c) { case SLASHes: return true; default: return false; } } #endif #if !has_getcwd && !has_getwd char * getcwd(path, size) char *path; size_t size; { static char const usrbinpwd[] = "/usr/bin/pwd"; # define binpwd (usrbinpwd+4) register FILE *fp; register int c; register char *p, *lim; int closeerrno, closeerror, e, fd[2], readerror, toolong, wstatus; pid_t child; # if !has_waitpid pid_t w; # endif if (!size) { errno = EINVAL; return 0; } if (pipe(fd) != 0) return 0; if (!(child = vfork())) { if ( close(fd[0]) == 0 && (fd[1] == STDOUT_FILENO || # ifdef F_DUPFD (VOID close(STDOUT_FILENO), fcntl(fd[1], F_DUPFD, STDOUT_FILENO)) # else dup2(fd[1], STDOUT_FILENO) # endif == STDOUT_FILENO && close(fd[1]) == 0 ) ) { VOID close(STDERR_FILENO); VOID execl(binpwd, binpwd, (char *)0); VOID execl(usrbinpwd, usrbinpwd, (char *)0); } _exit(EXIT_FAILURE); } e = errno; closeerror = close(fd[1]); closeerrno = errno; fp = 0; readerror = toolong = wstatus = 0; p = path; if (0 <= child) { fp = fdopen(fd[0], "r"); e = errno; if (fp) { lim = p + size; for (p = path; ; *p++ = c) { if ((c=getc(fp)) < 0) { if (feof(fp)) break; if (ferror(fp)) { readerror = 1; e = errno; break; } } if (p == lim) { toolong = 1; break; } } } # if has_waitpid if (waitpid(child, &wstatus, 0) < 0) wstatus = 1; # else do { if ((w = wait(&wstatus)) < 0) { wstatus = 1; break; } } while (w != child); # endif } if (!fp) { VOID close(fd[0]); errno = e; return 0; } if (fclose(fp) != 0) return 0; if (readerror) { errno = e; return 0; } if (closeerror) { errno = closeerrno; return 0; } if (toolong) { errno = ERANGE; return 0; } if (wstatus || p == path || *--p != '\n') { errno = EACCES; return 0; } *p = '\0'; return path; } #endif #ifdef PAIRTEST /* test program for pairfilenames() and getfullRCSname() */ char const cmdid[] = "pair"; main(argc, argv) int argc; char *argv[]; { int result; int initflag; quietflag = initflag = false; while(--argc, ++argv, argc>=1 && ((*argv)[0] == '-')) { switch ((*argv)[1]) { case 'p': workstdout = stdout; 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,rcsreadopen,!initflag,quietflag); if (result!=0) { diagnose("RCS file: %s; working file: %s\nFull RCS file name: %s\n", RCSfilename,workfilename,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\n",RCSfilename); } Ifclose(finptr); break; case -1:diagnose("RCS file doesn't exist\n"); break; } } while (++argv, --argc>=1); } exiting void exiterr() { dirtempunlink(); tempunlink(); _exit(EXIT_FAILURE); } #endif @ 5.8.2.1 log @Bump the rev number for rcsfreeze. Usually I forget this. Arghh :-( @ text @a40 12 * Revision 5.8.1.3 1993/04/13 19:51:54 heinz * RCS_link works a lot better now. * .guide is now recognized for AmigaGuide documents. I want to put the * rcs.guide file into RCS, too ;-) * * Revision 5.8.1.2 1993/01/18 18:15:39 heinz * A workaround for SAS/C giving EIO instead of ENOENT when accessing * a non existant file in a non existant directory. * * Revision 5.8.1.1 1993/01/18 14:38:26 heinz * Start of the AMIGA port of RCS 5.6. I call it HWGRCS now ;^) * d78 1 a78 1 * d81 1 a81 1 * d85 1 a85 1 * d89 1 a89 1 * d92 1 a92 1 * d95 1 a95 1 * d98 1 a98 1 * d101 1 a101 1 * d107 1 a107 1 * d111 1 a111 1 * d114 1 a114 1 * d143 1 a143 1 libId(fnmsId, "$Id: rcsfnms.c,v 5.8.1.3 1993/04/13 19:51:54 heinz Exp $") a150 1 #ifndef AMIGA a152 6 #else /* This is the default directory */ #define DEFRCSDIR "RCS/" /* What's the link file called? */ #define RCSLINKFILE "RCS_link" a153 5 #ifndef isSLASH int isSLASH(int c); #endif #endif d164 1 a164 1 char const *suffix, *comlead; d173 4 a176 4 "a", "-- ", /* Ada */ "ada", "-- ", "asm", ";; ", /* assembler (MS-DOS) */ "bat", ":: ", /* batch (MS-DOS) */ d178 11 a188 11 "c++", "// ", /* C++ in all its infinite guises */ "cc", "// ", "cpp", "// ", "cxx", "// ", "cl", ";;; ", /* Common Lisp */ "cmd", ":: ", /* command (OS/2) */ "cmf", "c ", /* CM Fortran */ "cs", " * ", /* C* */ "el", "; ", /* Emacs Lisp */ "f", "c ", /* Fortran */ "for", "c ", d190 2 a191 2 "hpp", "// ", /* C++ header */ "hxx", "// ", d193 11 a203 11 "lisp",";;; ", /* Lucid Lisp */ "lsp", ";; ", /* Microsoft Lisp */ "mac", ";; ", /* macro (DEC-10, MS-DOS, PDP-11, VMS, etc) */ "me", ".\\\" ",/* me-macros t/nroff*/ "ml", "; ", /* mocklisp */ "mm", ".\\\" ",/* mm-macros t/nroff*/ "ms", ".\\\" ",/* ms-macros t/nroff*/ "p", " * ", /* Pascal */ "pas", " * ", "pl", "% ", /* Prolog */ "tex", "% ", /* TeX */ d205 1 a205 8 #ifdef AMIGA "fd", "* ", /* function description files */ "a", "* ", /* assembler */ "asm", "* ", /* assembler */ "i", "* ", /* assembler include */ "guide", "@@REMARK ", /* AmigaGuide(R) */ #endif nil, "# " /* default for unknown suffix; must always be last */ a207 143 #ifdef AMIGA static char * str_dup(char *s) { char *d = NULL; if(s) { d = malloc(strlen(s) + 1); if(d) { strcpy(d, s); } /* if */ } /* if */ return(d); } /* str_dup */ static char *getrcsdirname(char const *d, size_t dlen) { char *name = NULL; char buf[256]; int fnamelenmax = dlen + sizeof(RCSLINKFILE); char *fnamebuf = malloc(fnamelenmax); /* First we try d/RCS_link. If this doesn't work we try RCS_link in the current directory. If we find one of them we return the contents. Otherwise we check the environment. If this doesn't work either we return the path we got with the default dir tacked on. */ if(fnamebuf) { FILE *fp; memcpy(fnamebuf, d, dlen); fnamebuf[dlen] = '\0'; strcat(fnamebuf, RCSLINKFILE); /* Do we have an RCS_link file that contains the real path name? */ fp = fopen(fnamebuf, "r"); if(!fp) { fp = fopen(RCSLINKFILE, "r"); } /* if */ if(fp) { char *s; int l; int addlen; fgets(buf, 255, fp); s = strchr(buf, '\n'); if(s) { *s = '\0'; } /* if */ l = strlen(buf); if(l) { char c = buf[l-1]; if(c!=':' && c!='/') { buf[l++] = '/'; buf[l] = 0; } /* if */ } /* if */ /* If RCS_link is an absolute path, we will only return RCS_link. If it is _not_ absolute we tack it onto the path we got. */ addlen = strchr(buf, ':') ? 0 : dlen; name = malloc(strlen(buf) + addlen + 1); if(name) { memcpy(name, d, addlen); name[addlen] = '\0'; strcat(name, buf); } /* if */ fclose(fp); } /* if */ free(fnamebuf); } /* if */ if(!name) { /* Now lets see if there is some preference */ char *env = getenv("RCS/DIRECTORY"); if(env) { int l = strlen(env); char *buf = malloc(l + 1 + 1); if(buf) { strcpy(buf, env); if(l) { char c = buf[l-1]; if(c!=':' && c!='/') { buf[l++] = '/'; buf[l] = 0; } /* if */ } /* if */ name = buf; } /* if */ free(env); } /* if */ } /* if */ if(!name) { /* Uhm, well, we return the path we got + "RCS/". The sizeof includes the +1 we need for the trailing zero */ name = malloc(dlen + sizeof(DEFRCSDIR)); if(name) { memcpy(name, d, dlen); name[dlen] = '\0'; strcat(name, DEFRCSDIR); } /* if */ } /* if */ /* If this returns NULL the calling function needs to use DEFRCSDIR. If this is nonzero, don't forget to free() it! */ return(name); } /* getrcsdirname */ #endif d209 1 a209 1 static char const * d213 8 a220 8 static char const *s; if (!s && !(s = cgetenv("TMPDIR")) /* Unix tradition */ && !(s = cgetenv("TMP")) /* DOS tradition */ && !(s = cgetenv("TEMP")) /* another DOS tradition */ ) s = TMPDIR; return s; d224 1 a224 1 char const * d226 1 a226 1 int n; d233 2 a234 2 char *p; char const *t = tfnames[n]; d236 2 a237 2 if (t) return t; d239 21 a259 21 catchints(); { # if has_mktemp char const *tp = tmp(); p = testalloc(strlen(tp) + 10); VOID sprintf(p, "%s%cT%cXXXXXX", tp, SLASH, '0'+n); if (!mktemp(p) || !*p) faterror("can't make temporary file name `%s%cT%cXXXXXX'", tp, SLASH, '0'+n ); # else static char tfnamebuf[TEMPNAMES][L_tmpnam]; p = tfnamebuf[n]; if (!tmpnam(p) || !*p) # ifdef P_tmpdir faterror("can't make temporary file name `%s...'",P_tmpdir); # else faterror("can't make temporary file name"); # endif # endif } d261 2 a262 2 tfnames[n] = p; return p; d265 1 a265 1 void d270 2 a271 2 register int i; register char *p; d273 10 a282 10 for (i = TEMPNAMES; 0 <= --i; ) if ((p = tfnames[i])) { VOID unlink(p); /* * We would tfree(p) here, * but this might dump core if we're handing a signal. * We're about to exit anyway, so we won't bother. */ tfnames[i] = 0; } d286 1 a286 1 static char const * d288 2 a289 2 register char const *sp; int ch; d295 1 a295 1 register char const c=ch, *r; d305 1 a305 1 static int d307 1 a307 1 register char const *suffix, *pattern; d309 17 a325 17 register int c; if (!pattern) return true; for (;;) switch (*suffix++ - (c = *pattern++)) { case 0: if (!c) return true; break; case 'A'-'a': if (ctab[c] == Letter) break; /* fall into */ default: return false; } d329 1 a329 1 static void d333 1 a333 1 register char const *Suffix; d336 1 a336 1 Head=nil; Dbranch=nil; AccessList=nil; Symbols=nil; Locks=nil; d342 5 a346 5 for (i=0; !suffix_matches(Suffix,comtable[i].suffix); i++) ; Comment.string = comtable[i].comlead; Comment.size = strlen(comtable[i].comlead); Lexinit(); /* note: if !finptr, reads nothing; only initializes */ d351 1 a351 1 # define LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED 0 d353 1 a353 1 # define LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED 1 d358 1 a358 1 # define filenametoolong(path) (NAME_MAX < strlen(basename(path))) d360 1 a360 1 static int d362 1 a362 1 char *path; d365 1 a365 1 static unsigned long dot_namemax; d367 20 a386 20 register size_t namelen; register char *base; register unsigned long namemax; base = path + dirlen(path); namelen = strlen(base); if (namelen <= _POSIX_NAME_MAX) /* fast check for shorties */ return false; if (base != path) { *--base = 0; namemax = pathconf(path, _PC_NAME_MAX); *base = SLASH; } else { /* Cache the results for the working directory, for speed. */ if (!dot_namemax) dot_namemax = pathconf(".", _PC_NAME_MAX); namemax = dot_namemax; } /* If pathconf() yielded -1, namemax is now ULONG_MAX. */ return namemaxsize < size) { if (b->size) tfree(b->string); else b->size = sizeof(malloc_type); while (b->size < size) b->size <<= 1; b->string = tnalloc(char, b->size); } d410 1 a410 1 void d412 2 a413 2 register struct buf *b; size_t size; d416 9 a424 9 if (b->size < size) { if (!b->size) bufalloc(b, size); else { while ((b->size <<= 1) < size) ; b->string = trealloc(char, b->string, b->size); } } d427 1 a427 1 void d429 1 a429 1 struct buf *b; d432 2 a433 2 if (b->size) tfree(b->string); d436 1 a436 1 struct cbuf d438 2 a439 2 struct buf *b; size_t s; d446 1 a446 1 struct cbuf cb; d448 7 a454 7 if ((cb.size = s)) cb.string = fremember(trealloc(char, b->string, s)); else { bufautoend(b); /* not really auto */ cb.string = ""; } return cb; d457 1 a457 1 char * d459 2 a460 2 register struct buf *b; char const **alim; d465 4 a468 4 size_t s = b->size; bufrealloc(b, s + 1); *alim = b->string + b->size; return b->string + s; d471 1 a471 1 void d473 2 a474 2 struct buf *b; char const *s; d477 3 a479 3 size_t blen = b->string ? strlen(b->string) : 0; bufrealloc(b, blen+strlen(s)+1); VOID strcpy(b->string+blen, s); d482 1 a482 1 void d484 2 a485 2 struct buf *b; char const *s; d488 2 a489 2 bufalloc(b, strlen(s)+1); VOID strcpy(b->string, s); d493 1 a493 1 char const * d495 1 a495 1 char const *p; d498 6 a503 9 register char const *b = p, *q = p; for (;;) switch (*q++) { #ifdef AMIGA case SLASH: #endif case SLASHes: b = q; break; case 0: return b; } d506 1 a506 1 size_t d508 1 a508 1 char const *p; d511 1 a511 1 return basename(p) - p; d515 1 a515 1 static size_t d517 1 a517 1 char const *x; d520 1 a520 1 register char const *p; d522 5 a526 8 p = x; for (;;) switch (*p) { case 0: case SLASHes: #ifdef AMIGA case SLASH: #endif return p - x; d528 4 a531 4 default: ++p; continue; } d534 1 a534 1 char const * d536 1 a536 1 char const *name; d539 2 a540 7 char const *x, *p, *nz; size_t dl, nl, xl; #ifdef AMIGA char *rcsdircopy = getrcsdirname("", 0); char *rcsdir = (rcsdircopy) ? rcsdircopy : DEFRCSDIR; size_t rcsdirlen = strlen(rcsdir); #endif d542 19 a560 60 nl = strlen(name); nz = name + nl; x = suffixes; do { if ((xl = suffixlen(x))) { if (xl <= nl && memcmp(p = nz-xl, x, xl) == 0) #ifdef AMIGA { if(rcsdircopy) { free(rcsdircopy); } /* if */ return(p); } /* if */ #else return p; #endif } else { /* Well, all of this is a nice try to find the rcs file but with the RCS_link feature of HWGRCS we can't really backtrace a filename without suffix. So this is usually a useless try unless the standard name RCS is used. Nothing I can do about it right now. I haven't invented RCS_link, either, so don't blame it on me. Arghhh, always that compatibility quest ... */ dl = dirlen(name); #ifdef AMIGA if(dl && isSLASH(name[dl-1])) { /* On the Amiga the SLASH or COLON is _included_ in the rcsdir! */ dl++; } /* if */ #endif if ( rcsdirlen < dl && !memcmp(p = name+(dl-=rcsdirlen+1), rcsdir, rcsdirlen) && (!dl || isSLASH(*--p)) ) #ifdef AMIGA { if(rcsdircopy) { free(rcsdircopy); } /* if */ return(nz); } /* if */ #else return nz; #endif } x += xl; } while (*x++); #ifdef AMIGA if(rcsdircopy) { free(rcsdircopy); } /* if */ #endif return 0; d563 1 a563 1 /*ARGSUSED*/ RILE * d565 3 a567 3 struct buf *RCSname; struct stat *status; int mustread; d572 1 a572 1 return Iopen(RCSname->string, FOPEN_R, status); d575 1 a575 1 static int d577 2 a578 2 RILE *(*rcsopen)P((struct buf*,struct stat*,int)); int mustread; d587 1 a587 1 int interesting, preferold; d589 14 a602 23 /* * We prefer an old name to that of a nonexisting new RCS file, * unless we tried locking the old name and failed. */ preferold = RCSbuf.string[0] && (mustread||frewrite); finptr = (*rcsopen)(&RCSb, &RCSstat, mustread); #ifdef AMIGA /* If we don't have any RCS dir and try some access for RCS/xx SAS/C won't return ENOENT for open() but EIO! So we fake an ENOENT here to keep RCS happy */ if(!finptr && errno == EIO) { errno = ENOENT; } /* if */ #endif interesting = finptr || errno!=ENOENT; if (interesting || !preferold) { /* Use the new name. */ RCSerrno = errno; bufscpy(&RCSbuf, RCSb.string); } return interesting; d605 1 a605 1 static int d607 4 a610 4 char const *d, *base, *x; size_t dlen, baselen, xlen; RILE *(*rcsopen)P((struct buf*,struct stat*,int)); int mustread; d623 1 a623 22 register char *p; #ifdef AMIGA /* getrcsdirname() will return a complete path with a "correct" rcs subdir specifier tacked on or it will replace the path with the "correct" name of the real directory. Service (and slash) included ;-) BTW, the stuff below s ugly but I can't see a way to make it nice */ char *rcsdircopy = getrcsdirname(d, dlen); char *rcsdir = (rcsdircopy) ? rcsdircopy : DEFRCSDIR; size_t rcsdirlen = strlen(rcsdir); bufalloc(&RCSb, rcsdirlen + 1 + baselen + xlen + 1); /* Try rcsdir/basex. */ VOID memcpy(p = RCSb.string, rcsdir, rcsdirlen); p += rcsdirlen; if(rcsdircopy) { free(rcsdircopy); } /* if */ #else bufalloc(&RCSb, dlen + rcsdirlen + 1 + baselen + xlen + 1); d625 1 a625 6 /* Try dRCS/basex. */ VOID memcpy(p = RCSb.string, d, dlen); VOID memcpy(p += dlen, rcsdir, rcsdirlen); p += rcsdirlen; *p++ = SLASH; #endif d627 20 a646 15 VOID memcpy(p, base, baselen); VOID memcpy(p += baselen, x, xlen); p[xlen] = 0; if (xlen) { if (finopen(rcsopen, mustread)) return true; /* Try dbasex. */ /* Start from scratch, because finopen() may have changed RCSb. */ VOID memcpy(p = RCSb.string, d, dlen); VOID memcpy(p += dlen, base, baselen); VOID memcpy(p += baselen, x, xlen); p[xlen] = 0; } return finopen(rcsopen, mustread); d649 1 a649 1 int d651 4 a654 4 int argc; char **argv; RILE *(*rcsopen)P((struct buf*,struct stat*,int)); int mustread, quiet; d673 1 a673 14 static struct buf tempbuf; register char *p, *arg, *RCS1; char const *purefname, *pureRCSname, *x; int paired; size_t arglen, dlen, baselen, xlen; if (!(arg = *argv)) return 0; /* already paired filename */ if (*arg == '-') { error("%s option is ignored after file names", arg); return 0; } purefname = basename(arg); d675 31 a705 18 /* Allocate buffer temporary to hold the default paired file name. */ p = arg; for (;;) { switch (*p++) { /* Beware characters that cause havoc with ci -k. */ case KDELIM: error("RCS file name `%s' contains %c", arg, KDELIM); return 0; case ' ': case '\n': case '\t': error("RCS file name `%s' contains white space", arg); return 0; default: continue; case 0: break; } break; } d707 1 a707 1 paired = false; d710 2 a711 2 if ((x = rcssuffix(arg))) { d713 17 a729 17 RCS1 = arg; pureRCSname = purefname; baselen = x - purefname; if ( 1 < argc && !rcssuffix(workfilename = p = argv[1]) && baselen <= (arglen = strlen(p)) && ((p+=arglen-baselen) == workfilename || isSLASH(p[-1])) && memcmp(purefname, p, baselen) == 0 ) { argv[1] = 0; paired = true; } else { bufscpy(&tempbuf, purefname); workfilename = p = tempbuf.string; p[baselen] = 0; } d732 2 a733 2 workfilename = arg; baselen = p - purefname - 1; d735 11 a745 11 if ( 1 < argc && (x = rcssuffix(RCS1 = argv[1])) && baselen <= x - RCS1 && ((pureRCSname=x-baselen)==RCS1 || isSLASH(pureRCSname[-1])) && memcmp(purefname, pureRCSname, baselen) == 0 ) { argv[1] = 0; paired = true; } else pureRCSname = RCS1 = 0; d751 3 a753 3 bufscpy(&RCSbuf, RCS1); finptr = (*rcsopen)(&RCSbuf, &RCSstat, mustread); RCSerrno = errno; d755 24 a778 24 bufscpy(&RCSbuf, ""); if (RCS1) /* RCS file name was given without path. */ VOID fin2open(arg, (size_t)0, pureRCSname, baselen, x, strlen(x), rcsopen, mustread ); else { /* No RCS file name was given. */ /* Try each suffix in turn. */ dlen = purefname-arg; x = suffixes; while (! fin2open(arg, dlen, purefname, baselen, x, xlen=suffixlen(x), rcsopen, mustread )) { x += xlen; if (!*x++) break; } } } RCSfilename = p = RCSbuf.string; if (finptr) { if (!S_ISREG(RCSstat.st_mode)) { error("%s isn't a regular file -- ignored", p); d782 8 a789 8 } else { if (RCSerrno!=ENOENT || mustread || !frewrite) { if (RCSerrno == EEXIST) error("RCS file %s is in use", p); else if (!quiet || RCSerrno!=ENOENT) enerror(RCSerrno, p); return 0; } d792 16 a807 16 # if LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED if (filenametoolong(p)) { error("RCS file name %s is too long", p); return 0; } # ifndef NAME_MAX /* * Check workfilename too, even though it cannot be longer, * because it may reside on a different filesystem. */ if (filenametoolong(workfilename)) { error("working file name %s is too long", workfilename); return 0; } # endif # endif d809 1 a809 1 if (paired && workstdout) d812 2 a813 2 prevkeys = false; return finptr ? 1 : -1; d817 1 a817 1 char const * d824 9 a832 9 static char const *wdptr; static struct buf rcsbuf, wdbuf; static size_t pathlength; register char const *realname; register size_t parentdirlength; register unsigned dotdotcounter; register char *d; register char const *wd; d834 1 a834 1 if (ROOTPATH(RCSfilename)) { d837 19 a855 19 if (!(wd = wdptr)) { /* Get working directory for the first time. */ if (!(d = cgetenv("PWD"))) { bufalloc(&wdbuf, SIZEABLE_PATH + 1); # if !has_getcwd && has_getwd d = getwd(wdbuf.string); # else while ( !(d = getcwd(wdbuf.string, wdbuf.size)) && errno==ERANGE ) bufalloc(&wdbuf, wdbuf.size<<1); # endif if (!d) efaterror("working directory"); } parentdirlength = strlen(d); while (parentdirlength && isSLASH(d[parentdirlength-1])) { d[--parentdirlength] = 0; d859 2 a860 2 wdptr = wd = d; pathlength = parentdirlength; d863 1 a863 1 /* Find how many `../'s to remove from RCSfilename. */ d866 2 a867 4 #ifdef AMIGA #else while (realname[0]=='.') { if (isSLASH(realname[1])) { d870 1 a870 1 } else if (realname[1]=='.' && isSLASH(realname[2])) { d874 2 a875 2 } else break; d877 3 a879 4 #endif /* Now remove dotdotcounter trailing directories from wd. */ parentdirlength = pathlength; while (dotdotcounter && parentdirlength) { d881 1 a881 1 if (isSLASH(wd[--parentdirlength])) { d885 8 a892 8 /* build full path name */ bufalloc(&rcsbuf, parentdirlength+strlen(realname)+2); d = rcsbuf.string; VOID memcpy(d, wd, parentdirlength); d += parentdirlength; *d++ = SLASH; VOID strcpy(d, realname); return rcsbuf.string; d897 1 a897 1 int d899 1 a899 1 int c; d901 6 a906 9 switch (c) { #ifdef AMIGA case SLASH: #endif case SLASHes: return true; default: return false; } d913 1 a913 1 char * d915 2 a916 2 char *path; size_t size; d918 2 a919 2 static char const usrbinpwd[] = "/usr/bin/pwd"; # define binpwd (usrbinpwd+4) d921 99 a1019 99 register FILE *fp; register int c; register char *p, *lim; int closeerrno, closeerror, e, fd[2], readerror, toolong, wstatus; pid_t child; # if !has_waitpid pid_t w; # endif if (!size) { errno = EINVAL; return 0; } if (pipe(fd) != 0) return 0; if (!(child = vfork())) { if ( close(fd[0]) == 0 && (fd[1] == STDOUT_FILENO || # ifdef F_DUPFD (VOID close(STDOUT_FILENO), fcntl(fd[1], F_DUPFD, STDOUT_FILENO)) # else dup2(fd[1], STDOUT_FILENO) # endif == STDOUT_FILENO && close(fd[1]) == 0 ) ) { VOID close(STDERR_FILENO); VOID execl(binpwd, binpwd, (char *)0); VOID execl(usrbinpwd, usrbinpwd, (char *)0); } _exit(EXIT_FAILURE); } e = errno; closeerror = close(fd[1]); closeerrno = errno; fp = 0; readerror = toolong = wstatus = 0; p = path; if (0 <= child) { fp = fdopen(fd[0], "r"); e = errno; if (fp) { lim = p + size; for (p = path; ; *p++ = c) { if ((c=getc(fp)) < 0) { if (feof(fp)) break; if (ferror(fp)) { readerror = 1; e = errno; break; } } if (p == lim) { toolong = 1; break; } } } # if has_waitpid if (waitpid(child, &wstatus, 0) < 0) wstatus = 1; # else do { if ((w = wait(&wstatus)) < 0) { wstatus = 1; break; } } while (w != child); # endif } if (!fp) { VOID close(fd[0]); errno = e; return 0; } if (fclose(fp) != 0) return 0; if (readerror) { errno = e; return 0; } if (closeerror) { errno = closeerrno; return 0; } if (toolong) { errno = ERANGE; return 0; } if (wstatus || p == path || *--p != '\n') { errno = EACCES; return 0; } *p = '\0'; return path; d1033 2 a1034 2 int initflag; quietflag = initflag = false; d1039 1 a1039 1 case 'p': workstdout = stdout; d1052 1 a1052 1 result = pairfilenames(argc,argv,rcsreadopen,!initflag,quietflag); d1054 3 a1056 3 diagnose("RCS file: %s; working file: %s\nFull RCS file name: %s\n", RCSfilename,workfilename,getfullRCSname() ); d1064 1 a1064 1 diagnose("RCS file %s exists\n",RCSfilename); d1066 1 a1066 1 Ifclose(finptr); d1069 1 a1069 1 case -1:diagnose("RCS file doesn't exist\n"); d1077 1 a1077 1 exiting void d1080 3 a1082 3 dirtempunlink(); tempunlink(); _exit(EXIT_FAILURE); @ 5.8.2.2 log @The Amiga specific file anem extensions were not really ok. The Ada extension is now an assembler extension and the other extensions are sorted alphabetically. @ text @a40 3 * Revision 5.8.2.1 1993/04/14 19:11:32 heinz * Bump the rev number for rcsfreeze. Usually I forget this. Arghh :-( * d155 1 a155 1 libId(fnmsId, "$Id: rcsfnms.c,v 5.8.2.1 1993/04/14 19:11:32 heinz Exp heinz $") a196 4 #ifdef AMIGA /* This is more important than Ada files! */ "a", "* ", /* assembler */ #else a197 1 #endif a211 3 #ifdef AMIGA "fd", "* ", /* function description files */ #endif a212 3 #ifdef AMIGA "guide", "@@REMARK ", /* AmigaGuide(R) */ #endif a215 3 #ifdef AMIGA "i", "* ", /* assembler include */ #endif d227 2 d230 5 a234 1 "ps", "% ", /* PostScript */ a235 2 "tex", "% ", /* TeX */ "y", " * ", /* yacc */ @ 5.8.2.3 log @Major cleanup work. Better relative path handling on the Amiga. @ text @a40 5 * Revision 5.8.2.2 1993/06/13 09:36:39 heinz * The Amiga specific file anem extensions were not really ok. * The Ada extension is now an assembler extension and the other * extensions are sorted alphabetically. * d158 1 a158 1 libId(fnmsId, "$Id: rcsfnms.c,v 5.8.2.2 1993/06/13 09:36:39 heinz Exp heinz $") d166 5 a170 2 #ifdef AMIGA a178 4 #else static char const rcsdir[] = "RCS"; #define rcsdirlen (sizeof(rcsdir)-1) a193 1 #ifdef AMIGA d200 1 d203 3 d220 1 d222 1 d224 1 d226 1 d230 1 d232 1 d244 1 d246 1 a246 41 "tex", "% ", /* TeX */ "y", " * ", /* yacc */ nil, "# " /* default for unknown suffix; must always be last */ }; #else static struct compair const 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. */ "a", "-- ", /* Ada */ "ada", "-- ", "asm", ";; ", /* assembler (MS-DOS) */ "bat", ":: ", /* batch (MS-DOS) */ "c", " * ", /* C */ "c++", "// ", /* C++ in all its infinite guises */ "cc", "// ", "cpp", "// ", "cxx", "// ", "cl", ";;; ", /* Common Lisp */ "cmd", ":: ", /* command (OS/2) */ "cmf", "c ", /* CM Fortran */ "cs", " * ", /* C* */ "el", "; ", /* Emacs Lisp */ "f", "c ", /* Fortran */ "for", "c ", "h", " * ", /* C-header */ "hpp", "// ", /* C++ header */ "hxx", "// ", "l", " * ", /* lex NOTE: conflict between lex and franzlisp */ "lisp",";;; ", /* Lucid Lisp */ "lsp", ";; ", /* Microsoft Lisp */ "mac", ";; ", /* macro (DEC-10, MS-DOS, PDP-11, VMS, etc) */ "me", ".\\\" ",/* me-macros t/nroff*/ "ml", "; ", /* mocklisp */ "mm", ".\\\" ",/* mm-macros t/nroff*/ "ms", ".\\\" ",/* ms-macros t/nroff*/ "p", " * ", /* Pascal */ "pas", " * ", "pl", "% ", /* Prolog */ a250 1 #endif a255 1 d270 1 a270 1 static char *_AMIGA_getrcsdirname(char const *d, size_t dlen) d391 2 a392 1 } /* _AMIGA_getrcsdirname */ a726 1 #ifdef AMIGA d734 2 a735 1 char *rcsdircopy = _AMIGA_getrcsdirname("", 0); d738 1 d743 2 a744 4 do { if ((xl = suffixlen(x))) { d746 1 d754 4 a757 5 } else { dl = dirlen(name); d765 2 d770 1 a770 1 rcsdir! We must compensate for that! */ d773 7 a779 2 if (rcsdirlen < dl) d781 1 a781 9 /* Ugly, but I don't want to break _STRICT_ANSI for certain reasons. */ int strnicmp(const char *, const char *, int); dl -= rcsdirlen + 1; p = name + dl; if((strnicmp(p, rcsdir, rcsdirlen) == 0) && (!dl || isSLASH(*--p))) d783 1 a783 5 if(rcsdircopy) { free(rcsdircopy); } /* if */ return(nz); d785 1 d787 4 a790 1 } /* if */ d793 1 a793 1 d798 1 a798 30 return 0; } #else char const * rcssuffix(name) char const *name; /* Yield the suffix of NAME if it is an RCS filename, 0 otherwise. */ { char const *x, *p, *nz; size_t dl, nl, xl; nl = strlen(name); nz = name + nl; x = suffixes; do { if ((xl = suffixlen(x))) { if (xl <= nl && memcmp(p = nz-xl, x, xl) == 0) return p; } else { dl = dirlen(name); if ( rcsdirlen < dl && !memcmp(p = name+(dl-=rcsdirlen+1), rcsdir, rcsdirlen) && (!dl || isSLASH(*--p)) ) return nz; } x += xl; } while (*x++); a800 1 #endif d835 9 d873 1 a873 1 /* _AMIGA_getrcsdirname() will return a complete path with a "correct" d876 2 a877 2 BTW, the stuff below is ugly but I can't see a way to make it nice */ char *rcsdircopy = _AMIGA_getrcsdirname(d, dlen); d1135 2 a1147 8 #ifdef AMIGA /* Same as above for Amiga parent paths! */ while(realname[0] == '/') { /* drop leading ../ and remember */ dotdotcounter ++; realname ++; } /* while */ @ 5.8.2.4 log @Changed all checks for AMIGA to _AMIGA. This is more standard like and helps future updates. Major patch cleanup on the way. [Note: Added a VOID_CLOSEDIR define for this global change, too!] @ text @a40 3 * Revision 5.8.2.3 1993/12/04 11:07:25 heinz * Major cleanup work. Better relative path handling on the Amiga. * d163 1 a163 1 libId(fnmsId, "$Id: rcsfnms.c,v 5.8.2.3 1993/12/04 11:07:25 heinz Exp heinz $") d171 1 a171 5 #ifdef _AMIGA /* The RCS path handling is pretty much hardcoded in the original. I have to support the RCS_link feature for the old Fish RCS users and because AmigaDOS doesn't have full hard/soft link support yet. So these changes are not bugfixes but enhancements to standard behaviour. */ d185 1 a185 1 #endif /* _AMIGA */ d200 1 a200 6 #ifdef _AMIGA /* I have a slightly changed suffix table for the Amiga. Rather than patching into individual entries, I duplicate the whole table and hva eonly one #ifdef this way. */ d287 1 a287 9 #endif /* _AMIGA */ #ifdef _AMIGA /* Here begins the RCS_link support for the Amiga. I have a strdup clone here, because I don't want to count on the library strdup() being available due to my choice of options in the smakefile. _AMIGA_getrcsdirname() does all the work of "finding" the right directory path */ d289 1 d430 1 a430 1 #endif /* _AMIGA */ d725 1 a725 2 #ifdef _AMIGA /* This is needed because SLASHes is just a ':'. SLASH is a separator, too! */ d727 1 a727 1 #endif /* _AMIGA */ d753 1 a753 2 #ifdef _AMIGA /* This is needed because SLASHes is just a ':'. SLASH is a separator, too! */ d755 1 a755 1 #endif /* _AMIGA */ d764 1 a764 8 #ifdef _AMIGA /* This is a complete replacement for the standard rcssuffix() on the Amiga. It is easier to maintain this way rather than having half a ton of single line patches. The changed rcssuffix is needed, because of AmigaDOS ':','/' paths and RCS_link. */ d869 1 a869 1 #endif /* _AMIGA */ d932 1 a932 5 #ifdef _AMIGA /* Another change for the Amiga that is needed for RCS_link and Amiga path support. */ d959 1 a959 1 #endif /* _AMIGA */ d1206 1 a1206 5 #ifdef _AMIGA /* We need to handle Amiga base relative paths, too! The Amiga doesn't have '../', just '/' */ d1214 1 a1214 1 #endif _AMIGA d1240 1 a1240 2 #ifdef _AMIGA /* This is needed because SLASHes is just a ':'. SLASH is a separator, too! */ d1242 1 a1242 1 #endif /* _AMIGA */ @ 5.8.2.5 log @Ooops. Messed up one endif during the previos update. @ text @a40 5 * Revision 5.8.2.4 1993/12/18 16:12:22 heinz * Changed all checks for AMIGA to _AMIGA. This is more standard like * and helps future updates. Major patch cleanup on the way. * [Note: Added a VOID_CLOSEDIR define for this global change, too!] * d166 1 a166 1 libId(fnmsId, "$Id: rcsfnms.c,v 5.8.2.4 1993/12/18 16:12:22 heinz Exp heinz $") d1250 1 a1250 1 #endif /* _AMIGA */ @ 5.8.2.6 log @rcssuffix returned a wrong value if you specifed e.g. "rcs/file.c,v" and had a suffix setup like "/,v". This messed up the workfilename. Now rcssuffix returns the true suffix, even if there is the rcsdir prepended to the filename. @ text @a40 3 * Revision 5.8.2.5 1993/12/18 16:20:08 heinz * Ooops. Messed up one endif during the previos update. * d171 1 a171 1 libId(fnmsId, "$Id: rcsfnms.c,v 5.8.2.5 1993/12/18 16:20:08 heinz Exp heinz $") d777 1 d779 2 a780 8 /* This is needed because SLASHes is just a ':' for the Amiga. As the separator for the -x option is a '/' which has nothing to do with filename separators, it should probably be hardcoded or at least a different define. */ case 0: case '/': #else case 0: case SLASHes: d853 1 a853 1 (!dl || isSLASH(p[-1]))) a858 30 /* Ok, the filename has the rcsdir prepended. This tells us that we have an rcsfile name. We still have to return the right suffix though, to make the derivation of workfilename work right in e.g. pairfilenames. If we don't do this little recursive stunt here, a -x of "/,v" (the POSIX default) will mess up workfilenames if I try e.g. a "co rcs/file.c,v". When rcssuffix is called, the empty first suffix makes us enter this rcsdir comparison which returns nz == "" in the unmodified source. pairfilenames would use "file.c,v" then as workfilename because we did not return the correct suffix ",v". */ { /* We know it is a rcs file, we still have to return the correct suffix if there is one! So we just use the basename to check for a suffix. */ const char *truesuffix = rcssuffix(basename(name)); if(truesuffix) { return(truesuffix); } /* if */ } @ 5.8.2.7 log @isSLASH is back to pure '/' checking via SLASH now. The Amiga ':' tests are done with isPATHSEP() in the appropriate places. Needed this to fix colon replacement by a slash in getfullRCSname(). @ text @a40 6 * Revision 5.8.2.6 1994/01/07 22:26:37 heinz * rcssuffix returned a wrong value if you specifed e.g. "rcs/file.c,v" * and had a suffix setup like "/,v". This messed up the workfilename. * Now rcssuffix returns the true suffix, even if there is the rcsdir * prepended to the filename. * d174 1 a174 1 libId(fnmsId, "$Id: rcsfnms.c,v 5.8.2.6 1994/01/07 22:26:37 heinz Exp heinz $") d753 2 a754 2 /* This is needed because SLASHes is just a '/'. ':' is a separator, too! */ case ':': d781 2 a782 1 /* As the separator for the -x option is a '/' which has nothing to do with a798 12 static int isPATHSEP(int c) { if(c == SLASH || c == ':') { return(true); } /* if */ return(false); } /* isPATHSEP */ d844 1 a844 1 if(dl && isPATHSEP(name[dl-1])) d861 1 a861 1 (!dl || isPATHSEP(p[-1]))) a1123 7 #ifdef _AMIGA /* For the Amiga, a ':' and '/' are path separators. So we use something better than isSLASH() */ ((p+=arglen-baselen) == workfilename || isPATHSEP(p[-1])) && #else a1124 1 #endif /* _AMIGA */ a1142 7 #ifdef _AMIGA /* For the Amiga, a ':' and '/' are path separators. So we use something better than isSLASH() */ ((pureRCSname=x-baselen)==RCS1 || isPATHSEP(pureRCSname[-1])) && #else a1143 1 #endif /* _AMIGA */ a1257 16 #ifdef _AMIGA /* This is a little tricky. Trailing slashes are deleted for the unix version to make the ../ and ./ removal work below. isSLASH finds a colon, too. This messes up absolute Amiga paths. So what we do is not to remove slashes but "terminate" the working directory with a slash if needed. With a "slash count + 1" the parent dir removal will work nicely. */ if(parentdirlength && !isPATHSEP(d[parentdirlength-1)) { d[parentdirlength++] = SLASH; d[parentdirlength] = 0; } /* if */ #else a1262 1 #endif /* _AMIGA */ a1285 10 /* Above, we terminated the wd with a slash if needed. We need to take a trailing slash into account for the removal of trailing dirs. We do that by incrementing dotdotcounter by 1 when we have a trailing slash. */ if(parentdirlength && isSLASH(d[parentdirlength-1)) { dotodotcounter++; } /* if */ d1287 1 a1287 1 while(realname[0] == SLASH) a1306 11 #ifdef _AMIGA /* Another one of those unixisms. Sloppy path handling where it is assumed that a slash is the one and only thing. Tss. At least RCS is alot better than CVS where everything is hardcoded. Gross. */ if(parentdirlength && !isPATHSEP(d[-1])) { *d++ = SLASH; } /* if */ #else a1307 1 #endif /* _AMIGA */ d1319 4 @ 5.8.2.8 log @Rule #1. Never check something in before you know it compiles. @ text @a40 5 * Revision 5.8.2.7 1994/01/19 17:07:59 heinz * isSLASH is back to pure '/' checking via SLASH now. The Amiga ':' tests * are done with isPATHSEP() in the appropriate places. Needed this to fix * colon replacement by a slash in getfullRCSname(). * d180 1 a180 1 libId(fnmsId, "$Id: rcsfnms.c,v 5.8.2.7 1994/01/19 17:07:59 heinz Exp heinz $") d1300 1 a1300 1 if(parentdirlength && !isPATHSEP(d[parentdirlength-1])) d1341 1 a1341 1 if(parentdirlength && isSLASH(d[parentdirlength-1])) d1343 1 a1343 1 dotdotcounter++; @ 5.8.2.9 log @getfullRCSname should not discard a drive name with a colon anymore. @ text @a40 3 * Revision 5.8.2.8 1994/01/19 17:31:19 heinz * Rule #1. Never check something in before you know it compiles. * d185 1 a185 1 libId(fnmsId, "$Id: rcsfnms.c,v 5.8.2.8 1994/01/19 17:31:19 heinz Exp heinz $") a1338 2 While trimming of trailing directories, we have to stop at a colon for the Amiga. Otherwise we kill absolute path names! d1358 1 a1358 21 /* Now remove dotdotcounter trailing directories from wd. */ parentdirlength = pathlength; while (dotdotcounter && parentdirlength) { /* We stop when we have reached the drive name! Because we still want an absolute path spec! */ if(wd[parentdirlength - 1] == ':') { break; } /* if */ /* move pointer backwards over trailing directory */ if (isSLASH(wd[--parentdirlength])) { dotdotcounter--; } /* if */ } /* while */ #else a1366 1 #endif /* _AMIGA */ @ 5.8.2.10 log @Added "ag" extension for AmigaGuide documents. @ text @a40 3 * Revision 5.8.2.9 1994/01/22 12:42:08 heinz * getfullRCSname should not discard a drive name with a colon anymore. * d188 1 a188 1 libId(fnmsId, "$Id: rcsfnms.c,v 5.8.2.9 1994/01/22 12:42:08 heinz Exp heinz $") a243 1 "ag", "@@REMARK ", /* AmigaGuide(R) */ @ 5.8.2.11 log @Added function to ignore RCS_link as argument in argv. @ text @a40 3 * Revision 5.8.2.10 1994/02/10 17:25:54 heinz * Added "ag" extension for AmigaGuide documents. * d191 1 a191 1 libId(fnmsId, "$Id: rcsfnms.c,v 5.8.2.10 1994/02/10 17:25:54 heinz Exp heinz $") a474 28 void AMIGA_ignorercslink(int *argcp, char **argv) { int i; for(i = 0; i < *argcp; i++) { /* If we find an RCS_link reference, we remove it! */ if(stricmp(basename(argv[i]), RCSFILENAME) == 0) { int j = i; while(j < *argcp) { argv[j] = argv[j+1]; j++; } /* while */ /* One arg less available! */ (*argcp)--; /* Try this slot again! */ i--; } /* if */ } /* while */ } /* AMIGA_ignorercslink */ @ 5.8.2.12 log @Support for the new keywords VER, AmigaREV, and AmigaProtection. @ text @a40 3 * Revision 5.8.2.11 1994/02/11 19:51:33 heinz * Added function to ignore RCS_link as argument in argv. * d194 1 a194 1 libId(fnmsId, "$Id: rcsfnms.c,v 5.8.2.11 1994/02/11 19:51:33 heinz Exp heinz $") a481 3 /* Ugly, but I don't want to break _STRICT_ANSI for certain reasons. */ int stricmp(const char *, const char *); d486 1 a486 1 if(stricmp(basename(argv[i]), RCSLINKFILE) == 0) @ 5.8.2.13 log @Added refdir support and made RCS_link to be a full config file. @ text @a40 3 * Revision 5.8.2.12 1994/02/12 19:20:21 heinz * Support for the new keywords VER, AmigaREV, and AmigaProtection. * d197 1 a197 1 libId(fnmsId, "$Id: rcsfnms.c,v 5.8.2.12 1994/02/12 19:20:21 heinz Exp heinz $") a219 8 /* I do some parsing with the RCS_link file. This helps! */ #include #undef VOID #include #include #undef VOID #define VOID (void) d338 1 a338 4 directory path. There is also support now for special options within the RCS_link file and a reference dir for the last checked in version of a working file. a339 1 char *AMIGA_refdirptr; a365 7 /* We don't have a default reference directory for this yet! */ if(AMIGA_refdirptr) { free(AMIGA_refdirptr); } /* if */ AMIGA_refdirptr = NULL; a410 20 /* If RCS_link is an absolute path, we will only return RCS_link. If it is _not_ absolute we tack it onto the path we got. */ addlen = strchr(buf, ':') ? 0 : dlen; name = malloc(strlen(buf) + addlen + 1); if(name) { memcpy(name, d, addlen); name[addlen] = '\0'; strcat(name, buf); } /* if */ } /* if */ /* Now let us check the reference directory name! */ fgets(buf, 255, fp); s = strchr(buf, '\n'); if(s) { *s = '\0'; d413 6 a418 1 if(buf[0]) d420 3 a422 1 AMIGA_refdirptr = str_dup(buf); d482 1 a482 39 static void AMIGA_ignoreargs(int *argcp, char **argv, char *pattern) { int i; int patl = strlen(pattern) * 2 + 2; char *pat = malloc(patl); if(pat) { if(ParsePatternNoCase(pattern, pat, (LONG)patl) >= 0) { /* First we remove all RCS_link references from the argv vector */ for(i = 1; i < *argcp; i++) { /* If we find an RCS_link reference, we remove it! */ if(argv[i][0] != '-' && MatchPatternNoCase(pat, (STRPTR)basename(argv[i]))) { int j = i; while(j < *argcp) { argv[j] = argv[j+1]; j++; } /* while */ /* One arg less available! */ (*argcp)--; /* Try this slot again! */ i--; } /* if */ } /* for */ } /* if */ free(pat); } /* if */ } /* AMIGA_ignoreargs */ char *AMIGA_handlercslink(int *argcp, char **argv) a487 8 int strnicmp(const char *, const char *, size_t); char *result = NULL; /* First we remove all RCS_link references from the argv vector */ AMIGA_ignoreargs(argcp, argv, RCSLINKFILE); /* Ok, now to the more involved stuff. We check RCS_link for special options that are only for the current directory */ d489 1 d491 2 a492 3 FILE *fp = fopen(RCSLINKFILE, "r"); if(fp) d494 1 a494 2 char buf[BUFSIZ], *s, *d; int l = strlen(argv[0]); d496 5 a500 2 /* Skip the line with a link name! */ fgets(buf, BUFSIZ, fp); d502 2 a503 2 /* Skip the line with a reference dir name! */ fgets(buf, BUFSIZ, fp); d505 2 a506 55 /* Check for an option line that we should use */ if(l) { while(!feof(fp)) { if(fgets(buf, BUFSIZ, fp)) { d = strchr(buf, '\n'); if(d) { *d = 0; } /* if */ /* Look for a line starting with the command name followed by a colon */ if(strnicmp(buf, argv[0], l) == 0 && buf[l] == ':') { s = buf + l + 1; if(*s) { result = str_dup(s); if(result) { break; } /* if */ } /* if */ } else { static const char ign[] = "ignore:"; /* A request to ignore filenames? */ if(strnicmp(buf, ign, sizeof(ign) - 1) == 0) { s = buf + sizeof(ign) - 1; while(*s && isspace(*s)) { s++; } /* while */ if(*s) { AMIGA_ignoreargs(argcp, argv, s); } /* if */ } /* if */ } /* if */ } /* if */ } /* while */ } /* if */ fclose(fp); d508 1 a508 3 } return(result); d510 1 a510 1 } /* AMIGA_handlercslink */ d921 1 a921 1 int strnicmp(const char *, const char *, size_t); @ 5.8.2.14 log @Wrong use of fgets messed up reference dir support. Argh! @ text @a40 3 * Revision 5.8.2.13 1994/03/14 09:21:04 heinz * Added refdir support and made RCS_link to be a full config file. * d200 1 a200 1 libId(fnmsId, "$Id: rcsfnms.c,v 5.8.2.13 1994/03/14 09:21:04 heinz Exp heinz $") d415 1 a415 4 if(!fgets(buf, 255, fp)) { buf[0] = 0; } /* if */ d448 1 a448 5 if(!fgets(buf, 255, fp)) { buf[0] = 0; } /* if */ @ 5.8.2.15 log @Added modula extension .mod and appropriate comment leader. @ text @a40 3 * Revision 5.8.2.14 1994/03/14 10:20:14 heinz * Wrong use of fgets messed up reference dir support. Argh! * d203 1 a203 1 libId(fnmsId, "$Id: rcsfnms.c,v 5.8.2.14 1994/03/14 10:20:14 heinz Exp heinz $") a294 1 "mod", " * ", /* Modula */ @ 5.8.1.1 log @Start of the AMIGA port of RCS 5.6. I call it HWGRCS now ;^) @ text @d2 1 a2 1 * RCS file name handling d5 3 a7 3 * creation and deletion of /tmp temporaries * pairing of RCS file names and working file names. * Testprogram: define PAIRTEST d78 1 a78 1 * d81 1 a81 1 * d85 1 a85 1 * d89 1 a89 1 * d92 1 a92 1 * d95 1 a95 1 * d98 1 a98 1 * d101 1 a101 1 * d107 1 a107 1 * d111 1 a111 1 * d114 1 a114 1 * a150 1 #ifndef AMIGA a152 5 #else #ifndef isSLASH int isSLASH(int c); #endif #endif d175 4 a178 4 "asm", ";; ", /* assembler (MS-DOS) */ "bat", ":: ", /* batch (MS-DOS) */ "c", " * ", /* C */ "c++", "// ", /* C++ in all its infinite guises */ d183 3 a185 3 "cmd", ":: ", /* command (OS/2) */ "cmf", "c ", /* CM Fortran */ "cs", " * ", /* C* */ d189 2 a190 2 "h", " * ", /* C-header */ "hpp", "// ", /* C++ header */ d192 4 a195 4 "l", " * ", /* lex NOTE: conflict between lex and franzlisp */ "lisp",";;; ", /* Lucid Lisp */ "lsp", ";; ", /* Microsoft Lisp */ "mac", ";; ", /* macro (DEC-10, MS-DOS, PDP-11, VMS, etc) */ d202 3 a204 9 "pl", "% ", /* Prolog */ "tex", "% ", /* TeX */ "y", " * ", /* yacc */ #ifdef AMIGA "fd", "* ", /* function description files */ "a", "* ", /* assembler */ "asm", "* ", /* assembler */ "i", "* ", /* assembler include */ #endif a207 76 #ifdef AMIGA static char * str_dup(char *s) { char *d = NULL; if(s) { d = malloc(strlen(s) + 1); if(d) { strcpy(d, s); } /* if */ } /* if */ return(d); } /* str_dup */ static char *getrcsdirname(void) { static char const *name; char buf[256]; if(!name) { /* Do we have an RCS_link file that contains the real path name? */ FILE *fp = fopen("RCS_link", "r"); if(fp) { char *s; int l; fgets(buf, 255, fp); s = strchr(buf, '\n'); if(s) { *s = '\0'; } /* if */ l = strlen(buf); if(l) { char c = buf[l-1]; if(c!=':' && c!='/') { buf[l++] = '/'; } /* if */ } /* if */ name = str_dup(buf); fclose(fp); } /* if */ } /* if */ if(!name) { /* Now lets see if there is some preference */ name = str_dup(getenv("RCS/DIRECTORY")); } /* if */ if(!name) { /* Let's take the default value ... */ name = "RCS/"; } /* if */ return(name); } /* getrcsdirname */ #endif d215 3 a217 3 && !(s = cgetenv("TMPDIR")) /* Unix tradition */ && !(s = cgetenv("TMP")) /* DOS tradition */ && !(s = cgetenv("TEMP")) /* another DOS tradition */ d296 5 a300 5 r = sp; while (*sp) { if (*sp++ == c) r=sp; } return r; d334 1 a334 1 register int i; d337 1 a337 1 StrictLocks=STRICT_LOCKING; d339 3 a341 3 /* guess the comment leader from the suffix*/ Suffix=bindex(workfilename, '.'); if (Suffix==workfilename) Suffix= ""; /* empty suffix; will get default*/ d477 1 a477 1 size_t blen = b->string ? strlen(b->string) : 0; a500 3 #ifdef AMIGA case SLASH: #endif a525 3 #ifdef AMIGA case SLASH: #endif a540 4 #ifdef AMIGA char *rcsdir = getrcsdirname(); size_t rcsdirlen = strlen(rcsdir); #endif a550 8 #ifdef AMIGA if(dl && isSLASH(name[dl-1])) { /* On the Amiga the SLASH or COLON is _included_ in the rcsdir! */ dl++; } /* if */ #endif a623 4 #ifdef AMIGA char *rcsdir = getrcsdirname(); size_t rcsdirlen = strlen(rcsdir); #endif a630 1 #ifndef AMIGA a631 1 #endif d709 1 a709 1 /* first check suffix to see whether it is an RCS file or not */ d712 1 a712 1 /* RCS file name given*/ d730 2 a731 2 } else { /* working file given; now try to find RCS file */ d734 1 a734 1 /* derive RCS file name*/ d746 5 a750 5 } /* now we have a (tentative) RCS filename in RCS1 and workfilename */ /* Second, try to find the right RCS file */ if (pureRCSname!=RCS1) { /* a path for RCSfile is given; single RCS file to look for */ d754 1 a754 1 } else { d762 1 a762 1 /* No RCS file name was given. */ d774 1 a774 1 } d779 3 a781 3 return 0; } Lexinit(); getadmin(); d790 2 a791 2 InitAdmin(); }; d810 1 a810 1 warn("Option -p is set; ignoring output file %s",workfilename); d835 2 a836 2 return(RCSfilename); } else { d856 3 a858 3 /* Check needed because some getwd implementations */ /* generate "/" for the root. */ } d861 2 a862 2 } /*the following must be redone since RCSfilename may change*/ d864 2 a865 4 dotdotcounter =0; realname = RCSfilename; #ifdef AMIGA #else d868 2 a869 2 /* drop leading ./ */ realname += 2; d871 3 a873 3 /* drop leading ../ and remember */ dotdotcounter++; realname += 3; d876 1 a876 2 } #endif d880 1 a880 1 /* move pointer backwards over trailing directory */ d882 3 a884 3 dotdotcounter--; } } d893 1 a893 1 } a901 3 #ifdef AMIGA case SLASH: #endif d1032 1 a1032 1 int result; d1036 2 a1037 2 while(--argc, ++argv, argc>=1 && ((*argv)[0] == '-')) { switch ((*argv)[1]) { d1040 9 a1048 9 break; case 'i': initflag=true; break; case 'q': quietflag=true; break; default: error("unknown option: %s", *argv); break; } } d1050 2 a1051 2 do { RCSfilename=workfilename=nil; d1053 1 a1053 1 if (result!=0) { d1057 7 a1063 7 } switch (result) { case 0: continue; /* already paired file */ case 1: if (initflag) { error("RCS file %s exists already",RCSfilename); } else { d1065 1 a1065 1 } d1067 1 a1067 1 break; d1070 2 a1071 2 break; } d1073 1 a1073 1 } while (++argv, --argc>=1); @ 5.8.1.2 log @A workaround for SAS/C giving EIO instead of ENOENT when accessing a non existant file in a non existant directory. @ text @a40 3 * Revision 5.8.1.1 1993/01/18 14:38:26 heinz * Start of the AMIGA port of RCS 5.6. I call it HWGRCS now ;^) * d143 1 a143 1 libId(fnmsId, "$Id: rcsfnms.c,v 5.8.1.1 1993/01/18 14:38:26 heinz Exp heinz $") a268 1 buf[l] = 0; d281 1 a281 24 char *env = getenv("RCS/DIRECTORY"); if(env) { int l = strlen(env); char *buf = malloc(strlen(env)+1+1); if(buf) { strcpy(buf, env); if(l) { char c = buf[l-1]; if(c!=':' && c!='/') { buf[l++] = '/'; buf[l] = 0; } /* if */ } /* if */ name = buf; } /* if */ } /* if */ a701 9 #ifdef AMIGA /* If we don't have any RCS dir and try some access for RCS/xx SAS/C won't return ENOENT for open() but EIO! So we fake an ENOENT here to keep RCS happy */ if(!finptr && errno == EIO) { errno = ENOENT; } /* if */ #endif @ 5.8.1.3 log @RCS_link works a lot better now. .guide is now recognized for AmigaGuide documents. I want to put the rcs.guide file into RCS, too ;-) @ text @d2 1 a2 1 * RCS file name handling d5 3 a7 3 * creation and deletion of /tmp temporaries * pairing of RCS file names and working file names. * Testprogram: define PAIRTEST a40 4 * Revision 5.8.1.2 1993/01/18 18:15:39 heinz * A workaround for SAS/C giving EIO instead of ENOENT when accessing * a non existant file in a non existant directory. * d146 1 a146 1 libId(fnmsId, "$Id: rcsfnms.c,v 5.8.1.2 1993/01/18 18:15:39 heinz Exp heinz $") a157 6 /* This is the default directory */ #define DEFRCSDIR "RCS/" /* What's the link file called? */ #define RCSLINKFILE "RCS_link" d173 1 a173 1 char const *suffix, *comlead; d182 32 a213 32 "a", "-- ", /* Ada */ "ada", "-- ", "asm", ";; ", /* assembler (MS-DOS) */ "bat", ":: ", /* batch (MS-DOS) */ "c", " * ", /* C */ "c++", "// ", /* C++ in all its infinite guises */ "cc", "// ", "cpp", "// ", "cxx", "// ", "cl", ";;; ", /* Common Lisp */ "cmd", ":: ", /* command (OS/2) */ "cmf", "c ", /* CM Fortran */ "cs", " * ", /* C* */ "el", "; ", /* Emacs Lisp */ "f", "c ", /* Fortran */ "for", "c ", "h", " * ", /* C-header */ "hpp", "// ", /* C++ header */ "hxx", "// ", "l", " * ", /* lex NOTE: conflict between lex and franzlisp */ "lisp",";;; ", /* Lucid Lisp */ "lsp", ";; ", /* Microsoft Lisp */ "mac", ";; ", /* macro (DEC-10, MS-DOS, PDP-11, VMS, etc) */ "me", ".\\\" ",/* me-macros t/nroff*/ "ml", "; ", /* mocklisp */ "mm", ".\\\" ",/* mm-macros t/nroff*/ "ms", ".\\\" ",/* ms-macros t/nroff*/ "p", " * ", /* Pascal */ "pas", " * ", "pl", "% ", /* Prolog */ "tex", "% ", /* TeX */ "y", " * ", /* yacc */ d215 4 a218 5 "fd", "* ", /* function description files */ "a", "* ", /* assembler */ "asm", "* ", /* assembler */ "i", "* ", /* assembler include */ "guide", "@@REMARK ", /* AmigaGuide(R) */ d220 1 a220 1 nil, "# " /* default for unknown suffix; must always be last */ d229 1 a229 1 d = malloc(strlen(s) + 1); d231 4 a234 4 if(d) { strcpy(d, s); } /* if */ d241 1 a241 1 static char *getrcsdirname(char const *d, size_t dlen) d243 1 a243 1 char *name = NULL; a244 2 int fnamelenmax = dlen + sizeof(RCSLINKFILE); char *fnamebuf = malloc(fnamelenmax); d246 1 a246 7 /* First we try d/RCS_link. If this doesn't work we try RCS_link in the current directory. If we find one of them we return the contents. Otherwise we check the environment. If this doesn't work either we return the path we got with the default dir tacked on. */ if(fnamebuf) d248 2 a249 1 FILE *fp; d251 24 a274 48 memcpy(fnamebuf, d, dlen); fnamebuf[dlen] = '\0'; strcat(fnamebuf, RCSLINKFILE); /* Do we have an RCS_link file that contains the real path name? */ fp = fopen(fnamebuf, "r"); if(!fp) { fp = fopen(RCSLINKFILE, "r"); } /* if */ if(fp) { char *s; int l; int addlen; fgets(buf, 255, fp); s = strchr(buf, '\n'); if(s) { *s = '\0'; } /* if */ l = strlen(buf); if(l) { char c = buf[l-1]; if(c!=':' && c!='/') { buf[l++] = '/'; buf[l] = 0; } /* if */ } /* if */ /* If RCS_link is an absolute path, we will only return RCS_link. If it is _not_ absolute we tack it onto the path we got. */ addlen = strchr(buf, ':') ? 0 : dlen; name = malloc(strlen(buf) + addlen + 1); if(name) { memcpy(name, d, addlen); name[addlen] = '\0'; strcat(name, buf); } /* if */ d276 1 a276 2 fclose(fp); } /* if */ d278 2 a279 1 free(fnamebuf); d284 2 a285 2 /* Now lets see if there is some preference */ char *env = getenv("RCS/DIRECTORY"); d287 22 a308 23 if(env) { int l = strlen(env); char *buf = malloc(l + 1 + 1); if(buf) { strcpy(buf, env); if(l) { char c = buf[l-1]; if(c!=':' && c!='/') { buf[l++] = '/'; buf[l] = 0; } /* if */ } /* if */ name = buf; } /* if */ free(env); } /* if */ d313 2 a314 11 /* Uhm, well, we return the path we got + "RCS/". The sizeof includes the +1 we need for the trailing zero */ name = malloc(dlen + sizeof(DEFRCSDIR)); if(name) { memcpy(name, d, dlen); name[dlen] = '\0'; strcat(name, DEFRCSDIR); } /* if */ a316 2 /* If this returns NULL the calling function needs to use DEFRCSDIR. If this is nonzero, don't forget to free() it! */ d324 1 a324 1 static char const * d328 8 a335 8 static char const *s; if (!s && !(s = cgetenv("TMPDIR")) /* Unix tradition */ && !(s = cgetenv("TMP")) /* DOS tradition */ && !(s = cgetenv("TEMP")) /* another DOS tradition */ ) s = TMPDIR; return s; d339 1 a339 1 char const * d341 1 a341 1 int n; d348 2 a349 2 char *p; char const *t = tfnames[n]; d351 2 a352 2 if (t) return t; d354 21 a374 21 catchints(); { # if has_mktemp char const *tp = tmp(); p = testalloc(strlen(tp) + 10); VOID sprintf(p, "%s%cT%cXXXXXX", tp, SLASH, '0'+n); if (!mktemp(p) || !*p) faterror("can't make temporary file name `%s%cT%cXXXXXX'", tp, SLASH, '0'+n ); # else static char tfnamebuf[TEMPNAMES][L_tmpnam]; p = tfnamebuf[n]; if (!tmpnam(p) || !*p) # ifdef P_tmpdir faterror("can't make temporary file name `%s...'",P_tmpdir); # else faterror("can't make temporary file name"); # endif # endif } d376 2 a377 2 tfnames[n] = p; return p; d380 1 a380 1 void d385 2 a386 2 register int i; register char *p; d388 10 a397 10 for (i = TEMPNAMES; 0 <= --i; ) if ((p = tfnames[i])) { VOID unlink(p); /* * We would tfree(p) here, * but this might dump core if we're handing a signal. * We're about to exit anyway, so we won't bother. */ tfnames[i] = 0; } d401 1 a401 1 static char const * d403 2 a404 2 register char const *sp; int ch; d410 6 a415 6 register char const c=ch, *r; r = sp; while (*sp) { if (*sp++ == c) r=sp; } return r; d420 1 a420 1 static int d422 1 a422 1 register char const *suffix, *pattern; d424 17 a440 17 register int c; if (!pattern) return true; for (;;) switch (*suffix++ - (c = *pattern++)) { case 0: if (!c) return true; break; case 'A'-'a': if (ctab[c] == Letter) break; /* fall into */ default: return false; } d444 1 a444 1 static void d448 2 a449 2 register char const *Suffix; register int i; d451 2 a452 2 Head=nil; Dbranch=nil; AccessList=nil; Symbols=nil; Locks=nil; StrictLocks=STRICT_LOCKING; d454 8 a461 8 /* guess the comment leader from the suffix*/ Suffix=bindex(workfilename, '.'); if (Suffix==workfilename) Suffix= ""; /* empty suffix; will get default*/ for (i=0; !suffix_matches(Suffix,comtable[i].suffix); i++) ; Comment.string = comtable[i].comlead; Comment.size = strlen(comtable[i].comlead); Lexinit(); /* note: if !finptr, reads nothing; only initializes */ d466 1 a466 1 # define LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED 0 d468 1 a468 1 # define LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED 1 d473 1 a473 1 # define filenametoolong(path) (NAME_MAX < strlen(basename(path))) d475 1 a475 1 static int d477 1 a477 1 char *path; d480 1 a480 1 static unsigned long dot_namemax; d482 20 a501 20 register size_t namelen; register char *base; register unsigned long namemax; base = path + dirlen(path); namelen = strlen(base); if (namelen <= _POSIX_NAME_MAX) /* fast check for shorties */ return false; if (base != path) { *--base = 0; namemax = pathconf(path, _PC_NAME_MAX); *base = SLASH; } else { /* Cache the results for the working directory, for speed. */ if (!dot_namemax) dot_namemax = pathconf(".", _PC_NAME_MAX); namemax = dot_namemax; } /* If pathconf() yielded -1, namemax is now ULONG_MAX. */ return namemaxsize < size) { if (b->size) tfree(b->string); else b->size = sizeof(malloc_type); while (b->size < size) b->size <<= 1; b->string = tnalloc(char, b->size); } d525 1 a525 1 void d527 2 a528 2 register struct buf *b; size_t size; d531 9 a539 9 if (b->size < size) { if (!b->size) bufalloc(b, size); else { while ((b->size <<= 1) < size) ; b->string = trealloc(char, b->string, b->size); } } d542 1 a542 1 void d544 1 a544 1 struct buf *b; d547 2 a548 2 if (b->size) tfree(b->string); d551 1 a551 1 struct cbuf d553 2 a554 2 struct buf *b; size_t s; d561 1 a561 1 struct cbuf cb; d563 7 a569 7 if ((cb.size = s)) cb.string = fremember(trealloc(char, b->string, s)); else { bufautoend(b); /* not really auto */ cb.string = ""; } return cb; d572 1 a572 1 char * d574 2 a575 2 register struct buf *b; char const **alim; d580 4 a583 4 size_t s = b->size; bufrealloc(b, s + 1); *alim = b->string + b->size; return b->string + s; d586 1 a586 1 void d588 2 a589 2 struct buf *b; char const *s; d592 3 a594 3 size_t blen = b->string ? strlen(b->string) : 0; bufrealloc(b, blen+strlen(s)+1); VOID strcpy(b->string+blen, s); d597 1 a597 1 void d599 2 a600 2 struct buf *b; char const *s; d603 2 a604 2 bufalloc(b, strlen(s)+1); VOID strcpy(b->string, s); d608 1 a608 1 char const * d610 1 a610 1 char const *p; d613 3 a615 3 register char const *b = p, *q = p; for (;;) switch (*q++) { d617 1 a617 1 case SLASH: d619 3 a621 3 case SLASHes: b = q; break; case 0: return b; } d624 1 a624 1 size_t d626 1 a626 1 char const *p; d629 1 a629 1 return basename(p) - p; d633 1 a633 1 static size_t d635 1 a635 1 char const *x; d638 1 a638 1 register char const *p; d640 4 a643 4 p = x; for (;;) switch (*p) { case 0: case SLASHes: d645 1 a645 1 case SLASH: d647 1 a647 1 return p - x; d649 4 a652 4 default: ++p; continue; } d655 1 a655 1 char const * d657 1 a657 1 char const *name; d660 2 a661 2 char const *x, *p, *nz; size_t dl, nl, xl; d663 2 a664 3 char *rcsdircopy = getrcsdirname("", 0); char *rcsdir = (rcsdircopy) ? rcsdircopy : DEFRCSDIR; size_t rcsdirlen = strlen(rcsdir); d667 9 a675 53 nl = strlen(name); nz = name + nl; x = suffixes; do { if ((xl = suffixlen(x))) { if (xl <= nl && memcmp(p = nz-xl, x, xl) == 0) #ifdef AMIGA { if(rcsdircopy) { free(rcsdircopy); } /* if */ return(p); } /* if */ #else return p; #endif } else { /* Well, all of this is a nice try to find the rcs file but with the RCS_link feature of HWGRCS we can't really backtrace a filename without suffix. So this is usually a useless try unless the standard name RCS is used. Nothing I can do about it right now. I haven't invented RCS_link, either, so don't blame it on me. Arghhh, always that compatibility quest ... */ dl = dirlen(name); #ifdef AMIGA if(dl && isSLASH(name[dl-1])) { /* On the Amiga the SLASH or COLON is _included_ in the rcsdir! */ dl++; } /* if */ #endif if ( rcsdirlen < dl && !memcmp(p = name+(dl-=rcsdirlen+1), rcsdir, rcsdirlen) && (!dl || isSLASH(*--p)) ) #ifdef AMIGA { if(rcsdircopy) { free(rcsdircopy); } /* if */ return(nz); } /* if */ #else return nz; #endif } x += xl; } while (*x++); d677 17 a693 6 if(rcsdircopy) { free(rcsdircopy); } /* if */ #endif return 0; d696 1 a696 1 /*ARGSUSED*/ RILE * d698 3 a700 3 struct buf *RCSname; struct stat *status; int mustread; d705 1 a705 1 return Iopen(RCSname->string, FOPEN_R, status); d708 1 a708 1 static int d710 2 a711 2 RILE *(*rcsopen)P((struct buf*,struct stat*,int)); int mustread; d720 1 a720 1 int interesting, preferold; d722 5 a726 5 /* * We prefer an old name to that of a nonexisting new RCS file, * unless we tried locking the old name and failed. */ preferold = RCSbuf.string[0] && (mustread||frewrite); d728 1 a728 1 finptr = (*rcsopen)(&RCSb, &RCSstat, mustread); d730 15 a744 15 /* If we don't have any RCS dir and try some access for RCS/xx SAS/C won't return ENOENT for open() but EIO! So we fake an ENOENT here to keep RCS happy */ if(!finptr && errno == EIO) { errno = ENOENT; } /* if */ #endif interesting = finptr || errno!=ENOENT; if (interesting || !preferold) { /* Use the new name. */ RCSerrno = errno; bufscpy(&RCSbuf, RCSb.string); } return interesting; d747 1 a747 1 static int d749 4 a752 4 char const *d, *base, *x; size_t dlen, baselen, xlen; RILE *(*rcsopen)P((struct buf*,struct stat*,int)); int mustread; d765 1 a765 1 register char *p; d767 5 a771 20 /* getrcsdirname() will return a complete path with a "correct" rcs subdir specifier tacked on or it will replace the path with the "correct" name of the real directory. Service (and slash) included ;-) BTW, the stuff below s ugly but I can't see a way to make it nice */ char *rcsdircopy = getrcsdirname(d, dlen); char *rcsdir = (rcsdircopy) ? rcsdircopy : DEFRCSDIR; size_t rcsdirlen = strlen(rcsdir); bufalloc(&RCSb, rcsdirlen + 1 + baselen + xlen + 1); /* Try rcsdir/basex. */ VOID memcpy(p = RCSb.string, rcsdir, rcsdirlen); p += rcsdirlen; if(rcsdircopy) { free(rcsdircopy); } /* if */ #else bufalloc(&RCSb, dlen + rcsdirlen + 1 + baselen + xlen + 1); d773 6 a778 5 /* Try dRCS/basex. */ VOID memcpy(p = RCSb.string, d, dlen); VOID memcpy(p += dlen, rcsdir, rcsdirlen); p += rcsdirlen; *p++ = SLASH; d780 15 a794 16 VOID memcpy(p, base, baselen); VOID memcpy(p += baselen, x, xlen); p[xlen] = 0; if (xlen) { if (finopen(rcsopen, mustread)) return true; /* Try dbasex. */ /* Start from scratch, because finopen() may have changed RCSb. */ VOID memcpy(p = RCSb.string, d, dlen); VOID memcpy(p += dlen, base, baselen); VOID memcpy(p += baselen, x, xlen); p[xlen] = 0; } return finopen(rcsopen, mustread); d797 1 a797 1 int d799 4 a802 4 int argc; char **argv; RILE *(*rcsopen)P((struct buf*,struct stat*,int)); int mustread, quiet; d821 1 a821 1 static struct buf tempbuf; d823 136 a958 136 register char *p, *arg, *RCS1; char const *purefname, *pureRCSname, *x; int paired; size_t arglen, dlen, baselen, xlen; if (!(arg = *argv)) return 0; /* already paired filename */ if (*arg == '-') { error("%s option is ignored after file names", arg); return 0; } purefname = basename(arg); /* Allocate buffer temporary to hold the default paired file name. */ p = arg; for (;;) { switch (*p++) { /* Beware characters that cause havoc with ci -k. */ case KDELIM: error("RCS file name `%s' contains %c", arg, KDELIM); return 0; case ' ': case '\n': case '\t': error("RCS file name `%s' contains white space", arg); return 0; default: continue; case 0: break; } break; } paired = false; /* first check suffix to see whether it is an RCS file or not */ if ((x = rcssuffix(arg))) { /* RCS file name given*/ RCS1 = arg; pureRCSname = purefname; baselen = x - purefname; if ( 1 < argc && !rcssuffix(workfilename = p = argv[1]) && baselen <= (arglen = strlen(p)) && ((p+=arglen-baselen) == workfilename || isSLASH(p[-1])) && memcmp(purefname, p, baselen) == 0 ) { argv[1] = 0; paired = true; } else { bufscpy(&tempbuf, purefname); workfilename = p = tempbuf.string; p[baselen] = 0; } } else { /* working file given; now try to find RCS file */ workfilename = arg; baselen = p - purefname - 1; /* derive RCS file name*/ if ( 1 < argc && (x = rcssuffix(RCS1 = argv[1])) && baselen <= x - RCS1 && ((pureRCSname=x-baselen)==RCS1 || isSLASH(pureRCSname[-1])) && memcmp(purefname, pureRCSname, baselen) == 0 ) { argv[1] = 0; paired = true; } else pureRCSname = RCS1 = 0; } /* now we have a (tentative) RCS filename in RCS1 and workfilename */ /* Second, try to find the right RCS file */ if (pureRCSname!=RCS1) { /* a path for RCSfile is given; single RCS file to look for */ bufscpy(&RCSbuf, RCS1); finptr = (*rcsopen)(&RCSbuf, &RCSstat, mustread); RCSerrno = errno; } else { bufscpy(&RCSbuf, ""); if (RCS1) /* RCS file name was given without path. */ VOID fin2open(arg, (size_t)0, pureRCSname, baselen, x, strlen(x), rcsopen, mustread ); else { /* No RCS file name was given. */ /* Try each suffix in turn. */ dlen = purefname-arg; x = suffixes; while (! fin2open(arg, dlen, purefname, baselen, x, xlen=suffixlen(x), rcsopen, mustread )) { x += xlen; if (!*x++) break; } } } RCSfilename = p = RCSbuf.string; if (finptr) { if (!S_ISREG(RCSstat.st_mode)) { error("%s isn't a regular file -- ignored", p); return 0; } Lexinit(); getadmin(); } else { if (RCSerrno!=ENOENT || mustread || !frewrite) { if (RCSerrno == EEXIST) error("RCS file %s is in use", p); else if (!quiet || RCSerrno!=ENOENT) enerror(RCSerrno, p); return 0; } InitAdmin(); }; # if LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED if (filenametoolong(p)) { error("RCS file name %s is too long", p); return 0; } # ifndef NAME_MAX /* * Check workfilename too, even though it cannot be longer, * because it may reside on a different filesystem. */ if (filenametoolong(workfilename)) { error("working file name %s is too long", workfilename); return 0; } # endif # endif if (paired && workstdout) warn("Option -p is set; ignoring output file %s",workfilename); d960 2 a961 2 prevkeys = false; return finptr ? 1 : -1; d965 1 a965 1 char const * d972 42 a1013 42 static char const *wdptr; static struct buf rcsbuf, wdbuf; static size_t pathlength; register char const *realname; register size_t parentdirlength; register unsigned dotdotcounter; register char *d; register char const *wd; if (ROOTPATH(RCSfilename)) { return(RCSfilename); } else { if (!(wd = wdptr)) { /* Get working directory for the first time. */ if (!(d = cgetenv("PWD"))) { bufalloc(&wdbuf, SIZEABLE_PATH + 1); # if !has_getcwd && has_getwd d = getwd(wdbuf.string); # else while ( !(d = getcwd(wdbuf.string, wdbuf.size)) && errno==ERANGE ) bufalloc(&wdbuf, wdbuf.size<<1); # endif if (!d) efaterror("working directory"); } parentdirlength = strlen(d); while (parentdirlength && isSLASH(d[parentdirlength-1])) { d[--parentdirlength] = 0; /* Check needed because some getwd implementations */ /* generate "/" for the root. */ } wdptr = wd = d; pathlength = parentdirlength; } /*the following must be redone since RCSfilename may change*/ /* Find how many `../'s to remove from RCSfilename. */ dotdotcounter =0; realname = RCSfilename; d1016 29 a1044 29 while (realname[0]=='.') { if (isSLASH(realname[1])) { /* drop leading ./ */ realname += 2; } else if (realname[1]=='.' && isSLASH(realname[2])) { /* drop leading ../ and remember */ dotdotcounter++; realname += 3; } else break; } #endif /* Now remove dotdotcounter trailing directories from wd. */ parentdirlength = pathlength; while (dotdotcounter && parentdirlength) { /* move pointer backwards over trailing directory */ if (isSLASH(wd[--parentdirlength])) { dotdotcounter--; } } /* build full path name */ bufalloc(&rcsbuf, parentdirlength+strlen(realname)+2); d = rcsbuf.string; VOID memcpy(d, wd, parentdirlength); d += parentdirlength; *d++ = SLASH; VOID strcpy(d, realname); return rcsbuf.string; } d1048 1 a1048 1 int d1050 1 a1050 1 int c; d1052 1 a1052 1 switch (c) { d1054 1 a1054 1 case SLASH: d1056 5 a1060 5 case SLASHes: return true; default: return false; } d1067 1 a1067 1 char * d1069 2 a1070 2 char *path; size_t size; d1072 2 a1073 2 static char const usrbinpwd[] = "/usr/bin/pwd"; # define binpwd (usrbinpwd+4) d1075 99 a1173 99 register FILE *fp; register int c; register char *p, *lim; int closeerrno, closeerror, e, fd[2], readerror, toolong, wstatus; pid_t child; # if !has_waitpid pid_t w; # endif if (!size) { errno = EINVAL; return 0; } if (pipe(fd) != 0) return 0; if (!(child = vfork())) { if ( close(fd[0]) == 0 && (fd[1] == STDOUT_FILENO || # ifdef F_DUPFD (VOID close(STDOUT_FILENO), fcntl(fd[1], F_DUPFD, STDOUT_FILENO)) # else dup2(fd[1], STDOUT_FILENO) # endif == STDOUT_FILENO && close(fd[1]) == 0 ) ) { VOID close(STDERR_FILENO); VOID execl(binpwd, binpwd, (char *)0); VOID execl(usrbinpwd, usrbinpwd, (char *)0); } _exit(EXIT_FAILURE); } e = errno; closeerror = close(fd[1]); closeerrno = errno; fp = 0; readerror = toolong = wstatus = 0; p = path; if (0 <= child) { fp = fdopen(fd[0], "r"); e = errno; if (fp) { lim = p + size; for (p = path; ; *p++ = c) { if ((c=getc(fp)) < 0) { if (feof(fp)) break; if (ferror(fp)) { readerror = 1; e = errno; break; } } if (p == lim) { toolong = 1; break; } } } # if has_waitpid if (waitpid(child, &wstatus, 0) < 0) wstatus = 1; # else do { if ((w = wait(&wstatus)) < 0) { wstatus = 1; break; } } while (w != child); # endif } if (!fp) { VOID close(fd[0]); errno = e; return 0; } if (fclose(fp) != 0) return 0; if (readerror) { errno = e; return 0; } if (closeerror) { errno = closeerrno; return 0; } if (toolong) { errno = ERANGE; return 0; } if (wstatus || p == path || *--p != '\n') { errno = EACCES; return 0; } *p = '\0'; return path; d1186 40 a1225 40 int result; int initflag; quietflag = initflag = false; while(--argc, ++argv, argc>=1 && ((*argv)[0] == '-')) { switch ((*argv)[1]) { case 'p': workstdout = stdout; 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,rcsreadopen,!initflag,quietflag); if (result!=0) { diagnose("RCS file: %s; working file: %s\nFull RCS file name: %s\n", RCSfilename,workfilename,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\n",RCSfilename); } Ifclose(finptr); break; case -1:diagnose("RCS file doesn't exist\n"); break; } d1227 1 a1227 1 } while (++argv, --argc>=1); d1231 1 a1231 1 exiting void d1234 3 a1236 3 dirtempunlink(); tempunlink(); _exit(EXIT_FAILURE); @