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,332 +16,359 @@ __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)
{
if (using_plan_a) {
i_size = 0;
if (using_plan_a) {
i_size = 0;
if (i_ptr != NULL)
free(i_ptr);
if (i_womp != NULL)
free(i_womp);
i_womp = NULL;
i_ptr = NULL;
}
else {
using_plan_a = TRUE; /* maybe the next one is smaller */
Close(tifd);
tifd = -1;
free(tibuf[0]);
free(tibuf[1]);
tibuf[0] = tibuf[1] = NULL;
tiline[0] = tiline[1] = -1;
tireclen = 0;
}
if (i_ptr != NULL)
free(i_ptr);
if (i_womp != NULL)
free(i_womp);
i_womp = NULL;
i_ptr = NULL;
} else {
using_plan_a = TRUE; /* maybe the next one is smaller */
Close(tifd);
tifd = -1;
free(tibuf[0]);
free(tibuf[1]);
tibuf[0] = tibuf[1] = NULL;
tiline[0] = tiline[1] = -1;
tireclen = 0;
}
}
/* Constuct the line index, somehow or other. */
/*
* Constuct the line index, somehow or other.
*/
void
scan_input(char *filename)
{
if (!plan_a(filename))
plan_b(filename);
if (verbose) {
say("Patching file %s using Plan %s...\n", filename,
(using_plan_a ? "A" : "B") );
}
if (!plan_a(filename))
plan_b(filename);
if (verbose) {
say("Patching file %s using Plan %s...\n", filename,
(using_plan_a ? "A" : "B") );
}
}
/* Try keeping everything in memory. */
/*
* Try keeping everything in memory.
*/
bool
plan_a(char *filename)
{
int ifd, statfailed;
char *s;
LINENUM iline;
char lbuf[MAXLINELEN];
int ifd, statfailed;
char *s;
LINENUM iline;
char lbuf[MAXLINELEN];
statfailed = stat(filename, &filestat);
if (statfailed && ok_to_create_file) {
if (verbose)
say("(Creating file %s...)\n",filename);
makedirs(filename, TRUE);
close(creat(filename, 0666));
statfailed = stat(filename, &filestat);
}
/* 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
/* I can't write to it. */
|| ((filestat.st_mode & 0022) == 0 && filestat.st_uid != myuid)) {
struct stat cstat;
char *cs = NULL;
char *filebase;
int pathlen;
if (statfailed && ok_to_create_file) {
if (verbose)
say("(Creating file %s...)\n",filename);
makedirs(filename, TRUE);
close(creat(filename, 0666));
statfailed = stat(filename, &filestat);
}
/*
* 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 ||
/* I can't write to it. */
((filestat.st_mode & 0022) == 0 && filestat.st_uid != myuid)) {
struct stat cstat;
char *cs = NULL;
char *filebase;
int pathlen;
filebase = basename(filename);
pathlen = filebase - filename;
filebase = basename(filename);
pathlen = filebase - filename;
/* Put any leading path into `s'.
Leave room in lbuf for the diff command. */
s = lbuf + 20;
strncpy(s, filename, pathlen);
/*
* 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)) {
Sprintf(buf, CHECKOUT, filename);
Sprintf(lbuf, RCSDIFF, filename);
cs = "RCS";
} 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. */
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",
filename, cs);
/* 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",
filename, cs);
if (system(lbuf))
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);
if (system(buf) || stat(filename, &filestat))
fatal("can't check out file %s from %s\n", filename, cs);
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)) {
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.
*/
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",
filename, cs);
/*
* 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",
filename, cs);
if (system(lbuf))
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);
if (system(buf) || stat(filename, &filestat))
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",
filename);
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);
}
filemode = filestat.st_mode;
if (!S_ISREG(filemode))
fatal("%s is not a normal file--can't patch\n", filename);
i_size = filestat.st_size;
if (out_of_mem) {
set_hunkmax(); /* make sure dynamic arrays are allocated */
out_of_mem = FALSE;
return FALSE; /* force plan b because plan a bombed */
}
filemode = filestat.st_mode;
if (!S_ISREG(filemode))
fatal("%s is not a normal file--can't patch\n", filename);
i_size = filestat.st_size;
if (out_of_mem) {
set_hunkmax(); /* make sure dynamic arrays are allocated */
out_of_mem = FALSE;
return FALSE; /* force plan b because plan a bombed */
}
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) {
/*
* 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')
i_womp[i_size++] = '\n';
i_womp[i_size] = '\0';
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. */
}
Close(ifd);
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 */
iline = 0;
for (s=i_womp; *s; s++) {
if (*s == '\n')
iline++;
}
i_ptr = malloc((iline + 2) * sizeof(char *));
if (i_ptr == NULL) { /* shucks, it was a near thing */
free(i_womp);
return FALSE;
}
/*
* Count the lines in the buffer so we know how many pointers we
* need.
*/
iline = 0;
for (s = i_womp; *s; s++) {
if (*s == '\n')
iline++;
}
i_ptr = malloc((iline + 2) * sizeof(char *));
if (i_ptr == NULL) { /* shucks, it was a near thing */
free(i_womp);
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') {
/* These are NOT null terminated. */
i_ptr[++iline] = s + 1;
}
}
input_lines = iline - 1;
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 */
}
input_lines = iline - 1;
/* now check for revision, if any */
if (revision != NULL) {
if (!rev_in_string(i_womp)) {
if (force) {
if (verbose)
say(
/* Now check for revision, if any. */
if (revision != NULL) {
if (!rev_in_string(i_womp)) {
if (force) {
if (verbose)
say(
"Warning: this file doesn't appear to be the %s version--patching anyway.\n",
revision);
}
else if (batch) {
fatal(
} else if (batch) {
fatal(
"this file doesn't appear to be the %s version--aborting.\n", revision);
}
else {
ask(
} else {
ask(
"This file doesn't appear to be the %s version--patch anyway? [n] ",
revision);
if (*buf != 'y')
fatal("aborted\n");
}
if (*buf != 'y')
fatal("aborted\n");
}
} else if (verbose)
say("Good. This file appears to be the %s version.\n",
revision);
}
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)
{
FILE *ifp;
int i = 0;
int maxlen = 1;
bool found_revision = (revision == NULL);
FILE *ifp;
int i = 0;
int maxlen = 1;
bool found_revision = (revision == NULL);
using_plan_a = FALSE;
if ((ifp = fopen(filename, "r")) == NULL)
pfatal("can't open file %s", filename);
if ((tifd = creat(TMPINNAME, 0666)) < 0)
pfatal("can't open file %s", TMPINNAME);
while (fgets(buf, sizeof buf, ifp) != NULL) {
if (revision != NULL && !found_revision && rev_in_string(buf))
found_revision = TRUE;
if ((i = strlen(buf)) > maxlen)
maxlen = i; /* find longest line */
}
if (revision != NULL) {
if (!found_revision) {
if (force) {
if (verbose)
say(
using_plan_a = FALSE;
if ((ifp = fopen(filename, "r")) == NULL)
pfatal("can't open file %s", filename);
if ((tifd = creat(TMPINNAME, 0666)) < 0)
pfatal("can't open file %s", TMPINNAME);
while (fgets(buf, sizeof buf, ifp) != NULL) {
if (revision != NULL && !found_revision && rev_in_string(buf))
found_revision = TRUE;
if ((i = strlen(buf)) > maxlen)
maxlen = i; /* Find longest line. */
}
if (revision != NULL) {
if (!found_revision) {
if (force) {
if (verbose)
say(
"Warning: this file doesn't appear to be the %s version--patching anyway.\n",
revision);
}
else if (batch) {
fatal(
revision);
} else if (batch) {
fatal(
"this file doesn't appear to be the %s version--aborting.\n", revision);
}
else {
ask(
} else {
ask(
"This file doesn't appear to be the %s version--patch anyway? [n] ",
revision);
if (*buf != 'y')
fatal("aborted\n");
}
revision);
if (*buf != 'y')
fatal("aborted\n");
}
} else if (verbose)
say("Good. This file appears to be the %s version.\n",
revision);
}
else if (verbose)
say("Good. This file appears to be the %s version.\n",
revision);
}
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 */
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) {
input_lines = i - 1;
if (i % lines_per_buf)
if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
pfatal("can't write temp file");
break;
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. */
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) {
input_lines = i - 1;
if (i % lines_per_buf)
if (write(tifd, tibuf[0], BUFFERSIZE)
< BUFFERSIZE)
pfatal("can't write temp file");
break;
}
}
Fclose(ifp);
Close(tifd);
if ((tifd = open(TMPINNAME, 0)) < 0) {
pfatal("can't reopen file %s", TMPINNAME);
}
}
Fclose(ifp);
Close(tifd);
if ((tifd = open(TMPINNAME, 0)) < 0) {
pfatal("can't reopen file %s", TMPINNAME);
}
}
/* 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)
{
if (line < 1 || line > input_lines)
return "";
if (using_plan_a)
return i_ptr[line];
else {
LINENUM offline = line % lines_per_buf;
LINENUM baseline = line - offline;
if (tiline[0] == baseline)
whichbuf = 0;
else if (tiline[1] == baseline)
whichbuf = 1;
if (line < 1 || line > input_lines)
return "";
if (using_plan_a)
return i_ptr[line];
else {
tiline[whichbuf] = baseline;
Lseek(tifd, baseline / lines_per_buf * BUFFERSIZE, 0);
if (read(tifd, tibuf[whichbuf], BUFFERSIZE) < 0)
pfatal("error reading tmp file %s", TMPINNAME);
LINENUM offline = line % lines_per_buf;
LINENUM baseline = line - offline;
if (tiline[0] == baseline)
whichbuf = 0;
else if (tiline[1] == baseline)
whichbuf = 1;
else {
tiline[whichbuf] = baseline;
Lseek(tifd, baseline / lines_per_buf * BUFFERSIZE, 0);
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)
{
char *s;
int patlen;
char *s;
int patlen;
if (revision == NULL)
return TRUE;
patlen = strlen(revision);
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] )) {
return TRUE;
if (revision == NULL)
return TRUE;
patlen = strlen(revision);
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] )) {
return TRUE;
}
}
}
return FALSE;
}

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,402 +15,429 @@ __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)
{
char bakname[512];
char *s;
int i;
int fromfd;
char bakname[512];
char *s;
int i;
int fromfd;
/* to stdout? */
/* to stdout? */
if (strEQ(to, "-")) {
if (strEQ(to, "-")) {
#ifdef DEBUGGING
if (debug & 4)
say("Moving %s to stdout.\n", from);
if (debug & 4)
say("Moving %s to stdout.\n", from);
#endif
fromfd = open(from, 0);
if (fromfd < 0)
pfatal("internal error, can't reopen %s", from);
while ((i=read(fromfd, buf, sizeof buf)) > 0)
if (write(1, buf, i) != 1)
pfatal("write failed");
Close(fromfd);
return 0;
}
fromfd = open(from, 0);
if (fromfd < 0)
pfatal("internal error, can't reopen %s", from);
while ((i = read(fromfd, buf, sizeof buf)) > 0)
if (write(1, buf, i) != 1)
pfatal("write failed");
Close(fromfd);
return 0;
}
if (origprae) {
Strcpy(bakname, origprae);
Strcat(bakname, to);
} else {
if (origprae) {
Strcpy(bakname, origprae);
Strcat(bakname, to);
} else {
#ifndef NODIR
char *backupname = find_backup_file_name(to);
if (backupname == (char *) 0)
fatal("out of memory\n");
Strcpy(bakname, backupname);
free(backupname);
char *backupname = find_backup_file_name(to);
if (backupname == NULL)
fatal("out of memory\n");
Strcpy(bakname, backupname);
free(backupname);
#else /* NODIR */
Strcpy(bakname, to);
Strcat(bakname, simple_backup_suffix);
Strcpy(bakname, to);
Strcat(bakname, simple_backup_suffix);
#endif /* NODIR */
}
}
if (stat(to, &filestat) == 0) { /* output file exists */
dev_t to_device = filestat.st_dev;
ino_t to_inode = filestat.st_ino;
char *simplename = bakname;
if (stat(to, &filestat) == 0) { /* output file exists */
dev_t to_device = filestat.st_dev;
ino_t to_inode = filestat.st_ino;
char *simplename = bakname;
for (s=bakname; *s; s++) {
if (*s == '/')
simplename = s+1;
for (s = bakname; *s; s++) {
if (*s == '/')
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.
*/
while (stat(bakname, &filestat) == 0 &&
to_device == filestat.st_dev &&
to_inode == filestat.st_ino) {
/* Skip initial non-lowercase chars. */
for (s = simplename;
*s && !islower((unsigned char)*s);
s++)
;
if (*s)
*s = toupper(*s);
else
Strcpy(simplename, simplename + 1);
}
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.
*/
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));
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)
if (write(bakfd, buf, i) != i)
pfatal("write failed");
Close(tofd);
Close(bakfd);
}
while (unlink(to) >= 0) ;
}
/* 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) {
/* Skip initial non-lowercase chars. */
for (s=simplename; *s && !islower((unsigned char)*s); s++) ;
if (*s)
*s = toupper(*s);
else
Strcpy(simplename, simplename+1);
}
while (unlink(bakname) >= 0) ; /* while() is for benefit of Eunice */
#ifdef DEBUGGING
if (debug & 4)
say("Moving %s to %s.\n", to, bakname);
say("Moving %s to %s.\n", from, to);
#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. */
int tofd;
int bakfd;
if (link(from, to) < 0) { /* different file system? */
int tofd;
bakfd = creat(bakname, 0666);
if (bakfd < 0) {
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)
if (write(bakfd, buf, i) != i)
pfatal("write failed");
Close(tofd);
Close(bakfd);
tofd = creat(to, 0666);
if (tofd < 0) {
say("Can't create %s, output is in %s: %s\n",
to, from, strerror(errno));
return -1;
}
fromfd = open(from, 0);
if (fromfd < 0)
pfatal("internal error, can't reopen %s", from);
while ((i = read(fromfd, buf, sizeof buf)) > 0)
if (write(tofd, buf, i) != i)
pfatal("write failed");
Close(fromfd);
Close(tofd);
}
while (unlink(to) >= 0) ;
}
#ifdef DEBUGGING
if (debug & 4)
say("Moving %s to %s.\n", from, to);
#endif
if (link(from, to) < 0) { /* different file system? */
int tofd;
tofd = creat(to, 0666);
if (tofd < 0) {
say("Can't create %s, output is in %s: %s\n",
to, from, strerror(errno));
return -1;
}
fromfd = open(from, 0);
if (fromfd < 0)
pfatal("internal error, can't reopen %s", from);
while ((i=read(fromfd, buf, sizeof buf)) > 0)
if (write(tofd, buf, i) != i)
pfatal("write failed");
Close(fromfd);
Close(tofd);
}
Unlink(from);
return 0;
Unlink(from);
return 0;
}
/* Copy a file. */
/*
* Copy a file.
*/
void
copy_file(char *from, char *to)
{
int tofd;
int fromfd;
int i;
tofd = creat(to, 0666);
if (tofd < 0)
pfatal("can't create %s", to);
fromfd = open(from, 0);
if (fromfd < 0)
pfatal("internal error, can't reopen %s", from);
while ((i=read(fromfd, buf, sizeof buf)) > 0)
if (write(tofd, buf, i) != i)
pfatal("write to %s failed", to);
Close(fromfd);
Close(tofd);
int tofd;
int fromfd;
int i;
tofd = creat(to, 0666);
if (tofd < 0)
pfatal("can't create %s", to);
fromfd = open(from, 0);
if (fromfd < 0)
pfatal("internal error, can't reopen %s", from);
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)
{
char *rv;
char *t;
char *rv;
char *t;
if (!s)
s = "Oops";
t = s;
while (*t++);
rv = malloc(t - s);
if (rv == NULL) {
if (using_plan_a)
out_of_mem = TRUE;
else
fatal("out of memory\n");
}
else {
t = rv;
while ((*t++ = *s++) != '\0');
}
return rv;
if (!s)
s = "Oops";
t = s;
while (*t++)
;
rv = malloc(t - s);
if (rv == NULL) {
if (using_plan_a)
out_of_mem = TRUE;
else
fatal("out of memory\n");
} else {
t = rv;
while ((*t++ = *s++) != '\0');
}
return rv;
}
/* Vanilla terminal output (buffered). */
/*
* Vanilla terminal output (buffered).
*/
void
say(const char *pat, ...)
{
va_list ap;
va_start(ap, pat);
va_list ap;
va_start(ap, pat);
vfprintf(stderr, pat, ap);
va_end(ap);
Fflush(stderr);
vfprintf(stderr, pat, ap);
va_end(ap);
Fflush(stderr);
}
/* Terminal output, pun intended. */
/*
* Terminal output, pun intended.
*/
void /* very void */
fatal(const char *pat, ...)
{
va_list ap;
va_start(ap, pat);
va_list ap;
va_start(ap, pat);
fprintf(stderr, "patch: **** ");
vfprintf(stderr, pat, ap);
va_end(ap);
my_exit(1);
fprintf(stderr, "patch: **** ");
vfprintf(stderr, pat, ap);
va_end(ap);
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, ...)
{
va_list ap;
int errnum = errno;
va_start(ap, pat);
va_list ap;
int errnum = errno;
va_start(ap, pat);
fprintf(stderr, "patch: **** ");
vfprintf(stderr, pat, ap);
fprintf(stderr, ": %s\n", strerror(errnum));
va_end(ap);
my_exit(1);
fprintf(stderr, "patch: **** ");
vfprintf(stderr, pat, ap);
fprintf(stderr, ": %s\n", strerror(errnum));
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, ...)
{
int ttyfd;
int r;
bool tty2 = isatty(2);
va_list ap;
va_start(ap, pat);
int ttyfd;
int r;
bool tty2 = isatty(2);
va_list ap;
va_start(ap, pat);
(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 */
Fflush(stdout);
write(1, buf, strlen(buf));
r = read(1, buf, sizeof buf);
}
else if ((ttyfd = open("/dev/tty", 2)) >= 0 && isatty(ttyfd)) {
(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 */
Fflush(stdout);
write(1, buf, strlen(buf));
r = read(1, buf, sizeof buf);
} 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 */
Fflush(stdin);
write(0, buf, strlen(buf));
r = read(0, buf, sizeof buf);
}
else { /* no terminal at all--default it */
buf[0] = '\n';
r = 1;
}
if (r <= 0)
buf[0] = 0;
else
buf[r] = '\0';
if (!tty2)
say("%s",buf);
write(ttyfd, buf, strlen(buf));
r = read(ttyfd, buf, sizeof buf);
Close(ttyfd);
} 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 */
buf[0] = '\n';
r = 1;
}
if (r <= 0)
buf[0] = 0;
else
buf[r] = '\0';
if (!tty2)
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);
if (hupval != SIG_IGN)
hupval = my_exit;
intval = signal(SIGINT, SIG_IGN);
if (intval != SIG_IGN)
intval = my_exit;
}
Signal(SIGHUP, hupval);
Signal(SIGINT, intval);
if (!reset) {
hupval = signal(SIGHUP, SIG_IGN);
if (hupval != SIG_IGN)
hupval = my_exit;
intval = signal(SIGINT, SIG_IGN);
if (intval != SIG_IGN)
intval = my_exit;
}
Signal(SIGHUP, hupval);
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()
{
Signal(SIGHUP, SIG_IGN);
Signal(SIGINT, SIG_IGN);
Signal(SIGHUP, SIG_IGN);
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)
{
char tmpbuf[256];
char *s = tmpbuf;
char *dirv[20]; /* Point to the NULs between elements. */
int i;
int dirvp = 0; /* Number of finished entries in dirv. */
char tmpbuf[256];
char *s = tmpbuf;
char *dirv[20]; /* Point to the NULs between elements. */
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. */
while (*filename) {
if (*filename == '/') {
filename++;
dirv[dirvp++] = s;
*s++ = '\0';
/*
* 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 {
*s++ = *filename++;
}
}
else {
*s++ = *filename++;
}
}
*s = '\0';
dirv[dirvp] = s;
if (striplast)
dirvp--;
if (dirvp < 0)
return;
*s = '\0';
dirv[dirvp] = s;
if (striplast)
dirvp--;
if (dirvp < 0)
return;
strcpy(buf, "mkdir");
s = buf;
for (i=0; i<=dirvp; i++) {
struct stat sbuf;
strcpy(buf, "mkdir");
s = buf;
for (i = 0; i <= dirvp; i++) {
struct stat sbuf;
if (stat(tmpbuf, &sbuf) && errno == ENOENT) {
while (*s) s++;
*s++ = ' ';
strcpy(s, tmpbuf);
if (stat(tmpbuf, &sbuf) && errno == ENOENT) {
while (*s)
s++;
*s++ = ' ';
strcpy(s, tmpbuf);
}
*dirv[i] = '/';
}
*dirv[i] = '/';
}
if (s != buf)
system(buf);
if (s != buf)
system(buf);
}
/* Make filenames more reasonable. */
/*
* Make filenames more reasonable.
*/
char *
fetchname(char *at, int strip_leading, int assume_exists)
{
char *fullname;
char *name;
char *t;
char tmpbuf[200];
int sleading = strip_leading;
char *fullname;
char *name;
char *t;
char tmpbuf[200];
int sleading = strip_leading;
if (!at)
return NULL;
while (isspace((unsigned char)*at))
at++;
if (!at)
return NULL;
while (isspace((unsigned char)*at))
at++;
#ifdef DEBUGGING
if (debug & 128)
say("fetchname %s %d %d\n",at,strip_leading,assume_exists);
if (debug & 128)
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 */
filename_is_dev_null = TRUE;
return NULL; /* against /dev/null. */
}
name = fullname = t = savestr(at);
/* Strip off up to `sleading' leading slashes and null terminate. */
for (; *t && !isspace((unsigned char)*t); t++)
if (*t == '/')
if (--sleading >= 0)
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 (strip_leading == 957 && name != fullname && *fullname != '/') {
name[-1] = '\0';
if (stat(fullname, &filestat) == 0 && S_ISDIR (filestat.st_mode)) {
name[-1] = '/';
name=fullname;
filename_is_dev_null = FALSE;
if (strnEQ(at, "/dev/null", 9)) {
/* So files can be created by diffing against /dev/null. */
filename_is_dev_null = TRUE;
return NULL;
}
}
name = fullname = t = savestr(at);
name = savestr(name);
free(fullname);
/* Strip off up to `sleading' leading slashes and null terminate. */
for (; *t && !isspace((unsigned char)*t); t++)
if (*t == '/')
if (--sleading >= 0)
name = t + 1;
*t = '\0';
if (stat(name, &filestat) && !assume_exists) {
char *filebase = basename(name);
int pathlen = filebase - name;
/*
* 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)) {
name[-1] = '/';
name = fullname;
}
}
/* Put any leading path into `tmpbuf'. */
strncpy(tmpbuf, name, pathlen);
name = savestr(name);
free(fullname);
#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;
}
if (stat(name, &filestat) && !assume_exists) {
char *filebase = basename(name);
int pathlen = filebase - name;
return name;
/* 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))
return name;
free(name);
name = NULL;
}
return name;
}