diff options
Diffstat (limited to 'util.c')
-rw-r--r-- | util.c | 502 |
1 files changed, 218 insertions, 284 deletions
@@ -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"); |