This commit is contained in:
kristerw 2002-03-11 23:29:02 +00:00
parent bc84308f58
commit 2b96113ff9
2 changed files with 631 additions and 577 deletions

View File

@ -1,7 +1,7 @@
/* $NetBSD: inp.c,v 1.8 2002/03/11 18:47:51 kristerw Exp $ */
/* $NetBSD: inp.c,v 1.9 2002/03/11 23:29:02 kristerw Exp $ */
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: inp.c,v 1.8 2002/03/11 18:47:51 kristerw Exp $");
__RCSID("$NetBSD: inp.c,v 1.9 2002/03/11 23:29:02 kristerw Exp $");
#endif /* not lint */
#include "EXTERN.h"
@ -16,20 +16,21 @@ __RCSID("$NetBSD: inp.c,v 1.8 2002/03/11 18:47:51 kristerw Exp $");
#include <unistd.h>
#include <fcntl.h>
/* Input-file-with-indexable-lines abstract type */
/* Input-file-with-indexable-lines abstract type. */
static long i_size; /* size of the input file */
static char *i_womp; /* plan a buffer for entire file */
static char **i_ptr; /* pointers to lines in i_womp */
static long i_size; /* Size of the input file */
static char *i_womp; /* Plan a buffer for entire file */
static char **i_ptr; /* Pointers to lines in i_womp */
static int tifd = -1; /* plan b virtual string array */
static char *tibuf[2]; /* plan b buffers */
static int tifd = -1; /* Plan b virtual string array */
static char *tibuf[2]; /* Plan b buffers */
static LINENUM tiline[2] = {-1, -1}; /* 1st line in each buffer */
static LINENUM lines_per_buf; /* how many lines per buffer */
static int tireclen; /* length of records in tmp file */
/* New patch--prepare to edit another file. */
static LINENUM lines_per_buf; /* How many lines per buffer */
static int tireclen; /* Length of records in tmp file */
/*
* New patch--prepare to edit another file.
*/
void
re_input(void)
{
@ -42,8 +43,7 @@ re_input(void)
free(i_womp);
i_womp = NULL;
i_ptr = NULL;
}
else {
} else {
using_plan_a = TRUE; /* maybe the next one is smaller */
Close(tifd);
tifd = -1;
@ -55,8 +55,9 @@ re_input(void)
}
}
/* Constuct the line index, somehow or other. */
/*
* Constuct the line index, somehow or other.
*/
void
scan_input(char *filename)
{
@ -68,8 +69,9 @@ scan_input(char *filename)
}
}
/* Try keeping everything in memory. */
/*
* Try keeping everything in memory.
*/
bool
plan_a(char *filename)
{
@ -86,12 +88,15 @@ plan_a(char *filename)
close(creat(filename, 0666));
statfailed = stat(filename, &filestat);
}
/* For nonexistent or read-only files, look for RCS or SCCS versions. */
if (statfailed
/*
* For nonexistent or read-only files, look for RCS or SCCS
* versions.
*/
if (statfailed ||
/* No one can write to it. */
|| (filestat.st_mode & 0222) == 0
(filestat.st_mode & 0222) == 0 ||
/* I can't write to it. */
|| ((filestat.st_mode & 0022) == 0 && filestat.st_uid != myuid)) {
((filestat.st_mode & 0022) == 0 && filestat.st_uid != myuid)) {
struct stat cstat;
char *cs = NULL;
char *filebase;
@ -100,51 +105,66 @@ plan_a(char *filename)
filebase = basename(filename);
pathlen = filebase - filename;
/* Put any leading path into `s'.
Leave room in lbuf for the diff command. */
/*
* Put any leading path into `s'.
* Leave room in lbuf for the diff command.
*/
s = lbuf + 20;
strncpy(s, filename, pathlen);
#define try(f, a1, a2) (Sprintf(s + pathlen, f, a1, a2), stat(s, &cstat) == 0)
#define try1(f, a1) (Sprintf(s + pathlen, f, a1), stat(s, &cstat) == 0)
if ( try("RCS/%s%s", filebase, RCSSUFFIX)
|| try1("RCS/%s" , filebase)
|| try( "%s%s", filebase, RCSSUFFIX)) {
if (try("RCS/%s%s", filebase, RCSSUFFIX) ||
try1("RCS/%s" , filebase) ||
try("%s%s", filebase, RCSSUFFIX)) {
Sprintf(buf, CHECKOUT, filename);
Sprintf(lbuf, RCSDIFF, filename);
cs = "RCS";
} else if ( try("SCCS/%s%s", SCCSPREFIX, filebase)
|| try( "%s%s", SCCSPREFIX, filebase)) {
} else if (try("SCCS/%s%s", SCCSPREFIX, filebase) ||
try("%s%s", SCCSPREFIX, filebase)) {
Sprintf(buf, GET, s);
Sprintf(lbuf, SCCSDIFF, s, filename);
cs = "SCCS";
} else if (statfailed)
fatal("can't find %s\n", filename);
/* else we can't write to it but it's not under a version
control system, so just proceed. */
/*
* else we can't write to it but it's not under a version
* control system, so just proceed.
*/
if (cs) {
if (!statfailed) {
if ((filestat.st_mode & 0222) != 0)
/* The owner can write to it. */
fatal("file %s seems to be locked by somebody else under %s\n",
fatal(
"file %s seems to be locked by somebody else under %s\n",
filename, cs);
/* It might be checked out unlocked. See if it's safe to
check out the default version locked. */
/*
* It might be checked out unlocked. See if
* it's safe to check out the default version
* locked.
*/
if (verbose)
say("Comparing file %s to default %s version...\n",
say(
"Comparing file %s to default %s version...\n",
filename, cs);
if (system(lbuf))
fatal("can't check out file %s: differs from default %s version\n",
fatal(
"can't check out file %s: differs from default %s version\n",
filename, cs);
}
if (verbose)
say("Checking out file %s from %s...\n", filename, cs);
say("Checking out file %s from %s...\n",
filename, cs);
if (system(buf) || stat(filename, &filestat))
fatal("can't check out file %s from %s\n", filename, cs);
fatal("can't check out file %s from %s\n",
filename, cs);
}
}
if (old_file_is_dev_null && ok_to_create_file && (filestat.st_size != 0)) {
fatal("patch creates new file but existing file %s not empty\n",
if (old_file_is_dev_null &&
ok_to_create_file &&
(filestat.st_size != 0)) {
fatal(
"patch creates new file but existing file %s not empty\n",
filename);
}
@ -158,25 +178,31 @@ plan_a(char *filename)
return FALSE; /* force plan b because plan a bombed */
}
i_womp = malloc(i_size+2);
i_womp = malloc(i_size + 2);
if (i_womp == NULL)
return FALSE;
if ((ifd = open(filename, 0)) < 0)
pfatal("can't open file %s", filename);
if (read(ifd, i_womp, i_size) != i_size) {
Close(ifd); /* probably means i_size > 15 or 16 bits worth */
free(i_womp); /* at this point it doesn't matter if i_womp was */
return FALSE; /* undersized. */
/*
* This probably means i_size > 15 or 16 bits worth at this
* point it doesn't matter if i_womp was undersized.
*/
Close(ifd);
free(i_womp);
return FALSE;
}
Close(ifd);
if (i_size && i_womp[i_size-1] != '\n')
if (i_size && i_womp[i_size - 1] != '\n')
i_womp[i_size++] = '\n';
i_womp[i_size] = '\0';
/* count the lines in the buffer so we know how many pointers we need */
/*
* Count the lines in the buffer so we know how many pointers we
* need.
*/
iline = 0;
for (s=i_womp; *s; s++) {
for (s = i_womp; *s; s++) {
if (*s == '\n')
iline++;
}
@ -186,18 +212,18 @@ plan_a(char *filename)
return FALSE;
}
/* now scan the buffer and build pointer array */
/* Now scan the buffer and build pointer array. */
iline = 1;
i_ptr[iline] = i_womp;
for (s=i_womp; *s; s++) {
if (*s == '\n')
i_ptr[++iline] = s+1; /* these are NOT null terminated */
for (s = i_womp; *s; s++) {
if (*s == '\n') {
/* These are NOT null terminated. */
i_ptr[++iline] = s + 1;
}
}
input_lines = iline - 1;
/* now check for revision, if any */
/* Now check for revision, if any. */
if (revision != NULL) {
if (!rev_in_string(i_womp)) {
if (force) {
@ -205,28 +231,27 @@ plan_a(char *filename)
say(
"Warning: this file doesn't appear to be the %s version--patching anyway.\n",
revision);
}
else if (batch) {
} else if (batch) {
fatal(
"this file doesn't appear to be the %s version--aborting.\n", revision);
}
else {
} else {
ask(
"This file doesn't appear to be the %s version--patch anyway? [n] ",
revision);
if (*buf != 'y')
fatal("aborted\n");
}
}
else if (verbose)
} else if (verbose)
say("Good. This file appears to be the %s version.\n",
revision);
}
return TRUE; /* plan a will work */
return TRUE; /* Plan a will work. */
}
/* Keep (virtually) nothing in memory. */
/*
* Keep (virtually) nothing in memory.
*/
void
plan_b(char *filename)
{
@ -244,7 +269,7 @@ plan_b(char *filename)
if (revision != NULL && !found_revision && rev_in_string(buf))
found_revision = TRUE;
if ((i = strlen(buf)) > maxlen)
maxlen = i; /* find longest line */
maxlen = i; /* Find longest line. */
}
if (revision != NULL) {
if (!found_revision) {
@ -253,39 +278,37 @@ plan_b(char *filename)
say(
"Warning: this file doesn't appear to be the %s version--patching anyway.\n",
revision);
}
else if (batch) {
} else if (batch) {
fatal(
"this file doesn't appear to be the %s version--aborting.\n", revision);
}
else {
} else {
ask(
"This file doesn't appear to be the %s version--patch anyway? [n] ",
revision);
if (*buf != 'y')
fatal("aborted\n");
}
}
else if (verbose)
} else if (verbose)
say("Good. This file appears to be the %s version.\n",
revision);
}
Fseek(ifp, 0L, 0); /* rewind file */
Fseek(ifp, 0L, 0); /* Rewind file. */
lines_per_buf = BUFFERSIZE / maxlen;
tireclen = maxlen;
tibuf[0] = malloc(BUFFERSIZE + 1);
tibuf[1] = malloc(BUFFERSIZE + 1);
if (tibuf[1] == NULL)
fatal("out of memory\n");
for (i=1; ; i++) {
if (! (i % lines_per_buf)) /* new block */
for (i = 1; ; i++) {
if (! (i % lines_per_buf)) /* New block. */
if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
pfatal("can't write temp file");
if (fgets(tibuf[0] + maxlen * (i%lines_per_buf), maxlen + 1, ifp)
== NULL) {
if (fgets(tibuf[0] + maxlen * (i % lines_per_buf),
maxlen + 1, ifp) == NULL) {
input_lines = i - 1;
if (i % lines_per_buf)
if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
if (write(tifd, tibuf[0], BUFFERSIZE)
< BUFFERSIZE)
pfatal("can't write temp file");
break;
}
@ -297,8 +320,9 @@ plan_b(char *filename)
}
}
/* Fetch a line from the input file, \n terminated, not necessarily \0. */
/*
* Fetch a line from the input file, \n terminated, not necessarily \0.
*/
char *
ifetch(LINENUM line, int whichbuf)
{
@ -320,12 +344,13 @@ ifetch(LINENUM line, int whichbuf)
if (read(tifd, tibuf[whichbuf], BUFFERSIZE) < 0)
pfatal("error reading tmp file %s", TMPINNAME);
}
return tibuf[whichbuf] + (tireclen*offline);
return tibuf[whichbuf] + (tireclen * offline);
}
}
/* True if the string argument contains the revision number we want. */
/*
* True if the string argument contains the revision number we want.
*/
bool
rev_in_string(char *string)
{
@ -335,11 +360,13 @@ rev_in_string(char *string)
if (revision == NULL)
return TRUE;
patlen = strlen(revision);
if (strnEQ(string,revision,patlen) && isspace((unsigned char)string[patlen]))
if (strnEQ(string,revision,patlen) &&
isspace((unsigned char)string[patlen]))
return TRUE;
for (s = string; *s; s++) {
if (isspace((unsigned char)*s) && strnEQ(s+1, revision, patlen) &&
isspace((unsigned char)s[patlen+1] )) {
if (isspace((unsigned char)*s) &&
strnEQ(s + 1, revision, patlen) &&
isspace((unsigned char)s[patlen + 1] )) {
return TRUE;
}
}

View File

@ -1,7 +1,7 @@
/* $NetBSD: util.c,v 1.10 2002/03/11 18:47:51 kristerw Exp $ */
/* $NetBSD: util.c,v 1.11 2002/03/11 23:29:02 kristerw Exp $ */
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: util.c,v 1.10 2002/03/11 18:47:51 kristerw Exp $");
__RCSID("$NetBSD: util.c,v 1.11 2002/03/11 23:29:02 kristerw Exp $");
#endif /* not lint */
#include "EXTERN.h"
@ -15,8 +15,9 @@ __RCSID("$NetBSD: util.c,v 1.10 2002/03/11 18:47:51 kristerw Exp $");
#include <unistd.h>
#include <fcntl.h>
/* Rename a file, copying it if necessary. */
/*
* Rename a file, copying it if necessary.
*/
int
move_file(char *from, char *to)
{
@ -35,7 +36,7 @@ move_file(char *from, char *to)
fromfd = open(from, 0);
if (fromfd < 0)
pfatal("internal error, can't reopen %s", from);
while ((i=read(fromfd, buf, sizeof buf)) > 0)
while ((i = read(fromfd, buf, sizeof buf)) > 0)
if (write(1, buf, i) != 1)
pfatal("write failed");
Close(fromfd);
@ -48,7 +49,7 @@ move_file(char *from, char *to)
} else {
#ifndef NODIR
char *backupname = find_backup_file_name(to);
if (backupname == (char *) 0)
if (backupname == NULL)
fatal("out of memory\n");
Strcpy(bakname, backupname);
free(backupname);
@ -63,44 +64,54 @@ move_file(char *from, char *to)
ino_t to_inode = filestat.st_ino;
char *simplename = bakname;
for (s=bakname; *s; s++) {
for (s = bakname; *s; s++) {
if (*s == '/')
simplename = s+1;
simplename = s + 1;
}
/* Find a backup name that is not the same file.
Change the first lowercase char into uppercase;
if that isn't sufficient, chop off the first char and try again. */
/*
* Find a backup name that is not the same file.
* Change the first lowercase char into uppercase;
* if that isn't sufficient, chop off the first char
* and try again.
*/
while (stat(bakname, &filestat) == 0 &&
to_device == filestat.st_dev && to_inode == filestat.st_ino) {
to_device == filestat.st_dev &&
to_inode == filestat.st_ino) {
/* Skip initial non-lowercase chars. */
for (s=simplename; *s && !islower((unsigned char)*s); s++) ;
for (s = simplename;
*s && !islower((unsigned char)*s);
s++)
;
if (*s)
*s = toupper(*s);
else
Strcpy(simplename, simplename+1);
Strcpy(simplename, simplename + 1);
}
while (unlink(bakname) >= 0) ; /* while() is for benefit of Eunice */
while (unlink(bakname) >= 0)
; /* while() is for benefit of Eunice */
#ifdef DEBUGGING
if (debug & 4)
say("Moving %s to %s.\n", to, bakname);
#endif
if (link(to, bakname) < 0) {
/* Maybe `to' is a symlink into a different file system.
Copying replaces the symlink with a file; using rename
would be better. */
/*
* Maybe `to' is a symlink into a different file
* system. Copying replaces the symlink with a file;
* using rename would be better.
*/
int tofd;
int bakfd;
bakfd = creat(bakname, 0666);
if (bakfd < 0) {
say("Can't backup %s, output is in %s: %s\n", to, from,
strerror(errno));
say("Can't backup %s, output is in %s: %s\n",
to, from, strerror(errno));
return -1;
}
tofd = open(to, 0);
if (tofd < 0)
pfatal("internal error, can't open %s", to);
while ((i=read(tofd, buf, sizeof buf)) > 0)
while ((i = read(tofd, buf, sizeof buf)) > 0)
if (write(bakfd, buf, i) != i)
pfatal("write failed");
Close(tofd);
@ -124,7 +135,7 @@ move_file(char *from, char *to)
fromfd = open(from, 0);
if (fromfd < 0)
pfatal("internal error, can't reopen %s", from);
while ((i=read(fromfd, buf, sizeof buf)) > 0)
while ((i = read(fromfd, buf, sizeof buf)) > 0)
if (write(tofd, buf, i) != i)
pfatal("write failed");
Close(fromfd);
@ -134,8 +145,9 @@ move_file(char *from, char *to)
return 0;
}
/* Copy a file. */
/*
* Copy a file.
*/
void
copy_file(char *from, char *to)
{
@ -149,15 +161,16 @@ copy_file(char *from, char *to)
fromfd = open(from, 0);
if (fromfd < 0)
pfatal("internal error, can't reopen %s", from);
while ((i=read(fromfd, buf, sizeof buf)) > 0)
while ((i = read(fromfd, buf, sizeof buf)) > 0)
if (write(tofd, buf, i) != i)
pfatal("write to %s failed", to);
Close(fromfd);
Close(tofd);
}
/* Allocate a unique area for a string. */
/*
* Allocate a unique area for a string.
*/
char *
savestr(char *s)
{
@ -167,23 +180,24 @@ savestr(char *s)
if (!s)
s = "Oops";
t = s;
while (*t++);
while (*t++)
;
rv = malloc(t - s);
if (rv == NULL) {
if (using_plan_a)
out_of_mem = TRUE;
else
fatal("out of memory\n");
}
else {
} else {
t = rv;
while ((*t++ = *s++) != '\0');
}
return rv;
}
/* Vanilla terminal output (buffered). */
/*
* Vanilla terminal output (buffered).
*/
void
say(const char *pat, ...)
{
@ -195,8 +209,9 @@ say(const char *pat, ...)
Fflush(stderr);
}
/* Terminal output, pun intended. */
/*
* Terminal output, pun intended.
*/
void /* very void */
fatal(const char *pat, ...)
{
@ -209,8 +224,9 @@ fatal(const char *pat, ...)
my_exit(1);
}
/* Say something from patch, something from the system, then silence . . . */
/*
* Say something from patch, something from the system, then silence...
*/
void /* very void */
pfatal(const char *pat, ...)
{
@ -224,8 +240,10 @@ pfatal(const char *pat, ...)
va_end(ap);
my_exit(1);
}
/* Get a response from the user, somehow or other. */
/*
* Get a response from the user, somehow or other.
*/
void
ask(const char *pat, ...)
{
@ -235,30 +253,26 @@ ask(const char *pat, ...)
va_list ap;
va_start(ap, pat);
(void) vsprintf(buf, pat, ap);
(void)vsprintf(buf, pat, ap);
va_end(ap);
Fflush(stderr);
write(2, buf, strlen(buf));
if (tty2) { /* might be redirected to a file */
r = read(2, buf, sizeof buf);
}
else if (isatty(1)) { /* this may be new file output */
} else if (isatty(1)) { /* this may be new file output */
Fflush(stdout);
write(1, buf, strlen(buf));
r = read(1, buf, sizeof buf);
}
else if ((ttyfd = open("/dev/tty", 2)) >= 0 && isatty(ttyfd)) {
} else if ((ttyfd = open("/dev/tty", 2)) >= 0 && isatty(ttyfd)) {
/* might be deleted or unwriteable */
write(ttyfd, buf, strlen(buf));
r = read(ttyfd, buf, sizeof buf);
Close(ttyfd);
}
else if (isatty(0)) { /* this is probably patch input */
} else if (isatty(0)) { /* this is probably patch input */
Fflush(stdin);
write(0, buf, strlen(buf));
r = read(0, buf, sizeof buf);
}
else { /* no terminal at all--default it */
} else { /* no terminal at all--default it */
buf[0] = '\n';
r = 1;
}
@ -267,15 +281,17 @@ ask(const char *pat, ...)
else
buf[r] = '\0';
if (!tty2)
say("%s",buf);
say("%s", buf);
}
/* How to handle certain events when not in a critical region. */
/*
* How to handle certain events when not in a critical region.
*/
void
set_signals(int reset)
{
static void (*hupval)(int),(*intval)(int);
static void (*hupval)(int);
static void (*intval)(int);
if (!reset) {
hupval = signal(SIGHUP, SIG_IGN);
@ -289,8 +305,9 @@ set_signals(int reset)
Signal(SIGINT, intval);
}
/* How to handle certain events when in a critical region. */
/*
* How to handle certain events when in a critical region.
*/
void
ignore_signals()
{
@ -298,9 +315,10 @@ ignore_signals()
Signal(SIGINT, SIG_IGN);
}
/* Make sure we'll have the directories to create a file.
If `striplast' is TRUE, ignore the last element of `filename'. */
/*
* Make sure we'll have the directories to create a file.
* If `striplast' is TRUE, ignore the last element of `filename'.
*/
void
makedirs(char *filename, bool striplast)
{
@ -310,15 +328,16 @@ makedirs(char *filename, bool striplast)
int i;
int dirvp = 0; /* Number of finished entries in dirv. */
/* Copy `filename' into `tmpbuf' with a NUL instead of a slash
between the directories. */
/*
* Copy `filename' into `tmpbuf' with a NUL instead of a slash
* between the directories.
*/
while (*filename) {
if (*filename == '/') {
filename++;
dirv[dirvp++] = s;
*s++ = '\0';
}
else {
} else {
*s++ = *filename++;
}
}
@ -331,11 +350,12 @@ makedirs(char *filename, bool striplast)
strcpy(buf, "mkdir");
s = buf;
for (i=0; i<=dirvp; i++) {
for (i = 0; i <= dirvp; i++) {
struct stat sbuf;
if (stat(tmpbuf, &sbuf) && errno == ENOENT) {
while (*s) s++;
while (*s)
s++;
*s++ = ' ';
strcpy(s, tmpbuf);
}
@ -345,8 +365,9 @@ makedirs(char *filename, bool striplast)
system(buf);
}
/* Make filenames more reasonable. */
/*
* Make filenames more reasonable.
*/
char *
fetchname(char *at, int strip_leading, int assume_exists)
{
@ -362,12 +383,13 @@ fetchname(char *at, int strip_leading, int assume_exists)
at++;
#ifdef DEBUGGING
if (debug & 128)
say("fetchname %s %d %d\n",at,strip_leading,assume_exists);
say("fetchname %s %d %d\n", at, strip_leading, assume_exists);
#endif
filename_is_dev_null = FALSE;
if (strnEQ(at, "/dev/null", 9)) { /* so files can be created by diffing */
if (strnEQ(at, "/dev/null", 9)) {
/* So files can be created by diffing against /dev/null. */
filename_is_dev_null = TRUE;
return NULL; /* against /dev/null. */
return NULL;
}
name = fullname = t = savestr(at);
@ -375,18 +397,21 @@ fetchname(char *at, int strip_leading, int assume_exists)
for (; *t && !isspace((unsigned char)*t); t++)
if (*t == '/')
if (--sleading >= 0)
name = t+1;
name = t + 1;
*t = '\0';
/* If no -p option was given (957 is the default value!),
we were given a relative pathname,
and the leading directories that we just stripped off all exist,
put them back on. */
/*
* If no -p option was given (957 is the default value!),
* we were given a relative pathname,
* and the leading directories that we just stripped off all exist,
* put them back on.
*/
if (strip_leading == 957 && name != fullname && *fullname != '/') {
name[-1] = '\0';
if (stat(fullname, &filestat) == 0 && S_ISDIR (filestat.st_mode)) {
if (stat(fullname, &filestat) == 0 &&
S_ISDIR(filestat.st_mode)) {
name[-1] = '/';
name=fullname;
name = fullname;
}
}
@ -400,13 +425,15 @@ fetchname(char *at, int strip_leading, int assume_exists)
/* Put any leading path into `tmpbuf'. */
strncpy(tmpbuf, name, pathlen);
#define try(f, a1, a2) (Sprintf(tmpbuf + pathlen, f, a1, a2), stat(tmpbuf, &filestat) == 0)
#define try1(f, a1) (Sprintf(tmpbuf + pathlen, f, a1), stat(tmpbuf, &filestat) == 0)
if ( try("RCS/%s%s", filebase, RCSSUFFIX)
|| try1("RCS/%s" , filebase)
|| try( "%s%s", filebase, RCSSUFFIX)
|| try("SCCS/%s%s", SCCSPREFIX, filebase)
|| try( "%s%s", SCCSPREFIX, filebase))
#define try(f, a1, a2) \
(Sprintf(tmpbuf + pathlen, f, a1, a2), stat(tmpbuf, &filestat) == 0)
#define try1(f, a1) \
(Sprintf(tmpbuf + pathlen, f, a1), stat(tmpbuf, &filestat) == 0)
if (try("RCS/%s%s", filebase, RCSSUFFIX) ||
try1("RCS/%s" , filebase) ||
try( "%s%s", filebase, RCSSUFFIX) ||
try("SCCS/%s%s", SCCSPREFIX, filebase) ||
try( "%s%s", SCCSPREFIX, filebase))
return name;
free(name);
name = NULL;