From fb6b9b91d11dacb448979bb7770182f1731e9f99 Mon Sep 17 00:00:00 2001 From: "Pedro F. Giffuni" Date: Sat, 27 Jul 2013 19:57:20 +0000 Subject: Virgin import of patch-2.5.9, the last official GPLv2 release. As in previous imports we dropped the mkinstall and pc directories as they are of no use to us. Differently from previous imports, patch.1 was not renamed and is maintained with its original name (patch.man). If we ever merge this into the main tree, care must be taken to rename it back. --- util.c | 502 ++++++++++++++++++++++++++++------------------------------------- 1 file changed, 218 insertions(+), 284 deletions(-) (limited to 'util.c') diff --git a/util.c b/util.c index 03a8e168a18b..6b88a5693766 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 #include +#include #include +#include #include #undef XTERN #define XTERN #include +#include #include #include @@ -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 -# define vararg_start va_start -#else -# define vararg_start(ap,p) va_start (ap) -# if HAVE_VARARGS_H -# include -# 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 -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"); -- cgit v1.2.3