15b4e6cb2Sbostic /*
25b4e6cb2Sbostic * RCS file name handling
35b4e6cb2Sbostic */
45b4e6cb2Sbostic /****************************************************************************
55b4e6cb2Sbostic * creation and deletion of /tmp temporaries
65b4e6cb2Sbostic * pairing of RCS file names and working file names.
75b4e6cb2Sbostic * Testprogram: define PAIRTEST
85b4e6cb2Sbostic ****************************************************************************
95b4e6cb2Sbostic */
105b4e6cb2Sbostic
115b4e6cb2Sbostic /* Copyright (C) 1982, 1988, 1989 Walter Tichy
125b4e6cb2Sbostic Copyright 1990, 1991 by Paul Eggert
135b4e6cb2Sbostic Distributed under license by the Free Software Foundation, Inc.
145b4e6cb2Sbostic
155b4e6cb2Sbostic This file is part of RCS.
165b4e6cb2Sbostic
175b4e6cb2Sbostic RCS is free software; you can redistribute it and/or modify
185b4e6cb2Sbostic it under the terms of the GNU General Public License as published by
195b4e6cb2Sbostic the Free Software Foundation; either version 2, or (at your option)
205b4e6cb2Sbostic any later version.
215b4e6cb2Sbostic
225b4e6cb2Sbostic RCS is distributed in the hope that it will be useful,
235b4e6cb2Sbostic but WITHOUT ANY WARRANTY; without even the implied warranty of
245b4e6cb2Sbostic MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
255b4e6cb2Sbostic GNU General Public License for more details.
265b4e6cb2Sbostic
275b4e6cb2Sbostic You should have received a copy of the GNU General Public License
285b4e6cb2Sbostic along with RCS; see the file COPYING. If not, write to
295b4e6cb2Sbostic the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
305b4e6cb2Sbostic
315b4e6cb2Sbostic Report problems and direct all questions to:
325b4e6cb2Sbostic
335b4e6cb2Sbostic rcs-bugs@cs.purdue.edu
345b4e6cb2Sbostic
355b4e6cb2Sbostic */
365b4e6cb2Sbostic
375b4e6cb2Sbostic
385b4e6cb2Sbostic
395b4e6cb2Sbostic
405b4e6cb2Sbostic /* $Log: rcsfnms.c,v $
415b4e6cb2Sbostic * Revision 5.8 1991/09/24 00:28:40 eggert
425b4e6cb2Sbostic * Don't export bindex().
435b4e6cb2Sbostic *
445b4e6cb2Sbostic * Revision 5.7 1991/08/19 03:13:55 eggert
455b4e6cb2Sbostic * Fix messages when rcswriteopen fails.
465b4e6cb2Sbostic * Look in $TMP and $TEMP if $TMPDIR isn't set. Tune.
475b4e6cb2Sbostic *
485b4e6cb2Sbostic * Revision 5.6 1991/04/21 11:58:23 eggert
495b4e6cb2Sbostic * Fix errno bugs. Add -x, RCSINIT, MS-DOS support.
505b4e6cb2Sbostic *
515b4e6cb2Sbostic * Revision 5.5 1991/02/26 17:48:38 eggert
525b4e6cb2Sbostic * Fix setuid bug. Support new link behavior.
535b4e6cb2Sbostic * Define more portable getcwd().
545b4e6cb2Sbostic *
555b4e6cb2Sbostic * Revision 5.4 1990/11/01 05:03:43 eggert
565b4e6cb2Sbostic * Permit arbitrary data in comment leaders.
575b4e6cb2Sbostic *
585b4e6cb2Sbostic * Revision 5.3 1990/09/14 22:56:16 hammer
595b4e6cb2Sbostic * added more filename extensions and their comment leaders
605b4e6cb2Sbostic *
615b4e6cb2Sbostic * Revision 5.2 1990/09/04 08:02:23 eggert
625b4e6cb2Sbostic * Fix typo when !RCSSEP.
635b4e6cb2Sbostic *
645b4e6cb2Sbostic * Revision 5.1 1990/08/29 07:13:59 eggert
655b4e6cb2Sbostic * Work around buggy compilers with defective argument promotion.
665b4e6cb2Sbostic *
675b4e6cb2Sbostic * Revision 5.0 1990/08/22 08:12:50 eggert
685b4e6cb2Sbostic * Ignore signals when manipulating the semaphore file.
695b4e6cb2Sbostic * Modernize list of file name extensions.
705b4e6cb2Sbostic * Permit paths of arbitrary length. Beware file names beginning with "-".
715b4e6cb2Sbostic * Remove compile-time limits; use malloc instead.
725b4e6cb2Sbostic * Permit dates past 1999/12/31. Make lock and temp files faster and safer.
735b4e6cb2Sbostic * Ansify and Posixate.
745b4e6cb2Sbostic * Don't use access(). Fix test for non-regular files. Tune.
755b4e6cb2Sbostic *
765b4e6cb2Sbostic * Revision 4.8 89/05/01 15:09:41 narten
775b4e6cb2Sbostic * changed getwd to not stat empty directories.
785b4e6cb2Sbostic *
795b4e6cb2Sbostic * Revision 4.7 88/08/09 19:12:53 eggert
805b4e6cb2Sbostic * Fix troff macro comment leader bug; add Prolog; allow cc -R; remove lint.
815b4e6cb2Sbostic *
825b4e6cb2Sbostic * Revision 4.6 87/12/18 11:40:23 narten
835b4e6cb2Sbostic * additional file types added from 4.3 BSD version, and SPARC assembler
845b4e6cb2Sbostic * comment character added. Also, more lint cleanups. (Guy Harris)
855b4e6cb2Sbostic *
865b4e6cb2Sbostic * Revision 4.5 87/10/18 10:34:16 narten
875b4e6cb2Sbostic * Updating version numbers. Changes relative to 1.1 actually relative
885b4e6cb2Sbostic * to verion 4.3
895b4e6cb2Sbostic *
905b4e6cb2Sbostic * Revision 1.3 87/03/27 14:22:21 jenkins
915b4e6cb2Sbostic * Port to suns
925b4e6cb2Sbostic *
935b4e6cb2Sbostic * Revision 1.2 85/06/26 07:34:28 svb
945b4e6cb2Sbostic * Comment leader '% ' for '*.tex' files added.
955b4e6cb2Sbostic *
965b4e6cb2Sbostic * Revision 4.3 83/12/15 12:26:48 wft
975b4e6cb2Sbostic * Added check for KDELIM in file names to pairfilenames().
985b4e6cb2Sbostic *
995b4e6cb2Sbostic * Revision 4.2 83/12/02 22:47:45 wft
1005b4e6cb2Sbostic * Added csh, red, and sl file name suffixes.
1015b4e6cb2Sbostic *
1025b4e6cb2Sbostic * Revision 4.1 83/05/11 16:23:39 wft
1035b4e6cb2Sbostic * Added initialization of Dbranch to InitAdmin(). Canged pairfilenames():
1045b4e6cb2Sbostic * 1. added copying of path from workfile to RCS file, if RCS file is omitted;
1055b4e6cb2Sbostic * 2. added getting the file status of RCS and working files;
1065b4e6cb2Sbostic * 3. added ignoring of directories.
1075b4e6cb2Sbostic *
1085b4e6cb2Sbostic * Revision 3.7 83/05/11 15:01:58 wft
1095b4e6cb2Sbostic * Added comtable[] which pairs file name suffixes with comment leaders;
1105b4e6cb2Sbostic * updated InitAdmin() accordingly.
1115b4e6cb2Sbostic *
1125b4e6cb2Sbostic * Revision 3.6 83/04/05 14:47:36 wft
1135b4e6cb2Sbostic * fixed Suffix in InitAdmin().
1145b4e6cb2Sbostic *
1155b4e6cb2Sbostic * Revision 3.5 83/01/17 18:01:04 wft
1165b4e6cb2Sbostic * Added getwd() and rename(); these can be removed by defining
1175b4e6cb2Sbostic * V4_2BSD, since they are not needed in 4.2 bsd.
1185b4e6cb2Sbostic * Changed sys/param.h to sys/types.h.
1195b4e6cb2Sbostic *
1205b4e6cb2Sbostic * Revision 3.4 82/12/08 21:55:20 wft
1215b4e6cb2Sbostic * removed unused variable.
1225b4e6cb2Sbostic *
1235b4e6cb2Sbostic * Revision 3.3 82/11/28 20:31:37 wft
1245b4e6cb2Sbostic * Changed mktempfile() to store the generated file names.
1255b4e6cb2Sbostic * Changed getfullRCSname() to store the file and pathname, and to
1265b4e6cb2Sbostic * delete leading "../" and "./".
1275b4e6cb2Sbostic *
1285b4e6cb2Sbostic * Revision 3.2 82/11/12 14:29:40 wft
1295b4e6cb2Sbostic * changed pairfilenames() to handle file.sfx,v; also deleted checkpathnosfx(),
1305b4e6cb2Sbostic * checksuffix(), checkfullpath(). Semaphore name generation updated.
1315b4e6cb2Sbostic * mktempfile() now checks for nil path; freefilename initialized properly.
1325b4e6cb2Sbostic * Added Suffix .h to InitAdmin. Added testprogram PAIRTEST.
1335b4e6cb2Sbostic * Moved rmsema, trysema, trydiraccess, getfullRCSname from rcsutil.c to here.
1345b4e6cb2Sbostic *
1355b4e6cb2Sbostic * Revision 3.1 82/10/18 14:51:28 wft
1365b4e6cb2Sbostic * InitAdmin() now initializes StrictLocks=STRICT_LOCKING (def. in rcsbase.h).
1375b4e6cb2Sbostic * renamed checkpath() to checkfullpath().
1385b4e6cb2Sbostic */
1395b4e6cb2Sbostic
1405b4e6cb2Sbostic
1415b4e6cb2Sbostic #include "rcsbase.h"
1425b4e6cb2Sbostic
1435b4e6cb2Sbostic libId(fnmsId, "$Id: rcsfnms.c,v 5.8 1991/09/24 00:28:40 eggert Exp $")
1445b4e6cb2Sbostic
1455b4e6cb2Sbostic char const *RCSfilename;
1465b4e6cb2Sbostic char *workfilename;
1475b4e6cb2Sbostic FILE *workstdout;
1485b4e6cb2Sbostic struct stat RCSstat;
1495b4e6cb2Sbostic char const *suffixes;
1505b4e6cb2Sbostic
1515b4e6cb2Sbostic static char const rcsdir[] = "RCS";
1525b4e6cb2Sbostic #define rcsdirlen (sizeof(rcsdir)-1)
1535b4e6cb2Sbostic
1545b4e6cb2Sbostic static struct buf RCSbuf, RCSb;
1555b4e6cb2Sbostic static int RCSerrno;
1565b4e6cb2Sbostic
1575b4e6cb2Sbostic
1585b4e6cb2Sbostic /* Temp file names to be unlinked when done, if they are not nil. */
1595b4e6cb2Sbostic #define TEMPNAMES 5 /* must be at least DIRTEMPNAMES (see rcsedit.c) */
1605b4e6cb2Sbostic static char *volatile tfnames[TEMPNAMES];
1615b4e6cb2Sbostic
1625b4e6cb2Sbostic
1635b4e6cb2Sbostic struct compair {
1645b4e6cb2Sbostic char const *suffix, *comlead;
1655b4e6cb2Sbostic };
1665b4e6cb2Sbostic
1675b4e6cb2Sbostic static struct compair const comtable[] = {
1685b4e6cb2Sbostic /* comtable pairs each filename suffix with a comment leader. The comment */
1695b4e6cb2Sbostic /* leader is placed before each line generated by the $Log keyword. This */
1705b4e6cb2Sbostic /* table is used to guess the proper comment leader from the working file's */
1715b4e6cb2Sbostic /* suffix during initial ci (see InitAdmin()). Comment leaders are needed */
1725b4e6cb2Sbostic /* for languages without multiline comments; for others they are optional. */
1735b4e6cb2Sbostic "a", "-- ", /* Ada */
1745b4e6cb2Sbostic "ada", "-- ",
1755b4e6cb2Sbostic "asm", ";; ", /* assembler (MS-DOS) */
1765b4e6cb2Sbostic "bat", ":: ", /* batch (MS-DOS) */
1775b4e6cb2Sbostic "c", " * ", /* C */
1785b4e6cb2Sbostic "c++", "// ", /* C++ in all its infinite guises */
1795b4e6cb2Sbostic "cc", "// ",
1805b4e6cb2Sbostic "cpp", "// ",
1815b4e6cb2Sbostic "cxx", "// ",
1825b4e6cb2Sbostic "cl", ";;; ", /* Common Lisp */
1835b4e6cb2Sbostic "cmd", ":: ", /* command (OS/2) */
1845b4e6cb2Sbostic "cmf", "c ", /* CM Fortran */
1855b4e6cb2Sbostic "cs", " * ", /* C* */
1865b4e6cb2Sbostic "el", "; ", /* Emacs Lisp */
1875b4e6cb2Sbostic "f", "c ", /* Fortran */
1885b4e6cb2Sbostic "for", "c ",
1895b4e6cb2Sbostic "h", " * ", /* C-header */
1905b4e6cb2Sbostic "hpp", "// ", /* C++ header */
1915b4e6cb2Sbostic "hxx", "// ",
1925b4e6cb2Sbostic "l", " * ", /* lex NOTE: conflict between lex and franzlisp */
1935b4e6cb2Sbostic "lisp",";;; ", /* Lucid Lisp */
1945b4e6cb2Sbostic "lsp", ";; ", /* Microsoft Lisp */
1955b4e6cb2Sbostic "mac", ";; ", /* macro (DEC-10, MS-DOS, PDP-11, VMS, etc) */
1965b4e6cb2Sbostic "me", ".\\\" ",/* me-macros t/nroff*/
1975b4e6cb2Sbostic "ml", "; ", /* mocklisp */
1985b4e6cb2Sbostic "mm", ".\\\" ",/* mm-macros t/nroff*/
1995b4e6cb2Sbostic "ms", ".\\\" ",/* ms-macros t/nroff*/
2005b4e6cb2Sbostic "p", " * ", /* Pascal */
2015b4e6cb2Sbostic "pas", " * ",
2025b4e6cb2Sbostic "pl", "% ", /* Prolog */
2035b4e6cb2Sbostic "tex", "% ", /* TeX */
2045b4e6cb2Sbostic "y", " * ", /* yacc */
2055b4e6cb2Sbostic nil, "# " /* default for unknown suffix; must always be last */
2065b4e6cb2Sbostic };
2075b4e6cb2Sbostic
2085b4e6cb2Sbostic #if has_mktemp
2095b4e6cb2Sbostic static char const *
tmp()2105b4e6cb2Sbostic tmp()
2115b4e6cb2Sbostic /* Yield the name of the tmp directory. */
2125b4e6cb2Sbostic {
2135b4e6cb2Sbostic static char const *s;
2145b4e6cb2Sbostic if (!s
2155b4e6cb2Sbostic && !(s = cgetenv("TMPDIR")) /* Unix tradition */
2165b4e6cb2Sbostic && !(s = cgetenv("TMP")) /* DOS tradition */
2175b4e6cb2Sbostic && !(s = cgetenv("TEMP")) /* another DOS tradition */
2185b4e6cb2Sbostic )
2195b4e6cb2Sbostic s = TMPDIR;
2205b4e6cb2Sbostic return s;
2215b4e6cb2Sbostic }
2225b4e6cb2Sbostic #endif
2235b4e6cb2Sbostic
2245b4e6cb2Sbostic char const *
maketemp(n)2255b4e6cb2Sbostic maketemp(n)
2265b4e6cb2Sbostic int n;
2275b4e6cb2Sbostic /* Create a unique filename using n and the process id and store it
2285b4e6cb2Sbostic * into the nth slot in tfnames.
2295b4e6cb2Sbostic * Because of storage in tfnames, tempunlink() can unlink the file later.
2305b4e6cb2Sbostic * Returns a pointer to the filename created.
2315b4e6cb2Sbostic */
2325b4e6cb2Sbostic {
2335b4e6cb2Sbostic char *p;
2345b4e6cb2Sbostic char const *t = tfnames[n];
2355b4e6cb2Sbostic
2365b4e6cb2Sbostic if (t)
2375b4e6cb2Sbostic return t;
2385b4e6cb2Sbostic
2395b4e6cb2Sbostic catchints();
2405b4e6cb2Sbostic {
2415b4e6cb2Sbostic # if has_mktemp
2425b4e6cb2Sbostic char const *tp = tmp();
2435b4e6cb2Sbostic p = testalloc(strlen(tp) + 10);
2445b4e6cb2Sbostic VOID sprintf(p, "%s%cT%cXXXXXX", tp, SLASH, '0'+n);
2455b4e6cb2Sbostic if (!mktemp(p) || !*p)
2465b4e6cb2Sbostic faterror("can't make temporary file name `%s%cT%cXXXXXX'",
2475b4e6cb2Sbostic tp, SLASH, '0'+n
2485b4e6cb2Sbostic );
2495b4e6cb2Sbostic # else
2505b4e6cb2Sbostic static char tfnamebuf[TEMPNAMES][L_tmpnam];
2515b4e6cb2Sbostic p = tfnamebuf[n];
2525b4e6cb2Sbostic if (!tmpnam(p) || !*p)
2535b4e6cb2Sbostic # ifdef P_tmpdir
2545b4e6cb2Sbostic faterror("can't make temporary file name `%s...'",P_tmpdir);
2555b4e6cb2Sbostic # else
2565b4e6cb2Sbostic faterror("can't make temporary file name");
2575b4e6cb2Sbostic # endif
2585b4e6cb2Sbostic # endif
2595b4e6cb2Sbostic }
2605b4e6cb2Sbostic
2615b4e6cb2Sbostic tfnames[n] = p;
2625b4e6cb2Sbostic return p;
2635b4e6cb2Sbostic }
2645b4e6cb2Sbostic
2655b4e6cb2Sbostic void
tempunlink()2665b4e6cb2Sbostic tempunlink()
2675b4e6cb2Sbostic /* Clean up maketemp() files. May be invoked by signal handler.
2685b4e6cb2Sbostic */
2695b4e6cb2Sbostic {
2705b4e6cb2Sbostic register int i;
2715b4e6cb2Sbostic register char *p;
2725b4e6cb2Sbostic
2735b4e6cb2Sbostic for (i = TEMPNAMES; 0 <= --i; )
2745b4e6cb2Sbostic if ((p = tfnames[i])) {
2755b4e6cb2Sbostic VOID unlink(p);
2765b4e6cb2Sbostic /*
2775b4e6cb2Sbostic * We would tfree(p) here,
2785b4e6cb2Sbostic * but this might dump core if we're handing a signal.
2795b4e6cb2Sbostic * We're about to exit anyway, so we won't bother.
2805b4e6cb2Sbostic */
2815b4e6cb2Sbostic tfnames[i] = 0;
2825b4e6cb2Sbostic }
2835b4e6cb2Sbostic }
2845b4e6cb2Sbostic
2855b4e6cb2Sbostic
2865b4e6cb2Sbostic static char const *
bindex(sp,ch)2875b4e6cb2Sbostic bindex(sp,ch)
2885b4e6cb2Sbostic register char const *sp;
2895b4e6cb2Sbostic int ch;
2905b4e6cb2Sbostic /* Function: Finds the last occurrence of character c in string sp
2915b4e6cb2Sbostic * and returns a pointer to the character just beyond it. If the
2925b4e6cb2Sbostic * character doesn't occur in the string, sp is returned.
2935b4e6cb2Sbostic */
2945b4e6cb2Sbostic {
2955b4e6cb2Sbostic register char const c=ch, *r;
2965b4e6cb2Sbostic r = sp;
2975b4e6cb2Sbostic while (*sp) {
2985b4e6cb2Sbostic if (*sp++ == c) r=sp;
2995b4e6cb2Sbostic }
3005b4e6cb2Sbostic return r;
3015b4e6cb2Sbostic }
3025b4e6cb2Sbostic
3035b4e6cb2Sbostic
3045b4e6cb2Sbostic
3055b4e6cb2Sbostic static int
suffix_matches(suffix,pattern)3065b4e6cb2Sbostic suffix_matches(suffix, pattern)
3075b4e6cb2Sbostic register char const *suffix, *pattern;
3085b4e6cb2Sbostic {
3095b4e6cb2Sbostic register int c;
3105b4e6cb2Sbostic if (!pattern)
3115b4e6cb2Sbostic return true;
3125b4e6cb2Sbostic for (;;)
3135b4e6cb2Sbostic switch (*suffix++ - (c = *pattern++)) {
3145b4e6cb2Sbostic case 0:
3155b4e6cb2Sbostic if (!c)
3165b4e6cb2Sbostic return true;
3175b4e6cb2Sbostic break;
3185b4e6cb2Sbostic
3195b4e6cb2Sbostic case 'A'-'a':
3205b4e6cb2Sbostic if (ctab[c] == Letter)
3215b4e6cb2Sbostic break;
3225b4e6cb2Sbostic /* fall into */
3235b4e6cb2Sbostic default:
3245b4e6cb2Sbostic return false;
3255b4e6cb2Sbostic }
3265b4e6cb2Sbostic }
3275b4e6cb2Sbostic
3285b4e6cb2Sbostic
3295b4e6cb2Sbostic static void
InitAdmin()3305b4e6cb2Sbostic InitAdmin()
3315b4e6cb2Sbostic /* function: initializes an admin node */
3325b4e6cb2Sbostic {
3335b4e6cb2Sbostic register char const *Suffix;
3345b4e6cb2Sbostic register int i;
3355b4e6cb2Sbostic
3365b4e6cb2Sbostic Head=nil; Dbranch=nil; AccessList=nil; Symbols=nil; Locks=nil;
3375b4e6cb2Sbostic StrictLocks=STRICT_LOCKING;
3385b4e6cb2Sbostic
3395b4e6cb2Sbostic /* guess the comment leader from the suffix*/
3405b4e6cb2Sbostic Suffix=bindex(workfilename, '.');
3415b4e6cb2Sbostic if (Suffix==workfilename) Suffix= ""; /* empty suffix; will get default*/
3425b4e6cb2Sbostic for (i=0; !suffix_matches(Suffix,comtable[i].suffix); i++)
3435b4e6cb2Sbostic ;
3445b4e6cb2Sbostic Comment.string = comtable[i].comlead;
3455b4e6cb2Sbostic Comment.size = strlen(comtable[i].comlead);
3465b4e6cb2Sbostic Lexinit(); /* note: if !finptr, reads nothing; only initializes */
3475b4e6cb2Sbostic }
3485b4e6cb2Sbostic
3495b4e6cb2Sbostic
350*0f30e20fSbostic #if defined(_POSIX_NO_TRUNC)
3515b4e6cb2Sbostic # define LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED 0
3525b4e6cb2Sbostic #else
3535b4e6cb2Sbostic # define LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED 1
3545b4e6cb2Sbostic #endif
3555b4e6cb2Sbostic
3565b4e6cb2Sbostic #if LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED
3575b4e6cb2Sbostic #ifdef NAME_MAX
3585b4e6cb2Sbostic # define filenametoolong(path) (NAME_MAX < strlen(basename(path)))
3595b4e6cb2Sbostic #else
3605b4e6cb2Sbostic static int
filenametoolong(path)3615b4e6cb2Sbostic filenametoolong(path)
3625b4e6cb2Sbostic char *path;
3635b4e6cb2Sbostic /* Yield true if the last file name in PATH is too long. */
3645b4e6cb2Sbostic {
3655b4e6cb2Sbostic static unsigned long dot_namemax;
3665b4e6cb2Sbostic
3675b4e6cb2Sbostic register size_t namelen;
3685b4e6cb2Sbostic register char *base;
3695b4e6cb2Sbostic register unsigned long namemax;
3705b4e6cb2Sbostic
3715b4e6cb2Sbostic base = path + dirlen(path);
3725b4e6cb2Sbostic namelen = strlen(base);
3735b4e6cb2Sbostic if (namelen <= _POSIX_NAME_MAX) /* fast check for shorties */
3745b4e6cb2Sbostic return false;
3755b4e6cb2Sbostic if (base != path) {
3765b4e6cb2Sbostic *--base = 0;
3775b4e6cb2Sbostic namemax = pathconf(path, _PC_NAME_MAX);
3785b4e6cb2Sbostic *base = SLASH;
3795b4e6cb2Sbostic } else {
3805b4e6cb2Sbostic /* Cache the results for the working directory, for speed. */
3815b4e6cb2Sbostic if (!dot_namemax)
3825b4e6cb2Sbostic dot_namemax = pathconf(".", _PC_NAME_MAX);
3835b4e6cb2Sbostic namemax = dot_namemax;
3845b4e6cb2Sbostic }
3855b4e6cb2Sbostic /* If pathconf() yielded -1, namemax is now ULONG_MAX. */
3865b4e6cb2Sbostic return namemax<namelen;
3875b4e6cb2Sbostic }
3885b4e6cb2Sbostic #endif
3895b4e6cb2Sbostic #endif
3905b4e6cb2Sbostic
3915b4e6cb2Sbostic void
bufalloc(b,size)3925b4e6cb2Sbostic bufalloc(b, size)
3935b4e6cb2Sbostic register struct buf *b;
3945b4e6cb2Sbostic size_t size;
3955b4e6cb2Sbostic /* Ensure *B is a name buffer of at least SIZE bytes.
3965b4e6cb2Sbostic * *B's old contents can be freed; *B's new contents are undefined.
3975b4e6cb2Sbostic */
3985b4e6cb2Sbostic {
3995b4e6cb2Sbostic if (b->size < size) {
4005b4e6cb2Sbostic if (b->size)
4015b4e6cb2Sbostic tfree(b->string);
4025b4e6cb2Sbostic else
4035b4e6cb2Sbostic b->size = sizeof(malloc_type);
4045b4e6cb2Sbostic while (b->size < size)
4055b4e6cb2Sbostic b->size <<= 1;
4065b4e6cb2Sbostic b->string = tnalloc(char, b->size);
4075b4e6cb2Sbostic }
4085b4e6cb2Sbostic }
4095b4e6cb2Sbostic
4105b4e6cb2Sbostic void
bufrealloc(b,size)4115b4e6cb2Sbostic bufrealloc(b, size)
4125b4e6cb2Sbostic register struct buf *b;
4135b4e6cb2Sbostic size_t size;
4145b4e6cb2Sbostic /* like bufalloc, except *B's old contents, if any, are preserved */
4155b4e6cb2Sbostic {
4165b4e6cb2Sbostic if (b->size < size) {
4175b4e6cb2Sbostic if (!b->size)
4185b4e6cb2Sbostic bufalloc(b, size);
4195b4e6cb2Sbostic else {
4205b4e6cb2Sbostic while ((b->size <<= 1) < size)
4215b4e6cb2Sbostic ;
4225b4e6cb2Sbostic b->string = trealloc(char, b->string, b->size);
4235b4e6cb2Sbostic }
4245b4e6cb2Sbostic }
4255b4e6cb2Sbostic }
4265b4e6cb2Sbostic
4275b4e6cb2Sbostic void
bufautoend(b)4285b4e6cb2Sbostic bufautoend(b)
4295b4e6cb2Sbostic struct buf *b;
4305b4e6cb2Sbostic /* Free an auto buffer at block exit. */
4315b4e6cb2Sbostic {
4325b4e6cb2Sbostic if (b->size)
4335b4e6cb2Sbostic tfree(b->string);
4345b4e6cb2Sbostic }
4355b4e6cb2Sbostic
4365b4e6cb2Sbostic struct cbuf
bufremember(b,s)4375b4e6cb2Sbostic bufremember(b, s)
4385b4e6cb2Sbostic struct buf *b;
4395b4e6cb2Sbostic size_t s;
4405b4e6cb2Sbostic /*
4415b4e6cb2Sbostic * Free the buffer B with used size S.
4425b4e6cb2Sbostic * Yield a cbuf with identical contents.
4435b4e6cb2Sbostic * The cbuf will be reclaimed when this input file is finished.
4445b4e6cb2Sbostic */
4455b4e6cb2Sbostic {
4465b4e6cb2Sbostic struct cbuf cb;
4475b4e6cb2Sbostic
4485b4e6cb2Sbostic if ((cb.size = s))
4495b4e6cb2Sbostic cb.string = fremember(trealloc(char, b->string, s));
4505b4e6cb2Sbostic else {
4515b4e6cb2Sbostic bufautoend(b); /* not really auto */
4525b4e6cb2Sbostic cb.string = "";
4535b4e6cb2Sbostic }
4545b4e6cb2Sbostic return cb;
4555b4e6cb2Sbostic }
4565b4e6cb2Sbostic
4575b4e6cb2Sbostic char *
bufenlarge(b,alim)4585b4e6cb2Sbostic bufenlarge(b, alim)
4595b4e6cb2Sbostic register struct buf *b;
4605b4e6cb2Sbostic char const **alim;
4615b4e6cb2Sbostic /* Make *B larger. Set *ALIM to its new limit, and yield the relocated value
4625b4e6cb2Sbostic * of its old limit.
4635b4e6cb2Sbostic */
4645b4e6cb2Sbostic {
4655b4e6cb2Sbostic size_t s = b->size;
4665b4e6cb2Sbostic bufrealloc(b, s + 1);
4675b4e6cb2Sbostic *alim = b->string + b->size;
4685b4e6cb2Sbostic return b->string + s;
4695b4e6cb2Sbostic }
4705b4e6cb2Sbostic
4715b4e6cb2Sbostic void
bufscat(b,s)4725b4e6cb2Sbostic bufscat(b, s)
4735b4e6cb2Sbostic struct buf *b;
4745b4e6cb2Sbostic char const *s;
4755b4e6cb2Sbostic /* Concatenate S to B's end. */
4765b4e6cb2Sbostic {
4775b4e6cb2Sbostic size_t blen = b->string ? strlen(b->string) : 0;
4785b4e6cb2Sbostic bufrealloc(b, blen+strlen(s)+1);
4795b4e6cb2Sbostic VOID strcpy(b->string+blen, s);
4805b4e6cb2Sbostic }
4815b4e6cb2Sbostic
4825b4e6cb2Sbostic void
bufscpy(b,s)4835b4e6cb2Sbostic bufscpy(b, s)
4845b4e6cb2Sbostic struct buf *b;
4855b4e6cb2Sbostic char const *s;
4865b4e6cb2Sbostic /* Copy S into B. */
4875b4e6cb2Sbostic {
4885b4e6cb2Sbostic bufalloc(b, strlen(s)+1);
4895b4e6cb2Sbostic VOID strcpy(b->string, s);
4905b4e6cb2Sbostic }
4915b4e6cb2Sbostic
4925b4e6cb2Sbostic
4935b4e6cb2Sbostic char const *
basename(p)4945b4e6cb2Sbostic basename(p)
4955b4e6cb2Sbostic char const *p;
4965b4e6cb2Sbostic /* Yield the address of the base filename of the pathname P. */
4975b4e6cb2Sbostic {
4985b4e6cb2Sbostic register char const *b = p, *q = p;
4995b4e6cb2Sbostic for (;;)
5005b4e6cb2Sbostic switch (*q++) {
5015b4e6cb2Sbostic case SLASHes: b = q; break;
5025b4e6cb2Sbostic case 0: return b;
5035b4e6cb2Sbostic }
5045b4e6cb2Sbostic }
5055b4e6cb2Sbostic
5065b4e6cb2Sbostic size_t
dirlen(p)5075b4e6cb2Sbostic dirlen(p)
5085b4e6cb2Sbostic char const *p;
5095b4e6cb2Sbostic /* Yield the length of P's directory, including its trailing SLASH. */
5105b4e6cb2Sbostic {
5115b4e6cb2Sbostic return basename(p) - p;
5125b4e6cb2Sbostic }
5135b4e6cb2Sbostic
5145b4e6cb2Sbostic
5155b4e6cb2Sbostic static size_t
suffixlen(x)5165b4e6cb2Sbostic suffixlen(x)
5175b4e6cb2Sbostic char const *x;
5185b4e6cb2Sbostic /* Yield the length of X, an RCS filename suffix. */
5195b4e6cb2Sbostic {
5205b4e6cb2Sbostic register char const *p;
5215b4e6cb2Sbostic
5225b4e6cb2Sbostic p = x;
5235b4e6cb2Sbostic for (;;)
5245b4e6cb2Sbostic switch (*p) {
5255b4e6cb2Sbostic case 0: case SLASHes:
5265b4e6cb2Sbostic return p - x;
5275b4e6cb2Sbostic
5285b4e6cb2Sbostic default:
5295b4e6cb2Sbostic ++p;
5305b4e6cb2Sbostic continue;
5315b4e6cb2Sbostic }
5325b4e6cb2Sbostic }
5335b4e6cb2Sbostic
5345b4e6cb2Sbostic char const *
rcssuffix(name)5355b4e6cb2Sbostic rcssuffix(name)
5365b4e6cb2Sbostic char const *name;
5375b4e6cb2Sbostic /* Yield the suffix of NAME if it is an RCS filename, 0 otherwise. */
5385b4e6cb2Sbostic {
5395b4e6cb2Sbostic char const *x, *p, *nz;
5405b4e6cb2Sbostic size_t dl, nl, xl;
5415b4e6cb2Sbostic
5425b4e6cb2Sbostic nl = strlen(name);
5435b4e6cb2Sbostic nz = name + nl;
5445b4e6cb2Sbostic x = suffixes;
5455b4e6cb2Sbostic do {
5465b4e6cb2Sbostic if ((xl = suffixlen(x))) {
5475b4e6cb2Sbostic if (xl <= nl && memcmp(p = nz-xl, x, xl) == 0)
5485b4e6cb2Sbostic return p;
5495b4e6cb2Sbostic } else {
5505b4e6cb2Sbostic dl = dirlen(name);
5515b4e6cb2Sbostic if (
5525b4e6cb2Sbostic rcsdirlen < dl &&
5535b4e6cb2Sbostic !memcmp(p = name+(dl-=rcsdirlen+1), rcsdir, rcsdirlen) &&
5545b4e6cb2Sbostic (!dl || isSLASH(*--p))
5555b4e6cb2Sbostic )
5565b4e6cb2Sbostic return nz;
5575b4e6cb2Sbostic }
5585b4e6cb2Sbostic x += xl;
5595b4e6cb2Sbostic } while (*x++);
5605b4e6cb2Sbostic return 0;
5615b4e6cb2Sbostic }
5625b4e6cb2Sbostic
5635b4e6cb2Sbostic /*ARGSUSED*/ RILE *
rcsreadopen(RCSname,status,mustread)5645b4e6cb2Sbostic rcsreadopen(RCSname, status, mustread)
5655b4e6cb2Sbostic struct buf *RCSname;
5665b4e6cb2Sbostic struct stat *status;
5675b4e6cb2Sbostic int mustread;
5685b4e6cb2Sbostic /* Open RCSNAME for reading and yield its FILE* descriptor.
5695b4e6cb2Sbostic * If successful, set *STATUS to its status.
5705b4e6cb2Sbostic * Pass this routine to pairfilenames() for read-only access to the file. */
5715b4e6cb2Sbostic {
5725b4e6cb2Sbostic return Iopen(RCSname->string, FOPEN_R, status);
5735b4e6cb2Sbostic }
5745b4e6cb2Sbostic
5755b4e6cb2Sbostic static int
5765b4e6cb2Sbostic finopen(rcsopen, mustread)
5775b4e6cb2Sbostic /* jlf RILE *(*rcsopen)P((struct buf*,struct stat*,int)); */
5785b4e6cb2Sbostic RILE *(*rcsopen)();
5795b4e6cb2Sbostic int mustread;
5805b4e6cb2Sbostic /*
5815b4e6cb2Sbostic * Use RCSOPEN to open an RCS file; MUSTREAD is set if the file must be read.
5825b4e6cb2Sbostic * Set finptr to the result and yield true if successful.
5835b4e6cb2Sbostic * RCSb holds the file's name.
5845b4e6cb2Sbostic * Set RCSbuf to the best RCS name found so far, and RCSerrno to its errno.
5855b4e6cb2Sbostic * Yield true if successful or if an unusual failure.
5865b4e6cb2Sbostic */
5875b4e6cb2Sbostic {
5885b4e6cb2Sbostic int interesting, preferold;
5895b4e6cb2Sbostic
5905b4e6cb2Sbostic /*
5915b4e6cb2Sbostic * We prefer an old name to that of a nonexisting new RCS file,
5925b4e6cb2Sbostic * unless we tried locking the old name and failed.
5935b4e6cb2Sbostic */
5945b4e6cb2Sbostic preferold = RCSbuf.string[0] && (mustread||frewrite);
5955b4e6cb2Sbostic
5965b4e6cb2Sbostic finptr = (*rcsopen)(&RCSb, &RCSstat, mustread);
5975b4e6cb2Sbostic interesting = finptr || errno!=ENOENT;
5985b4e6cb2Sbostic if (interesting || !preferold) {
5995b4e6cb2Sbostic /* Use the new name. */
6005b4e6cb2Sbostic RCSerrno = errno;
6015b4e6cb2Sbostic bufscpy(&RCSbuf, RCSb.string);
6025b4e6cb2Sbostic }
6035b4e6cb2Sbostic return interesting;
6045b4e6cb2Sbostic }
6055b4e6cb2Sbostic
6065b4e6cb2Sbostic static int
fin2open(d,dlen,base,baselen,x,xlen,rcsopen,mustread)6075b4e6cb2Sbostic fin2open(d, dlen, base, baselen, x, xlen, rcsopen, mustread)
6085b4e6cb2Sbostic char const *d, *base, *x;
6095b4e6cb2Sbostic size_t dlen, baselen, xlen;
6105b4e6cb2Sbostic /* jlf RILE *(*rcsopen)P((struct buf*,struct stat*,int)); */
6115b4e6cb2Sbostic RILE *(*rcsopen)();
6125b4e6cb2Sbostic int mustread;
6135b4e6cb2Sbostic /*
6145b4e6cb2Sbostic * D is a directory name with length DLEN (including trailing slash).
6155b4e6cb2Sbostic * BASE is a filename with length BASELEN.
6165b4e6cb2Sbostic * X is an RCS filename suffix with length XLEN.
6175b4e6cb2Sbostic * Use RCSOPEN to open an RCS file; MUSTREAD is set if the file must be read.
6185b4e6cb2Sbostic * Yield true if successful.
6195b4e6cb2Sbostic * Try dRCS/basex first; if that fails and x is nonempty, try dbasex.
6205b4e6cb2Sbostic * Put these potential names in RCSb.
6215b4e6cb2Sbostic * Set RCSbuf to the best RCS name found so far, and RCSerrno to its errno.
6225b4e6cb2Sbostic * Yield true if successful or if an unusual failure.
6235b4e6cb2Sbostic */
6245b4e6cb2Sbostic {
6255b4e6cb2Sbostic register char *p;
6265b4e6cb2Sbostic
6275b4e6cb2Sbostic bufalloc(&RCSb, dlen + rcsdirlen + 1 + baselen + xlen + 1);
6285b4e6cb2Sbostic
6295b4e6cb2Sbostic /* Try dRCS/basex. */
6305b4e6cb2Sbostic VOID memcpy(p = RCSb.string, d, dlen);
6315b4e6cb2Sbostic VOID memcpy(p += dlen, rcsdir, rcsdirlen);
6325b4e6cb2Sbostic p += rcsdirlen;
6335b4e6cb2Sbostic *p++ = SLASH;
6345b4e6cb2Sbostic VOID memcpy(p, base, baselen);
6355b4e6cb2Sbostic VOID memcpy(p += baselen, x, xlen);
6365b4e6cb2Sbostic p[xlen] = 0;
6375b4e6cb2Sbostic if (xlen) {
6385b4e6cb2Sbostic if (finopen(rcsopen, mustread))
6395b4e6cb2Sbostic return true;
6405b4e6cb2Sbostic
6415b4e6cb2Sbostic /* Try dbasex. */
6425b4e6cb2Sbostic /* Start from scratch, because finopen() may have changed RCSb. */
6435b4e6cb2Sbostic VOID memcpy(p = RCSb.string, d, dlen);
6445b4e6cb2Sbostic VOID memcpy(p += dlen, base, baselen);
6455b4e6cb2Sbostic VOID memcpy(p += baselen, x, xlen);
6465b4e6cb2Sbostic p[xlen] = 0;
6475b4e6cb2Sbostic }
6485b4e6cb2Sbostic return finopen(rcsopen, mustread);
6495b4e6cb2Sbostic }
6505b4e6cb2Sbostic
6515b4e6cb2Sbostic int
pairfilenames(argc,argv,rcsopen,mustread,quiet)6525b4e6cb2Sbostic pairfilenames(argc, argv, rcsopen, mustread, quiet)
6535b4e6cb2Sbostic int argc;
6545b4e6cb2Sbostic char **argv;
6555b4e6cb2Sbostic /* jlf RILE *(*rcsopen)P((struct buf*,struct stat*,int)); */
6565b4e6cb2Sbostic RILE *(*rcsopen)();
6575b4e6cb2Sbostic int mustread, quiet;
6585b4e6cb2Sbostic /* Function: Pairs the filenames pointed to by argv; argc indicates
6595b4e6cb2Sbostic * how many there are.
6605b4e6cb2Sbostic * Places a pointer to the RCS filename into RCSfilename,
6615b4e6cb2Sbostic * and a pointer to the name of the working file into workfilename.
6625b4e6cb2Sbostic * If both the workfilename and the RCS filename are given, and workstdout
6635b4e6cb2Sbostic * is set, a warning is printed.
6645b4e6cb2Sbostic *
6655b4e6cb2Sbostic * If the RCS file exists, places its status into RCSstat.
6665b4e6cb2Sbostic *
6675b4e6cb2Sbostic * If the RCS file exists, it is RCSOPENed for reading, the file pointer
6685b4e6cb2Sbostic * is placed into finptr, and the admin-node is read in; returns 1.
6695b4e6cb2Sbostic * If the RCS file does not exist and MUSTREAD,
6705b4e6cb2Sbostic * print an error unless QUIET and return 0.
6715b4e6cb2Sbostic * Otherwise, initialize the admin node and return -1.
6725b4e6cb2Sbostic *
6735b4e6cb2Sbostic * 0 is returned on all errors, e.g. files that are not regular files.
6745b4e6cb2Sbostic */
6755b4e6cb2Sbostic {
6765b4e6cb2Sbostic static struct buf tempbuf;
6775b4e6cb2Sbostic
6785b4e6cb2Sbostic register char *p, *arg, *RCS1;
6795b4e6cb2Sbostic char const *purefname, *pureRCSname, *x;
6805b4e6cb2Sbostic int paired;
6815b4e6cb2Sbostic size_t arglen, dlen, baselen, xlen;
6825b4e6cb2Sbostic
6835b4e6cb2Sbostic if (!(arg = *argv)) return 0; /* already paired filename */
6845b4e6cb2Sbostic if (*arg == '-') {
6855b4e6cb2Sbostic error("%s option is ignored after file names", arg);
6865b4e6cb2Sbostic return 0;
6875b4e6cb2Sbostic }
6885b4e6cb2Sbostic
6895b4e6cb2Sbostic purefname = basename(arg);
6905b4e6cb2Sbostic
6915b4e6cb2Sbostic /* Allocate buffer temporary to hold the default paired file name. */
6925b4e6cb2Sbostic p = arg;
6935b4e6cb2Sbostic for (;;) {
6945b4e6cb2Sbostic switch (*p++) {
6955b4e6cb2Sbostic /* Beware characters that cause havoc with ci -k. */
6965b4e6cb2Sbostic case KDELIM:
6975b4e6cb2Sbostic error("RCS file name `%s' contains %c", arg, KDELIM);
6985b4e6cb2Sbostic return 0;
6995b4e6cb2Sbostic case ' ': case '\n': case '\t':
7005b4e6cb2Sbostic error("RCS file name `%s' contains white space", arg);
7015b4e6cb2Sbostic return 0;
7025b4e6cb2Sbostic default:
7035b4e6cb2Sbostic continue;
7045b4e6cb2Sbostic case 0:
7055b4e6cb2Sbostic break;
7065b4e6cb2Sbostic }
7075b4e6cb2Sbostic break;
7085b4e6cb2Sbostic }
7095b4e6cb2Sbostic
7105b4e6cb2Sbostic paired = false;
7115b4e6cb2Sbostic
7125b4e6cb2Sbostic /* first check suffix to see whether it is an RCS file or not */
7135b4e6cb2Sbostic if ((x = rcssuffix(arg)))
7145b4e6cb2Sbostic {
7155b4e6cb2Sbostic /* RCS file name given*/
7165b4e6cb2Sbostic RCS1 = arg;
7175b4e6cb2Sbostic pureRCSname = purefname;
7185b4e6cb2Sbostic baselen = x - purefname;
7195b4e6cb2Sbostic if (
7205b4e6cb2Sbostic 1 < argc &&
7215b4e6cb2Sbostic !rcssuffix(workfilename = p = argv[1]) &&
7225b4e6cb2Sbostic baselen <= (arglen = strlen(p)) &&
7235b4e6cb2Sbostic ((p+=arglen-baselen) == workfilename || isSLASH(p[-1])) &&
7245b4e6cb2Sbostic memcmp(purefname, p, baselen) == 0
7255b4e6cb2Sbostic ) {
7265b4e6cb2Sbostic argv[1] = 0;
7275b4e6cb2Sbostic paired = true;
7285b4e6cb2Sbostic } else {
7295b4e6cb2Sbostic bufscpy(&tempbuf, purefname);
7305b4e6cb2Sbostic workfilename = p = tempbuf.string;
7315b4e6cb2Sbostic p[baselen] = 0;
7325b4e6cb2Sbostic }
7335b4e6cb2Sbostic } else {
7345b4e6cb2Sbostic /* working file given; now try to find RCS file */
7355b4e6cb2Sbostic workfilename = arg;
7365b4e6cb2Sbostic baselen = p - purefname - 1;
7375b4e6cb2Sbostic /* derive RCS file name*/
7385b4e6cb2Sbostic if (
7395b4e6cb2Sbostic 1 < argc &&
7405b4e6cb2Sbostic (x = rcssuffix(RCS1 = argv[1])) &&
7415b4e6cb2Sbostic baselen <= x - RCS1 &&
7425b4e6cb2Sbostic ((pureRCSname=x-baselen)==RCS1 || isSLASH(pureRCSname[-1])) &&
7435b4e6cb2Sbostic memcmp(purefname, pureRCSname, baselen) == 0
7445b4e6cb2Sbostic ) {
7455b4e6cb2Sbostic argv[1] = 0;
7465b4e6cb2Sbostic paired = true;
7475b4e6cb2Sbostic } else
7485b4e6cb2Sbostic pureRCSname = RCS1 = 0;
7495b4e6cb2Sbostic }
7505b4e6cb2Sbostic /* now we have a (tentative) RCS filename in RCS1 and workfilename */
7515b4e6cb2Sbostic /* Second, try to find the right RCS file */
7525b4e6cb2Sbostic if (pureRCSname!=RCS1) {
7535b4e6cb2Sbostic /* a path for RCSfile is given; single RCS file to look for */
7545b4e6cb2Sbostic bufscpy(&RCSbuf, RCS1);
7555b4e6cb2Sbostic finptr = (*rcsopen)(&RCSbuf, &RCSstat, mustread);
7565b4e6cb2Sbostic RCSerrno = errno;
7575b4e6cb2Sbostic } else {
7585b4e6cb2Sbostic bufscpy(&RCSbuf, "");
7595b4e6cb2Sbostic if (RCS1)
7605b4e6cb2Sbostic /* RCS file name was given without path. */
7615b4e6cb2Sbostic VOID fin2open(arg, (size_t)0, pureRCSname, baselen,
7625b4e6cb2Sbostic x, strlen(x), rcsopen, mustread
7635b4e6cb2Sbostic );
7645b4e6cb2Sbostic else {
7655b4e6cb2Sbostic /* No RCS file name was given. */
7665b4e6cb2Sbostic /* Try each suffix in turn. */
7675b4e6cb2Sbostic dlen = purefname-arg;
7685b4e6cb2Sbostic x = suffixes;
7695b4e6cb2Sbostic while (! fin2open(arg, dlen, purefname, baselen,
7705b4e6cb2Sbostic x, xlen=suffixlen(x), rcsopen, mustread
7715b4e6cb2Sbostic )) {
7725b4e6cb2Sbostic x += xlen;
7735b4e6cb2Sbostic if (!*x++)
7745b4e6cb2Sbostic break;
7755b4e6cb2Sbostic }
7765b4e6cb2Sbostic }
7775b4e6cb2Sbostic }
7785b4e6cb2Sbostic RCSfilename = p = RCSbuf.string;
7795b4e6cb2Sbostic if (finptr) {
7805b4e6cb2Sbostic if (!S_ISREG(RCSstat.st_mode)) {
7815b4e6cb2Sbostic error("%s isn't a regular file -- ignored", p);
7825b4e6cb2Sbostic return 0;
7835b4e6cb2Sbostic }
7845b4e6cb2Sbostic Lexinit(); getadmin();
7855b4e6cb2Sbostic } else {
7865b4e6cb2Sbostic if (RCSerrno!=ENOENT || mustread || !frewrite) {
7875b4e6cb2Sbostic if (RCSerrno == EEXIST)
7885b4e6cb2Sbostic error("RCS file %s is in use", p);
7895b4e6cb2Sbostic else if (!quiet || RCSerrno!=ENOENT)
7905b4e6cb2Sbostic enerror(RCSerrno, p);
7915b4e6cb2Sbostic return 0;
7925b4e6cb2Sbostic }
7935b4e6cb2Sbostic InitAdmin();
7945b4e6cb2Sbostic };
7955b4e6cb2Sbostic # if LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED
7965b4e6cb2Sbostic if (filenametoolong(p)) {
7975b4e6cb2Sbostic error("RCS file name %s is too long", p);
7985b4e6cb2Sbostic return 0;
7995b4e6cb2Sbostic }
8005b4e6cb2Sbostic # ifndef NAME_MAX
8015b4e6cb2Sbostic /*
8025b4e6cb2Sbostic * Check workfilename too, even though it cannot be longer,
8035b4e6cb2Sbostic * because it may reside on a different filesystem.
8045b4e6cb2Sbostic */
8055b4e6cb2Sbostic if (filenametoolong(workfilename)) {
8065b4e6cb2Sbostic error("working file name %s is too long", workfilename);
8075b4e6cb2Sbostic return 0;
8085b4e6cb2Sbostic }
8095b4e6cb2Sbostic # endif
8105b4e6cb2Sbostic # endif
8115b4e6cb2Sbostic
8125b4e6cb2Sbostic if (paired && workstdout)
8135b4e6cb2Sbostic warn("Option -p is set; ignoring output file %s",workfilename);
8145b4e6cb2Sbostic
8155b4e6cb2Sbostic prevkeys = false;
8165b4e6cb2Sbostic return finptr ? 1 : -1;
8175b4e6cb2Sbostic }
8185b4e6cb2Sbostic
8195b4e6cb2Sbostic
8205b4e6cb2Sbostic char const *
getfullRCSname()8215b4e6cb2Sbostic getfullRCSname()
8225b4e6cb2Sbostic /* Function: returns a pointer to the full path name of the RCS file.
8235b4e6cb2Sbostic * Gets the working directory's name at most once.
8245b4e6cb2Sbostic * Removes leading "../" and "./".
8255b4e6cb2Sbostic */
8265b4e6cb2Sbostic {
8275b4e6cb2Sbostic static char const *wdptr;
8285b4e6cb2Sbostic static struct buf rcsbuf, wdbuf;
8295b4e6cb2Sbostic static size_t pathlength;
8305b4e6cb2Sbostic
8315b4e6cb2Sbostic register char const *realname;
8325b4e6cb2Sbostic register size_t parentdirlength;
8335b4e6cb2Sbostic register unsigned dotdotcounter;
8345b4e6cb2Sbostic register char *d;
8355b4e6cb2Sbostic register char const *wd;
8365b4e6cb2Sbostic
8375b4e6cb2Sbostic if (ROOTPATH(RCSfilename)) {
8385b4e6cb2Sbostic return(RCSfilename);
8395b4e6cb2Sbostic } else {
8405b4e6cb2Sbostic if (!(wd = wdptr)) {
8415b4e6cb2Sbostic /* Get working directory for the first time. */
8425b4e6cb2Sbostic if (!(d = cgetenv("PWD"))) {
8435b4e6cb2Sbostic bufalloc(&wdbuf, SIZEABLE_PATH + 1);
8445b4e6cb2Sbostic # if !has_getcwd && has_getwd
8455b4e6cb2Sbostic d = getwd(wdbuf.string);
8465b4e6cb2Sbostic # else
8475b4e6cb2Sbostic while (
8485b4e6cb2Sbostic !(d = getcwd(wdbuf.string, wdbuf.size))
8495b4e6cb2Sbostic && errno==ERANGE
8505b4e6cb2Sbostic )
8515b4e6cb2Sbostic bufalloc(&wdbuf, wdbuf.size<<1);
8525b4e6cb2Sbostic # endif
8535b4e6cb2Sbostic if (!d)
8545b4e6cb2Sbostic efaterror("working directory");
8555b4e6cb2Sbostic }
8565b4e6cb2Sbostic parentdirlength = strlen(d);
8575b4e6cb2Sbostic while (parentdirlength && isSLASH(d[parentdirlength-1])) {
8585b4e6cb2Sbostic d[--parentdirlength] = 0;
8595b4e6cb2Sbostic /* Check needed because some getwd implementations */
8605b4e6cb2Sbostic /* generate "/" for the root. */
8615b4e6cb2Sbostic }
8625b4e6cb2Sbostic wdptr = wd = d;
8635b4e6cb2Sbostic pathlength = parentdirlength;
8645b4e6cb2Sbostic }
8655b4e6cb2Sbostic /*the following must be redone since RCSfilename may change*/
8665b4e6cb2Sbostic /* Find how many `../'s to remove from RCSfilename. */
8675b4e6cb2Sbostic dotdotcounter =0;
8685b4e6cb2Sbostic realname = RCSfilename;
8695b4e6cb2Sbostic while (realname[0]=='.') {
8705b4e6cb2Sbostic if (isSLASH(realname[1])) {
8715b4e6cb2Sbostic /* drop leading ./ */
8725b4e6cb2Sbostic realname += 2;
8735b4e6cb2Sbostic } else if (realname[1]=='.' && isSLASH(realname[2])) {
8745b4e6cb2Sbostic /* drop leading ../ and remember */
8755b4e6cb2Sbostic dotdotcounter++;
8765b4e6cb2Sbostic realname += 3;
8775b4e6cb2Sbostic } else
8785b4e6cb2Sbostic break;
8795b4e6cb2Sbostic }
8805b4e6cb2Sbostic /* Now remove dotdotcounter trailing directories from wd. */
8815b4e6cb2Sbostic parentdirlength = pathlength;
8825b4e6cb2Sbostic while (dotdotcounter && parentdirlength) {
8835b4e6cb2Sbostic /* move pointer backwards over trailing directory */
8845b4e6cb2Sbostic if (isSLASH(wd[--parentdirlength])) {
8855b4e6cb2Sbostic dotdotcounter--;
8865b4e6cb2Sbostic }
8875b4e6cb2Sbostic }
8885b4e6cb2Sbostic /* build full path name */
8895b4e6cb2Sbostic bufalloc(&rcsbuf, parentdirlength+strlen(realname)+2);
8905b4e6cb2Sbostic d = rcsbuf.string;
8915b4e6cb2Sbostic VOID memcpy(d, wd, parentdirlength);
8925b4e6cb2Sbostic d += parentdirlength;
8935b4e6cb2Sbostic *d++ = SLASH;
8945b4e6cb2Sbostic VOID strcpy(d, realname);
8955b4e6cb2Sbostic return rcsbuf.string;
8965b4e6cb2Sbostic }
8975b4e6cb2Sbostic }
8985b4e6cb2Sbostic
8995b4e6cb2Sbostic #ifndef isSLASH
9005b4e6cb2Sbostic int
isSLASH(c)9015b4e6cb2Sbostic isSLASH(c)
9025b4e6cb2Sbostic int c;
9035b4e6cb2Sbostic {
9045b4e6cb2Sbostic switch (c) {
9055b4e6cb2Sbostic case SLASHes:
9065b4e6cb2Sbostic return true;
9075b4e6cb2Sbostic default:
9085b4e6cb2Sbostic return false;
9095b4e6cb2Sbostic }
9105b4e6cb2Sbostic }
9115b4e6cb2Sbostic #endif
9125b4e6cb2Sbostic
9135b4e6cb2Sbostic
9145b4e6cb2Sbostic #if !has_getcwd && !has_getwd
9155b4e6cb2Sbostic
9165b4e6cb2Sbostic char *
getcwd(path,size)9175b4e6cb2Sbostic getcwd(path, size)
9185b4e6cb2Sbostic char *path;
9195b4e6cb2Sbostic size_t size;
9205b4e6cb2Sbostic {
9215b4e6cb2Sbostic static char const usrbinpwd[] = "/usr/bin/pwd";
9225b4e6cb2Sbostic # define binpwd (usrbinpwd+4)
9235b4e6cb2Sbostic
9245b4e6cb2Sbostic register FILE *fp;
9255b4e6cb2Sbostic register int c;
9265b4e6cb2Sbostic register char *p, *lim;
9275b4e6cb2Sbostic int closeerrno, closeerror, e, fd[2], readerror, toolong, wstatus;
9285b4e6cb2Sbostic pid_t child;
9295b4e6cb2Sbostic # if !has_waitpid
9305b4e6cb2Sbostic pid_t w;
9315b4e6cb2Sbostic # endif
9325b4e6cb2Sbostic
9335b4e6cb2Sbostic if (!size) {
9345b4e6cb2Sbostic errno = EINVAL;
9355b4e6cb2Sbostic return 0;
9365b4e6cb2Sbostic }
9375b4e6cb2Sbostic if (pipe(fd) != 0)
9385b4e6cb2Sbostic return 0;
9395b4e6cb2Sbostic if (!(child = vfork())) {
9405b4e6cb2Sbostic if (
9415b4e6cb2Sbostic close(fd[0]) == 0 &&
9425b4e6cb2Sbostic (fd[1] == STDOUT_FILENO ||
9435b4e6cb2Sbostic # ifdef F_DUPFD
9445b4e6cb2Sbostic (VOID close(STDOUT_FILENO),
9455b4e6cb2Sbostic fcntl(fd[1], F_DUPFD, STDOUT_FILENO))
9465b4e6cb2Sbostic # else
9475b4e6cb2Sbostic dup2(fd[1], STDOUT_FILENO)
9485b4e6cb2Sbostic # endif
9495b4e6cb2Sbostic == STDOUT_FILENO &&
9505b4e6cb2Sbostic close(fd[1]) == 0
9515b4e6cb2Sbostic )
9525b4e6cb2Sbostic ) {
9535b4e6cb2Sbostic VOID close(STDERR_FILENO);
9545b4e6cb2Sbostic VOID execl(binpwd, binpwd, (char *)0);
9555b4e6cb2Sbostic VOID execl(usrbinpwd, usrbinpwd, (char *)0);
9565b4e6cb2Sbostic }
9575b4e6cb2Sbostic _exit(EXIT_FAILURE);
9585b4e6cb2Sbostic }
9595b4e6cb2Sbostic e = errno;
9605b4e6cb2Sbostic closeerror = close(fd[1]);
9615b4e6cb2Sbostic closeerrno = errno;
9625b4e6cb2Sbostic fp = 0;
9635b4e6cb2Sbostic readerror = toolong = wstatus = 0;
9645b4e6cb2Sbostic p = path;
9655b4e6cb2Sbostic if (0 <= child) {
9665b4e6cb2Sbostic fp = fdopen(fd[0], "r");
9675b4e6cb2Sbostic e = errno;
9685b4e6cb2Sbostic if (fp) {
9695b4e6cb2Sbostic lim = p + size;
9705b4e6cb2Sbostic for (p = path; ; *p++ = c) {
9715b4e6cb2Sbostic if ((c=getc(fp)) < 0) {
9725b4e6cb2Sbostic if (feof(fp))
9735b4e6cb2Sbostic break;
9745b4e6cb2Sbostic if (ferror(fp)) {
9755b4e6cb2Sbostic readerror = 1;
9765b4e6cb2Sbostic e = errno;
9775b4e6cb2Sbostic break;
9785b4e6cb2Sbostic }
9795b4e6cb2Sbostic }
9805b4e6cb2Sbostic if (p == lim) {
9815b4e6cb2Sbostic toolong = 1;
9825b4e6cb2Sbostic break;
9835b4e6cb2Sbostic }
9845b4e6cb2Sbostic }
9855b4e6cb2Sbostic }
9865b4e6cb2Sbostic # if has_waitpid
9875b4e6cb2Sbostic if (waitpid(child, &wstatus, 0) < 0)
9885b4e6cb2Sbostic wstatus = 1;
9895b4e6cb2Sbostic # else
9905b4e6cb2Sbostic do {
9915b4e6cb2Sbostic if ((w = wait(&wstatus)) < 0) {
9925b4e6cb2Sbostic wstatus = 1;
9935b4e6cb2Sbostic break;
9945b4e6cb2Sbostic }
9955b4e6cb2Sbostic } while (w != child);
9965b4e6cb2Sbostic # endif
9975b4e6cb2Sbostic }
9985b4e6cb2Sbostic if (!fp) {
9995b4e6cb2Sbostic VOID close(fd[0]);
10005b4e6cb2Sbostic errno = e;
10015b4e6cb2Sbostic return 0;
10025b4e6cb2Sbostic }
10035b4e6cb2Sbostic if (fclose(fp) != 0)
10045b4e6cb2Sbostic return 0;
10055b4e6cb2Sbostic if (readerror) {
10065b4e6cb2Sbostic errno = e;
10075b4e6cb2Sbostic return 0;
10085b4e6cb2Sbostic }
10095b4e6cb2Sbostic if (closeerror) {
10105b4e6cb2Sbostic errno = closeerrno;
10115b4e6cb2Sbostic return 0;
10125b4e6cb2Sbostic }
10135b4e6cb2Sbostic if (toolong) {
10145b4e6cb2Sbostic errno = ERANGE;
10155b4e6cb2Sbostic return 0;
10165b4e6cb2Sbostic }
10175b4e6cb2Sbostic if (wstatus || p == path || *--p != '\n') {
10185b4e6cb2Sbostic errno = EACCES;
10195b4e6cb2Sbostic return 0;
10205b4e6cb2Sbostic }
10215b4e6cb2Sbostic *p = '\0';
10225b4e6cb2Sbostic return path;
10235b4e6cb2Sbostic }
10245b4e6cb2Sbostic #endif
10255b4e6cb2Sbostic
10265b4e6cb2Sbostic
10275b4e6cb2Sbostic #ifdef PAIRTEST
10285b4e6cb2Sbostic /* test program for pairfilenames() and getfullRCSname() */
10295b4e6cb2Sbostic
10305b4e6cb2Sbostic char const cmdid[] = "pair";
10315b4e6cb2Sbostic
main(argc,argv)10325b4e6cb2Sbostic main(argc, argv)
10335b4e6cb2Sbostic int argc; char *argv[];
10345b4e6cb2Sbostic {
10355b4e6cb2Sbostic int result;
10365b4e6cb2Sbostic int initflag;
10375b4e6cb2Sbostic quietflag = initflag = false;
10385b4e6cb2Sbostic
10395b4e6cb2Sbostic while(--argc, ++argv, argc>=1 && ((*argv)[0] == '-')) {
10405b4e6cb2Sbostic switch ((*argv)[1]) {
10415b4e6cb2Sbostic
10425b4e6cb2Sbostic case 'p': workstdout = stdout;
10435b4e6cb2Sbostic break;
10445b4e6cb2Sbostic case 'i': initflag=true;
10455b4e6cb2Sbostic break;
10465b4e6cb2Sbostic case 'q': quietflag=true;
10475b4e6cb2Sbostic break;
10485b4e6cb2Sbostic default: error("unknown option: %s", *argv);
10495b4e6cb2Sbostic break;
10505b4e6cb2Sbostic }
10515b4e6cb2Sbostic }
10525b4e6cb2Sbostic
10535b4e6cb2Sbostic do {
10545b4e6cb2Sbostic RCSfilename=workfilename=nil;
10555b4e6cb2Sbostic result = pairfilenames(argc,argv,rcsreadopen,!initflag,quietflag);
10565b4e6cb2Sbostic if (result!=0) {
10575b4e6cb2Sbostic diagnose("RCS file: %s; working file: %s\nFull RCS file name: %s\n",
10585b4e6cb2Sbostic RCSfilename,workfilename,getfullRCSname()
10595b4e6cb2Sbostic );
10605b4e6cb2Sbostic }
10615b4e6cb2Sbostic switch (result) {
10625b4e6cb2Sbostic case 0: continue; /* already paired file */
10635b4e6cb2Sbostic
10645b4e6cb2Sbostic case 1: if (initflag) {
10655b4e6cb2Sbostic error("RCS file %s exists already",RCSfilename);
10665b4e6cb2Sbostic } else {
10675b4e6cb2Sbostic diagnose("RCS file %s exists\n",RCSfilename);
10685b4e6cb2Sbostic }
10695b4e6cb2Sbostic Ifclose(finptr);
10705b4e6cb2Sbostic break;
10715b4e6cb2Sbostic
10725b4e6cb2Sbostic case -1:diagnose("RCS file doesn't exist\n");
10735b4e6cb2Sbostic break;
10745b4e6cb2Sbostic }
10755b4e6cb2Sbostic
10765b4e6cb2Sbostic } while (++argv, --argc>=1);
10775b4e6cb2Sbostic
10785b4e6cb2Sbostic }
10795b4e6cb2Sbostic
10805b4e6cb2Sbostic exiting void
exiterr()10815b4e6cb2Sbostic exiterr()
10825b4e6cb2Sbostic {
10835b4e6cb2Sbostic dirtempunlink();
10845b4e6cb2Sbostic tempunlink();
10855b4e6cb2Sbostic _exit(EXIT_FAILURE);
10865b4e6cb2Sbostic }
10875b4e6cb2Sbostic #endif
1088