summaryrefslogtreecommitdiff
path: root/usr.bin/patch/util.c
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
commitd6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch)
treeece253b876159b39c620e62b6c9b1174642e070e /usr.bin/patch/util.c
initial import of NetBSD tree
Diffstat (limited to 'usr.bin/patch/util.c')
-rw-r--r--usr.bin/patch/util.c441
1 files changed, 441 insertions, 0 deletions
diff --git a/usr.bin/patch/util.c b/usr.bin/patch/util.c
new file mode 100644
index 00000000000..6ae9e0fd5c7
--- /dev/null
+++ b/usr.bin/patch/util.c
@@ -0,0 +1,441 @@
+#ifndef lint
+static char rcsid[] = "$Id: util.c,v 1.1 1995/10/18 08:45:56 deraadt Exp $";
+#endif /* not lint */
+
+#include "EXTERN.h"
+#include "common.h"
+#include "INTERN.h"
+#include "util.h"
+#include "backupfile.h"
+
+void my_exit();
+
+/* Rename a file, copying it if necessary. */
+
+int
+move_file(from,to)
+char *from, *to;
+{
+ char bakname[512];
+ Reg1 char *s;
+ Reg2 int i;
+ Reg3 int fromfd;
+
+ /* to stdout? */
+
+ if (strEQ(to, "-")) {
+#ifdef DEBUGGING
+ if (debug & 4)
+ say2("Moving %s to stdout.\n", from);
+#endif
+ fromfd = open(from, 0);
+ if (fromfd < 0)
+ pfatal2("internal error, can't reopen %s", from);
+ while ((i=read(fromfd, buf, sizeof buf)) > 0)
+ if (write(1, buf, i) != 1)
+ pfatal1("write failed");
+ Close(fromfd);
+ return 0;
+ }
+
+ if (origprae) {
+ Strcpy(bakname, origprae);
+ Strcat(bakname, to);
+ } else {
+#ifndef NODIR
+ char *backupname = find_backup_file_name(to);
+ if (backupname == (char *) 0)
+ fatal1("out of memory\n");
+ Strcpy(bakname, backupname);
+ free(backupname);
+#else /* NODIR */
+ 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;
+
+ 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(*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)
+ say3("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. */
+ Reg4 int tofd;
+ Reg5 int bakfd;
+
+ bakfd = creat(bakname, 0666);
+ if (bakfd < 0) {
+ say4("Can't backup %s, output is in %s: %s\n", to, from,
+ strerror(errno));
+ return -1;
+ }
+ tofd = open(to, 0);
+ if (tofd < 0)
+ pfatal2("internal error, can't open %s", to);
+ while ((i=read(tofd, buf, sizeof buf)) > 0)
+ if (write(bakfd, buf, i) != i)
+ pfatal1("write failed");
+ Close(tofd);
+ Close(bakfd);
+ }
+ while (unlink(to) >= 0) ;
+ }
+#ifdef DEBUGGING
+ if (debug & 4)
+ say3("Moving %s to %s.\n", from, to);
+#endif
+ if (link(from, to) < 0) { /* different file system? */
+ Reg4 int tofd;
+
+ tofd = creat(to, 0666);
+ if (tofd < 0) {
+ say4("Can't create %s, output is in %s: %s\n",
+ to, from, strerror(errno));
+ return -1;
+ }
+ fromfd = open(from, 0);
+ if (fromfd < 0)
+ pfatal2("internal error, can't reopen %s", from);
+ while ((i=read(fromfd, buf, sizeof buf)) > 0)
+ if (write(tofd, buf, i) != i)
+ pfatal1("write failed");
+ Close(fromfd);
+ Close(tofd);
+ }
+ Unlink(from);
+ return 0;
+}
+
+/* Copy a file. */
+
+void
+copy_file(from,to)
+char *from, *to;
+{
+ Reg3 int tofd;
+ Reg2 int fromfd;
+ Reg1 int i;
+
+ tofd = creat(to, 0666);
+ if (tofd < 0)
+ pfatal2("can't create %s", to);
+ fromfd = open(from, 0);
+ if (fromfd < 0)
+ pfatal2("internal error, can't reopen %s", from);
+ while ((i=read(fromfd, buf, sizeof buf)) > 0)
+ if (write(tofd, buf, i) != i)
+ pfatal2("write to %s failed", to);
+ Close(fromfd);
+ Close(tofd);
+}
+
+/* Allocate a unique area for a string. */
+
+char *
+savestr(s)
+Reg1 char *s;
+{
+ Reg3 char *rv;
+ Reg2 char *t;
+
+ if (!s)
+ s = "Oops";
+ t = s;
+ while (*t++);
+ rv = malloc((MEM) (t - s));
+ if (rv == Nullch) {
+ if (using_plan_a)
+ out_of_mem = TRUE;
+ else
+ fatal1("out of memory\n");
+ }
+ else {
+ t = rv;
+ while (*t++ = *s++);
+ }
+ return rv;
+}
+
+#if defined(lint) && defined(CANVARARG)
+
+/*VARARGS ARGSUSED*/
+say(pat) char *pat; { ; }
+/*VARARGS ARGSUSED*/
+fatal(pat) char *pat; { ; }
+/*VARARGS ARGSUSED*/
+pfatal(pat) char *pat; { ; }
+/*VARARGS ARGSUSED*/
+ask(pat) char *pat; { ; }
+
+#else
+
+/* Vanilla terminal output (buffered). */
+
+void
+say(pat,arg1,arg2,arg3)
+char *pat;
+long arg1,arg2,arg3;
+{
+ fprintf(stderr, pat, arg1, arg2, arg3);
+ Fflush(stderr);
+}
+
+/* Terminal output, pun intended. */
+
+void /* very void */
+fatal(pat,arg1,arg2,arg3)
+char *pat;
+long arg1,arg2,arg3;
+{
+ fprintf(stderr, "patch: **** ");
+ fprintf(stderr, pat, arg1, arg2, arg3);
+ my_exit(1);
+}
+
+/* Say something from patch, something from the system, then silence . . . */
+
+void /* very void */
+pfatal(pat,arg1,arg2,arg3)
+char *pat;
+long arg1,arg2,arg3;
+{
+ int errnum = errno;
+
+ fprintf(stderr, "patch: **** ");
+ fprintf(stderr, pat, arg1, arg2, arg3);
+ fprintf(stderr, ": %s\n", strerror(errnum));
+ my_exit(1);
+}
+
+/* Get a response from the user, somehow or other. */
+
+void
+ask(pat,arg1,arg2,arg3)
+char *pat;
+long arg1,arg2,arg3;
+{
+ int ttyfd;
+ int r;
+ bool tty2 = isatty(2);
+
+ Sprintf(buf, pat, arg1, arg2, arg3);
+ 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)
+ say1(buf);
+}
+#endif /* lint */
+
+/* How to handle certain events when not in a critical region. */
+
+void
+set_signals(reset)
+int reset;
+{
+#ifndef lint
+#ifdef VOIDSIG
+ static void (*hupval)(),(*intval)();
+#else
+ static int (*hupval)(),(*intval)();
+#endif
+
+ if (!reset) {
+ hupval = signal(SIGHUP, SIG_IGN);
+ if (hupval != SIG_IGN)
+#ifdef VOIDSIG
+ hupval = my_exit;
+#else
+ hupval = (int(*)())my_exit;
+#endif
+ intval = signal(SIGINT, SIG_IGN);
+ if (intval != SIG_IGN)
+#ifdef VOIDSIG
+ intval = my_exit;
+#else
+ intval = (int(*)())my_exit;
+#endif
+ }
+ Signal(SIGHUP, hupval);
+ Signal(SIGINT, intval);
+#endif
+}
+
+/* How to handle certain events when in a critical region. */
+
+void
+ignore_signals()
+{
+#ifndef lint
+ Signal(SIGHUP, SIG_IGN);
+ Signal(SIGINT, SIG_IGN);
+#endif
+}
+
+/* Make sure we'll have the directories to create a file.
+ If `striplast' is TRUE, ignore the last element of `filename'. */
+
+void
+makedirs(filename,striplast)
+Reg1 char *filename;
+bool striplast;
+{
+ char tmpbuf[256];
+ Reg2 char *s = tmpbuf;
+ char *dirv[20]; /* Point to the NULs between elements. */
+ Reg3 int i;
+ Reg4 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';
+ }
+ else {
+ *s++ = *filename++;
+ }
+ }
+ *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;
+
+ if (stat(tmpbuf, &sbuf) && errno == ENOENT) {
+ while (*s) s++;
+ *s++ = ' ';
+ strcpy(s, tmpbuf);
+ }
+ *dirv[i] = '/';
+ }
+ if (s != buf)
+ system(buf);
+}
+
+/* Make filenames more reasonable. */
+
+char *
+fetchname(at,strip_leading,assume_exists)
+char *at;
+int strip_leading;
+int assume_exists;
+{
+ char *fullname;
+ char *name;
+ Reg1 char *t;
+ char tmpbuf[200];
+ int sleading = strip_leading;
+
+ if (!at)
+ return Nullch;
+ while (isspace(*at))
+ at++;
+#ifdef DEBUGGING
+ if (debug & 128)
+ say4("fetchname %s %d %d\n",at,strip_leading,assume_exists);
+#endif
+ if (strnEQ(at, "/dev/null", 9)) /* so files can be created by diffing */
+ return Nullch; /* against /dev/null. */
+ name = fullname = t = savestr(at);
+
+ /* Strip off up to `sleading' leading slashes and null terminate. */
+ for (; *t && !isspace(*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;
+ }
+ }
+
+ name = savestr(name);
+ free(fullname);
+
+ if (stat(name, &filestat) && !assume_exists) {
+ char *filebase = basename(name);
+ int pathlen = filebase - 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)
+ if ( try("RCS/%s%s", filebase, RCSSUFFIX)
+ || try("RCS/%s" , filebase, 0)
+ || try( "%s%s", filebase, RCSSUFFIX)
+ || try("SCCS/%s%s", SCCSPREFIX, filebase)
+ || try( "%s%s", SCCSPREFIX, filebase))
+ return name;
+ free(name);
+ name = Nullch;
+ }
+
+ return name;
+}