Some laptops return other values for working toucpads. Allow test_aux_port to
[dragonfly.git] / contrib / patch / util.c
1 /* utility functions for `patch' */
2
3 /* $Id: util.c,v 1.24 1997/07/10 08:16:12 eggert Exp $ */
4
5 /*
6 Copyright 1986 Larry Wall
7 Copyright 1992, 1993, 1997 Free Software Foundation, Inc.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; see the file COPYING.
21 If not, write to the Free Software Foundation,
22 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 */
24
25 #define XTERN extern
26 #include <common.h>
27 #include <backupfile.h>
28 #include <quotearg.h>
29 #include <version.h>
30 #undef XTERN
31 #define XTERN
32 #include <util.h>
33
34 #include <maketime.h>
35 #include <partime.h>
36
37 #include <signal.h>
38 #if !defined SIGCHLD && defined SIGCLD
39 #define SIGCHLD SIGCLD
40 #endif
41 #if ! HAVE_RAISE
42 # define raise(sig) kill (getpid (), sig)
43 #endif
44
45 #ifdef __STDC__
46 # include <stdarg.h>
47 # define vararg_start va_start
48 #else
49 # define vararg_start(ap,p) va_start (ap)
50 # if HAVE_VARARGS_H
51 #  include <varargs.h>
52 # else
53    typedef char *va_list;
54 #  define va_dcl int va_alist;
55 #  define va_start(ap) ((ap) = (va_list) &va_alist)
56 #  define va_arg(ap, t) (((t *) ((ap) += sizeof (t)))  [-1])
57 #  define va_end(ap)
58 # endif
59 #endif
60
61 static void makedirs PARAMS ((char *));
62
63 /* Move a file FROM to TO, renaming it if possible and copying it if necessary.
64    If we must create TO, use MODE to create it.
65    If FROM is null, remove TO (ignoring FROMSTAT).
66    Back up TO if BACKUP is nonzero.  */
67
68 #ifdef __STDC__
69 /* If mode_t doesn't promote to itself, we can't use old-style definition.  */
70 void
71 move_file (char const *from, char *to, mode_t mode, int backup)
72 #else
73 void
74 move_file (from, to, mode, backup)
75      char const *from;
76      char *to;
77      mode_t mode;
78      int backup;
79 #endif
80 {
81   struct stat to_st;
82   int to_errno = ! backup ? -1 : stat (to, &to_st) == 0 ? 0 : errno;
83
84   if (backup)
85     {
86       int try_makedirs_errno = 0;
87       char *bakname;
88
89       if (origprae || origbase)
90         {
91           char const *p = origprae ? origprae : "";
92           char const *b = origbase ? origbase : "";
93           char const *o = base_name (to);
94           size_t plen = strlen (p);
95           size_t tlen = o - to;
96           size_t blen = strlen (b);
97           size_t osize = strlen (o) + 1;
98           bakname = xmalloc (plen + tlen + blen + osize);
99           memcpy (bakname, p, plen);
100           memcpy (bakname + plen, to, tlen);
101           memcpy (bakname + plen + tlen, b, blen);
102           memcpy (bakname + plen + tlen + blen, o, osize);
103           for (p += FILESYSTEM_PREFIX_LEN (p);  *p;  p++)
104             if (ISSLASH (*p))
105               {
106                 try_makedirs_errno = ENOENT;
107                 break;
108               }
109         }
110       else
111         {
112           bakname = find_backup_file_name (to);
113           if (!bakname)
114             memory_fatal ();
115         }
116
117       if (to_errno)
118         {
119           int fd;
120           if (debug & 4)
121             say ("creating empty unreadable file `%s'\n", bakname);
122           try_makedirs_errno = ENOENT;
123           unlink (bakname);
124           while ((fd = creat (bakname, 0)) < 0)
125             {
126               if (errno != try_makedirs_errno)
127                 pfatal ("can't create file `%s'", bakname);
128               makedirs (bakname);
129               try_makedirs_errno = 0;
130             }
131           if (close (fd) != 0)
132             pfatal ("can't close `%s'", bakname);
133         }
134       else
135         {
136           if (debug & 4)
137             say ("renaming `%s' to `%s'\n", to, bakname);
138           while (rename (to, bakname) != 0)
139             {
140               if (errno != try_makedirs_errno)
141                 pfatal ("can't rename `%s' to `%s'", to, bakname);
142               makedirs (bakname);
143               try_makedirs_errno = 0;
144             }
145         }
146
147       free (bakname);
148     }
149
150   if (from)
151     {
152       if (debug & 4)
153         say ("renaming `%s' to `%s'\n", from, to);
154
155       if (rename (from, to) != 0)
156         {
157           int to_dir_known_to_exist = 0;
158
159           if (errno == ENOENT
160               && (to_errno == -1 || to_errno == ENOENT))
161             {
162               makedirs (to);
163               to_dir_known_to_exist = 1;
164               if (rename (from, to) == 0)
165                 return;
166             }
167
168           if (errno == EXDEV)
169             {
170               if (! backup)
171                 {
172                   if (unlink (to) == 0)
173                     to_dir_known_to_exist = 1;
174                   else if (errno != ENOENT)
175                     pfatal ("can't remove `%s'", to);
176                 }
177               if (! to_dir_known_to_exist)
178                 makedirs (to);
179               copy_file (from, to, mode);
180               return;
181             }
182
183           pfatal ("can't rename `%s' to `%s'", from, to);
184         }
185     }
186   else if (! backup)
187     {
188       if (debug & 4)
189         say ("removing `%s'\n", to);
190       if (unlink (to) != 0)
191         pfatal ("can't remove `%s'", to);
192     }
193 }
194
195 /* Create FILE with OPEN_FLAGS, and with MODE adjusted so that
196    we can read and write the file and that the file is not executable.
197    Return the file descriptor.  */
198 #ifdef __STDC__
199 /* If mode_t doesn't promote to itself, we can't use old-style definition.  */
200 int
201 create_file (char const *file, int open_flags, mode_t mode)
202 #else
203 int
204 create_file (file, open_flags, mode)
205      char const *file;
206      int open_flags;
207      mode_t mode;
208 #endif
209 {
210   int fd;
211   mode |= S_IRUSR | S_IWUSR;
212   mode &= ~ (S_IXUSR | S_IXGRP | S_IXOTH);
213   if (! (O_CREAT && O_TRUNC))
214     close (creat (file, mode));
215   fd = open (file, O_CREAT | O_TRUNC | open_flags, mode);
216   if (fd < 0)
217     pfatal ("can't create `%s'", file);
218   return fd;
219 }
220
221 /* Copy a file. */
222
223 #ifdef __STDC__
224 /* If mode_t doesn't promote to itself, we can't use old-style definition.  */
225 void
226 copy_file (char const *from, char const *to, mode_t mode)
227 #else
228 void
229 copy_file (from, to, mode)
230      char const *from;
231      char const *to;
232      mode_t mode;
233 #endif
234 {
235   int tofd;
236   int fromfd;
237   size_t i;
238
239   if ((fromfd = open (from, O_RDONLY | O_BINARY)) < 0)
240     pfatal ("can't reopen `%s'", from);
241   tofd = create_file (to, O_WRONLY | O_BINARY, mode);
242   while ((i = read (fromfd, buf, bufsize)) != 0)
243     {
244       if (i == -1)
245         read_fatal ();
246       if (write (tofd, buf, i) != i)
247         write_fatal ();
248     }
249   if (close (fromfd) != 0)
250     read_fatal ();
251   if (close (tofd) != 0)
252     write_fatal ();
253 }
254
255 static char const DEV_NULL[] = NULL_DEVICE;
256
257 static char const SCCSPREFIX[] = "s.";
258 static char const GET[] = "get ";
259 static char const GET_LOCKED[] = "get -e ";
260 static char const SCCSDIFF1[] = "get -p ";
261 static char const SCCSDIFF2[] = "|diff - %s";
262
263 static char const RCSSUFFIX[] = ",v";
264 static char const CHECKOUT[] = "co %s";
265 static char const CHECKOUT_LOCKED[] = "co -l %s";
266 static char const RCSDIFF1[] = "rcsdiff %s";
267
268 /* Return "RCS" if FILENAME is controlled by RCS,
269    "SCCS" if it is controlled by SCCS, and 0 otherwise.
270    READONLY is nonzero if we desire only readonly access to FILENAME.
271    FILESTAT describes FILENAME's status or is 0 if FILENAME does not exist.
272    If successful and if GETBUF is nonzero, set *GETBUF to a command
273    that gets the file; similarly for DIFFBUF and a command to diff the file.
274    *GETBUF and *DIFFBUF must be freed by the caller.  */
275 char const *
276 version_controller (filename, readonly, filestat, getbuf, diffbuf)
277      char const *filename;
278      int readonly;
279      struct stat const *filestat;
280      char **getbuf;
281      char **diffbuf;
282 {
283   struct stat cstat;
284   char const *filebase = base_name (filename);
285   char const *dotslash = *filename == '-' ? "./" : "";
286   size_t dir_len = filebase - filename;
287   size_t filenamelen = strlen (filename);
288   size_t maxfixlen = sizeof "SCCS/" - 1 + sizeof SCCSPREFIX - 1;
289   size_t maxtrysize = filenamelen + maxfixlen + 1;
290   size_t quotelen = quote_system_arg (0, filename);
291   size_t maxgetsize = sizeof GET_LOCKED + quotelen + maxfixlen;
292   size_t maxdiffsize =
293     (sizeof SCCSDIFF1 + sizeof SCCSDIFF2 + sizeof DEV_NULL - 1
294      + 2 * quotelen + maxfixlen);
295   char *trybuf = xmalloc (maxtrysize);
296   char const *r = 0;
297
298   strcpy (trybuf, filename);
299
300 #define try1(f,a1)    (sprintf (trybuf + dir_len, f, a1),    stat (trybuf, &cstat) == 0)
301 #define try2(f,a1,a2) (sprintf (trybuf + dir_len, f, a1,a2), stat (trybuf, &cstat) == 0)
302
303   /* Check that RCS file is not working file.
304      Some hosts don't report file name length errors.  */
305
306   if ((try2 ("RCS/%s%s", filebase, RCSSUFFIX)
307        || try1 ("RCS/%s", filebase)
308        || try2 ("%s%s", filebase, RCSSUFFIX))
309       && ! (filestat
310             && filestat->st_dev == cstat.st_dev
311             && filestat->st_ino == cstat.st_ino))
312     {
313       if (getbuf)
314         {
315           char *p = *getbuf = xmalloc (maxgetsize);
316           sprintf (p, readonly ? CHECKOUT : CHECKOUT_LOCKED, dotslash);
317           p += strlen (p);
318           p += quote_system_arg (p, filename);
319           *p = '\0';
320         }
321
322       if (diffbuf)
323         {
324           char *p = *diffbuf = xmalloc (maxdiffsize);
325           sprintf (p, RCSDIFF1, dotslash);
326           p += strlen (p);
327           p += quote_system_arg (p, filename);
328           *p++ = '>';
329           strcpy (p, DEV_NULL);
330         }
331
332       r = "RCS";
333     }
334   else if (try2 ("SCCS/%s%s", SCCSPREFIX, filebase)
335            || try2 ("%s%s", SCCSPREFIX, filebase))
336     {
337       if (getbuf)
338         {
339           char *p = *getbuf = xmalloc (maxgetsize);
340           sprintf (p, readonly ? GET : GET_LOCKED);
341           p += strlen (p);
342           p += quote_system_arg (p, trybuf);
343           *p = '\0';
344         }
345
346       if (diffbuf)
347         {
348           char *p = *diffbuf = xmalloc (maxdiffsize);
349           strcpy (p, SCCSDIFF1);
350           p += sizeof SCCSDIFF1 - 1;
351           p += quote_system_arg (p, trybuf);
352           sprintf (p, SCCSDIFF2, dotslash);
353           p += strlen (p);
354           p += quote_system_arg (p, filename);
355           *p++ = '>';
356           strcpy (p, DEV_NULL);
357         }
358
359       r = "SCCS";
360     }
361
362   free (trybuf);
363   return r;
364 }
365
366 /* Get FILENAME from version control system CS.  The file already exists if
367    EXISTS is nonzero.  Only readonly access is needed if READONLY is nonzero.
368    Use the command GETBUF to actually get the named file.
369    Store the resulting file status into *FILESTAT.
370    Return nonzero if successful.  */
371 int
372 version_get (filename, cs, exists, readonly, getbuf, filestat)
373      char const *filename;
374      char const *cs;
375      int exists;
376      int readonly;
377      char const *getbuf;
378      struct stat *filestat;
379 {
380   if (patch_get < 0)
381     {
382       ask ("Get file `%s' from %s%s? [y] ", filename,
383            cs, readonly ? "" : " with lock");
384       if (*buf == 'n')
385         return 0;
386     }
387
388   if (dry_run)
389     {
390       if (! exists)
391         fatal ("can't do dry run on nonexistent version-controlled file `%s'; invoke `%s' and try again",
392                filename, getbuf);
393     }
394   else
395     {
396       if (verbosity == VERBOSE)
397         say ("Getting file `%s' from %s%s...\n", filename,
398              cs, readonly ? "" : " with lock");
399       if (systemic (getbuf) != 0)
400         fatal ("can't get file `%s' from %s", filename, cs);
401       if (stat (filename, filestat) != 0)
402         pfatal ("%s", filename);
403     }
404   
405   return 1;
406 }
407
408 /* Allocate a unique area for a string. */
409
410 char *
411 savebuf (s, size)
412      register char const *s;
413      register size_t size;
414 {
415   register char *rv;
416
417   assert (s && size);
418   rv = malloc (size);
419
420   if (! rv)
421     {
422       if (! using_plan_a)
423         memory_fatal ();
424     }
425   else
426     memcpy (rv, s, size);
427
428   return rv;
429 }
430
431 char *
432 savestr(s)
433      char const *s;
434 {
435   return savebuf (s, strlen (s) + 1);
436 }
437
438 void
439 remove_prefix (p, prefixlen)
440      char *p;
441      size_t prefixlen;
442 {
443   char const *s = p + prefixlen;
444   while ((*p++ = *s++))
445     continue;
446 }
447
448 #if !HAVE_VPRINTF
449 #define vfprintf my_vfprintf
450 static int vfprintf PARAMS ((FILE *, char const *, va_list));
451 static int
452 vfprintf (stream, format, args)
453      FILE *stream;
454      char const *format;
455      va_list args;
456 {
457 #if !HAVE_DOPRNT && HAVE__DOPRINTF
458 # define _doprnt _doprintf
459 #endif
460 #if HAVE_DOPRNT || HAVE__DOPRINTF
461   _doprnt (format, args, stream);
462   return ferror (stream) ? -1 : 0;
463 #else
464   int *a = (int *) args;
465   return fprintf (stream, format,
466                   a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]);
467 #endif
468 }
469 #endif /* !HAVE_VPRINTF */
470
471 /* Terminal output, pun intended. */
472
473 #ifdef __STDC__
474 void
475 fatal (char const *format, ...)
476 #else
477 /*VARARGS1*/ void
478 fatal (format, va_alist)
479      char const *format;
480      va_dcl
481 #endif
482 {
483   va_list args;
484   fprintf (stderr, "%s: **** ", program_name);
485   vararg_start (args, format);
486   vfprintf (stderr, format, args);
487   va_end (args);
488   putc ('\n', stderr);
489   fflush (stderr);
490   fatal_exit (0);
491 }
492
493 void
494 memory_fatal ()
495 {
496   fatal ("out of memory");
497 }
498
499 void
500 read_fatal ()
501 {
502   pfatal ("read error");
503 }
504
505 void
506 write_fatal ()
507 {
508   pfatal ("write error");
509 }
510
511 /* Say something from patch, something from the system, then silence . . . */
512
513 #ifdef __STDC__
514 void
515 pfatal (char const *format, ...)
516 #else
517 /*VARARGS1*/ void
518 pfatal (format, va_alist)
519      char const *format;
520      va_dcl
521 #endif
522 {
523   int errnum = errno;
524   va_list args;
525   fprintf (stderr, "%s: **** ", program_name);
526   vararg_start (args, format);
527   vfprintf (stderr, format, args);
528   va_end (args);
529   fflush (stderr); /* perror bypasses stdio on some hosts.  */
530   errno = errnum;
531   perror (" ");
532   fflush (stderr);
533   fatal_exit (0);
534 }
535
536 /* Tell the user something.  */
537
538 #ifdef __STDC__
539 void
540 say (char const *format, ...)
541 #else
542 /*VARARGS1*/ void
543 say (format, va_alist)
544      char const *format;
545      va_dcl
546 #endif
547 {
548   va_list args;
549   vararg_start (args, format);
550   vfprintf (stdout, format, args);
551   va_end (args);
552   fflush (stdout);
553 }
554
555 /* Get a response from the user, somehow or other. */
556
557 #ifdef __STDC__
558 void
559 ask (char const *format, ...)
560 #else
561 /*VARARGS1*/ void
562 ask (format, va_alist)
563      char const *format;
564      va_dcl
565 #endif
566 {
567   static int ttyfd = -2;
568   int r;
569   va_list args;
570
571   vararg_start (args, format);
572   vfprintf (stdout, format, args);
573   va_end (args);
574   fflush (stdout);
575
576   if (ttyfd == -2)
577     {
578       /* If standard output is not a tty, don't bother opening /dev/tty,
579          since it's unlikely that stdout will be seen by the tty user.
580          The isatty test also works around a bug in GNU Emacs 19.34 under Linux
581          which makes a call-process `patch' hang when it reads from /dev/tty.
582          POSIX.2 requires that we read /dev/tty, though.  */
583       ttyfd = (posixly_correct || isatty (STDOUT_FILENO)
584                ? open (TTY_DEVICE, O_RDONLY)
585                : -1);
586     }
587
588   if (ttyfd < 0)
589     {
590       /* No terminal at all -- default it.  */
591       printf ("\n");
592       buf[0] = '\n';
593       buf[1] = '\0';
594     }
595   else
596     {
597       size_t s = 0;
598       while ((r = read (ttyfd, buf + s, bufsize - 1 - s)) == bufsize - 1 - s
599              && buf[bufsize - 2] != '\n')
600         {
601           s = bufsize - 1;
602           bufsize *= 2;
603           buf = realloc (buf, bufsize);
604           if (!buf)
605             memory_fatal ();
606         }
607       if (r == 0)
608         printf ("EOF\n");
609       else if (r < 0)
610         {
611           perror ("tty read");
612           fflush (stderr);
613           close (ttyfd);
614           ttyfd = -1;
615           r = 0;
616         }
617       buf[s + r] = '\0';
618     }
619 }
620
621 /* Return nonzero if it OK to reverse a patch.  */
622
623 #ifdef __STDC__
624 int
625 ok_to_reverse (char const *format, ...)
626 #else
627 ok_to_reverse (format, va_alist)
628      char const *format;
629      va_dcl
630 #endif
631 {
632   int r = 0;
633
634   if (noreverse || ! (force && verbosity == SILENT))
635     {
636       va_list args;
637       vararg_start (args, format);
638       vfprintf (stdout, format, args);
639       va_end (args);
640     }
641
642   if (noreverse)
643     {
644       printf ("  Skipping patch.\n");
645       skip_rest_of_patch = TRUE;
646       r = 0;
647     }
648   else if (force)
649     {
650       if (verbosity != SILENT)
651         printf ("  Applying it anyway.\n");
652       r = 0;
653     }
654   else if (batch)
655     {
656       say (reverse ? "  Ignoring -R.\n" : "  Assuming -R.\n");
657       r = 1;
658     }
659   else
660     {
661       ask (reverse ? "  Ignore -R? [n] " : "  Assume -R? [n] ");
662       r = *buf == 'y';
663       if (! r)
664         {
665           ask ("Apply anyway? [n] ");
666           if (*buf != 'y')
667             {
668               if (verbosity != SILENT)
669                 say ("Skipping patch.\n");
670               skip_rest_of_patch = TRUE;
671             }
672         }
673     }
674
675   return r;
676 }
677
678 /* How to handle certain events when not in a critical region. */
679
680 #define NUM_SIGS (sizeof (sigs) / sizeof (*sigs))
681 static int const sigs[] = {
682 #ifdef SIGHUP
683        SIGHUP,
684 #endif
685 #ifdef SIGPIPE
686        SIGPIPE,
687 #endif
688 #ifdef SIGTERM
689        SIGTERM,
690 #endif
691 #ifdef SIGXCPU
692        SIGXCPU,
693 #endif
694 #ifdef SIGXFSZ
695        SIGXFSZ,
696 #endif
697        SIGINT
698 };
699
700 #if !HAVE_SIGPROCMASK
701 #define sigset_t int
702 #define sigemptyset(s) (*(s) = 0)
703 #ifndef sigmask
704 #define sigmask(sig) (1 << ((sig) - 1))
705 #endif
706 #define sigaddset(s, sig) (*(s) |= sigmask (sig))
707 #define sigismember(s, sig) ((*(s) & sigmask (sig)) != 0)
708 #ifndef SIG_BLOCK
709 #define SIG_BLOCK 0
710 #endif
711 #ifndef SIG_UNBLOCK
712 #define SIG_UNBLOCK (SIG_BLOCK + 1)
713 #endif
714 #ifndef SIG_SETMASK
715 #define SIG_SETMASK (SIG_BLOCK + 2)
716 #endif
717 #define sigprocmask(how, n, o) \
718   ((how) == SIG_BLOCK \
719    ? ((o) ? *(o) = sigblock (*(n)) : sigblock (*(n))) \
720    : (how) == SIG_UNBLOCK \
721    ? sigsetmask (((o) ? *(o) = sigblock (0) : sigblock (0)) & ~*(n)) \
722    : (o ? *(o) = sigsetmask (*(n)) : sigsetmask (*(n))))
723 #if !HAVE_SIGSETMASK
724 #define sigblock(mask) 0
725 #define sigsetmask(mask) 0
726 #endif
727 #endif
728
729 static sigset_t initial_signal_mask;
730 static sigset_t signals_to_block;
731
732 #if ! HAVE_SIGACTION
733 static RETSIGTYPE fatal_exit_handler PARAMS ((int)) __attribute__ ((noreturn));
734 static RETSIGTYPE
735 fatal_exit_handler (sig)
736      int sig;
737 {
738   signal (sig, SIG_IGN);
739   fatal_exit (sig);
740 }
741 #endif
742
743 void
744 set_signals(reset)
745 int reset;
746 {
747   int i;
748 #if HAVE_SIGACTION
749   struct sigaction initial_act, fatal_act;
750   fatal_act.sa_handler = fatal_exit;
751   sigemptyset (&fatal_act.sa_mask);
752   fatal_act.sa_flags = 0;
753 #define setup_handler(sig) sigaction (sig, &fatal_act, (struct sigaction *) 0)
754 #else
755 #define setup_handler(sig) signal (sig, fatal_exit_handler)
756 #endif
757
758   if (!reset)
759     {
760 #ifdef SIGCHLD
761       /* System V fork+wait does not work if SIGCHLD is ignored.  */
762       signal (SIGCHLD, SIG_DFL);
763 #endif
764       sigemptyset (&signals_to_block);
765       for (i = 0;  i < NUM_SIGS;  i++)
766         {
767           int ignoring_signal;
768 #if HAVE_SIGACTION
769           if (sigaction (sigs[i], (struct sigaction *) 0, &initial_act) != 0)
770             continue;
771           ignoring_signal = initial_act.sa_handler == SIG_IGN;
772 #else
773           ignoring_signal = signal (sigs[i], SIG_IGN) == SIG_IGN;
774 #endif
775           if (! ignoring_signal)
776             {
777               sigaddset (&signals_to_block, sigs[i]);
778               setup_handler (sigs[i]);
779             }
780         }
781     }
782   else
783     {
784       /* Undo the effect of ignore_signals.  */
785 #if HAVE_SIGPROCMASK || HAVE_SIGSETMASK
786       sigprocmask (SIG_SETMASK, &initial_signal_mask, (sigset_t *) 0);
787 #else
788       for (i = 0;  i < NUM_SIGS;  i++)
789         if (sigismember (&signals_to_block, sigs[i]))
790           setup_handler (sigs[i]);
791 #endif
792     }
793 }
794
795 /* How to handle certain events when in a critical region. */
796
797 void
798 ignore_signals()
799 {
800 #if HAVE_SIGPROCMASK || HAVE_SIGSETMASK
801   sigprocmask (SIG_BLOCK, &signals_to_block, &initial_signal_mask);
802 #else
803   int i;
804   for (i = 0;  i < NUM_SIGS;  i++)
805     if (sigismember (&signals_to_block, sigs[i]))
806       signal (sigs[i], SIG_IGN);
807 #endif
808 }
809
810 void
811 exit_with_signal (sig)
812      int sig;
813 {
814   sigset_t s;
815   signal (sig, SIG_DFL);
816   sigemptyset (&s);
817   sigaddset (&s, sig);
818   sigprocmask (SIG_UNBLOCK, &s, (sigset_t *) 0);
819   raise (sig);
820   exit (2);
821 }
822
823 int
824 systemic (command)
825      char const *command;
826 {
827   if (debug & 8)
828     say ("+ %s\n", command);
829   fflush (stdout);
830   return system (command);
831 }
832
833 #if !HAVE_MKDIR
834 /* These mkdir and rmdir substitutes are good enough for `patch';
835    they are not general emulators.  */
836
837 static int doprogram PARAMS ((char const *, char const *));
838 static int mkdir PARAMS ((char const *, mode_t));
839 static int rmdir PARAMS ((char const *));
840
841 static int
842 doprogram (program, arg)
843      char const *program;
844      char const *arg;
845 {
846   int result;
847   static char const DISCARD_OUTPUT[] = " 2>/dev/null";
848   size_t program_len = strlen (program);
849   char *cmd = xmalloc (program_len + 1 + quote_system_arg (0, arg)
850                        + sizeof DISCARD_OUTPUT);
851   char *p = cmd;
852   strcpy (p, program);
853   p += program_len;
854   *p++ = ' ';
855   p += quote_system_arg (p, arg);
856   strcpy (p, DISCARD_OUTPUT);
857   result = systemic (cmd);
858   free (cmd);
859   return result;
860 }
861
862 #ifdef __STDC__
863 /* If mode_t doesn't promote to itself, we can't use old-style definition.  */
864 static int
865 mkdir (char const *path, mode_t mode)
866 #else
867 static int
868 mkdir (path, mode)
869      char const *path;
870      mode_t mode; /* ignored */
871 #endif
872 {
873   return doprogram ("mkdir", path);
874 }
875
876 static int
877 rmdir (path)
878      char const *path;
879 {
880   int result = doprogram ("rmdir", path);
881   errno = EEXIST;
882   return result;
883 }
884 #endif
885
886 /* Replace '/' with '\0' in FILENAME if it marks a place that
887    needs testing for the existence of directory.  Return the address
888    of the last location replaced, or 0 if none were replaced.  */
889 static char *replace_slashes PARAMS ((char *));
890 static char *
891 replace_slashes (filename)
892      char *filename;
893 {
894   char *f;
895   char *last_location_replaced = 0;
896   char const *component_start;
897
898   for (f = filename + FILESYSTEM_PREFIX_LEN (filename);  ISSLASH (*f);  f++)
899     continue;
900
901   component_start = f;
902
903   for (; *f; f++)
904     if (ISSLASH (*f))
905       {
906         char *slash = f;
907
908         /* Treat multiple slashes as if they were one slash.  */
909         while (ISSLASH (f[1]))
910           f++;
911
912         /* Ignore slashes at the end of the path.  */
913         if (! f[1])
914           break;
915
916         /* "." and ".." need not be tested.  */
917         if (! (slash - component_start <= 2
918                && component_start[0] == '.' && slash[-1] == '.'))
919           {
920             *slash = '\0';
921             last_location_replaced = slash;
922           }
923
924         component_start = f + 1;
925       }
926
927   return last_location_replaced;
928 }
929
930 /* Make sure we'll have the directories to create a file.
931    Ignore the last element of `filename'.  */
932
933 static void
934 makedirs (filename)
935      register char *filename;
936 {
937   register char *f;
938   register char *flim = replace_slashes (filename);
939
940   if (flim)
941     {
942       /* Create any missing directories, replacing NULs by '/'s.
943          Ignore errors.  We may have to keep going even after an EEXIST,
944          since the path may contain ".."s; and when there is an EEXIST
945          failure the system may return some other error number.
946          Any problems will eventually be reported when we create the file.  */
947       for (f = filename;  f <= flim;  f++)
948         if (!*f)
949           {
950             mkdir (filename,
951                    S_IRUSR|S_IWUSR|S_IXUSR
952                    |S_IRGRP|S_IWGRP|S_IXGRP
953                    |S_IROTH|S_IWOTH|S_IXOTH);
954             *f = '/';
955           }
956     }
957 }
958
959 /* Remove empty ancestor directories of FILENAME.
960    Ignore errors, since the path may contain ".."s, and when there
961    is an EEXIST failure the system may return some other error number.  */
962 void
963 removedirs (filename)
964      char *filename;
965 {
966   size_t i;
967
968   for (i = strlen (filename);  i != 0;  i--)
969     if (ISSLASH (filename[i])
970         && ! (ISSLASH (filename[i - 1])
971               || (filename[i - 1] == '.'
972                   && (i == 1
973                       || ISSLASH (filename[i - 2])
974                       || (filename[i - 2] == '.'
975                           && (i == 2
976                               || ISSLASH (filename[i - 3])))))))
977       {
978         filename[i] = '\0';
979         if (rmdir (filename) == 0 && verbosity == VERBOSE)
980           say ("Removed empty directory `%s'.\n", filename);
981         filename[i] = '/';
982       }
983 }
984
985 static time_t initial_time;
986
987 void
988 init_time ()
989 {
990   time (&initial_time);
991 }
992
993 /* Make filenames more reasonable. */
994
995 char *
996 fetchname (at, strip_leading, pstamp)
997 char *at;
998 int strip_leading;
999 time_t *pstamp;
1000 {
1001     char *name;
1002     register char *t;
1003     int sleading = strip_leading;
1004     time_t stamp = (time_t) -1;
1005
1006     while (ISSPACE ((unsigned char) *at))
1007         at++;
1008     if (debug & 128)
1009         say ("fetchname %s %d\n", at, strip_leading);
1010
1011     name = at;
1012     /* Strip off up to `sleading' leading slashes and null terminate.  */
1013     for (t = at;  *t;  t++)
1014       {
1015         if (ISSLASH (*t))
1016           {
1017             while (ISSLASH (t[1]))
1018               t++;
1019             if (--sleading >= 0)
1020                 name = t+1;
1021           }
1022         else if (ISSPACE ((unsigned char) *t))
1023           {
1024             if (set_time | set_utc)
1025               stamp = str2time (t, initial_time, set_utc ? 0L : TM_LOCAL_ZONE);
1026             else
1027               {
1028                 /* The head says the file is nonexistent if the timestamp
1029                    is the epoch; but the listed time is local time, not UTC,
1030                    and POSIX.1 allows local time to be 24 hours away from UTC.
1031                    So match any time within 24 hours of the epoch.
1032                    Use a default time zone 24 hours behind UTC so that any
1033                    non-zoned time within 24 hours of the epoch is valid.  */
1034                 stamp = str2time (t, initial_time, -24L * 60 * 60);
1035                 if (0 <= stamp && stamp <= 2 * 24L * 60 * 60)
1036                   stamp = 0;
1037               }
1038
1039             *t = '\0';
1040             break;
1041           }
1042       }
1043
1044     if (!*name)
1045       return 0;
1046
1047     /* Allow files to be created by diffing against /dev/null.  */
1048     if (strcmp (at, "/dev/null") == 0)
1049       {
1050         if (pstamp)
1051           *pstamp = 0;
1052         return 0;
1053       }
1054
1055     if (pstamp)
1056       *pstamp = stamp;
1057
1058     return savestr (name);
1059 }
1060
1061 GENERIC_OBJECT *
1062 xmalloc (size)
1063      size_t size;
1064 {
1065   register GENERIC_OBJECT *p = malloc (size);
1066   if (!p)
1067     memory_fatal ();
1068   return p;
1069 }
1070
1071 void
1072 Fseek (stream, offset, ptrname)
1073      FILE *stream;
1074      file_offset offset;
1075      int ptrname;
1076 {
1077   if (file_seek (stream, offset, ptrname) != 0)
1078     pfatal ("fseek");
1079 }