Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / gnu / usr.bin / patch / util.c
1 /* $FreeBSD: src/gnu/usr.bin/patch/util.c,v 1.7.6.2 2002/04/30 20:40:02 gad Exp $ */
2 /* $DragonFly: src/gnu/usr.bin/patch/Attic/util.c,v 1.2 2003/06/17 04:25:47 dillon Exp $ */
3
4 #include <paths.h>
5
6 #include "EXTERN.h"
7 #include "common.h"
8 #include "INTERN.h"
9 #include "util.h"
10 #include "backupfile.h"
11
12 void    my_exit(int _status);           /* in patch.c */
13
14 #ifndef HAVE_STRERROR
15 static char *
16 private_strerror (errnum)
17      int errnum;
18 {
19   extern char *sys_errlist[];
20   extern int sys_nerr;
21
22   if (errnum > 0 && errnum <= sys_nerr)
23     return sys_errlist[errnum];
24   return "Unknown system error";
25 }
26 #define strerror private_strerror
27 #endif /* !HAVE_STRERROR */
28
29 /* Rename a file, copying it if necessary. */
30
31 int
32 move_file(char *from, char *to)
33 {
34     char bakname[512];
35     Reg1 char *s;
36     Reg2 int i;
37     Reg3 int fromfd;
38
39     /* to stdout? */
40
41     if (strEQ(to, "-")) {
42 #ifdef DEBUGGING
43         if (debug & 4)
44             say2("Moving %s to stdout.\n", from);
45 #endif
46         fromfd = open(from, 0);
47         if (fromfd < 0)
48             pfatal2("internal error, can't reopen %s", from);
49         while ((i=read(fromfd, buf, sizeof buf)) > 0)
50             if (write(1, buf, i) != 1)
51                 pfatal1("write failed");
52         Close(fromfd);
53         return 0;
54     }
55
56     if (origprae) {
57         Strcpy(bakname, origprae);
58         Strcat(bakname, to);
59     } else {
60 #ifndef NODIR
61         char *backupname = find_backup_file_name(to);
62         if (backupname == (char *) 0)
63             fatal1("out of memory\n");
64         Strcpy(bakname, backupname);
65         free(backupname);
66 #else /* NODIR */
67         Strcpy(bakname, to);
68         Strcat(bakname, simple_backup_suffix);
69 #endif /* NODIR */
70     }
71
72     if (stat(to, &filestat) == 0) {     /* output file exists */
73         dev_t to_device = filestat.st_dev;
74         ino_t to_inode  = filestat.st_ino;
75         char *simplename = bakname;
76
77         for (s=bakname; *s; s++) {
78             if (*s == '/')
79                 simplename = s+1;
80         }
81         /* Find a backup name that is not the same file.
82            Change the first lowercase char into uppercase;
83            if that isn't sufficient, chop off the first char and try again.  */
84         while (stat(bakname, &filestat) == 0 &&
85                 to_device == filestat.st_dev && to_inode == filestat.st_ino) {
86             /* Skip initial non-lowercase chars.  */
87             for (s=simplename; *s && !islower((unsigned char)*s); s++) ;
88             if (*s)
89                 *s = toupper((unsigned char)*s);
90             else
91                 Strcpy(simplename, simplename+1);
92         }
93         while (unlink(bakname) >= 0) ;  /* while() is for benefit of Eunice */
94 #ifdef DEBUGGING
95         if (debug & 4)
96             say3("Moving %s to %s.\n", to, bakname);
97 #endif
98         if (rename(to, bakname) < 0) {
99             say4("Can't backup %s, output is in %s: %s\n", to, from,
100                  strerror(errno));
101             return -1;
102         }
103         while (unlink(to) >= 0) ;
104     }
105 #ifdef DEBUGGING
106     if (debug & 4)
107         say3("Moving %s to %s.\n", from, to);
108 #endif
109     if (rename(from, to) < 0) {         /* different file system? */
110         Reg4 int tofd;
111
112         tofd = creat(to, 0666);
113         if (tofd < 0) {
114             say4("Can't create %s, output is in %s: %s\n",
115               to, from, strerror(errno));
116             return -1;
117         }
118         fromfd = open(from, 0);
119         if (fromfd < 0)
120             pfatal2("internal error, can't reopen %s", from);
121         while ((i=read(fromfd, buf, sizeof buf)) > 0)
122             if (write(tofd, buf, i) != i)
123                 pfatal1("write failed");
124         Close(fromfd);
125         Close(tofd);
126     }
127     Unlink(from);
128     return 0;
129 }
130
131 /* Copy a file. */
132
133 void
134 copy_file(char *from, char *to)
135 {
136     Reg3 int tofd;
137     Reg2 int fromfd;
138     Reg1 int i;
139
140     tofd = creat(to, 0666);
141     if (tofd < 0)
142         pfatal2("can't create %s", to);
143     fromfd = open(from, 0);
144     if (fromfd < 0)
145         pfatal2("internal error, can't reopen %s", from);
146     while ((i=read(fromfd, buf, sizeof buf)) > 0)
147         if (write(tofd, buf, i) != i)
148             pfatal2("write to %s failed", to);
149     Close(fromfd);
150     Close(tofd);
151 }
152
153 /* Allocate a unique area for a string. */
154
155 char *
156 savestr(char *s)
157 {
158     Reg3 char *rv;
159     Reg2 char *t;
160
161     if (!s)
162         s = "Oops";
163     t = s;
164     while (*t++);
165     rv = malloc((MEM) (t - s));
166     if (rv == Nullch) {
167         if (using_plan_a)
168             out_of_mem = TRUE;
169         else
170             fatal1("out of memory\n");
171     }
172     else {
173         t = rv;
174         while ((*t++ = *s++));
175     }
176     return rv;
177 }
178
179 #if defined(lint) && defined(CANVARARG)
180
181 /*VARARGS ARGSUSED*/
182 say(pat) char *pat; { ; }
183 /*VARARGS ARGSUSED*/
184 fatal(pat) char *pat; { ; }
185 /*VARARGS ARGSUSED*/
186 pfatal(pat) char *pat; { ; }
187 /*VARARGS ARGSUSED*/
188 ask(pat) char *pat; { ; }
189
190 #else
191
192 /* Vanilla terminal output (buffered). */
193
194 void
195 say(pat,arg1,arg2,arg3)
196 char *pat;
197 long arg1,arg2,arg3;
198 {
199     fprintf(stderr, pat, arg1, arg2, arg3);
200     Fflush(stderr);
201 }
202
203 /* Terminal output, pun intended. */
204
205 void                            /* very void */
206 fatal(pat,arg1,arg2,arg3)
207 char *pat;
208 long arg1,arg2,arg3;
209 {
210     fprintf(stderr, "patch: **** ");
211     fprintf(stderr, pat, arg1, arg2, arg3);
212     my_exit(1);
213 }
214
215 /* Say something from patch, something from the system, then silence . . . */
216
217 void                            /* very void */
218 pfatal(pat,arg1,arg2,arg3)
219 char *pat;
220 long arg1,arg2,arg3;
221 {
222     int errnum = errno;
223
224     fprintf(stderr, "patch: **** ");
225     fprintf(stderr, pat, arg1, arg2, arg3);
226     fprintf(stderr, ": %s\n", strerror(errnum));
227     my_exit(1);
228 }
229
230 /* Get a response from the user, somehow or other. */
231
232 int
233 ask(pat,arg1,arg2,arg3)
234 char *pat;
235 long arg1,arg2,arg3;
236 {
237     int ttyfd;
238     int r;
239     bool tty2 = isatty(2);
240
241     Sprintf(buf, pat, arg1, arg2, arg3);
242     Fflush(stderr);
243     write(2, buf, strlen(buf));
244     if (tty2) {                         /* might be redirected to a file */
245         r = read(2, buf, sizeof buf);
246     }
247     else if (isatty(1)) {               /* this may be new file output */
248         Fflush(stdout);
249         write(1, buf, strlen(buf));
250         r = read(1, buf, sizeof buf);
251     }
252     else if ((ttyfd = open(_PATH_TTY, 2)) >= 0 && isatty(ttyfd)) {
253                                         /* might be deleted or unwriteable */
254         write(ttyfd, buf, strlen(buf));
255         r = read(ttyfd, buf, sizeof buf);
256         Close(ttyfd);
257     }
258     else if (isatty(0)) {               /* this is probably patch input */
259         Fflush(stdin);
260         write(0, buf, strlen(buf));
261         r = read(0, buf, sizeof buf);
262     }
263     else {                              /* no terminal at all--default it */
264         buf[0] = '\n';
265         buf[1] = 0;
266         say1(buf);
267         return 0;                       /* signal possible error */
268     }
269     if (r <= 0)
270         buf[0] = 0;
271     else
272         buf[r] = '\0';
273     if (!tty2)
274         say1(buf);
275
276     if (r <= 0)
277         return 0;                       /* if there was an error, return it */
278     else
279         return 1;
280 }
281 #endif /* lint */
282
283 /* How to handle certain events when not in a critical region. */
284
285 void
286 set_signals(int reset)
287 {
288 #ifndef lint
289     static RETSIGTYPE (*hupval)(),(*intval)();
290
291     if (!reset) {
292         hupval = signal(SIGHUP, SIG_IGN);
293         if (hupval != SIG_IGN)
294             hupval = (RETSIGTYPE(*)())my_exit;
295         intval = signal(SIGINT, SIG_IGN);
296         if (intval != SIG_IGN)
297             intval = (RETSIGTYPE(*)())my_exit;
298     }
299     Signal(SIGHUP, hupval);
300     Signal(SIGINT, intval);
301 #endif
302 }
303
304 /* How to handle certain events when in a critical region. */
305
306 void
307 ignore_signals(void)
308 {
309 #ifndef lint
310     Signal(SIGHUP, SIG_IGN);
311     Signal(SIGINT, SIG_IGN);
312 #endif
313 }
314
315 /* Make sure we'll have the directories to create a file.
316    If `striplast' is TRUE, ignore the last element of `filename'.  */
317
318 void
319 makedirs(filename,striplast)
320 Reg1 char *filename;
321 bool striplast;
322 {
323     char tmpbuf[256];
324     Reg2 char *s = tmpbuf;
325     char *dirv[20];             /* Point to the NULs between elements.  */
326     Reg3 int i;
327     Reg4 int dirvp = 0;         /* Number of finished entries in dirv. */
328
329     /* Copy `filename' into `tmpbuf' with a NUL instead of a slash
330        between the directories.  */
331     while (*filename) {
332         if (*filename == '/') {
333             filename++;
334             dirv[dirvp++] = s;
335             *s++ = '\0';
336         }
337         else {
338             *s++ = *filename++;
339         }
340     }
341     *s = '\0';
342     dirv[dirvp] = s;
343     if (striplast)
344         dirvp--;
345     if (dirvp < 0)
346         return;
347
348     strcpy(buf, "mkdir");
349     s = buf;
350     for (i=0; i<=dirvp; i++) {
351         struct stat sbuf;
352
353         if (stat(tmpbuf, &sbuf) && errno == ENOENT) {
354             while (*s) s++;
355             *s++ = ' ';
356             strcpy(s, tmpbuf);
357         }
358         *dirv[i] = '/';
359     }
360     if (s != buf)
361         system(buf);
362 }
363
364 /* Make filenames more reasonable. */
365
366 char *
367 fetchname(char *at, int strip_leading, int assume_exists)
368 {
369     char *fullname;
370     char *name;
371     Reg1 char *t;
372     char tmpbuf[200];
373     int sleading = strip_leading;
374
375     if (!at)
376         return Nullch;
377     while (isspace((unsigned char)*at))
378         at++;
379 #ifdef DEBUGGING
380     if (debug & 128)
381         say4("fetchname %s %d %d\n",at,strip_leading,assume_exists);
382 #endif
383     if (strnEQ(at, _PATH_DEVNULL, sizeof _PATH_DEVNULL - 1))    /* so files can be created by diffing */
384         return Nullch;                  /*   against /dev/null. */
385     name = fullname = t = savestr(at);
386
387     /* Strip off up to `sleading' leading slashes and null terminate.  */
388     for (; *t && !isspace((unsigned char)*t); t++)
389         if (*t == '/')
390             if (--sleading >= 0)
391                 name = t+1;
392     *t = '\0';
393
394     /* If no -p option was given (957 is the default value!),
395        we were given a relative pathname,
396        and the leading directories that we just stripped off all exist,
397        put them back on.  */
398     if (strip_leading == 957 && name != fullname && *fullname != '/') {
399         name[-1] = '\0';
400         if (stat(fullname, &filestat) == 0 && S_ISDIR (filestat.st_mode)) {
401             name[-1] = '/';
402             name=fullname;
403         }
404     }
405
406     name = savestr(name);
407     free(fullname);
408
409     if (stat(name, &filestat) && !assume_exists) {
410         char *filebase = basename(name);
411         int pathlen = filebase - name;
412
413         /* Put any leading path into `tmpbuf'.  */
414         strncpy(tmpbuf, name, pathlen);
415
416 #define try(f, a1, a2) (Sprintf(tmpbuf + pathlen, f, a1, a2), stat(tmpbuf, &filestat) == 0)
417         if (   try("RCS/%s%s", filebase, RCSSUFFIX)
418             || try("RCS/%s%s", filebase,        "")
419             || try(    "%s%s", filebase, RCSSUFFIX)
420             || try("SCCS/%s%s", SCCSPREFIX, filebase)
421             || try(     "%s%s", SCCSPREFIX, filebase))
422           return name;
423         free(name);
424         name = Nullch;
425     }
426
427     return name;
428 }
429
430 char *
431 xmalloc(unsigned int size)
432 {
433   register char *p = (char *) malloc (size);
434   if (!p)
435     fatal("out of memory");
436   return p;
437 }