head	5.8;
branch	5.8.2;
access;
symbols
	HWGRCSP12F:5.8.2.16
	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	5.8.2.16;

5.8.2.16
date	94.10.09.17.14.11;	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 namemax<namelen;
}
#endif
#endif

	void
bufalloc(b, size)
	register struct buf *b;
	size_t size;
/* Ensure *B is a name buffer of at least SIZE bytes.
 * *B's old contents can be freed; *B's new contents are undefined.
 */
{
	if (b->size < 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 namemax<namelen;
d391 1
a391 1
        void
d393 2
a394 2
        register struct buf *b;
        size_t size;
d399 9
a407 9
        if (b->size < 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 <ctype.h>
#undef VOID
#include <dos/dosasl.h>
#include <proto/dos.h>
#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.2.16
log
@getfullRCSname had an enforcer hit on second invocation.
@
text
@a40 3
 * Revision 5.8.2.15  1994/03/31  16:48:30  heinz
 * Added modula extension .mod and appropriate comment leader.
 *
d206 1
a206 1
libId(fnmsId, "$Id: rcsfnms.c,v 5.8.2.15 1994/03/31 16:48:30 heinz Exp heinz $")
d1540 1
a1540 2
                parentdirlength = pathlength;
                if(parentdirlength && isSLASH(wd[parentdirlength-1]))
@


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 namemax<namelen;
d506 1
a506 1
        void
d508 2
a509 2
        register struct buf *b;
        size_t size;
d514 9
a522 9
        if (b->size < 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);
@
