util.c revision 95601
169793Sobrien/* $FreeBSD: head/gnu/usr.bin/patch/util.c 95601 2002-04-28 01:33:45Z gad $ */ 269793Sobrien 369793Sobrien#include <paths.h> 469793Sobrien 532672Sache#include "EXTERN.h" 632672Sache#include "common.h" 732672Sache#include "INTERN.h" 832672Sache#include "util.h" 932672Sache#include "backupfile.h" 1032672Sache 1195601Sgadvoid my_exit(int _status); /* in patch.c */ 1232672Sache 1332672Sache#ifndef HAVE_STRERROR 1432672Sachestatic char * 1532672Sacheprivate_strerror (errnum) 1632672Sache int errnum; 1732672Sache{ 1832672Sache extern char *sys_errlist[]; 1932672Sache extern int sys_nerr; 2032672Sache 2132672Sache if (errnum > 0 && errnum <= sys_nerr) 2232672Sache return sys_errlist[errnum]; 2332672Sache return "Unknown system error"; 2432672Sache} 2532672Sache#define strerror private_strerror 2632672Sache#endif /* !HAVE_STRERROR */ 2732672Sache 2832672Sache/* Rename a file, copying it if necessary. */ 2932672Sache 3032672Sacheint 3195601Sgadmove_file(char *from, char *to) 3232672Sache{ 3332672Sache char bakname[512]; 3432672Sache Reg1 char *s; 3532672Sache Reg2 int i; 3632672Sache Reg3 int fromfd; 3732672Sache 3832672Sache /* to stdout? */ 3932672Sache 4032672Sache if (strEQ(to, "-")) { 4132672Sache#ifdef DEBUGGING 4232672Sache if (debug & 4) 4332672Sache say2("Moving %s to stdout.\n", from); 4432672Sache#endif 4532672Sache fromfd = open(from, 0); 4632672Sache if (fromfd < 0) 4732672Sache pfatal2("internal error, can't reopen %s", from); 4832672Sache while ((i=read(fromfd, buf, sizeof buf)) > 0) 4932672Sache if (write(1, buf, i) != 1) 5032672Sache pfatal1("write failed"); 5132672Sache Close(fromfd); 5232672Sache return 0; 5332672Sache } 5432672Sache 5532672Sache if (origprae) { 5632672Sache Strcpy(bakname, origprae); 5732672Sache Strcat(bakname, to); 5832672Sache } else { 5932672Sache#ifndef NODIR 6032672Sache char *backupname = find_backup_file_name(to); 6132672Sache if (backupname == (char *) 0) 6232672Sache fatal1("out of memory\n"); 6332672Sache Strcpy(bakname, backupname); 6432672Sache free(backupname); 6532672Sache#else /* NODIR */ 6632672Sache Strcpy(bakname, to); 6732672Sache Strcat(bakname, simple_backup_suffix); 6832672Sache#endif /* NODIR */ 6932672Sache } 7032672Sache 7132672Sache if (stat(to, &filestat) == 0) { /* output file exists */ 7232672Sache dev_t to_device = filestat.st_dev; 7332672Sache ino_t to_inode = filestat.st_ino; 7432672Sache char *simplename = bakname; 7532672Sache 7632672Sache for (s=bakname; *s; s++) { 7732672Sache if (*s == '/') 7832672Sache simplename = s+1; 7932672Sache } 8032672Sache /* Find a backup name that is not the same file. 8132672Sache Change the first lowercase char into uppercase; 8232672Sache if that isn't sufficient, chop off the first char and try again. */ 8332672Sache while (stat(bakname, &filestat) == 0 && 8432672Sache to_device == filestat.st_dev && to_inode == filestat.st_ino) { 8532672Sache /* Skip initial non-lowercase chars. */ 8632672Sache for (s=simplename; *s && !islower((unsigned char)*s); s++) ; 8732672Sache if (*s) 8832672Sache *s = toupper((unsigned char)*s); 8932672Sache else 9032672Sache Strcpy(simplename, simplename+1); 9132672Sache } 9232672Sache while (unlink(bakname) >= 0) ; /* while() is for benefit of Eunice */ 9332672Sache#ifdef DEBUGGING 9432672Sache if (debug & 4) 9532672Sache say3("Moving %s to %s.\n", to, bakname); 9632672Sache#endif 9732672Sache if (rename(to, bakname) < 0) { 9832672Sache say4("Can't backup %s, output is in %s: %s\n", to, from, 9932672Sache strerror(errno)); 10032672Sache return -1; 10132672Sache } 10232672Sache while (unlink(to) >= 0) ; 10332672Sache } 10432672Sache#ifdef DEBUGGING 10532672Sache if (debug & 4) 10632672Sache say3("Moving %s to %s.\n", from, to); 10732672Sache#endif 10832672Sache if (rename(from, to) < 0) { /* different file system? */ 10932672Sache Reg4 int tofd; 11032672Sache 11132672Sache tofd = creat(to, 0666); 11232672Sache if (tofd < 0) { 11332672Sache say4("Can't create %s, output is in %s: %s\n", 11432672Sache to, from, strerror(errno)); 11532672Sache return -1; 11632672Sache } 11732672Sache fromfd = open(from, 0); 11832672Sache if (fromfd < 0) 11932672Sache pfatal2("internal error, can't reopen %s", from); 12032672Sache while ((i=read(fromfd, buf, sizeof buf)) > 0) 12132672Sache if (write(tofd, buf, i) != i) 12232672Sache pfatal1("write failed"); 12332672Sache Close(fromfd); 12432672Sache Close(tofd); 12532672Sache } 12632672Sache Unlink(from); 12732672Sache return 0; 12832672Sache} 12932672Sache 13032672Sache/* Copy a file. */ 13132672Sache 13232672Sachevoid 13395601Sgadcopy_file(char *from, char *to) 13432672Sache{ 13532672Sache Reg3 int tofd; 13632672Sache Reg2 int fromfd; 13732672Sache Reg1 int i; 13832672Sache 13932672Sache tofd = creat(to, 0666); 14032672Sache if (tofd < 0) 14132672Sache pfatal2("can't create %s", to); 14232672Sache fromfd = open(from, 0); 14332672Sache if (fromfd < 0) 14432672Sache pfatal2("internal error, can't reopen %s", from); 14532672Sache while ((i=read(fromfd, buf, sizeof buf)) > 0) 14632672Sache if (write(tofd, buf, i) != i) 14732672Sache pfatal2("write to %s failed", to); 14832672Sache Close(fromfd); 14932672Sache Close(tofd); 15032672Sache} 15132672Sache 15232672Sache/* Allocate a unique area for a string. */ 15332672Sache 15432672Sachechar * 15595601Sgadsavestr(char *s) 15632672Sache{ 15732672Sache Reg3 char *rv; 15832672Sache Reg2 char *t; 15932672Sache 16032672Sache if (!s) 16132672Sache s = "Oops"; 16232672Sache t = s; 16332672Sache while (*t++); 16432672Sache rv = malloc((MEM) (t - s)); 16532672Sache if (rv == Nullch) { 16632672Sache if (using_plan_a) 16732672Sache out_of_mem = TRUE; 16832672Sache else 16932672Sache fatal1("out of memory\n"); 17032672Sache } 17132672Sache else { 17232672Sache t = rv; 17332672Sache while ((*t++ = *s++)); 17432672Sache } 17532672Sache return rv; 17632672Sache} 17732672Sache 17832672Sache#if defined(lint) && defined(CANVARARG) 17932672Sache 18032672Sache/*VARARGS ARGSUSED*/ 18132672Sachesay(pat) char *pat; { ; } 18232672Sache/*VARARGS ARGSUSED*/ 18332672Sachefatal(pat) char *pat; { ; } 18432672Sache/*VARARGS ARGSUSED*/ 18532672Sachepfatal(pat) char *pat; { ; } 18632672Sache/*VARARGS ARGSUSED*/ 18732672Sacheask(pat) char *pat; { ; } 18832672Sache 18932672Sache#else 19032672Sache 19132672Sache/* Vanilla terminal output (buffered). */ 19232672Sache 19332672Sachevoid 19432672Sachesay(pat,arg1,arg2,arg3) 19532672Sachechar *pat; 19632672Sachelong arg1,arg2,arg3; 19732672Sache{ 19832672Sache fprintf(stderr, pat, arg1, arg2, arg3); 19932672Sache Fflush(stderr); 20032672Sache} 20132672Sache 20232672Sache/* Terminal output, pun intended. */ 20332672Sache 20432672Sachevoid /* very void */ 20532672Sachefatal(pat,arg1,arg2,arg3) 20632672Sachechar *pat; 20732672Sachelong arg1,arg2,arg3; 20832672Sache{ 20932672Sache fprintf(stderr, "patch: **** "); 21032672Sache fprintf(stderr, pat, arg1, arg2, arg3); 21132672Sache my_exit(1); 21232672Sache} 21332672Sache 21432672Sache/* Say something from patch, something from the system, then silence . . . */ 21532672Sache 21632672Sachevoid /* very void */ 21732672Sachepfatal(pat,arg1,arg2,arg3) 21832672Sachechar *pat; 21932672Sachelong arg1,arg2,arg3; 22032672Sache{ 22132672Sache int errnum = errno; 22232672Sache 22332672Sache fprintf(stderr, "patch: **** "); 22432672Sache fprintf(stderr, pat, arg1, arg2, arg3); 22532672Sache fprintf(stderr, ": %s\n", strerror(errnum)); 22632672Sache my_exit(1); 22732672Sache} 22832672Sache 22932672Sache/* Get a response from the user, somehow or other. */ 23032672Sache 23132672Sacheint 23232672Sacheask(pat,arg1,arg2,arg3) 23332672Sachechar *pat; 23432672Sachelong arg1,arg2,arg3; 23532672Sache{ 23632672Sache int ttyfd; 23732672Sache int r; 23832672Sache bool tty2 = isatty(2); 23932672Sache 24032672Sache Sprintf(buf, pat, arg1, arg2, arg3); 24132672Sache Fflush(stderr); 24232672Sache write(2, buf, strlen(buf)); 24332672Sache if (tty2) { /* might be redirected to a file */ 24432672Sache r = read(2, buf, sizeof buf); 24532672Sache } 24632672Sache else if (isatty(1)) { /* this may be new file output */ 24732672Sache Fflush(stdout); 24832672Sache write(1, buf, strlen(buf)); 24932672Sache r = read(1, buf, sizeof buf); 25032672Sache } 25169793Sobrien else if ((ttyfd = open(_PATH_TTY, 2)) >= 0 && isatty(ttyfd)) { 25232672Sache /* might be deleted or unwriteable */ 25332672Sache write(ttyfd, buf, strlen(buf)); 25432672Sache r = read(ttyfd, buf, sizeof buf); 25532672Sache Close(ttyfd); 25632672Sache } 25732672Sache else if (isatty(0)) { /* this is probably patch input */ 25832672Sache Fflush(stdin); 25932672Sache write(0, buf, strlen(buf)); 26032672Sache r = read(0, buf, sizeof buf); 26132672Sache } 26232672Sache else { /* no terminal at all--default it */ 26332672Sache buf[0] = '\n'; 26432672Sache buf[1] = 0; 26532672Sache say1(buf); 26632672Sache return 0; /* signal possible error */ 26732672Sache } 26832672Sache if (r <= 0) 26932672Sache buf[0] = 0; 27032672Sache else 27132672Sache buf[r] = '\0'; 27232672Sache if (!tty2) 27332672Sache say1(buf); 27432672Sache 27532672Sache if (r <= 0) 27632672Sache return 0; /* if there was an error, return it */ 27732672Sache else 27832672Sache return 1; 27932672Sache} 28032672Sache#endif /* lint */ 28132672Sache 28232672Sache/* How to handle certain events when not in a critical region. */ 28332672Sache 28432672Sachevoid 28595601Sgadset_signals(int reset) 28632672Sache{ 28732672Sache#ifndef lint 28832672Sache static RETSIGTYPE (*hupval)(),(*intval)(); 28932672Sache 29032672Sache if (!reset) { 29132672Sache hupval = signal(SIGHUP, SIG_IGN); 29232672Sache if (hupval != SIG_IGN) 29332672Sache hupval = (RETSIGTYPE(*)())my_exit; 29432672Sache intval = signal(SIGINT, SIG_IGN); 29532672Sache if (intval != SIG_IGN) 29632672Sache intval = (RETSIGTYPE(*)())my_exit; 29732672Sache } 29832672Sache Signal(SIGHUP, hupval); 29932672Sache Signal(SIGINT, intval); 30032672Sache#endif 30132672Sache} 30232672Sache 30332672Sache/* How to handle certain events when in a critical region. */ 30432672Sache 30532672Sachevoid 30695601Sgadignore_signals(void) 30732672Sache{ 30832672Sache#ifndef lint 30932672Sache Signal(SIGHUP, SIG_IGN); 31032672Sache Signal(SIGINT, SIG_IGN); 31132672Sache#endif 31232672Sache} 31332672Sache 31432672Sache/* Make sure we'll have the directories to create a file. 31532672Sache If `striplast' is TRUE, ignore the last element of `filename'. */ 31632672Sache 31732672Sachevoid 31832672Sachemakedirs(filename,striplast) 31932672SacheReg1 char *filename; 32032672Sachebool striplast; 32132672Sache{ 32232672Sache char tmpbuf[256]; 32332672Sache Reg2 char *s = tmpbuf; 32432672Sache char *dirv[20]; /* Point to the NULs between elements. */ 32532672Sache Reg3 int i; 32632672Sache Reg4 int dirvp = 0; /* Number of finished entries in dirv. */ 32732672Sache 32832672Sache /* Copy `filename' into `tmpbuf' with a NUL instead of a slash 32932672Sache between the directories. */ 33032672Sache while (*filename) { 33132672Sache if (*filename == '/') { 33232672Sache filename++; 33332672Sache dirv[dirvp++] = s; 33432672Sache *s++ = '\0'; 33532672Sache } 33632672Sache else { 33732672Sache *s++ = *filename++; 33832672Sache } 33932672Sache } 34032672Sache *s = '\0'; 34132672Sache dirv[dirvp] = s; 34232672Sache if (striplast) 34332672Sache dirvp--; 34432672Sache if (dirvp < 0) 34532672Sache return; 34632672Sache 34732672Sache strcpy(buf, "mkdir"); 34832672Sache s = buf; 34932672Sache for (i=0; i<=dirvp; i++) { 35032672Sache struct stat sbuf; 35132672Sache 35232672Sache if (stat(tmpbuf, &sbuf) && errno == ENOENT) { 35332672Sache while (*s) s++; 35432672Sache *s++ = ' '; 35532672Sache strcpy(s, tmpbuf); 35632672Sache } 35732672Sache *dirv[i] = '/'; 35832672Sache } 35932672Sache if (s != buf) 36032672Sache system(buf); 36132672Sache} 36232672Sache 36332672Sache/* Make filenames more reasonable. */ 36432672Sache 36532672Sachechar * 36695601Sgadfetchname(char *at, int strip_leading, int assume_exists) 36732672Sache{ 36832672Sache char *fullname; 36932672Sache char *name; 37032672Sache Reg1 char *t; 37132672Sache char tmpbuf[200]; 37232672Sache int sleading = strip_leading; 37332672Sache 37432672Sache if (!at) 37532672Sache return Nullch; 37632672Sache while (isspace((unsigned char)*at)) 37732672Sache at++; 37832672Sache#ifdef DEBUGGING 37932672Sache if (debug & 128) 38032672Sache say4("fetchname %s %d %d\n",at,strip_leading,assume_exists); 38132672Sache#endif 38269793Sobrien if (strnEQ(at, _PATH_DEVNULL, sizeof _PATH_DEVNULL - 1)) /* so files can be created by diffing */ 38332672Sache return Nullch; /* against /dev/null. */ 38432672Sache name = fullname = t = savestr(at); 38532672Sache 38632672Sache /* Strip off up to `sleading' leading slashes and null terminate. */ 38732672Sache for (; *t && !isspace((unsigned char)*t); t++) 38832672Sache if (*t == '/') 38932672Sache if (--sleading >= 0) 39032672Sache name = t+1; 39132672Sache *t = '\0'; 39232672Sache 39332672Sache /* If no -p option was given (957 is the default value!), 39432672Sache we were given a relative pathname, 39532672Sache and the leading directories that we just stripped off all exist, 39632672Sache put them back on. */ 39732672Sache if (strip_leading == 957 && name != fullname && *fullname != '/') { 39832672Sache name[-1] = '\0'; 39932672Sache if (stat(fullname, &filestat) == 0 && S_ISDIR (filestat.st_mode)) { 40032672Sache name[-1] = '/'; 40132672Sache name=fullname; 40232672Sache } 40332672Sache } 40432672Sache 40532672Sache name = savestr(name); 40632672Sache free(fullname); 40732672Sache 40832672Sache if (stat(name, &filestat) && !assume_exists) { 40932672Sache char *filebase = basename(name); 41032672Sache int pathlen = filebase - name; 41132672Sache 41232672Sache /* Put any leading path into `tmpbuf'. */ 41332672Sache strncpy(tmpbuf, name, pathlen); 41432672Sache 41532672Sache#define try(f, a1, a2) (Sprintf(tmpbuf + pathlen, f, a1, a2), stat(tmpbuf, &filestat) == 0) 41632672Sache if ( try("RCS/%s%s", filebase, RCSSUFFIX) 41732672Sache || try("RCS/%s%s", filebase, "") 41832672Sache || try( "%s%s", filebase, RCSSUFFIX) 41932672Sache || try("SCCS/%s%s", SCCSPREFIX, filebase) 42032672Sache || try( "%s%s", SCCSPREFIX, filebase)) 42132672Sache return name; 42232672Sache free(name); 42332672Sache name = Nullch; 42432672Sache } 42532672Sache 42632672Sache return name; 42732672Sache} 42832672Sache 42932672Sachechar * 43095601Sgadxmalloc(unsigned int size) 43132672Sache{ 43232672Sache register char *p = (char *) malloc (size); 43332672Sache if (!p) 43432672Sache fatal("out of memory"); 43532672Sache return p; 43632672Sache} 437