summaryrefslogtreecommitdiff
path: root/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'util.c')
-rw-r--r--util.c502
1 files changed, 218 insertions, 284 deletions
diff --git a/util.c b/util.c
index 03a8e168a18b4..6b88a5693766f 100644
--- a/util.c
+++ b/util.c
@@ -1,35 +1,38 @@
/* utility functions for `patch' */
-/* $Id: util.c,v 1.24 1997/07/10 08:16:12 eggert Exp $ */
+/* $Id: util.c,v 1.36 2003/05/20 14:04:53 eggert Exp $ */
-/*
-Copyright 1986 Larry Wall
-Copyright 1992, 1993, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1986 Larry Wall
-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.
+ Copyright (C) 1992, 1993, 1997, 1998, 1999, 2001, 2002, 2003 Free
+ Software Foundation, Inc.
-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.
+ 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.
-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.
-*/
+ 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 <dirname.h>
#include <quotearg.h>
+#include <quotesys.h>
#include <version.h>
#undef XTERN
#define XTERN
#include <util.h>
+#include <xalloc.h>
#include <maketime.h>
#include <partime.h>
@@ -38,45 +41,25 @@ If not, write to the Free Software Foundation,
#if !defined SIGCHLD && defined SIGCLD
#define SIGCHLD SIGCLD
#endif
-#if ! HAVE_RAISE
+#if ! HAVE_RAISE && ! defined 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
+#include <stdarg.h>
-static void makedirs PARAMS ((char *));
+static void makedirs (char *);
-/* Move a file FROM to TO, renaming it if possible and copying it if necessary.
+/* Move a file FROM (where *FROM_NEEDS_REMOVAL is nonzero if FROM
+ needs removal when cleaning up at the end of execution)
+ 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. */
+ FROM_NEEDS_REMOVAL must be nonnull if FROM is nonnull.
+ Back up TO if BACKUP is true. */
-#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
+move_file (char const *from, int volatile *from_needs_removal,
+ char *to, mode_t mode, bool backup)
{
struct stat to_st;
int to_errno = ! backup ? -1 : stat (to, &to_st) == 0 ? 0 : errno;
@@ -109,7 +92,7 @@ move_file (from, to, mode, backup)
}
else
{
- bakname = find_backup_file_name (to);
+ bakname = find_backup_file_name (to, backup_type);
if (!bakname)
memory_fatal ();
}
@@ -117,28 +100,32 @@ move_file (from, to, mode, backup)
if (to_errno)
{
int fd;
+
if (debug & 4)
- say ("creating empty unreadable file `%s'\n", bakname);
+ say ("Creating empty unreadable file %s\n", quotearg (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);
+ pfatal ("Can't create file %s", quotearg (bakname));
makedirs (bakname);
try_makedirs_errno = 0;
}
if (close (fd) != 0)
- pfatal ("can't close `%s'", bakname);
+ pfatal ("Can't close file %s", quotearg (bakname));
}
else
{
if (debug & 4)
- say ("renaming `%s' to `%s'\n", to, bakname);
+ say ("Renaming file %s to %s\n",
+ quotearg_n (0, to), quotearg_n (1, bakname));
while (rename (to, bakname) != 0)
{
if (errno != try_makedirs_errno)
- pfatal ("can't rename `%s' to `%s'", to, bakname);
+ pfatal ("Can't rename file %s to %s",
+ quotearg_n (0, to), quotearg_n (1, bakname));
makedirs (bakname);
try_makedirs_errno = 0;
}
@@ -150,11 +137,12 @@ move_file (from, to, mode, backup)
if (from)
{
if (debug & 4)
- say ("renaming `%s' to `%s'\n", from, to);
+ say ("Renaming file %s to %s\n",
+ quotearg_n (0, from), quotearg_n (1, to));
if (rename (from, to) != 0)
{
- int to_dir_known_to_exist = 0;
+ bool to_dir_known_to_exist = false;
if (errno == ENOENT
&& (to_errno == -1 || to_errno == ENOENT))
@@ -162,7 +150,7 @@ move_file (from, to, mode, backup)
makedirs (to);
to_dir_known_to_exist = 1;
if (rename (from, to) == 0)
- return;
+ goto rename_succeeded;
}
if (errno == EXDEV)
@@ -170,42 +158,42 @@ move_file (from, to, mode, backup)
if (! backup)
{
if (unlink (to) == 0)
- to_dir_known_to_exist = 1;
+ to_dir_known_to_exist = true;
else if (errno != ENOENT)
- pfatal ("can't remove `%s'", to);
+ pfatal ("Can't remove file %s", quotearg (to));
}
if (! to_dir_known_to_exist)
makedirs (to);
- copy_file (from, to, mode);
+ copy_file (from, to, 0, mode);
return;
}
- pfatal ("can't rename `%s' to `%s'", from, to);
+ pfatal ("Can't rename file %s to %s",
+ quotearg_n (0, from), quotearg_n (1, to));
}
+
+ rename_succeeded:
+ /* Do not clear *FROM_NEEDS_REMOVAL if it's possible that the
+ rename returned zero because FROM and TO are hard links to
+ the same file. */
+ if (0 < to_errno
+ || (to_errno == 0 && to_st.st_nlink <= 1))
+ *from_needs_removal = 0;
}
else if (! backup)
{
if (debug & 4)
- say ("removing `%s'\n", to);
+ say ("Removing file %s\n", quotearg (to));
if (unlink (to) != 0)
- pfatal ("can't remove `%s'", to);
+ pfatal ("Can't remove file %s", quotearg (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;
@@ -214,34 +202,25 @@ create_file (file, open_flags, mode)
close (creat (file, mode));
fd = open (file, O_CREAT | O_TRUNC | open_flags, mode);
if (fd < 0)
- pfatal ("can't create `%s'", file);
+ pfatal ("Can't create file %s", quotearg (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
+copy_file (char const *from, char const *to, int to_flags, mode_t mode)
{
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);
+ pfatal ("Can't reopen file %s", quotearg (from));
+ tofd = create_file (to, O_WRONLY | O_BINARY | to_flags, mode);
while ((i = read (fromfd, buf, bufsize)) != 0)
{
- if (i == -1)
+ if (i == (size_t) -1)
read_fatal ();
if (write (tofd, buf, i) != i)
write_fatal ();
@@ -254,41 +233,45 @@ copy_file (from, to, mode)
static char const DEV_NULL[] = NULL_DEVICE;
+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";
+
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";
+static char const CLEARTOOL_CO[] = "cleartool co -unr -nc ";
+
+static char const PERFORCE_CO[] = "p4 edit ";
/* 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.
+ "SCCS" if it is controlled by SCCS,
+ "ClearCase" if it is controlled by Clearcase,
+ "Perforce" if it is controlled by Perforce,
+ and 0 otherwise.
+ READONLY is true 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.
+ that gets the file; similarly for DIFFBUF and a command to diff the file
+ (but set *DIFFBUF to 0 if the diff operation is meaningless).
*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;
+version_controller (char const *filename, bool 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 dirlen = 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 maxgetsize = sizeof CLEARTOOL_CO + quotelen + maxfixlen;
size_t maxdiffsize =
(sizeof SCCSDIFF1 + sizeof SCCSDIFF2 + sizeof DEV_NULL - 1
+ 2 * quotelen + maxfixlen);
@@ -297,8 +280,8 @@ version_controller (filename, readonly, filestat, getbuf, diffbuf)
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)
+#define try1(f,a1) (sprintf (trybuf + dirlen, f, a1), stat (trybuf, &cstat) == 0)
+#define try2(f,a1,a2) (sprintf (trybuf + dirlen, f, a1,a2), stat (trybuf, &cstat) == 0)
/* Check that RCS file is not working file.
Some hosts don't report file name length errors. */
@@ -358,29 +341,58 @@ version_controller (filename, readonly, filestat, getbuf, diffbuf)
r = "SCCS";
}
+ else if (!readonly && filestat
+ && try1 ("%s@@", filebase) && S_ISDIR (cstat.st_mode))
+ {
+ if (getbuf)
+ {
+ char *p = *getbuf = xmalloc (maxgetsize);
+ strcpy (p, CLEARTOOL_CO);
+ p += sizeof CLEARTOOL_CO - 1;
+ p += quote_system_arg (p, filename);
+ *p = '\0';
+ }
+
+ if (diffbuf)
+ *diffbuf = 0;
+
+ r = "ClearCase";
+ }
+ else if (!readonly && filestat &&
+ (getenv("P4PORT") || getenv("P4USER") || getenv("P4CONFIG")))
+ {
+ if (getbuf)
+ {
+ char *p = *getbuf = xmalloc (maxgetsize);
+ strcpy (p, PERFORCE_CO);
+ p += sizeof PERFORCE_CO - 1;
+ p += quote_system_arg (p, filename);
+ *p = '\0';
+ }
+
+ if (diffbuf)
+ *diffbuf = 0;
+
+ r = "Perforce";
+ }
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.
+ EXISTS. Only readonly access is needed if READONLY.
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;
+ Return true if successful. */
+bool
+version_get (char const *filename, char const *cs, bool exists, bool readonly,
+ char const *getbuf, struct stat *filestat)
{
if (patch_get < 0)
{
- ask ("Get file `%s' from %s%s? [y] ", filename,
- cs, readonly ? "" : " with lock");
+ ask ("Get file %s from %s%s? [y] ",
+ quotearg (filename), cs, readonly ? "" : " with lock");
if (*buf == 'n')
return 0;
}
@@ -388,29 +400,27 @@ version_get (filename, cs, exists, readonly, getbuf, filestat)
if (dry_run)
{
if (! exists)
- fatal ("can't do dry run on nonexistent version-controlled file `%s'; invoke `%s' and try again",
- filename, getbuf);
+ fatal ("can't do dry run on nonexistent version-controlled file %s; invoke `%s' and try again",
+ quotearg (filename), getbuf);
}
else
{
if (verbosity == VERBOSE)
- say ("Getting file `%s' from %s%s...\n", filename,
+ say ("Getting file %s from %s%s...\n", quotearg (filename),
cs, readonly ? "" : " with lock");
if (systemic (getbuf) != 0)
- fatal ("can't get file `%s' from %s", filename, cs);
+ fatal ("Can't get file %s from %s", quotearg (filename), cs);
if (stat (filename, filestat) != 0)
- pfatal ("%s", filename);
+ pfatal ("%s", quotearg (filename));
}
-
+
return 1;
}
/* Allocate a unique area for a string. */
char *
-savebuf (s, size)
- register char const *s;
- register size_t size;
+savebuf (register char const *s, register size_t size)
{
register char *rv;
@@ -429,30 +439,47 @@ savebuf (s, size)
}
char *
-savestr(s)
- char const *s;
+savestr (char const *s)
{
return savebuf (s, strlen (s) + 1);
}
void
-remove_prefix (p, prefixlen)
- char *p;
- size_t prefixlen;
+remove_prefix (char *p, size_t prefixlen)
{
char const *s = p + prefixlen;
while ((*p++ = *s++))
continue;
}
+char *
+format_linenum (char numbuf[LINENUM_LENGTH_BOUND + 1], LINENUM n)
+{
+ char *p = numbuf + LINENUM_LENGTH_BOUND;
+ *p = '\0';
+
+ if (n < 0)
+ {
+ do
+ *--p = '0' - (int) (n % 10);
+ while ((n /= 10) != 0);
+
+ *--p = '-';
+ }
+ else
+ {
+ do
+ *--p = '0' + (int) (n % 10);
+ while ((n /= 10) != 0);
+ }
+
+ return p;
+}
+
#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;
+vfprintf (FILE *stream, char const *format, va_list args)
{
#if !HAVE_DOPRNT && HAVE__DOPRINTF
# define _doprnt _doprintf
@@ -470,19 +497,12 @@ vfprintf (stream, format, args)
/* 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);
+ va_start (args, format);
vfprintf (stderr, format, args);
va_end (args);
putc ('\n', stderr);
@@ -491,39 +511,32 @@ fatal (format, va_alist)
}
void
-memory_fatal ()
+memory_fatal (void)
{
fatal ("out of memory");
}
void
-read_fatal ()
+read_fatal (void)
{
pfatal ("read error");
}
void
-write_fatal ()
+write_fatal (void)
{
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);
+ va_start (args, format);
vfprintf (stderr, format, args);
va_end (args);
fflush (stderr); /* perror bypasses stdio on some hosts. */
@@ -535,18 +548,11 @@ pfatal (format, va_alist)
/* 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);
+ va_start (args, format);
vfprintf (stdout, format, args);
va_end (args);
fflush (stdout);
@@ -554,21 +560,14 @@ say (format, va_alist)
/* 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);
+ va_start (args, format);
vfprintf (stdout, format, args);
va_end (args);
fflush (stdout);
@@ -579,7 +578,8 @@ ask (format, va_alist)
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. */
+ POSIX.1-2001 XCU line 26599 requires that we read /dev/tty,
+ though. */
ttyfd = (posixly_correct || isatty (STDOUT_FILENO)
? open (TTY_DEVICE, O_RDONLY)
: -1);
@@ -620,21 +620,15 @@ ask (format, va_alist)
/* Return nonzero if it OK to reverse a patch. */
-#ifdef __STDC__
-int
+bool
ok_to_reverse (char const *format, ...)
-#else
-ok_to_reverse (format, va_alist)
- char const *format;
- va_dcl
-#endif
{
- int r = 0;
+ bool r = false;
if (noreverse || ! (force && verbosity == SILENT))
{
va_list args;
- vararg_start (args, format);
+ va_start (args, format);
vfprintf (stdout, format, args);
va_end (args);
}
@@ -642,19 +636,17 @@ ok_to_reverse (format, va_alist)
if (noreverse)
{
printf (" Skipping patch.\n");
- skip_rest_of_patch = TRUE;
- r = 0;
+ skip_rest_of_patch = true;
}
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;
+ r = true;
}
else
{
@@ -667,7 +659,7 @@ ok_to_reverse (format, va_alist)
{
if (verbosity != SILENT)
say ("Skipping patch.\n");
- skip_rest_of_patch = TRUE;
+ skip_rest_of_patch = true;
}
}
}
@@ -730,10 +722,9 @@ 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 (int) __attribute__ ((noreturn));
static RETSIGTYPE
-fatal_exit_handler (sig)
- int sig;
+fatal_exit_handler (int sig)
{
signal (sig, SIG_IGN);
fatal_exit (sig);
@@ -741,8 +732,7 @@ fatal_exit_handler (sig)
#endif
void
-set_signals(reset)
-int reset;
+set_signals (bool reset)
{
int i;
#if HAVE_SIGACTION
@@ -764,7 +754,7 @@ int reset;
sigemptyset (&signals_to_block);
for (i = 0; i < NUM_SIGS; i++)
{
- int ignoring_signal;
+ bool ignoring_signal;
#if HAVE_SIGACTION
if (sigaction (sigs[i], (struct sigaction *) 0, &initial_act) != 0)
continue;
@@ -795,7 +785,7 @@ int reset;
/* How to handle certain events when in a critical region. */
void
-ignore_signals()
+ignore_signals (void)
{
#if HAVE_SIGPROCMASK || HAVE_SIGSETMASK
sigprocmask (SIG_BLOCK, &signals_to_block, &initial_signal_mask);
@@ -808,8 +798,7 @@ ignore_signals()
}
void
-exit_with_signal (sig)
- int sig;
+exit_with_signal (int sig)
{
sigset_t s;
signal (sig, SIG_DFL);
@@ -821,8 +810,7 @@ exit_with_signal (sig)
}
int
-systemic (command)
- char const *command;
+systemic (char const *command)
{
if (debug & 8)
say ("+ %s\n", command);
@@ -830,66 +818,11 @@ systemic (command)
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;
+replace_slashes (char *filename)
{
char *f;
char *last_location_replaced = 0;
@@ -931,8 +864,7 @@ replace_slashes (filename)
Ignore the last element of `filename'. */
static void
-makedirs (filename)
- register char *filename;
+makedirs (register char *filename)
{
register char *f;
register char *flim = replace_slashes (filename);
@@ -960,8 +892,7 @@ makedirs (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;
+removedirs (char *filename)
{
size_t i;
@@ -977,7 +908,7 @@ removedirs (filename)
{
filename[i] = '\0';
if (rmdir (filename) == 0 && verbosity == VERBOSE)
- say ("Removed empty directory `%s'.\n", filename);
+ say ("Removed empty directory %s\n", quotearg (filename));
filename[i] = '/';
}
}
@@ -985,7 +916,7 @@ removedirs (filename)
static time_t initial_time;
void
-init_time ()
+init_time (void)
{
time (&initial_time);
}
@@ -993,10 +924,7 @@ init_time ()
/* Make filenames more reasonable. */
char *
-fetchname (at, strip_leading, pstamp)
-char *at;
-int strip_leading;
-time_t *pstamp;
+fetchname (char *at, int strip_leading, time_t *pstamp)
{
char *name;
register char *t;
@@ -1009,33 +937,46 @@ time_t *pstamp;
say ("fetchname %s %d\n", at, strip_leading);
name = at;
- /* Strip off up to `sleading' leading slashes and null terminate. */
+ /* Strip up to `strip_leading' leading slashes and null terminate.
+ If `strip_leading' is negative, strip all leading slashes. */
for (t = at; *t; t++)
{
if (ISSLASH (*t))
{
while (ISSLASH (t[1]))
t++;
- if (--sleading >= 0)
+ if (strip_leading < 0 || --sleading >= 0)
name = t+1;
}
else if (ISSPACE ((unsigned char) *t))
{
+ /* Allow file names with internal spaces,
+ but only if a tab separates the file name from the date. */
+ char const *u = t;
+ while (*u != '\t' && ISSPACE ((unsigned char) u[1]))
+ u++;
+ if (*u != '\t' && strchr (u + 1, '\t'))
+ continue;
+
if (set_time | set_utc)
- stamp = str2time (t, initial_time, set_utc ? 0L : TM_LOCAL_ZONE);
+ stamp = str2time (&u, 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)
+ and POSIX.1 allows local time offset anywhere in the range
+ -25:00 < offset < +26:00. Match any time in that
+ range by assuming local time is -25:00 and then matching
+ any ``local'' time T in the range 0 < T < 25+26 hours. */
+ stamp = str2time (&u, initial_time, -25L * 60 * 60);
+ if (0 < stamp && stamp < (25 + 26) * 60L * 60)
stamp = 0;
}
+ if (*u && ! ISSPACE ((unsigned char) *u))
+ stamp = (time_t) -1;
+
*t = '\0';
break;
}
@@ -1044,7 +985,9 @@ time_t *pstamp;
if (!*name)
return 0;
- /* Allow files to be created by diffing against /dev/null. */
+ /* If the name is "/dev/null", ignore the name and mark the file
+ as being nonexistent. The name "/dev/null" appears in patches
+ regardless of how NULL_DEVICE is spelled. */
if (strcmp (at, "/dev/null") == 0)
{
if (pstamp)
@@ -1052,27 +995,18 @@ time_t *pstamp;
return 0;
}
+ /* Ignore the name if it doesn't have enough slashes to strip off. */
+ if (0 < sleading)
+ 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;
+Fseek (FILE *stream, file_offset offset, int ptrname)
{
if (file_seek (stream, offset, ptrname) != 0)
pfatal ("fseek");