summaryrefslogtreecommitdiffstats
path: root/contrib/patch/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/patch/util.c')
-rw-r--r--contrib/patch/util.c1070
1 files changed, 1070 insertions, 0 deletions
diff --git a/contrib/patch/util.c b/contrib/patch/util.c
new file mode 100644
index 0000000..935b325
--- /dev/null
+++ b/contrib/patch/util.c
@@ -0,0 +1,1070 @@
+/* utility functions for `patch' */
+
+/* $Id: util.c,v 1.22 1997/06/13 06:28:37 eggert Exp $ */
+
+/*
+Copyright 1986 Larry Wall
+Copyright 1992, 1993, 1997 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#define XTERN extern
+#include <common.h>
+#include <backupfile.h>
+#include <quotearg.h>
+#include <version.h>
+#undef XTERN
+#define XTERN
+#include <util.h>
+
+#include <maketime.h>
+#include <partime.h>
+
+#include <signal.h>
+#if !defined SIGCHLD && defined SIGCLD
+#define SIGCHLD SIGCLD
+#endif
+#if ! HAVE_RAISE
+# define raise(sig) kill (getpid (), sig)
+#endif
+
+#ifdef __STDC__
+# include <stdarg.h>
+# define vararg_start va_start
+#else
+# define vararg_start(ap,p) va_start (ap)
+# if HAVE_VARARGS_H
+# include <varargs.h>
+# else
+ typedef char *va_list;
+# define va_dcl int va_alist;
+# define va_start(ap) ((ap) = (va_list) &va_alist)
+# define va_arg(ap, t) (((t *) ((ap) += sizeof (t))) [-1])
+# define va_end(ap)
+# endif
+#endif
+
+static void makedirs PARAMS ((char *));
+
+/* Move a file FROM to TO, renaming it if possible and copying it if necessary.
+ If we must create TO, use MODE to create it.
+ If FROM is null, remove TO (ignoring FROMSTAT).
+ Back up TO if BACKUP is nonzero. */
+
+#ifdef __STDC__
+/* If mode_t doesn't promote to itself, we can't use old-style definition. */
+void
+move_file (char const *from, char *to, mode_t mode, int backup)
+#else
+void
+move_file (from, to, mode, backup)
+ char const *from;
+ char *to;
+ mode_t mode;
+ int backup;
+#endif
+{
+ struct stat to_st;
+ int to_errno = ! backup ? -1 : stat (to, &to_st) == 0 ? 0 : errno;
+
+ if (backup)
+ {
+ int try_makedirs_errno = 0;
+ char *bakname;
+
+ if (origprae || origbase)
+ {
+ char const *p = origprae ? origprae : "";
+ char const *b = origbase ? origbase : "";
+ char const *o = base_name (to);
+ size_t plen = strlen (p);
+ size_t tlen = o - to;
+ size_t blen = strlen (b);
+ size_t osize = strlen (o) + 1;
+ bakname = xmalloc (plen + tlen + blen + osize);
+ memcpy (bakname, p, plen);
+ memcpy (bakname + plen, to, tlen);
+ memcpy (bakname + plen + tlen, b, blen);
+ memcpy (bakname + plen + tlen + blen, o, osize);
+ for (p += FILESYSTEM_PREFIX_LEN (p); *p; p++)
+ if (ISSLASH (*p))
+ {
+ try_makedirs_errno = ENOENT;
+ break;
+ }
+ }
+ else
+ {
+ bakname = find_backup_file_name (to);
+ if (!bakname)
+ memory_fatal ();
+ }
+
+ if (to_errno)
+ {
+ int fd;
+ if (debug & 4)
+ say ("creating empty unreadable file `%s'\n", bakname);
+ try_makedirs_errno = ENOENT;
+ unlink (bakname);
+ while ((fd = creat (bakname, 0)) < 0)
+ {
+ if (errno != try_makedirs_errno)
+ pfatal ("can't create file `%s'", bakname);
+ makedirs (bakname);
+ try_makedirs_errno = 0;
+ }
+ if (close (fd) != 0)
+ pfatal ("can't close `%s'", bakname);
+ }
+ else
+ {
+ if (debug & 4)
+ say ("renaming `%s' to `%s'\n", to, bakname);
+ while (rename (to, bakname) != 0)
+ {
+ if (errno != try_makedirs_errno)
+ pfatal ("can't rename `%s' to `%s'", to, bakname);
+ makedirs (bakname);
+ try_makedirs_errno = 0;
+ }
+ }
+
+ free (bakname);
+ }
+
+ if (from)
+ {
+ if (debug & 4)
+ say ("renaming `%s' to `%s'\n", from, to);
+
+ if (rename (from, to) != 0)
+ {
+ if (errno == ENOENT
+ && (to_errno == -1 || to_errno == ENOENT))
+ {
+ makedirs (to);
+ if (rename (from, to) == 0)
+ return;
+ }
+
+#ifdef EXDEV
+ if (errno == EXDEV)
+ {
+ if (! backup && unlink (to) != 0 && errno != ENOENT)
+ pfatal ("can't remove `%s'", to);
+ copy_file (from, to, mode);
+ return;
+ }
+#endif
+ pfatal ("can't rename `%s' to `%s'", from, to);
+ }
+ }
+ else if (! backup)
+ {
+ if (debug & 4)
+ say ("removing `%s'\n", to);
+ if (unlink (to) != 0)
+ pfatal ("can't remove `%s'", to);
+ }
+}
+
+/* Create FILE with OPEN_FLAGS, and with MODE adjusted so that
+ we can read and write the file and that the file is not executable.
+ Return the file descriptor. */
+#ifdef __STDC__
+/* If mode_t doesn't promote to itself, we can't use old-style definition. */
+int
+create_file (char const *file, int open_flags, mode_t mode)
+#else
+int
+create_file (file, open_flags, mode)
+ char const *file;
+ int open_flags;
+ mode_t mode;
+#endif
+{
+ int fd;
+ mode |= S_IRUSR | S_IWUSR;
+ mode &= ~ (S_IXUSR | S_IXGRP | S_IXOTH);
+ if (! (O_CREAT && O_TRUNC))
+ close (creat (file, mode));
+ fd = open (file, O_CREAT | O_TRUNC | open_flags, mode);
+ if (fd < 0)
+ pfatal ("can't create `%s'", file);
+ return fd;
+}
+
+/* Copy a file. */
+
+#ifdef __STDC__
+/* If mode_t doesn't promote to itself, we can't use old-style definition. */
+void
+copy_file (char const *from, char const *to, mode_t mode)
+#else
+void
+copy_file (from, to, mode)
+ char const *from;
+ char const *to;
+ mode_t mode;
+#endif
+{
+ int tofd;
+ int fromfd;
+ size_t i;
+
+ if ((fromfd = open (from, O_RDONLY | O_BINARY)) < 0)
+ pfatal ("can't reopen `%s'", from);
+ tofd = create_file (to, O_WRONLY | O_BINARY, mode);
+ while ((i = read (fromfd, buf, bufsize)) != 0)
+ {
+ if (i == -1)
+ read_fatal ();
+ if (write (tofd, buf, i) != i)
+ write_fatal ();
+ }
+ if (close (fromfd) != 0)
+ read_fatal ();
+ if (close (tofd) != 0)
+ write_fatal ();
+}
+
+static char const DEV_NULL[] = NULL_DEVICE;
+
+static char const SCCSPREFIX[] = "s.";
+static char const GET[] = "get ";
+static char const GET_LOCKED[] = "get -e ";
+static char const SCCSDIFF1[] = "get -p ";
+static char const SCCSDIFF2[] = "|diff - %s";
+
+static char const RCSSUFFIX[] = ",v";
+static char const CHECKOUT[] = "co %s";
+static char const CHECKOUT_LOCKED[] = "co -l %s";
+static char const RCSDIFF1[] = "rcsdiff %s";
+
+/* Return "RCS" if FILENAME is controlled by RCS,
+ "SCCS" if it is controlled by SCCS, and 0 otherwise.
+ READONLY is nonzero if we desire only readonly access to FILENAME.
+ FILESTAT describes FILENAME's status or is 0 if FILENAME does not exist.
+ If successful and if GETBUF is nonzero, set *GETBUF to a command
+ that gets the file; similarly for DIFFBUF and a command to diff the file.
+ *GETBUF and *DIFFBUF must be freed by the caller. */
+char const *
+version_controller (filename, readonly, filestat, getbuf, diffbuf)
+ char const *filename;
+ int readonly;
+ struct stat const *filestat;
+ char **getbuf;
+ char **diffbuf;
+{
+ struct stat cstat;
+ char const *filebase = base_name (filename);
+ char const *dotslash = *filename == '-' ? "./" : "";
+ size_t dir_len = filebase - filename;
+ size_t filenamelen = strlen (filename);
+ size_t maxfixlen = sizeof "SCCS/" - 1 + sizeof SCCSPREFIX - 1;
+ size_t maxtrysize = filenamelen + maxfixlen + 1;
+ size_t quotelen = quote_system_arg (0, filename);
+ size_t maxgetsize = sizeof GET_LOCKED + quotelen + maxfixlen;
+ size_t maxdiffsize =
+ (sizeof SCCSDIFF1 + sizeof SCCSDIFF2 + sizeof DEV_NULL - 1
+ + 2 * quotelen + maxfixlen);
+ char *trybuf = xmalloc (maxtrysize);
+ char const *r = 0;
+
+ strcpy (trybuf, filename);
+
+#define try1(f,a1) (sprintf (trybuf + dir_len, f, a1), stat (trybuf, &cstat) == 0)
+#define try2(f,a1,a2) (sprintf (trybuf + dir_len, f, a1,a2), stat (trybuf, &cstat) == 0)
+
+ /* Check that RCS file is not working file.
+ Some hosts don't report file name length errors. */
+
+ if ((try2 ("RCS/%s%s", filebase, RCSSUFFIX)
+ || try1 ("RCS/%s", filebase)
+ || try2 ("%s%s", filebase, RCSSUFFIX))
+ && ! (filestat
+ && filestat->st_dev == cstat.st_dev
+ && filestat->st_ino == cstat.st_ino))
+ {
+ if (getbuf)
+ {
+ char *p = *getbuf = xmalloc (maxgetsize);
+ sprintf (p, readonly ? CHECKOUT : CHECKOUT_LOCKED, dotslash);
+ p += strlen (p);
+ p += quote_system_arg (p, filename);
+ *p = '\0';
+ }
+
+ if (diffbuf)
+ {
+ char *p = *diffbuf = xmalloc (maxdiffsize);
+ sprintf (p, RCSDIFF1, dotslash);
+ p += strlen (p);
+ p += quote_system_arg (p, filename);
+ *p++ = '>';
+ strcpy (p, DEV_NULL);
+ }
+
+ r = "RCS";
+ }
+ else if (try2 ("SCCS/%s%s", SCCSPREFIX, filebase)
+ || try2 ("%s%s", SCCSPREFIX, filebase))
+ {
+ if (getbuf)
+ {
+ char *p = *getbuf = xmalloc (maxgetsize);
+ sprintf (p, readonly ? GET : GET_LOCKED);
+ p += strlen (p);
+ p += quote_system_arg (p, trybuf);
+ *p = '\0';
+ }
+
+ if (diffbuf)
+ {
+ char *p = *diffbuf = xmalloc (maxdiffsize);
+ strcpy (p, SCCSDIFF1);
+ p += sizeof SCCSDIFF1 - 1;
+ p += quote_system_arg (p, trybuf);
+ sprintf (p, SCCSDIFF2, dotslash);
+ p += strlen (p);
+ p += quote_system_arg (p, filename);
+ *p++ = '>';
+ strcpy (p, DEV_NULL);
+ }
+
+ r = "SCCS";
+ }
+
+ free (trybuf);
+ return r;
+}
+
+/* Get FILENAME from version control system CS. The file already exists if
+ EXISTS is nonzero. Only readonly access is needed if READONLY is nonzero.
+ Use the command GETBUF to actually get the named file.
+ Store the resulting file status into *FILESTAT.
+ Return nonzero if successful. */
+int
+version_get (filename, cs, exists, readonly, getbuf, filestat)
+ char const *filename;
+ char const *cs;
+ int exists;
+ int readonly;
+ char const *getbuf;
+ struct stat *filestat;
+{
+ if (patch_get < 0)
+ {
+ ask ("Get file `%s' from %s%s? [y] ", filename,
+ cs, readonly ? "" : " with lock");
+ if (*buf == 'n')
+ return 0;
+ }
+
+ if (dry_run)
+ {
+ if (! exists)
+ fatal ("can't do dry run on nonexistent version-controlled file `%s'; invoke `%s' and try again",
+ filename, getbuf);
+ }
+ else
+ {
+ if (verbosity == VERBOSE)
+ say ("Getting file `%s' from %s%s...\n", filename,
+ cs, readonly ? "" : " with lock");
+ if (systemic (getbuf) != 0)
+ fatal ("can't get file `%s' from %s", filename, cs);
+ if (stat (filename, filestat) != 0)
+ pfatal ("%s", filename);
+ }
+
+ return 1;
+}
+
+/* Allocate a unique area for a string. */
+
+char *
+savebuf (s, size)
+ register char const *s;
+ register size_t size;
+{
+ register char *rv;
+
+ assert (s && size);
+ rv = malloc (size);
+
+ if (! rv)
+ {
+ if (! using_plan_a)
+ memory_fatal ();
+ }
+ else
+ memcpy (rv, s, size);
+
+ return rv;
+}
+
+char *
+savestr(s)
+ char const *s;
+{
+ return savebuf (s, strlen (s) + 1);
+}
+
+void
+remove_prefix (p, prefixlen)
+ char *p;
+ size_t prefixlen;
+{
+ char const *s = p + prefixlen;
+ while ((*p++ = *s++))
+ continue;
+}
+
+#if !HAVE_VPRINTF
+#define vfprintf my_vfprintf
+static int vfprintf PARAMS ((FILE *, char const *, va_list));
+static int
+vfprintf (stream, format, args)
+ FILE *stream;
+ char const *format;
+ va_list args;
+{
+#if !HAVE_DOPRNT && HAVE__DOPRINTF
+# define _doprnt _doprintf
+#endif
+#if HAVE_DOPRNT || HAVE__DOPRINTF
+ _doprnt (format, args, stream);
+ return ferror (stream) ? -1 : 0;
+#else
+ int *a = (int *) args;
+ return fprintf (stream, format,
+ a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]);
+#endif
+}
+#endif /* !HAVE_VPRINTF */
+
+/* Terminal output, pun intended. */
+
+#ifdef __STDC__
+void
+fatal (char const *format, ...)
+#else
+/*VARARGS1*/ void
+fatal (format, va_alist)
+ char const *format;
+ va_dcl
+#endif
+{
+ va_list args;
+ fprintf (stderr, "%s: **** ", program_name);
+ vararg_start (args, format);
+ vfprintf (stderr, format, args);
+ va_end (args);
+ putc ('\n', stderr);
+ fflush (stderr);
+ fatal_exit (0);
+}
+
+void
+memory_fatal ()
+{
+ fatal ("out of memory");
+}
+
+void
+read_fatal ()
+{
+ pfatal ("read error");
+}
+
+void
+write_fatal ()
+{
+ pfatal ("write error");
+}
+
+/* Say something from patch, something from the system, then silence . . . */
+
+#ifdef __STDC__
+void
+pfatal (char const *format, ...)
+#else
+/*VARARGS1*/ void
+pfatal (format, va_alist)
+ char const *format;
+ va_dcl
+#endif
+{
+ int errnum = errno;
+ va_list args;
+ fprintf (stderr, "%s: **** ", program_name);
+ vararg_start (args, format);
+ vfprintf (stderr, format, args);
+ va_end (args);
+ fflush (stderr); /* perror bypasses stdio on some hosts. */
+ errno = errnum;
+ perror (" ");
+ fflush (stderr);
+ fatal_exit (0);
+}
+
+/* Tell the user something. */
+
+#ifdef __STDC__
+void
+say (char const *format, ...)
+#else
+/*VARARGS1*/ void
+say (format, va_alist)
+ char const *format;
+ va_dcl
+#endif
+{
+ va_list args;
+ vararg_start (args, format);
+ vfprintf (stdout, format, args);
+ va_end (args);
+ fflush (stdout);
+}
+
+/* Get a response from the user, somehow or other. */
+
+#ifdef __STDC__
+void
+ask (char const *format, ...)
+#else
+/*VARARGS1*/ void
+ask (format, va_alist)
+ char const *format;
+ va_dcl
+#endif
+{
+ static int ttyfd = -2;
+ int r;
+ va_list args;
+
+ vararg_start (args, format);
+ vfprintf (stdout, format, args);
+ va_end (args);
+ fflush (stdout);
+
+ if (ttyfd == -2)
+ {
+ /* If standard output is not a tty, don't bother opening /dev/tty,
+ since it's unlikely that stdout will be seen by the tty user.
+ The isatty test also works around a bug in GNU Emacs 19.34 under Linux
+ which makes a call-process `patch' hang when it reads from /dev/tty.
+ POSIX.2 requires that we read /dev/tty, though. */
+ ttyfd = (posixly_correct || isatty (STDOUT_FILENO)
+ ? open (TTY_DEVICE, O_RDONLY)
+ : -1);
+ }
+
+ if (ttyfd < 0)
+ {
+ /* No terminal at all -- default it. */
+ printf ("\n");
+ buf[0] = '\n';
+ buf[1] = '\0';
+ }
+ else
+ {
+ size_t s = 0;
+ while ((r = read (ttyfd, buf + s, bufsize - 1 - s)) == bufsize - 1 - s
+ && buf[bufsize - 2] != '\n')
+ {
+ s = bufsize - 1;
+ bufsize *= 2;
+ buf = realloc (buf, bufsize);
+ if (!buf)
+ memory_fatal ();
+ }
+ if (r == 0)
+ printf ("EOF\n");
+ else if (r < 0)
+ {
+ perror ("tty read");
+ fflush (stderr);
+ close (ttyfd);
+ ttyfd = -1;
+ r = 0;
+ }
+ buf[s + r] = '\0';
+ }
+}
+
+/* Return nonzero if it OK to reverse a patch. */
+
+#ifdef __STDC__
+int
+ok_to_reverse (char const *format, ...)
+#else
+ok_to_reverse (format, va_alist)
+ char const *format;
+ va_dcl
+#endif
+{
+ int r = 0;
+
+ if (noreverse || ! (force && verbosity == SILENT))
+ {
+ va_list args;
+ vararg_start (args, format);
+ vfprintf (stdout, format, args);
+ va_end (args);
+ }
+
+ if (noreverse)
+ {
+ printf (" Skipping patch.\n");
+ skip_rest_of_patch = TRUE;
+ r = 0;
+ }
+ else if (force)
+ {
+ if (verbosity != SILENT)
+ printf (" Applying it anyway.\n");
+ r = 0;
+ }
+ else if (batch)
+ {
+ say (reverse ? " Ignoring -R.\n" : " Assuming -R.\n");
+ r = 1;
+ }
+ else
+ {
+ ask (reverse ? " Ignore -R? [y] " : " Assume -R? [y] ");
+ r = *buf != 'n';
+ if (! r)
+ {
+ ask ("Apply anyway? [n] ");
+ if (*buf != 'y')
+ {
+ if (verbosity != SILENT)
+ say ("Skipping patch.\n");
+ skip_rest_of_patch = TRUE;
+ }
+ }
+ }
+
+ return r;
+}
+
+/* How to handle certain events when not in a critical region. */
+
+#define NUM_SIGS (sizeof (sigs) / sizeof (*sigs))
+static int const sigs[] = {
+#ifdef SIGHUP
+ SIGHUP,
+#endif
+#ifdef SIGPIPE
+ SIGPIPE,
+#endif
+#ifdef SIGTERM
+ SIGTERM,
+#endif
+#ifdef SIGXCPU
+ SIGXCPU,
+#endif
+#ifdef SIGXFSZ
+ SIGXFSZ,
+#endif
+ SIGINT
+};
+
+#if !HAVE_SIGPROCMASK
+#define sigset_t int
+#define sigemptyset(s) (*(s) = 0)
+#ifndef sigmask
+#define sigmask(sig) (1 << ((sig) - 1))
+#endif
+#define sigaddset(s, sig) (*(s) |= sigmask (sig))
+#define sigismember(s, sig) ((*(s) & sigmask (sig)) != 0)
+#ifndef SIG_BLOCK
+#define SIG_BLOCK 0
+#endif
+#ifndef SIG_UNBLOCK
+#define SIG_UNBLOCK (SIG_BLOCK + 1)
+#endif
+#ifndef SIG_SETMASK
+#define SIG_SETMASK (SIG_BLOCK + 2)
+#endif
+#define sigprocmask(how, n, o) \
+ ((how) == SIG_BLOCK \
+ ? ((o) ? *(o) = sigblock (*(n)) : sigblock (*(n))) \
+ : (how) == SIG_UNBLOCK \
+ ? sigsetmask (((o) ? *(o) = sigblock (0) : sigblock (0)) & ~*(n)) \
+ : (o ? *(o) = sigsetmask (*(n)) : sigsetmask (*(n))))
+#if !HAVE_SIGSETMASK
+#define sigblock(mask) 0
+#define sigsetmask(mask) 0
+#endif
+#endif
+
+static sigset_t initial_signal_mask;
+static sigset_t signals_to_block;
+
+#if ! HAVE_SIGACTION
+static RETSIGTYPE fatal_exit_handler PARAMS ((int)) __attribute__ ((noreturn));
+static RETSIGTYPE
+fatal_exit_handler (sig)
+ int sig;
+{
+ signal (sig, SIG_IGN);
+ fatal_exit (sig);
+}
+#endif
+
+void
+set_signals(reset)
+int reset;
+{
+ int i;
+#if HAVE_SIGACTION
+ struct sigaction initial_act, fatal_act;
+ fatal_act.sa_handler = fatal_exit;
+ sigemptyset (&fatal_act.sa_mask);
+ fatal_act.sa_flags = 0;
+#define setup_handler(sig) sigaction (sig, &fatal_act, (struct sigaction *) 0)
+#else
+#define setup_handler(sig) signal (sig, fatal_exit_handler)
+#endif
+
+ if (!reset)
+ {
+#ifdef SIGCHLD
+ /* System V fork+wait does not work if SIGCHLD is ignored. */
+ signal (SIGCHLD, SIG_DFL);
+#endif
+ sigemptyset (&signals_to_block);
+ for (i = 0; i < NUM_SIGS; i++)
+ {
+ int ignoring_signal;
+#if HAVE_SIGACTION
+ if (sigaction (sigs[i], (struct sigaction *) 0, &initial_act) != 0)
+ continue;
+ ignoring_signal = initial_act.sa_handler == SIG_IGN;
+#else
+ ignoring_signal = signal (sigs[i], SIG_IGN) == SIG_IGN;
+#endif
+ if (! ignoring_signal)
+ {
+ sigaddset (&signals_to_block, sigs[i]);
+ setup_handler (sigs[i]);
+ }
+ }
+ }
+ else
+ {
+ /* Undo the effect of ignore_signals. */
+#if HAVE_SIGPROCMASK || HAVE_SIGSETMASK
+ sigprocmask (SIG_SETMASK, &initial_signal_mask, (sigset_t *) 0);
+#else
+ for (i = 0; i < NUM_SIGS; i++)
+ if (sigismember (&signals_to_block, sigs[i]))
+ setup_handler (sigs[i]);
+#endif
+ }
+}
+
+/* How to handle certain events when in a critical region. */
+
+void
+ignore_signals()
+{
+#if HAVE_SIGPROCMASK || HAVE_SIGSETMASK
+ sigprocmask (SIG_BLOCK, &signals_to_block, &initial_signal_mask);
+#else
+ int i;
+ for (i = 0; i < NUM_SIGS; i++)
+ if (sigismember (&signals_to_block, sigs[i]))
+ signal (sigs[i], SIG_IGN);
+#endif
+}
+
+void
+exit_with_signal (sig)
+ int sig;
+{
+ sigset_t s;
+ signal (sig, SIG_DFL);
+ sigemptyset (&s);
+ sigaddset (&s, sig);
+ sigprocmask (SIG_UNBLOCK, &s, (sigset_t *) 0);
+ raise (sig);
+ exit (2);
+}
+
+int
+systemic (command)
+ char const *command;
+{
+ if (debug & 8)
+ say ("+ %s\n", command);
+ fflush (stdout);
+ return system (command);
+}
+
+#if !HAVE_MKDIR
+/* These mkdir and rmdir substitutes are good enough for `patch';
+ they are not general emulators. */
+
+static int doprogram PARAMS ((char const *, char const *));
+static int mkdir PARAMS ((char const *, mode_t));
+static int rmdir PARAMS ((char const *));
+
+static int
+doprogram (program, arg)
+ char const *program;
+ char const *arg;
+{
+ int result;
+ static char const DISCARD_OUTPUT[] = " 2>/dev/null";
+ size_t program_len = strlen (program);
+ char *cmd = xmalloc (program_len + 1 + quote_system_arg (0, arg)
+ + sizeof DISCARD_OUTPUT);
+ char *p = cmd;
+ strcpy (p, program);
+ p += program_len;
+ *p++ = ' ';
+ p += quote_system_arg (p, arg);
+ strcpy (p, DISCARD_OUTPUT);
+ result = systemic (cmd);
+ free (cmd);
+ return result;
+}
+
+#ifdef __STDC__
+/* If mode_t doesn't promote to itself, we can't use old-style definition. */
+static int
+mkdir (char const *path, mode_t mode)
+#else
+static int
+mkdir (path, mode)
+ char const *path;
+ mode_t mode; /* ignored */
+#endif
+{
+ return doprogram ("mkdir", path);
+}
+
+static int
+rmdir (path)
+ char const *path;
+{
+ int result = doprogram ("rmdir", path);
+ errno = EEXIST;
+ return result;
+}
+#endif
+
+/* Replace '/' with '\0' in FILENAME if it marks a place that
+ needs testing for the existence of directory. Return the address
+ of the last location replaced, or 0 if none were replaced. */
+static char *replace_slashes PARAMS ((char *));
+static char *
+replace_slashes (filename)
+ char *filename;
+{
+ char *f;
+ char *last_location_replaced = 0;
+ char const *component_start;
+
+ for (f = filename + FILESYSTEM_PREFIX_LEN (filename); ISSLASH (*f); f++)
+ continue;
+
+ component_start = f;
+
+ for (; *f; f++)
+ if (ISSLASH (*f))
+ {
+ char *slash = f;
+
+ /* Treat multiple slashes as if they were one slash. */
+ while (ISSLASH (f[1]))
+ f++;
+
+ /* Ignore slashes at the end of the path. */
+ if (! f[1])
+ break;
+
+ /* "." and ".." need not be tested. */
+ if (! (slash - component_start <= 2
+ && component_start[0] == '.' && slash[-1] == '.'))
+ {
+ *slash = '\0';
+ last_location_replaced = slash;
+ }
+
+ component_start = f + 1;
+ }
+
+ return last_location_replaced;
+}
+
+/* Make sure we'll have the directories to create a file.
+ Ignore the last element of `filename'. */
+
+static void
+makedirs (filename)
+ register char *filename;
+{
+ register char *f;
+ register char *flim = replace_slashes (filename);
+
+ if (flim)
+ {
+ /* Create any missing directories, replacing NULs by '/'s.
+ Ignore errors. We may have to keep going even after an EEXIST,
+ since the path may contain ".."s; and when there is an EEXIST
+ failure the system may return some other error number.
+ Any problems will eventually be reported when we create the file. */
+ for (f = filename; f <= flim; f++)
+ if (!*f)
+ {
+ mkdir (filename,
+ S_IRUSR|S_IWUSR|S_IXUSR
+ |S_IRGRP|S_IWGRP|S_IXGRP
+ |S_IROTH|S_IWOTH|S_IXOTH);
+ *f = '/';
+ }
+ }
+}
+
+/* Remove empty ancestor directories of FILENAME.
+ Ignore errors, since the path may contain ".."s, and when there
+ is an EEXIST failure the system may return some other error number. */
+void
+removedirs (filename)
+ char *filename;
+{
+ size_t i;
+
+ for (i = strlen (filename); i != 0; i--)
+ if (ISSLASH (filename[i])
+ && ! (ISSLASH (filename[i - 1])
+ || (filename[i - 1] == '.'
+ && (i == 1
+ || ISSLASH (filename[i - 2])
+ || (filename[i - 2] == '.'
+ && (i == 2
+ || ISSLASH (filename[i - 3])))))))
+ {
+ filename[i] = '\0';
+ if (rmdir (filename) == 0 && verbosity == VERBOSE)
+ say ("Removed empty directory `%s'.\n", filename);
+ filename[i] = '/';
+ }
+}
+
+static time_t initial_time;
+
+void
+init_time ()
+{
+ time (&initial_time);
+}
+
+/* Make filenames more reasonable. */
+
+char *
+fetchname (at, strip_leading, pstamp)
+char *at;
+int strip_leading;
+time_t *pstamp;
+{
+ char *name;
+ register char *t;
+ int sleading = strip_leading;
+ time_t stamp = (time_t) -1;
+
+ while (ISSPACE ((unsigned char) *at))
+ at++;
+ if (debug & 128)
+ say ("fetchname %s %d\n", at, strip_leading);
+
+ name = at;
+ /* Strip off up to `sleading' leading slashes and null terminate. */
+ for (t = at; *t; t++)
+ {
+ if (ISSLASH (*t))
+ {
+ while (ISSLASH (t[1]))
+ t++;
+ if (--sleading >= 0)
+ name = t+1;
+ }
+ else if (ISSPACE ((unsigned char) *t))
+ {
+ if (set_time | set_utc)
+ stamp = str2time (t, initial_time, set_utc ? 0L : TM_LOCAL_ZONE);
+ else
+ {
+ /* The head says the file is nonexistent if the timestamp
+ is the epoch; but the listed time is local time, not UTC,
+ and POSIX.1 allows local time to be 24 hours away from UTC.
+ So match any time within 24 hours of the epoch.
+ Use a default time zone 24 hours behind UTC so that any
+ non-zoned time within 24 hours of the epoch is valid. */
+ stamp = str2time (t, initial_time, -24L * 60 * 60);
+ if (0 <= stamp && stamp <= 2 * 24L * 60 * 60)
+ stamp = 0;
+ }
+
+ *t = '\0';
+ break;
+ }
+ }
+
+ if (!*name)
+ return 0;
+
+ /* Allow files to be created by diffing against /dev/null. */
+ if (strcmp (at, "/dev/null") == 0)
+ {
+ if (pstamp)
+ *pstamp = 0;
+ return 0;
+ }
+
+ if (pstamp)
+ *pstamp = stamp;
+
+ return savestr (name);
+}
+
+GENERIC_OBJECT *
+xmalloc (size)
+ size_t size;
+{
+ register GENERIC_OBJECT *p = malloc (size);
+ if (!p)
+ memory_fatal ();
+ return p;
+}
+
+void
+Fseek (stream, offset, ptrname)
+ FILE *stream;
+ file_offset offset;
+ int ptrname;
+{
+ if (file_seek (stream, offset, ptrname) != 0)
+ pfatal ("fseek");
+}
OpenPOWER on IntegriCloud