Home | History | Annotate | Line # | Download | only in patch
util.c revision 1.1.1.1
      1      1.1  cgd #include "EXTERN.h"
      2      1.1  cgd #include "common.h"
      3      1.1  cgd #include "INTERN.h"
      4      1.1  cgd #include "util.h"
      5      1.1  cgd 
      6      1.1  cgd /* Rename a file, copying it if necessary. */
      7      1.1  cgd 
      8      1.1  cgd int
      9      1.1  cgd move_file(from,to)
     10      1.1  cgd char *from, *to;
     11      1.1  cgd {
     12      1.1  cgd     char bakname[512];
     13      1.1  cgd     Reg1 char *s;
     14      1.1  cgd     Reg2 int i;
     15      1.1  cgd     Reg3 int fromfd;
     16      1.1  cgd 
     17      1.1  cgd     /* to stdout? */
     18      1.1  cgd 
     19      1.1  cgd     if (strEQ(to, "-")) {
     20      1.1  cgd #ifdef DEBUGGING
     21      1.1  cgd 	if (debug & 4)
     22      1.1  cgd 	    say2("Moving %s to stdout.\n", from);
     23      1.1  cgd #endif
     24      1.1  cgd 	fromfd = open(from, 0);
     25      1.1  cgd 	if (fromfd < 0)
     26  1.1.1.1  tls 	    fatal2("patch: internal error, can't reopen %s\n", from);
     27      1.1  cgd 	while ((i=read(fromfd, buf, sizeof buf)) > 0)
     28      1.1  cgd 	    if (write(1, buf, i) != 1)
     29  1.1.1.1  tls 		fatal1("patch: write failed\n");
     30      1.1  cgd 	Close(fromfd);
     31      1.1  cgd 	return 0;
     32      1.1  cgd     }
     33      1.1  cgd 
     34  1.1.1.1  tls     Strcpy(bakname, to);
     35  1.1.1.1  tls     Strcat(bakname, origext?origext:ORIGEXT);
     36  1.1.1.1  tls     if (stat(to, &filestat) >= 0) {	/* output file exists */
     37      1.1  cgd 	dev_t to_device = filestat.st_dev;
     38      1.1  cgd 	ino_t to_inode  = filestat.st_ino;
     39      1.1  cgd 	char *simplename = bakname;
     40      1.1  cgd 
     41      1.1  cgd 	for (s=bakname; *s; s++) {
     42      1.1  cgd 	    if (*s == '/')
     43      1.1  cgd 		simplename = s+1;
     44      1.1  cgd 	}
     45  1.1.1.1  tls 	/* find a backup name that is not the same file */
     46  1.1.1.1  tls 	while (stat(bakname, &filestat) >= 0 &&
     47      1.1  cgd 		to_device == filestat.st_dev && to_inode == filestat.st_ino) {
     48      1.1  cgd 	    for (s=simplename; *s && !islower(*s); s++) ;
     49      1.1  cgd 	    if (*s)
     50      1.1  cgd 		*s = toupper(*s);
     51      1.1  cgd 	    else
     52      1.1  cgd 		Strcpy(simplename, simplename+1);
     53      1.1  cgd 	}
     54      1.1  cgd 	while (unlink(bakname) >= 0) ;	/* while() is for benefit of Eunice */
     55      1.1  cgd #ifdef DEBUGGING
     56      1.1  cgd 	if (debug & 4)
     57      1.1  cgd 	    say3("Moving %s to %s.\n", to, bakname);
     58      1.1  cgd #endif
     59      1.1  cgd 	if (link(to, bakname) < 0) {
     60  1.1.1.1  tls 	    say3("patch: can't backup %s, output is in %s\n",
     61  1.1.1.1  tls 		to, from);
     62  1.1.1.1  tls 	    return -1;
     63      1.1  cgd 	}
     64      1.1  cgd 	while (unlink(to) >= 0) ;
     65      1.1  cgd     }
     66      1.1  cgd #ifdef DEBUGGING
     67      1.1  cgd     if (debug & 4)
     68      1.1  cgd 	say3("Moving %s to %s.\n", from, to);
     69      1.1  cgd #endif
     70      1.1  cgd     if (link(from, to) < 0) {		/* different file system? */
     71      1.1  cgd 	Reg4 int tofd;
     72      1.1  cgd 
     73      1.1  cgd 	tofd = creat(to, 0666);
     74      1.1  cgd 	if (tofd < 0) {
     75  1.1.1.1  tls 	    say3("patch: can't create %s, output is in %s.\n",
     76  1.1.1.1  tls 	      to, from);
     77      1.1  cgd 	    return -1;
     78      1.1  cgd 	}
     79      1.1  cgd 	fromfd = open(from, 0);
     80      1.1  cgd 	if (fromfd < 0)
     81  1.1.1.1  tls 	    fatal2("patch: internal error, can't reopen %s\n", from);
     82      1.1  cgd 	while ((i=read(fromfd, buf, sizeof buf)) > 0)
     83      1.1  cgd 	    if (write(tofd, buf, i) != i)
     84  1.1.1.1  tls 		fatal1("patch: write failed\n");
     85      1.1  cgd 	Close(fromfd);
     86      1.1  cgd 	Close(tofd);
     87      1.1  cgd     }
     88      1.1  cgd     Unlink(from);
     89      1.1  cgd     return 0;
     90      1.1  cgd }
     91      1.1  cgd 
     92      1.1  cgd /* Copy a file. */
     93      1.1  cgd 
     94      1.1  cgd void
     95      1.1  cgd copy_file(from,to)
     96      1.1  cgd char *from, *to;
     97      1.1  cgd {
     98      1.1  cgd     Reg3 int tofd;
     99      1.1  cgd     Reg2 int fromfd;
    100      1.1  cgd     Reg1 int i;
    101      1.1  cgd 
    102      1.1  cgd     tofd = creat(to, 0666);
    103      1.1  cgd     if (tofd < 0)
    104  1.1.1.1  tls 	fatal2("patch: can't create %s.\n", to);
    105      1.1  cgd     fromfd = open(from, 0);
    106      1.1  cgd     if (fromfd < 0)
    107  1.1.1.1  tls 	fatal2("patch: internal error, can't reopen %s\n", from);
    108      1.1  cgd     while ((i=read(fromfd, buf, sizeof buf)) > 0)
    109      1.1  cgd 	if (write(tofd, buf, i) != i)
    110  1.1.1.1  tls 	    fatal2("patch: write (%s) failed\n", to);
    111      1.1  cgd     Close(fromfd);
    112      1.1  cgd     Close(tofd);
    113      1.1  cgd }
    114      1.1  cgd 
    115      1.1  cgd /* Allocate a unique area for a string. */
    116      1.1  cgd 
    117      1.1  cgd char *
    118      1.1  cgd savestr(s)
    119      1.1  cgd Reg1 char *s;
    120      1.1  cgd {
    121      1.1  cgd     Reg3 char *rv;
    122      1.1  cgd     Reg2 char *t;
    123      1.1  cgd 
    124      1.1  cgd     if (!s)
    125      1.1  cgd 	s = "Oops";
    126      1.1  cgd     t = s;
    127      1.1  cgd     while (*t++);
    128      1.1  cgd     rv = malloc((MEM) (t - s));
    129      1.1  cgd     if (rv == Nullch) {
    130      1.1  cgd 	if (using_plan_a)
    131      1.1  cgd 	    out_of_mem = TRUE;
    132      1.1  cgd 	else
    133  1.1.1.1  tls 	    fatal1("patch: out of memory (savestr)\n");
    134      1.1  cgd     }
    135      1.1  cgd     else {
    136      1.1  cgd 	t = rv;
    137      1.1  cgd 	while (*t++ = *s++);
    138      1.1  cgd     }
    139      1.1  cgd     return rv;
    140      1.1  cgd }
    141      1.1  cgd 
    142      1.1  cgd #if defined(lint) && defined(CANVARARG)
    143      1.1  cgd 
    144      1.1  cgd /*VARARGS ARGSUSED*/
    145      1.1  cgd say(pat) char *pat; { ; }
    146      1.1  cgd /*VARARGS ARGSUSED*/
    147      1.1  cgd fatal(pat) char *pat; { ; }
    148      1.1  cgd /*VARARGS ARGSUSED*/
    149      1.1  cgd ask(pat) char *pat; { ; }
    150      1.1  cgd 
    151      1.1  cgd #else
    152      1.1  cgd 
    153      1.1  cgd /* Vanilla terminal output (buffered). */
    154      1.1  cgd 
    155      1.1  cgd void
    156      1.1  cgd say(pat,arg1,arg2,arg3)
    157      1.1  cgd char *pat;
    158  1.1.1.1  tls int arg1,arg2,arg3;
    159      1.1  cgd {
    160      1.1  cgd     fprintf(stderr, pat, arg1, arg2, arg3);
    161      1.1  cgd     Fflush(stderr);
    162      1.1  cgd }
    163      1.1  cgd 
    164      1.1  cgd /* Terminal output, pun intended. */
    165      1.1  cgd 
    166      1.1  cgd void				/* very void */
    167      1.1  cgd fatal(pat,arg1,arg2,arg3)
    168      1.1  cgd char *pat;
    169  1.1.1.1  tls int arg1,arg2,arg3;
    170      1.1  cgd {
    171  1.1.1.1  tls     void my_exit();
    172      1.1  cgd 
    173  1.1.1.1  tls     say(pat, arg1, arg2, arg3);
    174      1.1  cgd     my_exit(1);
    175      1.1  cgd }
    176      1.1  cgd 
    177      1.1  cgd /* Get a response from the user, somehow or other. */
    178      1.1  cgd 
    179      1.1  cgd void
    180      1.1  cgd ask(pat,arg1,arg2,arg3)
    181      1.1  cgd char *pat;
    182  1.1.1.1  tls int arg1,arg2,arg3;
    183      1.1  cgd {
    184      1.1  cgd     int ttyfd;
    185      1.1  cgd     int r;
    186      1.1  cgd     bool tty2 = isatty(2);
    187      1.1  cgd 
    188      1.1  cgd     Sprintf(buf, pat, arg1, arg2, arg3);
    189      1.1  cgd     Fflush(stderr);
    190      1.1  cgd     write(2, buf, strlen(buf));
    191      1.1  cgd     if (tty2) {				/* might be redirected to a file */
    192      1.1  cgd 	r = read(2, buf, sizeof buf);
    193      1.1  cgd     }
    194      1.1  cgd     else if (isatty(1)) {		/* this may be new file output */
    195      1.1  cgd 	Fflush(stdout);
    196      1.1  cgd 	write(1, buf, strlen(buf));
    197      1.1  cgd 	r = read(1, buf, sizeof buf);
    198      1.1  cgd     }
    199      1.1  cgd     else if ((ttyfd = open("/dev/tty", 2)) >= 0 && isatty(ttyfd)) {
    200      1.1  cgd 					/* might be deleted or unwriteable */
    201      1.1  cgd 	write(ttyfd, buf, strlen(buf));
    202      1.1  cgd 	r = read(ttyfd, buf, sizeof buf);
    203      1.1  cgd 	Close(ttyfd);
    204      1.1  cgd     }
    205      1.1  cgd     else if (isatty(0)) {		/* this is probably patch input */
    206      1.1  cgd 	Fflush(stdin);
    207      1.1  cgd 	write(0, buf, strlen(buf));
    208      1.1  cgd 	r = read(0, buf, sizeof buf);
    209      1.1  cgd     }
    210      1.1  cgd     else {				/* no terminal at all--default it */
    211      1.1  cgd 	buf[0] = '\n';
    212      1.1  cgd 	r = 1;
    213      1.1  cgd     }
    214      1.1  cgd     if (r <= 0)
    215      1.1  cgd 	buf[0] = 0;
    216      1.1  cgd     else
    217      1.1  cgd 	buf[r] = '\0';
    218      1.1  cgd     if (!tty2)
    219      1.1  cgd 	say1(buf);
    220      1.1  cgd }
    221  1.1.1.1  tls #endif lint
    222      1.1  cgd 
    223      1.1  cgd /* How to handle certain events when not in a critical region. */
    224      1.1  cgd 
    225      1.1  cgd void
    226  1.1.1.1  tls set_signals()
    227      1.1  cgd {
    228  1.1.1.1  tls     void my_exit();
    229      1.1  cgd 
    230  1.1.1.1  tls #ifndef lint
    231  1.1.1.1  tls     if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
    232  1.1.1.1  tls 	Signal(SIGHUP, my_exit);
    233  1.1.1.1  tls     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
    234  1.1.1.1  tls 	Signal(SIGINT, my_exit);
    235      1.1  cgd #endif
    236      1.1  cgd }
    237      1.1  cgd 
    238      1.1  cgd /* How to handle certain events when in a critical region. */
    239      1.1  cgd 
    240      1.1  cgd void
    241      1.1  cgd ignore_signals()
    242      1.1  cgd {
    243      1.1  cgd #ifndef lint
    244      1.1  cgd     Signal(SIGHUP, SIG_IGN);
    245      1.1  cgd     Signal(SIGINT, SIG_IGN);
    246      1.1  cgd #endif
    247      1.1  cgd }
    248      1.1  cgd 
    249  1.1.1.1  tls /* Make sure we'll have the directories to create a file. */
    250      1.1  cgd 
    251      1.1  cgd void
    252      1.1  cgd makedirs(filename,striplast)
    253      1.1  cgd Reg1 char *filename;
    254      1.1  cgd bool striplast;
    255      1.1  cgd {
    256      1.1  cgd     char tmpbuf[256];
    257      1.1  cgd     Reg2 char *s = tmpbuf;
    258  1.1.1.1  tls     char *dirv[20];
    259      1.1  cgd     Reg3 int i;
    260  1.1.1.1  tls     Reg4 int dirvp = 0;
    261      1.1  cgd 
    262      1.1  cgd     while (*filename) {
    263      1.1  cgd 	if (*filename == '/') {
    264      1.1  cgd 	    filename++;
    265      1.1  cgd 	    dirv[dirvp++] = s;
    266      1.1  cgd 	    *s++ = '\0';
    267      1.1  cgd 	}
    268      1.1  cgd 	else {
    269      1.1  cgd 	    *s++ = *filename++;
    270      1.1  cgd 	}
    271      1.1  cgd     }
    272      1.1  cgd     *s = '\0';
    273      1.1  cgd     dirv[dirvp] = s;
    274      1.1  cgd     if (striplast)
    275      1.1  cgd 	dirvp--;
    276      1.1  cgd     if (dirvp < 0)
    277      1.1  cgd 	return;
    278      1.1  cgd     strcpy(buf, "mkdir");
    279      1.1  cgd     s = buf;
    280      1.1  cgd     for (i=0; i<=dirvp; i++) {
    281  1.1.1.1  tls 	while (*s) s++;
    282  1.1.1.1  tls 	*s++ = ' ';
    283  1.1.1.1  tls 	strcpy(s, tmpbuf);
    284      1.1  cgd 	*dirv[i] = '/';
    285      1.1  cgd     }
    286  1.1.1.1  tls     system(buf);
    287      1.1  cgd }
    288      1.1  cgd 
    289      1.1  cgd /* Make filenames more reasonable. */
    290      1.1  cgd 
    291      1.1  cgd char *
    292      1.1  cgd fetchname(at,strip_leading,assume_exists)
    293      1.1  cgd char *at;
    294      1.1  cgd int strip_leading;
    295      1.1  cgd int assume_exists;
    296      1.1  cgd {
    297  1.1.1.1  tls     char *s;
    298      1.1  cgd     char *name;
    299      1.1  cgd     Reg1 char *t;
    300      1.1  cgd     char tmpbuf[200];
    301      1.1  cgd 
    302      1.1  cgd     if (!at)
    303      1.1  cgd 	return Nullch;
    304  1.1.1.1  tls     s = savestr(at);
    305  1.1.1.1  tls     for (t=s; isspace(*t); t++) ;
    306  1.1.1.1  tls     name = t;
    307      1.1  cgd #ifdef DEBUGGING
    308      1.1  cgd     if (debug & 128)
    309  1.1.1.1  tls 	say4("fetchname %s %d %d\n",name,strip_leading,assume_exists);
    310      1.1  cgd #endif
    311  1.1.1.1  tls     if (strnEQ(name, "/dev/null", 9))	/* so files can be created by diffing */
    312      1.1  cgd 	return Nullch;			/*   against /dev/null. */
    313      1.1  cgd     for (; *t && !isspace(*t); t++)
    314      1.1  cgd 	if (*t == '/')
    315  1.1.1.1  tls 	    if (--strip_leading >= 0)
    316      1.1  cgd 		name = t+1;
    317      1.1  cgd     *t = '\0';
    318  1.1.1.1  tls     if (name != s && *s != '/') {
    319      1.1  cgd 	name[-1] = '\0';
    320  1.1.1.1  tls 	if (stat(s, &filestat) && filestat.st_mode & S_IFDIR) {
    321      1.1  cgd 	    name[-1] = '/';
    322  1.1.1.1  tls 	    name=s;
    323      1.1  cgd 	}
    324      1.1  cgd     }
    325      1.1  cgd     name = savestr(name);
    326  1.1.1.1  tls     Sprintf(tmpbuf, "RCS/%s", name);
    327  1.1.1.1  tls     free(s);
    328  1.1.1.1  tls     if (stat(name, &filestat) < 0 && !assume_exists) {
    329  1.1.1.1  tls 	Strcat(tmpbuf, RCSSUFFIX);
    330  1.1.1.1  tls 	if (stat(tmpbuf, &filestat) < 0 && stat(tmpbuf+4, &filestat) < 0) {
    331  1.1.1.1  tls 	    Sprintf(tmpbuf, "SCCS/%s%s", SCCSPREFIX, name);
    332  1.1.1.1  tls 	    if (stat(tmpbuf, &filestat) < 0 && stat(tmpbuf+5, &filestat) < 0) {
    333  1.1.1.1  tls 		free(name);
    334  1.1.1.1  tls 		name = Nullch;
    335  1.1.1.1  tls 	    }
    336  1.1.1.1  tls 	}
    337      1.1  cgd     }
    338      1.1  cgd     return name;
    339      1.1  cgd }
    340