diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
commit | d6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch) | |
tree | ece253b876159b39c620e62b6c9b1174642e070e /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.c | 441 |
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; +} |