diff options
author | Andreas Gruenbacher <agruen@suse.de> | 2009-03-12 15:15:17 +0100 |
---|---|---|
committer | Andreas Gruenbacher <agruen@suse.de> | 2009-03-12 15:15:17 +0100 |
commit | 6263c220df2b94ae8156c378dc5161779d894297 (patch) | |
tree | 52d1c3fd61d567edd0d9eab977f1acc44a7d754d | |
parent | 1adb4535a31d825f10a5bd1ef10b52a7425073bd (diff) | |
download | patch-2.4.tar.gz |
Import of patch-2.4.tar.gzv2.4
-rw-r--r-- | ChangeLog | 263 | ||||
-rw-r--r-- | Makefile.in | 30 | ||||
-rw-r--r-- | NEWS | 72 | ||||
-rw-r--r-- | acconfig.h | 3 | ||||
-rw-r--r-- | backupfile.c | 5 | ||||
-rw-r--r-- | common.h | 27 | ||||
-rw-r--r-- | config.hin | 9 | ||||
-rwxr-xr-x | configure | 92 | ||||
-rw-r--r-- | configure.in | 20 | ||||
-rw-r--r-- | inp.c | 136 | ||||
-rw-r--r-- | maketime.c | 11 | ||||
-rw-r--r-- | patch.c | 330 | ||||
-rw-r--r-- | patch.man | 507 | ||||
-rw-r--r-- | pc/djgpp/config.h | 139 | ||||
-rw-r--r-- | pc/djgpp/config.sed | 65 | ||||
-rw-r--r-- | pc/djgpp/configure.bat | 4 | ||||
-rw-r--r-- | pc/djgpp/configure.sed | 36 | ||||
-rw-r--r-- | pch.c | 195 | ||||
-rw-r--r-- | pch.h | 3 | ||||
-rw-r--r-- | util.c | 297 | ||||
-rw-r--r-- | util.h | 6 |
21 files changed, 1476 insertions, 774 deletions
@@ -1,3 +1,222 @@ +1997-06-19 Paul Eggert <eggert@pogo.gnu.ai.mit.edu> + + * configure.in (VERSION): Version 2.4 released. + * NEWS: Patch is now verbose when patches do not match exactly. + +1997-06-17 Paul Eggert <eggert@twinsun.com> + + * pc/djgpp/configure.sed (config.h): Remove redundant $(srcdir). + + * configure.in (VERSION): Bump to 2.3.9. + * patch.c (main): By default, warn about hunks that succeed + with nonzero offset. + * patch.man: Add LC_ALL=C advice for making patches. + * pc/djgpp/configure.sed (config.h): Fix paths to dependent files. + +1997-06-17 Paul Eggert <eggert@twinsun.com> + + * configure.in (VERSION): Bump to 2.3.8. + + * pch.c (open_patch_file): Test stdin for fseekability. + (intuit_diff_type): Missing context diff headers are now warnings, + not errors; some people use patches with them (e.g. when retrying + rejects). + + * patch.c (struct outstate): + New type, collecting together some output state vars. + (apply_hunk, copy_till, spew_output, init_output): Use it. + Keep track of whether some output has been generated. + (backup_if_mismatch): New var. + (ofp): Remove, in favor of local struct outstate vars. + (main): Use struct outstate. Initialize backup_if_mismatch to + be the inverse of posixly_correct. Keep track of whether mismatches + occur, and use this to implement backup_if_mismatch. + Report files that are not empty after patching, but should be. + (longopts, option_help, get_some_switches): New options + --backup-if-mismatch, --no-backup-if-mismatch. + (get_some_switches): -B, -Y, -z no longer set backup_type. + * backupfile.c (find_backup_file_name): + Treat backup_type == none like simple. + + * Makefile.in (CONFIG_HDRS): + Remove var; no longer needed by djgpp port. + (DISTFILES_PC_DJGPP): Rename pc/djgpp/config.sed to + pc/djgpp/configure.sed; remove pc/djgpp/config.h in favor of + new file that edits it, called pc/djgpp/config.sed. + * pc/djgpp/configure.bat: Rename config.sed to configure.sed. + * pc/djgpp/configure.sed (CONFIG_HDRS): Remove. + (config.h): Add rule to build this from config.hin and + pc/djgpp/config.sed. + * pc/djgpp/config.sed: + Convert from .h file to .sed script that generates .h file. + + * NEWS: Describe --backup-if-mismatch, --no-backup-if-mismatch. + * patch.man: + Describe new options --backup-if-mismatch, --no-backup-if-mismatch + and their ramifications. Use unreadable backup to represent + nonexistent file. + +1997-06-12 Paul Eggert <eggert@twinsun.com> + + * configure.in (VERSION): Bump to 2.3.7. + (AC_CHECK_FUNCS): Add `raise'. + + * Makefile.in (inp.o): No longer depends on quotearg.h. + + * common.h (outfile): New decl (was private var named `output'). + (invc): New decl. + (GENERIC_OBJECT): Renamed from VOID. + (NULL_DEVICE, TTY_DEVICE): New macros. + + * patch.c (output): Remove; renamed to `outfile' and moved to common.h. + (main): `failed' is count, not boolean. + Say "Skipping patch." when deciding to skip patch. + (get_some_switches): Set invc when setting inname. + + * inp.c: Do not include <quotearg.h>. + (SCCSPREFIX, GET, GET_LOCKED, SCCSDIFF1, SCCSDIFF2, SCCSDIFF3, + RCSSUFFIX, CHECKOUT, CHECKOUT_LOCKED, RCSDIFF1, RCSDIFF2): + Move to util.c. + (get_input_file): Invoke new functions version_controller and + version_get to simplify this code. + (plan_b): "/dev/tty" -> NULL_DEVICE + + * pch.h (pch_timestamp): New decl. + * pch.c (p_timestamp): New var; takes over from global timestamp array. + (pch_timestamp): New function to export p_timestamp. + (there_is_another_patch): Use blander wording when you can't intuit + the file name. + Say "Skipping patch." when deciding to skip patch. + (intuit_diff_type): Look for version-controlled but nonexistent files + when intuiting file names; set invc accordingly. + Ignore Index: line if either old or new line is present, and if + POSIXLY_CORRECT is not set. + (do_ed_script): Flush stdout before invoking popen, since it may + send output to stdout. + + * util.h (version_controller, version_get): New decls. + * util.c: Include <quotearg.h> earlier. + (raise): New macro, if ! HAVE_RAISE. + (move_file): Create empty unreadable file when backing up a nonexistent + file. + (DEV_NULL): New constant. + (SCCSPREFIX, GET. GET_LOCKED, SCCSDIFF1, SCCSDIFF2, + RCSSUFFIX, CHECKOUT, CHECKOUT_LOCKED, RCSDIFF1): Moved here from inp.c. + (version_controller, version_get): New functions. + (ask): Look only at /dev/tty for answers; and when standard output is + not a terminal and ! posixly_correct, don't even look there. + Remove unnecessary fflushes of stdout. + (ok_to_reverse): Say "Skipping patch." when deciding to skip patch.. + (sigs): SIGPIPE might not be defined. + (exit_with_signal): Use `raise' instead of `kill'. + (systemic): fflush stdout before invoking subsidiary command. + + * patch.man: Document recent changes. + Add "COMPATIBILITY ISSUES" section. + + * NEWS: New COMPATIBILITY ISSUES for man page. + Changed verbosity when fuzz is found. + File name intuition is changed, again. + Backups are made unreadable when the file did not exist. + + * pc/djgpp/config.h (HAVE_STRUCT_UTIMBUF): Define. + (HAVE_RAISE): New macro. + (HAVE_UTIME_H): Define. + (TZ_is_unset): Do not define; it's not a serious problem with `patch' + to have TZ be unset in DOS. + +1997-06-08 Paul Eggert <eggert@twinsun.com> + + * configure.in (VERSION): Bump to 2.3.6. + (AC_CHECK_HEADERS): Add utime.h. + * acconfig.h, configure.in, pc/djgpp/config.h (HAVE_STRUCT_UTIMBUF): + New macro. + * pc/djgpp/config.h (HAVE_UTIME_H, TZ_is_unset): New macros. + + * NEWS, patch.man: Describe new -Z, -T options, new numeric + option for -G, retired -G, and more verbose default behavior + with fuzz. + + * pch.c (intuit_diff_type): Record times reported for files in headers. + Remove head_says_nonexistent[x], since it's now equivalent to + !timestamp[x]. + * util.h (fetchname): Change argument head_says_nonexistent to + timestamp. + * util.c: #include <partime.h> for TM_LOCAL_ZONE. + Don't include <time.h> since common.h now includes it. + (ok_to_reverse): noreverse and batch cases now output regardless of + verbosity. + (fetchname): Change argument head_says_nonexistent to pstamp, and + store header timestamp into *pstamp. + If -T or -Z option is given, match time stamps more precisely. + (ask): Remove unnecessary close of ttyfd. + When there is no terminal at all, output a newline to make the + output look nicer. After reporting EOF, flush stdout; + when an input error, report the error type. + + * inp.c (get_input_file): + Ask user whether to get file if patch_get is negative. + + * Makefile.in (clean): Don't clean */*.o; clean core* and *core. + +1997-06-04 Paul Eggert <eggert@twinsun.com> + + * configure.in (VERSION): Bump to 2.3.5. + + * util.c (ok_to_reverse): + Be less chatty if verbosity is SILENT and we don't + have to ask the user. If force is nonzero, apply the patch anyway. + + * pch.c (there_is_another_patch): + Before skipping rest of patch, skip to + the patch start, so that another_hunk can skip it properly. + (intuit_diff_type): Slight wording change for missing headers, to + regularize with other diagnostics. Fix off-by-one error when setting + p_input_line when scanning the first hunk to check for deleted files. + +1997-06-03 Paul Eggert <eggert@twinsun.com> + + * configure.in (VERSION): Bump to 2.3.4. + + * NEWS: Now matches more generously against nonexistent or empty files. + + * pch.c (there_is_another_patch): Move warning about not being + able to intuit file names here from skip_to. + (intuit_diff_type): Fatal error if we find a headless unified + or context diff. + + * util.c (ask): Null-terminate buffer properly even if it grew. + (fetchname): No need to test for null first argument. + +1997-06-02 Paul Eggert <eggert@twinsun.com> + + * configure.in (VERSION): Bump to 2.3.3. + * pch.c (p_says_nonexistent, pch_says_nonexistent): Is now 1 for empty, + 2 for nonexistent. + (intuit_diff_type): Set p_says_nonexistent according to new meaning. + Treat empty files like nonexistent files when reversing. + (skip_to): Output better diagnostic when we can't intuit a file name. + * patch.c (main): + Count bytes, not lines, when testing whether a file is empty, + since it may contain only non-newline chars. + pch_says_nonexistent now returns 2 for nonexistent files. + +1997-06-01 Paul Eggert <eggert@twinsun.com> + + * configure.in (VERSION): Bump to 2.3.2. + * pch.c (open_patch_file): + Fix bug when computing size of patch read from a pipe. + +1997-05-30 Paul Eggert <eggert@twinsun.com> + + * configure.in (VERSION): Bump to 2.3.1. + + * Makefile.in (transform, patch_name): New vars, + for proper implementation of AC_ARG_PROGRAM. + (install, uninstall): Use them. + (install-strip): New rule. + * pc/djgpp/config.sed (program_transform_name): Set to empty. + 1997-05-30 Paul Eggert <eggert@twinsun.com> * configure.in (VERSION), NEWS: Version 2.3 released. @@ -88,50 +307,6 @@ * Makefile.in (DISTFILES_PC): Remove pc/quotearg.c. * pc/djgpp/config.sed: Remove unnecessary hooks for quotearg and SHELL. -1997-05-18 Paul Eggert <eggert@pogo.gnu.ai.mit.edu> - - * configure.in (VERSION): Increase to 2.2.9. - (AC_TYPE_MODE_T): Add. - - * pch.c (hunkmax): Now of type LINENUM. - (malformed): Add decl. - (there_is_another_patch): Skip inname-detection if skip_rest_of_patch. - (intuit_diff_type): To determine whether file appears to have been - deleted, look at replacement, not pattern. - If there is a mismatch between existence of file and whether the - patch claims to change whether the file exists, ask whether to - reverse the patch. - (another_hunk): New parameter REV specifying whether to reverse the - hunk. All callers changed. - (do_ed_script): Add assertion to ensure input file exists. - - * common.h (noreverse): New decl. - (ok_to_reverse): Remove decl. - - * patch.c (noreverse): Now extern. - (main): New environment var PATCH_VERSION_CONTROL overrides VERSION_CONTROL. - Don't assert(hunk) if we're skipping the patch; we may not have any hunks. - When removing a file, back it up if backups are desired. - Don't chmod output file if input file did not exist. - chmod rej file to input file's mode minus executable bits. - (locate_hunk): Go back to old way of a single fuzz parameter, but - handle it more precisely: context diffs with partial contexts - can only match file ends, since the partial context can occur - only at the start or end of file. - All callers changed. - (create_output_file): Use create_file to create files. - (ok_to_reverse): Move to util.c. - - * inp.c (scan_input, get_input_file): Quote file names in diagnostics. - (get_input_file): Set inerrno if it's not already set. - Don't create file; it's now the caller's responsibility. - (plan_b): Use /dev/null if input size is zero, since it might not exist. - Use create_file to create temporary file. - - * NEWS: Add PATCH_VERSION_CONTROL; DOS port is untested. - - * patch.man: PATCH_VERSION_CONTROL overrides VERSION_CONTROL. - 1997-05-18 Paul Eggert <eggert@twinsun.com> * configure.in (VERSION): Increase to 2.2.9. diff --git a/Makefile.in b/Makefile.in index d517ed5..9f0b14a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -28,6 +28,7 @@ ed_PROGRAM = @ed_PROGRAM@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ +transform = @program_transform_name@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ @@ -45,11 +46,10 @@ bindir = $(exec_prefix)/bin # Where to put the manual pages. man1dir = $(prefix)/man/man1 -# Extension (not including `.') for the manual page filenames. +# Extension (including `.') for the manual page filenames. man1ext = .1 -# Hooks for nonstandard builds. -CONFIG_HDRS = config.h +# Hook for nonstandard builds. CONFIG_STATUS = config.status #### End of system configuration section. #### @@ -68,8 +68,10 @@ MISC = COPYING ChangeLog INSTALL Makefile.in NEWS README \ install-sh mkinstalldirs patch.man DISTFILES = $(MISC) $(SRCS) $(HDRS) DISTFILES_PC = pc/chdirsaf.c -DISTFILES_PC_DJGPP = pc/djgpp/README pc/djgpp/config.h \ - pc/djgpp/config.sed pc/djgpp/configure.bat +DISTFILES_PC_DJGPP = pc/djgpp/README pc/djgpp/config.sed \ + pc/djgpp/configure.bat pc/djgpp/configure.sed + +patch_name = `echo patch | sed '$(transform)'` all:: patch @@ -87,15 +89,17 @@ patch: $(OBJS) $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) install:: all installdirs - $(INSTALL_PROGRAM) patch $(bindir)/`echo patch | sed '$(transform)'` - -$(INSTALL_DATA) $(srcdir)/patch.man \ - $(man1dir)/`echo patch | sed '$(transform)'`$(man1ext) + $(INSTALL_PROGRAM) patch $(bindir)/$(patch_name) + -$(INSTALL_DATA) $(srcdir)/patch.man $(man1dir)/$(patch_name)$(man1ext) installdirs:: $(SHELL) $(srcdir)/mkinstalldirs $(bindir) $(man1dir) +install-strip:: + $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install + uninstall:: - rm -f $(bindir)/patch $(man1dir)/patch$(man1ext) + rm -f $(bindir)/$(patch_name) $(man1dir)/$(patch_name)$(man1ext) Makefile: Makefile.in $(CONFIG_STATUS) $(SHELL) $(CONFIG_STATUS) @@ -113,7 +117,7 @@ TAGS: $(HDRS) patchlevel.h $(SRCS) etags $(HDRS) patchlevel.h $(SRCS) clean:: - rm -f patch *.o */*.o core + rm -f patch core* *core *.o mostlyclean:: clean @@ -138,17 +142,17 @@ dist:: $(DISTFILES) $(DISTFILES_PC) $(DISTFILES_PC_DJGPP) tar -chf - $(PV) | gzip -9 >$(PV).tar.gz rm -rf $(PV) -$(OBJS): $(CONFIG_HDRS) +$(OBJS): config.h addext.o: backupfile.h argmatch.o: argmatch.h backupfile.o: argmatch.h backupfile.h basename.o: backupfile.h getopt.o getopt1.o: getopt.h maketime.o: maketime.h partime.h -inp.o: backupfile.h common.h inp.h pch.h quotearg.h util.h +inp.o: backupfile.h common.h inp.h pch.h util.h partime.o: partime.h patch.o: argmatch.h backupfile.h common.h getopt.h inp.h pch.h util.h version.h pch.o: common.h inp.h pch.h util.h quotearg.o: quotearg.h -util.o: backupfile.h common.h maketime.h quotearg.h util.h version.h +util.o: backupfile.h common.h maketime.h partime.h quotearg.h util.h version.h version.o: common.h patchlevel.h util.h version.h @@ -3,6 +3,46 @@ Known problems: * The diffutils 2.7 documentation for `patch' is obsolete; this should be fixed in diffutils 2.8. Until then, see `patch --help' or `man patch'. +Change in version 2.4: + +* New options: + -Z or --set-utc sets times of patched files, assuming diff uses UTC (GMT). + -T or --set-time is similar, assuming local time (not recommended). + --backup-if-mismatch makes a backup if the patch does not match exactly + --no-backup-if-mismatch makes a backup only if otherwise requested + +* The default is now --backup-if-mismatch unless POSIXLY_CORRECT is set. + +* The -B or --prefix, -Y or --basename-prefix, and -z or --suffix options + no longer affect whether backups are made (as they did in patch 2.2 and 2.3); + they now merely specify the file names used when simple backups are made. + +* When patching a nonexistent file and making backups, an empty backup file + is now made (just as with traditional patch); but the backup file is + unreadable, as a way of indicating that it represents a nonexistent file. + +* `patch' now matches against empty and nonexistent files more generously. + A patch against an empty file applies to a nonexistent file, and vice versa. + +* -g or --get and PATCH_GET now have a numeric value that specifies + whether `patch' is getting files. + If the value is positive, working files are gotten from RCS or SCCS files; + if zero, `patch' ignores RCS and SCCS and working files are not gotten; + and if negative, `patch' asks the user whether to get each file. + The default is normally negative, but it is zero if POSIXLY_CORRECT is set. + +* The -G or --no-get option introduced in GNU patch 2.3 has been removed; + use -g0 instead. + +* The method used to intuit names of files to be patched is changed again: + `Index:' lines are normally ignored for context diffs, + and RCS and SCCS files are normally looked for when files do not exist. + The complete new method is described in the man page. + +* By default, `patch' is now more verbose when patches do not match exactly. + +* The manual page has a new COMPATIBILITY ISSUES section. + Changes in version 2.3: * Unless the POSIXLY_CORRECT environment variable is set: @@ -11,35 +51,19 @@ Changes in version 2.3: nonexistent files if the input is a context diff. A file is assumed to not exist if its context diff header suggests that it is empty, and if the header timestamp - is within 24 hours of 1970-01-01 00:00:00 UTC. + looks like it might be equivalent to 1970-01-01 00:00:00 UTC. - Files that ``become nonexistent'' after patching are now removed. When a file is removed, any empty ancestor directories are also removed. * Files are now automatically gotten from RCS and SCCS - if the -g or --get option is specified, - or if the PATCH_GET environment variable is set - and the -G or --no-get option is not specified. + if the -g or --get option is specified. + (The -G or --no-get option, also introduced in 2.3, was withdrawn in 2.4.) * If the PATCH_VERSION_CONTROL environment variable is set, it overrides the VERSION_CONTROL environment variable. -* The method used to intuit names of files to be patched is now as follows: - - - Take the old and new names from the context header if present, - and take the index name from the `Index:' line if present. - Consider the file names to be in the order (old, new, index). - - If some named files exist, use the first one if POSIXLY_CORRECT is set, - the best one otherwise. - - If no named files exist, some names are given, POSIXLY_CORRECT is not set, - and the patch appears to create a file, then use the best name - requiring the creation of the fewest directories. - - Otherwise, ask the user for a file name. - - The ``best'' of a nonempty list of file names is defined as follows: - - Take the names with the fewest path name components; - of those, take the names with the shortest basename; - of those, take the shortest names; - of those, take the first name. +* The method used to intuit names of files to be patched is changed. + (It was further revised in 2.4; see above.) * The new --binary option makes `patch' read and write files in binary mode. This option has no effect on POSIX-compliant hosts; @@ -73,8 +97,8 @@ Changes in version 2.2: * Patch now complies better with POSIX.2 if your host complies with POSIX.1. Therefore: - - By default, no backups are made. Set the VERSION_CONTROL environment - variable to "existing" if you prefer patch's traditional behavior. + - By default, no backups are made. + (But this was changed again in patch 2.4; see above.) - The simple backup file name for F defaults to F.orig regardless of whether the file system supports long file names, and F~ is used only if F.orig is too long for that particular file. @@ -89,6 +113,7 @@ Changes in version 2.2: consulted if none of the above files exist. However, if the patch appears to create a file, the file does not have to exist: instead, the first name with the longest existing directory prefix is taken. + (These rules were changed again in patch 2.3 and 2.4; see above.) - Exit status 0 means success, 1 means hunks were rejected, 2 means trouble. - `-l' ignores changes only in spaces and tabs, not in other white space. - If no `-p' option is given, `-pINFINITY' is assumed, instead of trying @@ -107,6 +132,7 @@ Changes in version 2.2: * RCS is used only if the version control method is `existing' and there is already an RCS file. Similarly for SCCS. + (But this was changed again in patch 2.3 and 2.4; see above.) * Copyright notices have been clarified. Every file in this version of `patch' can be distributed under the GNU General Public License. See README for @@ -9,3 +9,6 @@ /* Define if memchr works. */ #undef HAVE_MEMCHR + +/* Define if `struct utimbuf' is declared -- usually in <utime.h>. */ +#undef HAVE_STRUCT_UTIMBUF diff --git a/backupfile.c b/backupfile.c index 4b0f2ec..3b91be0 100644 --- a/backupfile.c +++ b/backupfile.c @@ -109,8 +109,7 @@ static int version_number __BACKUPFILE_P ((const char *, const char *, size_t)); /* Return the name of the new backup file for file FILE, allocated with malloc. Return 0 if out of memory. - FILE must not end with a '/' unless it is the root directory. - Do not call this function if backup_type == none. */ + FILE must not end with a '/' unless it is the root directory. */ char * find_backup_file_name (file) @@ -133,7 +132,7 @@ find_backup_file_name (file) strcpy (s, file); #if HAVE_DIR - if (backup_type != simple) + if (backup_type != simple && backup_type != none) { int highest_backup; size_t dir_len = base_name (s) - s; @@ -1,6 +1,6 @@ /* common definitions for `patch' */ -/* $Id: common.h,v 1.16 1997/05/26 05:34:43 eggert Exp $ */ +/* $Id: common.h,v 1.18 1997/06/13 06:28:37 eggert Exp $ */ /* Copyright 1986, 1988 Larry Wall @@ -44,6 +44,7 @@ If not, write to the Free Software Foundation, #include <assert.h> #include <stdio.h> #include <sys/types.h> +#include <time.h> #include <sys/stat.h> #if ! defined S_ISDIR && defined S_IFDIR @@ -148,7 +149,9 @@ XTERN size_t bufsize; /* allocated size of buf */ XTERN bool using_plan_a; /* try to keep everything in memory */ XTERN char *inname; +XTERN char *outfile; XTERN int inerrno; +XTERN int invc; XTERN struct stat instat; XTERN bool dry_run; XTERN bool posixly_correct; @@ -174,6 +177,8 @@ XTERN bool skip_rest_of_patch; XTERN int strippath; XTERN bool canonicalize; XTERN int patch_get; +XTERN int set_time; +XTERN int set_utc; enum diff { @@ -190,9 +195,9 @@ XTERN enum diff diff_type; XTERN char *revision; /* prerequisite revision, if any */ #ifdef __STDC__ -# define VOID void +# define GENERIC_OBJECT void #else -# define VOID char +# define GENERIC_OBJECT char #endif #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 6) || __STRICT_ANSI__ @@ -207,7 +212,7 @@ XTERN char *revision; /* prerequisite revision, if any */ # endif #endif -VOID *xmalloc PARAMS ((size_t)); +GENERIC_OBJECT *xmalloc PARAMS ((size_t)); void fatal_exit PARAMS ((int)) __attribute__ ((noreturn)); #include <errno.h> @@ -221,7 +226,7 @@ extern int errno; # if !HAVE_MEMCHR # define memcmp(s1, s2, n) bcmp (s1, s2, n) # define memcpy(d, s, n) bcopy (s, d, n) -VOID *memchr (); +GENERIC_OBJECT *memchr (); # endif #endif @@ -230,8 +235,8 @@ VOID *memchr (); #else long atol (); char *getenv (); -VOID *malloc (); -VOID *realloc (); +GENERIC_OBJECT *malloc (); +GENERIC_OBJECT *realloc (); #endif #if HAVE_UNISTD_H @@ -292,3 +297,11 @@ off_t lseek (); #else # define binary_transput 0 #endif + +#ifndef NULL_DEVICE +#define NULL_DEVICE "/dev/null" +#endif + +#ifndef TTY_DEVICE +#define TTY_DEVICE "/dev/tty" +#endif @@ -54,6 +54,9 @@ /* Define if memchr works. */ #undef HAVE_MEMCHR +/* Define if `struct utimbuf' is declared -- usually in <utime.h>. */ +#undef HAVE_STRUCT_UTIMBUF + /* Define if you have the _doprintf function. */ #undef HAVE__DOPRINTF @@ -75,6 +78,9 @@ /* Define if you have the pathconf function. */ #undef HAVE_PATHCONF +/* Define if you have the raise function. */ +#undef HAVE_RAISE + /* Define if you have the rename function. */ #undef HAVE_RENAME @@ -111,5 +117,8 @@ /* Define if you have the <unistd.h> header file. */ #undef HAVE_UNISTD_H +/* Define if you have the <utime.h> header file. */ +#undef HAVE_UTIME_H + /* Define if you have the <varargs.h> header file. */ #undef HAVE_VARARGS_H @@ -540,7 +540,7 @@ test "$program_transform_name" = "" && program_transform_name="s,x,x," PACKAGE=patch -VERSION=2.3 +VERSION=2.4 @@ -1349,7 +1349,7 @@ EOF fi -for ac_hdr in fcntl.h limits.h string.h unistd.h varargs.h +for ac_hdr in fcntl.h limits.h string.h unistd.h utime.h varargs.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 @@ -1531,9 +1531,45 @@ EOF fi +echo $ac_n "checking for struct utimbuf""... $ac_c" 1>&6 +echo "configure:1536: checking for struct utimbuf" >&5 +if eval "test \"`echo '$''{'patch_cv_sys_struct_utimbuf'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1541 "configure" +#include "confdefs.h" +#include <sys/types.h> +#if HAVE_UTIME_H +#include <utime.h> +#endif +int main() { +static struct utimbuf x; x.actime = x.modtime; +; return 0; } +EOF +if { (eval echo configure:1551: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + patch_cv_sys_struct_utimbuf=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + patch_cv_sys_struct_utimbuf=no +fi +rm -f conftest* +fi + +echo "$ac_t""$patch_cv_sys_struct_utimbuf" 1>&6 +if test $patch_cv_sys_struct_utimbuf = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_STRUCT_UTIMBUF 1 +EOF + +fi + # Check for NetBSD 1.0 bug, where memchr(..., 0) returns nonzero. echo $ac_n "checking for working memchr""... $ac_c" 1>&6 -echo "configure:1537: checking for working memchr" >&5 +echo "configure:1573: checking for working memchr" >&5 if eval "test \"`echo '$''{'ac_cv_func_memchr'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1542,12 +1578,12 @@ else ac_cv_func_memchr=no else cat > conftest.$ac_ext <<EOF -#line 1546 "configure" +#line 1582 "configure" #include "confdefs.h" #include <string.h> main () { exit (memchr ("", 0, 0) != 0 || memchr ("", 1, 0) != 0); } EOF -if { (eval echo configure:1551: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:1587: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then ac_cv_func_memchr=yes else @@ -1569,12 +1605,12 @@ EOF fi echo $ac_n "checking for getopt_long""... $ac_c" 1>&6 -echo "configure:1573: checking for getopt_long" >&5 +echo "configure:1609: checking for getopt_long" >&5 if eval "test \"`echo '$''{'ac_cv_func_getopt_long'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1578 "configure" +#line 1614 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char getopt_long(); below. */ @@ -1597,7 +1633,7 @@ getopt_long(); ; return 0; } EOF -if { (eval echo configure:1601: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:1637: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_getopt_long=yes" else @@ -1618,15 +1654,15 @@ LIBOBJS="$LIBOBJS getopt1.o getopt.o" fi -for ac_func in _doprintf isascii memcmp mkdir mktemp pathconf sigaction sigprocmask sigsetmask +for ac_func in _doprintf isascii memcmp mkdir mktemp pathconf raise sigaction sigprocmask sigsetmask do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:1625: checking for $ac_func" >&5 +echo "configure:1661: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1630 "configure" +#line 1666 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -1649,7 +1685,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:1653: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:1689: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -1676,12 +1712,12 @@ done for ac_func in memchr rename do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:1680: checking for $ac_func" >&5 +echo "configure:1716: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1685 "configure" +#line 1721 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -1704,7 +1740,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:1708: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:1744: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -1731,7 +1767,7 @@ done echo $ac_n "checking whether closedir returns void""... $ac_c" 1>&6 -echo "configure:1735: checking whether closedir returns void" >&5 +echo "configure:1771: checking whether closedir returns void" >&5 if eval "test \"`echo '$''{'ac_cv_func_closedir_void'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1739,13 +1775,13 @@ else ac_cv_func_closedir_void=yes else cat > conftest.$ac_ext <<EOF -#line 1743 "configure" +#line 1779 "configure" #include "confdefs.h" #include <sys/types.h> #include <$ac_header_dirent> int closedir(); main() { exit(closedir(opendir(".")) != 0); } EOF -if { (eval echo configure:1749: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:1785: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then ac_cv_func_closedir_void=no else @@ -1768,12 +1804,12 @@ EOF fi echo $ac_n "checking for vprintf""... $ac_c" 1>&6 -echo "configure:1772: checking for vprintf" >&5 +echo "configure:1808: checking for vprintf" >&5 if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1777 "configure" +#line 1813 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char vprintf(); below. */ @@ -1796,7 +1832,7 @@ vprintf(); ; return 0; } EOF -if { (eval echo configure:1800: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:1836: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_vprintf=yes" else @@ -1820,12 +1856,12 @@ fi if test "$ac_cv_func_vprintf" != yes; then echo $ac_n "checking for _doprnt""... $ac_c" 1>&6 -echo "configure:1824: checking for _doprnt" >&5 +echo "configure:1860: checking for _doprnt" >&5 if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1829 "configure" +#line 1865 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char _doprnt(); below. */ @@ -1848,7 +1884,7 @@ _doprnt(); ; return 0; } EOF -if { (eval echo configure:1852: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:1888: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func__doprnt=yes" else @@ -1874,7 +1910,7 @@ fi echo $ac_n "checking for long file names""... $ac_c" 1>&6 -echo "configure:1878: checking for long file names" >&5 +echo "configure:1914: checking for long file names" >&5 if eval "test \"`echo '$''{'ac_cv_sys_long_file_names'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1919,12 +1955,12 @@ fi echo $ac_n "checking for d_ino member in directory struct""... $ac_c" 1>&6 -echo "configure:1923: checking for d_ino member in directory struct" >&5 +echo "configure:1959: checking for d_ino member in directory struct" >&5 if eval "test \"`echo '$''{'patch_cv_sys_d_ino_in_dirent'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1928 "configure" +#line 1964 "configure" #include "confdefs.h" #include <sys/types.h> @@ -1947,7 +1983,7 @@ int main() { struct dirent dp; dp.d_ino = 0; ; return 0; } EOF -if { (eval echo configure:1951: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:1987: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* patch_cv_sys_d_ino_in_dirent=yes else diff --git a/configure.in b/configure.in index 902f83f..7d5b0e8 100644 --- a/configure.in +++ b/configure.in @@ -8,7 +8,7 @@ AC_CONFIG_HEADER(config.h:config.hin) AC_ARG_PROGRAM PACKAGE=patch -VERSION=2.3 +VERSION=2.4 AC_SUBST(PACKAGE) AC_SUBST(VERSION) @@ -60,13 +60,27 @@ AC_C_CONST AC_HEADER_DIRENT AC_HEADER_STDC -AC_CHECK_HEADERS(fcntl.h limits.h string.h unistd.h varargs.h) +AC_CHECK_HEADERS(fcntl.h limits.h string.h unistd.h utime.h varargs.h) AC_TYPE_MODE_T AC_TYPE_OFF_T AC_TYPE_SIGNAL AC_TYPE_SIZE_T +dnl Some systems have utime.h but don't declare the struct anywhere. +AC_MSG_CHECKING(for struct utimbuf) +AC_CACHE_VAL(patch_cv_sys_struct_utimbuf, +[AC_TRY_COMPILE([#include <sys/types.h> +#if HAVE_UTIME_H +#include <utime.h> +#endif], [static struct utimbuf x; x.actime = x.modtime;], + patch_cv_sys_struct_utimbuf=yes, + patch_cv_sys_struct_utimbuf=no)]) +AC_MSG_RESULT($patch_cv_sys_struct_utimbuf) +if test $patch_cv_sys_struct_utimbuf = yes; then + AC_DEFINE(HAVE_STRUCT_UTIMBUF) +fi + # Check for NetBSD 1.0 bug, where memchr(..., 0) returns nonzero. AC_MSG_CHECKING(for working memchr) AC_CACHE_VAL(ac_cv_func_memchr, @@ -83,7 +97,7 @@ fi AC_CHECK_FUNC(getopt_long, , [LIBOBJS="$LIBOBJS getopt1.o getopt.o"]) AC_SUBST(LIBOBJS) -AC_CHECK_FUNCS(_doprintf isascii memcmp mkdir mktemp pathconf sigaction sigprocmask sigsetmask) +AC_CHECK_FUNCS(_doprintf isascii memcmp mkdir mktemp pathconf raise sigaction sigprocmask sigsetmask) AC_REPLACE_FUNCS(memchr rename) AC_FUNC_CLOSEDIR_VOID AC_FUNC_VPRINTF @@ -1,6 +1,6 @@ /* inputting files to be patched */ -/* $Id: inp.c,v 1.14 1997/05/26 05:34:43 eggert Exp $ */ +/* $Id: inp.c,v 1.16 1997/06/13 06:28:37 eggert Exp $ */ /* Copyright 1986, 1988 Larry Wall @@ -26,25 +26,11 @@ If not, write to the Free Software Foundation, #include <common.h> #include <backupfile.h> #include <pch.h> -#include <quotearg.h> #include <util.h> #undef XTERN #define XTERN #include <inp.h> -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 SCCSDIFF3[] = ">/dev/null"; - -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"; -#define RCSDIFF2 SCCSDIFF3 - /* Input-file-with-indexable-lines abstract type */ static char const **i_ptr; /* pointers to lines in plan A buffer */ @@ -148,92 +134,28 @@ get_input_file (filename, outname) char const *outname; { int elsewhere = strcmp (filename, outname); + char const *cs; + char *diffbuf; + char *getbuf; if (inerrno == -1) inerrno = stat (inname, &instat) == 0 ? 0 : errno; /* Perhaps look for RCS or SCCS versions. */ if (patch_get + && invc != 0 && (inerrno || (! elsewhere && (/* No one can write to it. */ (instat.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) == 0 /* Only the owner (who's not me) can write to it. */ || ((instat.st_mode & (S_IWGRP|S_IWOTH)) == 0 - && instat.st_uid != geteuid ()))))) { - struct stat cstat; - char const *cs = 0; - 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 SCCSDIFF3 - 2 - + 2 * quotelen + maxfixlen); - char *trybuf = xmalloc (maxtrysize + maxgetsize + maxdiffsize); - char *getbuf = trybuf + maxtrysize; - char *diffbuf = getbuf + maxgetsize; - - 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) - if (( try2 ("RCS/%s%s", filebase, RCSSUFFIX) - || try1 ("RCS/%s" , filebase) - || try2 ( "%s%s", filebase, RCSSUFFIX)) - && - /* Check that RCS file is not working file. - Some hosts don't report file name length errors. */ - (inerrno - || instat.st_dev != cstat.st_dev - || instat.st_ino != cstat.st_ino)) { - - char *p = getbuf; - sprintf (p, elsewhere ? CHECKOUT : CHECKOUT_LOCKED, dotslash); - p += strlen (p); - p += quote_system_arg (p, filename); - *p = '\0'; - - p = diffbuf; - sprintf (p, RCSDIFF1, dotslash); - p += strlen (p); - p += quote_system_arg (p, filename); - strcpy (p, RCSDIFF2); - - cs = "RCS"; - - } else if ( try2 ("SCCS/%s%s", SCCSPREFIX, filebase) - || try2 ( "%s%s", SCCSPREFIX, filebase)) { - - char *p = getbuf; - sprintf (p, elsewhere ? GET : GET_LOCKED); - p += strlen (p); - p += quote_system_arg (p, trybuf); - *p = '\0'; - - p = diffbuf; - 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); - strcpy (p, SCCSDIFF3); - - cs = "SCCS"; - - } else if (inerrno && !pch_says_nonexistent (reverse)) - { - errno = inerrno; - pfatal ("can't find file `%s'", filename); - } - /* else we can't write to it but it's not under a version - control system, so just proceed. */ - if (cs) { + && instat.st_uid != geteuid ())))) + && (invc = !! (cs = (version_controller + (filename, elsewhere, + inerrno ? (struct stat *) 0 : &instat, + &getbuf, &diffbuf))))) { + if (!inerrno) { if (!elsewhere && (instat.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) != 0) @@ -252,27 +174,19 @@ get_input_file (filename, outname) cs = 0; } } - if (cs) - { - if (dry_run) - { - if (inerrno) - fatal ("can't do dry run on nonexistent version-controlled file `%s'; invoke `%s' and try again", - filename, buf); - } - else - { - if (verbosity == VERBOSE) - say ("Getting file `%s' from %s...\n", filename, cs); - if (systemic (getbuf) != 0 - || stat (filename, &instat) != 0) - fatal ("can't get file `%s' from %s", filename, cs); - inerrno = 0; - } - } - } - free (trybuf); - } + + if (cs && version_get (filename, cs, ! inerrno, elsewhere, getbuf, + &instat)) + inerrno = 0; + + free (getbuf); + free (diffbuf); + + } else if (inerrno && !pch_says_nonexistent (reverse)) + { + errno = inerrno; + pfatal ("can't find file `%s'", filename); + } if (inerrno) { @@ -397,7 +311,7 @@ plan_b(filename) register LINENUM line; if (instat.st_size == 0) - filename = "/dev/null"; + filename = NULL_DEVICE; if (! (ifp = fopen (filename, binary_transput ? "rb" : "r"))) pfatal ("can't open file `%s'", filename); tifd = create_file (TMPINNAME, O_RDWR | O_BINARY, (mode_t) 0); @@ -36,6 +36,8 @@ # define const # endif # endif + /* MIPS RISCOS4.52 defines time_t in <sys/types.h> not <time.h>. */ +# include <sys/types.h> # if HAVE_LIMITS_H # include <limits.h> # endif @@ -57,7 +59,7 @@ #include <maketime.h> char const maketId[] = - "$Id: maketime.c,v 5.13 1997/05/15 17:33:14 eggert Exp $"; + "$Id: maketime.c,v 5.15 1997/06/17 16:54:36 eggert Exp $"; static int isleap P ((int)); static int month_days P ((struct tm const *)); @@ -101,10 +103,10 @@ time2tm (unixtime, localzone) int localzone; { struct tm *tm; -#if TZ_must_be_set +#ifdef TZ_is_unset static char const *TZ; if (!TZ && !(TZ = getenv ("TZ"))) - faterror ("The TZ environment variable is not set; please set it to your timezone"); + TZ_is_unset ("The TZ environment variable is not set; please set it to your timezone"); #endif if (localzone || !(tm = gmtime (&unixtime))) tm = localtime (&unixtime); @@ -114,7 +116,8 @@ time2tm (unixtime, localzone) /* Yield A - B, measured in seconds. */ time_t difftm (a, b) - struct tm const *a, *b; + struct tm const *a; + struct tm const *b; { int ay = a->tm_year + (TM_YEAR_ORIGIN - 1); int by = b->tm_year + (TM_YEAR_ORIGIN - 1); @@ -1,6 +1,6 @@ /* patch - a program to apply diffs to original files */ -/* $Id: patch.c,v 1.17 1997/05/26 05:34:43 eggert Exp $ */ +/* $Id: patch.c,v 1.22 1997/06/17 22:32:49 eggert Exp $ */ /* Copyright 1984, 1985, 1986, 1987, 1988 Larry Wall @@ -34,25 +34,46 @@ If not, write to the Free Software Foundation, #include <util.h> #include <version.h> +#if HAVE_UTIME_H +# include <utime.h> +#endif +/* Some nonstandard hosts don't declare this structure even in <utime.h>. */ +#if ! HAVE_STRUCT_UTIMBUF +struct utimbuf +{ + time_t actime; + time_t modtime; +}; +#endif + +/* Output stream state. */ +struct outstate +{ + FILE *ofp; + int after_newline; + int zero_output; +}; + /* procedures */ static FILE *create_output_file PARAMS ((char const *)); static LINENUM locate_hunk PARAMS ((LINENUM)); -static bool apply_hunk PARAMS ((bool *, LINENUM)); -static bool copy_till PARAMS ((bool *, LINENUM)); +static bool apply_hunk PARAMS ((struct outstate *, LINENUM)); +static bool copy_till PARAMS ((struct outstate *, LINENUM)); static bool patch_match PARAMS ((LINENUM, LINENUM, LINENUM, LINENUM)); static bool similar PARAMS ((char const *, size_t, char const *, size_t)); -static bool spew_output PARAMS ((bool *)); +static bool spew_output PARAMS ((struct outstate *)); static char const *make_temp PARAMS ((int)); -static int numeric_optarg PARAMS ((char const *)); +static int numeric_string PARAMS ((char const *, int, char const *)); static void abort_hunk PARAMS ((void)); static void cleanup PARAMS ((void)); static void get_some_switches PARAMS ((void)); -static void init_output PARAMS ((char const *)); +static void init_output PARAMS ((char const *, struct outstate *)); static void init_reject PARAMS ((char const *)); static void reinitialize_almost_everything PARAMS ((void)); static void usage PARAMS ((FILE *, int)) __attribute__((noreturn)); +static int backup_if_mismatch; static int remove_empty_files; /* TRUE if -R was specified on command line. */ @@ -70,10 +91,8 @@ static char const end_defined[] = "\n#endif /* %s */\n"; static int Argc; static char * const *Argv; -static FILE *ofp; /* output file pointer */ static FILE *rejfp; /* reject file pointer */ -static char *output; static char const *patchname; static char *rejname; static char const * volatile TMPREJNAME; @@ -94,7 +113,9 @@ main(argc,argv) int argc; char **argv; { + char const *val; bool somefailed = FALSE; + struct outstate outstate; init_time (); @@ -105,8 +126,11 @@ char **argv; strippath = INT_MAX; - patch_get = getenv ("PATCH_GET") != 0; posixly_correct = getenv ("POSIXLY_CORRECT") != 0; + backup_if_mismatch = ! posixly_correct; + patch_get = ((val = getenv ("PATCH_GET")) + ? numeric_string (val, 1, "PATCH_GET value") + : posixly_correct - 1); { char const *v; @@ -134,8 +158,7 @@ char **argv; Argv = argv; get_some_switches(); - if (output) - init_output (output); + init_output (outfile, &outstate); /* Make sure we clean up in case of disaster. */ set_signals(0); @@ -147,22 +170,32 @@ char **argv; ) { /* for each patch in patch file */ int hunk = 0; int failed = 0; - char *outname = output ? output : inname; + int mismatch = 0; + char *outname = outfile ? outfile : inname; if (!skip_rest_of_patch) get_input_file (inname, outname); if (diff_type == ED_DIFF) { + outstate.zero_output = 0; if (! dry_run) - do_ed_script (ofp); + { + do_ed_script (outstate.ofp); + if (! outfile) + { + struct stat statbuf; + if (stat (TMPOUTNAME, &statbuf) != 0) + pfatal ("%s", TMPOUTNAME); + outstate.zero_output = statbuf.st_size == 0; + } + } } else { int got_hunk; int apply_anyway = 0; - bool after_newline = TRUE; /* initialize the patched file */ - if (!skip_rest_of_patch && !output) - init_output(TMPOUTNAME); + if (! skip_rest_of_patch && ! outfile) + init_output (TMPOUTNAME, &outstate); /* initialize reject file */ init_reject(TMPREJNAME); @@ -188,7 +221,10 @@ char **argv; if (!skip_rest_of_patch) { do { where = locate_hunk(fuzz); - if (hunk == 1 && !where && !(force|apply_anyway)) { + if (! where || fuzz || last_offset) + mismatch = 1; + if (hunk == 1 && ! where && ! (force | apply_anyway) + && reverse == reverse_flag_specified) { /* dwim for reversed patch? */ if (!pch_swap()) { say ( @@ -221,10 +257,10 @@ char **argv; && ++fuzz <= mymaxfuzz); if (skip_rest_of_patch) { /* just got decided */ - if (ofp && !output) + if (outstate.ofp && ! outfile) { - fclose (ofp); - ofp = 0; + fclose (outstate.ofp); + outstate.ofp = 0; } } } @@ -233,26 +269,27 @@ char **argv; if (skip_rest_of_patch) { abort_hunk(); failed++; - if (verbosity != SILENT) + if (verbosity == VERBOSE) say ("Hunk #%d ignored at %ld.\n", hunk, newwhere); } else if (!where || (where == 1 && pch_says_nonexistent (reverse) - && input_lines)) { + && instat.st_size)) { if (where) - say ("\nPatch attempted to create file `%s', which already exists.\n", inname); + say ("Patch attempted to create file `%s', which already exists.\n", inname); abort_hunk(); failed++; if (verbosity != SILENT) say ("Hunk #%d FAILED at %ld.\n", hunk, newwhere); } - else { - if (! apply_hunk (&after_newline, where)) { - abort_hunk (); - failed++; - if (verbosity != SILENT) - say ("Hunk #%d FAILED at %ld.\n", hunk, newwhere); - } else if (verbosity == VERBOSE) { + else if (! apply_hunk (&outstate, where)) { + abort_hunk (); + failed++; + if (verbosity != SILENT) + say ("Hunk #%d FAILED at %ld.\n", hunk, newwhere); + } else { + if (verbosity == VERBOSE + || (verbosity != SILENT && (fuzz || last_offset))) { say ("Hunk #%d succeeded at %ld", hunk, newwhere); if (fuzz) say (" with fuzz %ld", fuzz); @@ -265,13 +302,13 @@ char **argv; } if (got_hunk < 0 && using_plan_a) { - if (output) + if (outfile) fatal ("out of memory using Plan A"); say ("\n\nRan out of memory using Plan A -- trying again...\n\n"); - if (ofp) + if (outstate.ofp) { - fclose (ofp); - ofp = 0; + fclose (outstate.ofp); + outstate.ofp = 0; } fclose (rejfp); continue; @@ -281,19 +318,21 @@ char **argv; if (!skip_rest_of_patch) { assert (hunk); - skip_rest_of_patch = ! spew_output (&after_newline); + if (! spew_output (&outstate)) + { + say ("Skipping patch.\n"); + skip_rest_of_patch = TRUE; + } } } /* and put the output where desired */ ignore_signals (); - if (!skip_rest_of_patch && !output) { - struct stat statbuf; - - if ((remove_empty_files - || (pch_says_nonexistent (reverse ^ 1) && !posixly_correct)) - && stat (TMPOUTNAME, &statbuf) == 0 - && statbuf.st_size == 0) + if (! skip_rest_of_patch && ! outfile) { + if (outstate.zero_output + && (remove_empty_files + || (pch_says_nonexistent (reverse ^ 1) == 2 + && ! posixly_correct))) { if (verbosity == VERBOSE) say ("Removing file `%s'%s.\n", outname, @@ -301,16 +340,49 @@ char **argv; if (! dry_run) { move_file ((char *) 0, outname, (mode_t) 0, - backup_type != none); + (backup_type != none + || (backup_if_mismatch && (mismatch | failed)))); removedirs (outname); } } else { + if (! outstate.zero_output + && pch_says_nonexistent (reverse ^ 1)) + { + mismatch = 1; + if (verbosity != SILENT) + say ("File `%s' is not empty after patch, as expected.\n", + outname); + } + if (! dry_run) { + time_t t; + move_file (TMPOUTNAME, outname, instat.st_mode, - backup_type != none); + (backup_type != none + || (backup_if_mismatch && (mismatch | failed)))); + + if ((set_time | set_utc) + && (t = pch_timestamp (reverse ^ 1)) != (time_t) -1) + { + struct utimbuf utimbuf; + utimbuf.actime = utimbuf.modtime = t; + + if (! force && ! inerrno + && ! pch_says_nonexistent (reverse) + && (t = pch_timestamp (reverse)) != (time_t) -1 + && t != instat.st_mtime) + say ("not setting time of file `%s' (time mismatch)\n", + outname); + else if (! force && (mismatch | failed)) + say ("not setting time of file `%s' (contents mismatch)\n", + outname); + else if (utime (outname, &utimbuf) != 0) + pfatal ("can't set timestamp on file `%s'", outname); + } + if (! inerrno && chmod (outname, instat.st_mode) != 0) pfatal ("can't set permissions on file `%s'", outname); } @@ -348,7 +420,7 @@ char **argv; } set_signals (1); } - if (ofp && (ferror (ofp) || fclose (ofp) != 0)) + if (outstate.ofp && (ferror (outstate.ofp) || fclose (outstate.ofp) != 0)) write_fatal (); cleanup (); if (somefailed) @@ -385,7 +457,7 @@ reinitialize_almost_everything() skip_rest_of_patch = FALSE; } -static char const shortopts[] = "bB:cd:D:eEfF:gGi:lnNo:p:r:RstuvV:x:Y:z:"; +static char const shortopts[] = "bB:cd:D:eEfF:g:i:lnNo:p:r:RstTuvV:x:Y:z:Z"; static struct option const longopts[] = { {"backup", no_argument, NULL, 'b'}, @@ -398,7 +470,6 @@ static struct option const longopts[] = {"force", no_argument, NULL, 'f'}, {"fuzz", required_argument, NULL, 'F'}, {"get", no_argument, NULL, 'g'}, - {"no-get", no_argument, NULL, 'G'}, {"input", required_argument, NULL, 'i'}, {"ignore-whitespace", no_argument, NULL, 'l'}, {"normal", no_argument, NULL, 'n'}, @@ -410,16 +481,20 @@ static struct option const longopts[] = {"quiet", no_argument, NULL, 's'}, {"silent", no_argument, NULL, 's'}, {"batch", no_argument, NULL, 't'}, + {"set-time", no_argument, NULL, 'T'}, {"unified", no_argument, NULL, 'u'}, {"version", no_argument, NULL, 'v'}, {"version-control", required_argument, NULL, 'V'}, {"debug", required_argument, NULL, 'x'}, {"basename-prefix", required_argument, NULL, 'Y'}, {"suffix", required_argument, NULL, 'z'}, + {"set-utc", no_argument, NULL, 'Z'}, {"dry-run", no_argument, NULL, 129}, {"verbose", no_argument, NULL, 130}, {"binary", no_argument, NULL, 131}, {"help", no_argument, NULL, 132}, + {"backup-if-mismatch", no_argument, NULL, 133}, + {"no-backup-if-mismatch", no_argument, NULL, 134}, {NULL, no_argument, NULL, 0} }; @@ -449,18 +524,22 @@ static char const *const option_help[] = " -D NAME --ifdef=NAME Make merged if-then-else output using NAME.", " -E --remove-empty-files Remove output files that are empty after patching.", "", +" -Z --set-utc Set times of patched files, assuming diff uses UTC (GMT).", +" -T --set-time Likewise, assuming local time.", +"", "Backup and version control options:", "", " -V STYLE --version-control=STYLE Use STYLE version control.", " STYLE is either 'simple', 'numbered', or 'existing'.", "", -" -b --backup Save the original contents of each file F into F.orig.", +" -b --backup Back up the original contents of each file.", +" --backup-if-mismatch Back up if the patch does not match exactly.", +" --no-backup-if-mismatch Back up mismatches only if otherwise requested.", " -B PREFIX --prefix=PREFIX Prepend PREFIX to backup file names.", " -Y PREFIX --basename-prefix=PREFIX Prepend PREFIX to backup file basenames.", " -z SUFFIX --suffix=SUFFIX Append SUFFIX to backup file names.", "", -" -g --get Get files from RCS or SCCS.", -" -G --no-get Do not get files.", +" -g NUM --get=NUM Get files from RCS or SCCS if positive; ask if negative.", "", "Miscellaneous options:", "", @@ -544,7 +623,6 @@ get_some_switches() if (!*optarg) fatal ("backup prefix is empty"); origprae = savestr (optarg); - backup_type = simple; break; case 'c': diff_type = CONTEXT_DIFF; @@ -566,13 +644,10 @@ get_some_switches() force = TRUE; break; case 'F': - maxfuzz = numeric_optarg ("fuzz factor"); + maxfuzz = numeric_string (optarg, 0, "fuzz factor"); break; case 'g': - patch_get = 1; - break; - case 'G': - patch_get = 0; + patch_get = numeric_string (optarg, 1, "get option value"); break; case 'i': patchname = savestr (optarg); @@ -589,10 +664,10 @@ get_some_switches() case 'o': if (strcmp (optarg, "-") == 0) fatal ("can't output patches to standard output"); - output = savestr (optarg); + outfile = savestr (optarg); break; case 'p': - strippath = numeric_optarg ("strip count"); + strippath = numeric_string (optarg, 0, "strip count"); break; case 'r': rejname = savestr (optarg); @@ -607,6 +682,9 @@ get_some_switches() case 't': batch = TRUE; break; + case 'T': + set_time = 1; + break; case 'u': diff_type = UNI_DIFF; break; @@ -619,21 +697,22 @@ get_some_switches() break; #if DEBUGGING case 'x': - debug = numeric_optarg ("debugging option"); + debug = numeric_string (optarg, 1, "debugging option"); break; #endif case 'Y': if (!*optarg) fatal ("backup basename prefix is empty"); origbase = savestr (optarg); - backup_type = simple; break; case 'z': case_z: if (!*optarg) fatal ("backup suffix is empty"); simple_backup_suffix = savestr (optarg); - backup_type = simple; + break; + case 'Z': + set_utc = 1; break; case 129: dry_run = TRUE; @@ -648,6 +727,12 @@ get_some_switches() break; case 132: usage (stdout, 0); + case 133: + backup_if_mismatch = 1; + break; + case 134: + backup_if_mismatch = 0; + break; default: usage (stderr, 2); } @@ -657,6 +742,7 @@ get_some_switches() if (optind < Argc) { inname = savestr (Argv[optind++]); + invc = -1; if (optind < Argc) { patchname = savestr (Argv[optind++]); @@ -670,30 +756,41 @@ get_some_switches() } } -/* Handle a numeric option of type ARGTYPE_MSGID by converting - optarg to a nonnegative integer, returning the result. */ +/* Handle STRING (possibly negative if NEGATIVE_ALLOWED is nonzero) + of type ARGTYPE_MSGID by converting it to an integer, + returning the result. */ static int -numeric_optarg (argtype_msgid) +numeric_string (string, negative_allowed, argtype_msgid) + char const *string; + int negative_allowed; char const *argtype_msgid; { int value = 0; - char const *p = optarg; + char const *p = string; + int sign = *p == '-' ? -1 : 1; + + p += *p == '-' || *p == '+'; do { int v10 = value * 10; int digit = *p - '0'; + int signed_digit = sign * digit; + int next_value = v10 + signed_digit; if (9 < (unsigned) digit) - fatal ("%s `%s' is not a number", argtype_msgid, optarg); + fatal ("%s `%s' is not a number", argtype_msgid, string); - if (v10 / 10 != value || v10 + digit < v10) - fatal ("%s `%s' is too large", argtype_msgid, optarg); + if (v10 / 10 != value || (next_value < v10) != (signed_digit < 0)) + fatal ("%s `%s' is too large", argtype_msgid, string); - value = v10 + digit; + value = next_value; } while (*++p); + if (value < 0 && ! negative_allowed) + fatal ("%s `%s' is negative", argtype_msgid, string); + return value; } @@ -825,9 +922,9 @@ abort_hunk() /* We found where to apply it (we hope), so do it. */ static bool -apply_hunk (after_newline, where) -bool *after_newline; -LINENUM where; +apply_hunk (outstate, where) + struct outstate *outstate; + LINENUM where; { register LINENUM old = 1; register LINENUM lastline = pch_ptrn_lines (); @@ -835,7 +932,7 @@ LINENUM where; register enum {OUTSIDE, IN_IFNDEF, IN_IFDEF, IN_ELSE} def_state = OUTSIDE; register char const *R_do_defines = do_defines; register LINENUM pat_end = pch_end (); - register FILE *fp = ofp; + register FILE *fp = outstate->ofp; where--; while (pch_char(new) == '=' || pch_char(new) == '\n') @@ -843,21 +940,23 @@ LINENUM where; while (old <= lastline) { if (pch_char(old) == '-') { - assert (*after_newline); - if (! copy_till (after_newline, where + old - 1)) + assert (outstate->after_newline); + if (! copy_till (outstate, where + old - 1)) return FALSE; if (R_do_defines) { if (def_state == OUTSIDE) { - fprintf (fp, *after_newline + if_defined, R_do_defines); + fprintf (fp, outstate->after_newline + if_defined, + R_do_defines); def_state = IN_IFNDEF; } else if (def_state == IN_IFDEF) { - fprintf (fp, *after_newline + else_defined); + fprintf (fp, outstate->after_newline + else_defined); def_state = IN_ELSE; } if (ferror (fp)) write_fatal (); - *after_newline = pch_write_line (old, fp); + outstate->after_newline = pch_write_line (old, fp); + outstate->zero_output = 0; } last_frozen_line++; old++; @@ -866,21 +965,23 @@ LINENUM where; break; } else if (pch_char(new) == '+') { - if (! copy_till (after_newline, where + old - 1)) + if (! copy_till (outstate, where + old - 1)) return FALSE; if (R_do_defines) { if (def_state == IN_IFNDEF) { - fprintf (fp, *after_newline + else_defined); + fprintf (fp, outstate->after_newline + else_defined); def_state = IN_ELSE; } else if (def_state == OUTSIDE) { - fprintf (fp, *after_newline + if_defined, R_do_defines); + fprintf (fp, outstate->after_newline + if_defined, + R_do_defines); def_state = IN_IFDEF; } if (ferror (fp)) write_fatal (); } - *after_newline = pch_write_line (new, fp); + outstate->after_newline = pch_write_line (new, fp); + outstate->zero_output = 0; new++; } else if (pch_char(new) != pch_char(old)) { @@ -892,10 +993,10 @@ LINENUM where; pch_hunk_beg() + new); } else if (pch_char(new) == '!') { - assert (*after_newline); - if (! copy_till (after_newline, where + old - 1)) + assert (outstate->after_newline); + if (! copy_till (outstate, where + old - 1)) return FALSE; - assert (*after_newline); + assert (outstate->after_newline); if (R_do_defines) { fprintf (fp, not_defined, R_do_defines); if (ferror (fp)) @@ -906,7 +1007,7 @@ LINENUM where; do { if (R_do_defines) { - *after_newline = pch_write_line (old, fp); + outstate->after_newline = pch_write_line (old, fp); } last_frozen_line++; old++; @@ -914,7 +1015,7 @@ LINENUM where; while (pch_char (old) == '!'); if (R_do_defines) { - fprintf (fp, *after_newline + else_defined); + fprintf (fp, outstate->after_newline + else_defined); if (ferror (fp)) write_fatal (); def_state = IN_ELSE; @@ -922,54 +1023,59 @@ LINENUM where; do { - *after_newline = pch_write_line (new, fp); + outstate->after_newline = pch_write_line (new, fp); new++; } while (pch_char (new) == '!'); + outstate->zero_output = 0; } else { assert(pch_char(new) == ' '); old++; new++; if (R_do_defines && def_state != OUTSIDE) { - fprintf (fp, *after_newline + end_defined, R_do_defines); + fprintf (fp, outstate->after_newline + end_defined, + R_do_defines); if (ferror (fp)) write_fatal (); - *after_newline = TRUE; + outstate->after_newline = 1; def_state = OUTSIDE; } } } if (new <= pat_end && pch_char(new) == '+') { - if (! copy_till (after_newline, where + old - 1)) + if (! copy_till (outstate, where + old - 1)) return FALSE; if (R_do_defines) { if (def_state == OUTSIDE) { - fprintf (fp, *after_newline + if_defined, R_do_defines); + fprintf (fp, outstate->after_newline + if_defined, + R_do_defines); def_state = IN_IFDEF; } else if (def_state == IN_IFNDEF) { - fprintf (fp, *after_newline + else_defined); + fprintf (fp, outstate->after_newline + else_defined); def_state = IN_ELSE; } if (ferror (fp)) write_fatal (); + outstate->zero_output = 0; } do { - if (!*after_newline && putc ('\n', fp) == EOF) + if (! outstate->after_newline && putc ('\n', fp) == EOF) write_fatal (); - *after_newline = pch_write_line (new, fp); + outstate->after_newline = pch_write_line (new, fp); + outstate->zero_output = 0; new++; } while (new <= pat_end && pch_char (new) == '+'); } if (R_do_defines && def_state != OUTSIDE) { - fprintf (fp, *after_newline + end_defined, R_do_defines); + fprintf (fp, outstate->after_newline + end_defined, R_do_defines); if (ferror (fp)) write_fatal (); - *after_newline = TRUE; + outstate->after_newline = 1; } return TRUE; } @@ -990,10 +1096,13 @@ create_output_file (name) /* Open the new file. */ static void -init_output(name) +init_output (name, outstate) char const *name; + struct outstate *outstate; { - ofp = create_output_file (name); + outstate->ofp = name ? create_output_file (name) : (FILE *) 0; + outstate->after_newline = 1; + outstate->zero_output = 1; } /* Open a file to put hunks we can't locate. */ @@ -1008,12 +1117,12 @@ init_reject(name) /* Copy input file to output, up to wherever hunk is to be applied. */ static bool -copy_till (after_newline, lastline) - register bool *after_newline; +copy_till (outstate, lastline) + register struct outstate *outstate; register LINENUM lastline; { register LINENUM R_last_frozen_line = last_frozen_line; - register FILE *fp = ofp; + register FILE *fp = outstate->ofp; register char const *s; size_t size; @@ -1027,10 +1136,11 @@ copy_till (after_newline, lastline) s = ifetch (++R_last_frozen_line, 0, &size); if (size) { - if ((!*after_newline && putc ('\n', fp) == EOF) + if ((! outstate->after_newline && putc ('\n', fp) == EOF) || ! fwrite (s, sizeof *s, size, fp)) write_fatal (); - *after_newline = s[size - 1] == '\n'; + outstate->after_newline = s[size - 1] == '\n'; + outstate->zero_output = 0; } } last_frozen_line = R_last_frozen_line; @@ -1040,21 +1150,21 @@ copy_till (after_newline, lastline) /* Finish copying the input file to the output file. */ static bool -spew_output (after_newline) - bool *after_newline; +spew_output (outstate) + struct outstate *outstate; { if (debug & 256) say ("il=%ld lfl=%ld\n", input_lines, last_frozen_line); if (last_frozen_line < input_lines) - if (! copy_till (after_newline, input_lines)) + if (! copy_till (outstate, input_lines)) return FALSE; - if (ofp && !output) + if (outstate->ofp && ! outfile) { - if (fclose (ofp) != 0) + if (fclose (outstate->ofp) != 0) write_fatal (); - ofp = 0; + outstate->ofp = 0; } return TRUE; @@ -2,7 +2,7 @@ .de Id .ds Dt \\$4 .. -.Id $Id: patch.man,v 1.16 1997/05/30 08:03:48 eggert Exp $ +.Id $Id: patch.man,v 1.20 1997/06/17 22:32:49 eggert Exp $ .ds = \-\^\- .de Sp .if t .sp .3 @@ -20,7 +20,7 @@ patch \- apply a diff file to an original .Sp but usually just .Sp -.BI "patch \-p" "number" +.BI "patch \-p" "num" .BI < patchfile .SH DESCRIPTION .B patch @@ -115,9 +115,6 @@ As each hunk is completed, you are told if the hunk failed, and if so which line (in the new file) .B patch thought the hunk should go on. -If the -.B \*=verbose -option is given, you are also told about hunks that succeeded. If the hunk is installed at a different line from the line number specified in the diff you are told the offset. @@ -127,38 +124,76 @@ indicate that a hunk was installed in the wrong place. You are also told if a fuzz factor was used to make the match, in which case you should also be slightly suspicious. +If the +.B \*=verbose +option is given, you are also told about hunks that match exactly. .PP If no original file .I origfile is specified on the command line, .B patch tries to figure out from the leading garbage what the name of the file -to edit is. +to edit is, using the following rules. +.TP 3 +.B " \(bu" If the header is that of a context diff, .B patch -takes the old and new file names in the header, -and if there is an -.B Index:\& -line in the leading garbage, -.B patch -obtains the name in that line; any +takes the old and new file names in the header. +Any .B /dev/null names are ignored. -These names are considered to be in the order (old, new, index), +.TP +.B " \(bu" +If there is an +.B Index:\& +line in the leading garbage +and if either the old and new names are both absent or the +.B POSIXLY_CORRECT +environment variable is set, +.B patch +takes the name in the +.B Index:\& +line. +.TP +.B " \(bu" +For the purpose of the following rules, +the names are considered to be in the order (old, new, index), regardless of the order that they appear in the header. +.TP +.B " \(bu" If some of the named files exist, .B patch uses the first name if the .B POSIXLY_CORRECT environment variable is set, and the best name otherwise. -If no named files exist, some names are given, +.TP +.B " \(bu" +If +.B patch +is not ignoring \s-1RCS\s0 and \s-1SCCS\s0 (see the +.BI "\-g " num +or +.BI \*=get= num +option), and no named files exist +but an \s-1RCS\s0 or \s-1SCCS\s0 master is found, +.B patch +uses the first named file with an \s-1RCS\s0 or \s-1SCCS\s0 master. +.TP +.B " \(bu" +If no named files exist, no \s-1RCS\s0 or \s-1SCCS\s0 master was found, +some names are given, .B POSIXLY_CORRECT is not set, and the patch appears to create a file, .B patch uses the best name requiring the creation of the fewest directories. +.TP +.B " \(bu" If no file name results from the above heuristics, you are asked for the name of the file to patch. -To determine the best of a nonempty list of file names, +.LP +To determine the +.I best +of a nonempty list of file names, .B patch first takes all the names with the fewest path name components; of those, it then takes all the names with the shortest basename; @@ -175,22 +210,6 @@ If not, .B patch asks for confirmation before proceeding. .PP -If an -\s-1RCS\s0 file is handy, -and the original file cannot be found -or is read-only and matches the default version, -and if version control -(see the -.B \-V -or -.B \*=version\-control -option) -is set to -.BR existing , -.B patch -attempts to get and lock the file. -\s-1SCCS\s0 is treated in a similar way. -.PP The upshot of all this is that you should be able to say, while in a news interface, something like the following: .Sp @@ -213,20 +232,38 @@ mentioned previously. .TP 3 \fB\-b\fP or \fB\*=backup\fP Make backup files. +That is, when patching a file, +rename or copy the original instead of removing it. +When backing up a file that does not exist, +an empty, unreadable backup file is created +as a placeholder to represent the nonexistent file. +.Sp This option is equivalent to .BR \*=version\-control=simple ; see the .B \-V or .B \*=version\-control -option for details. -In older versions of -.BR patch , -this option had an argument specifying the simple backup suffix; -this argument has been moved to the -.B \-z option. .TP +.B \*=backup\-if\-mismatch +Back up a file if the patch does not match the file exactly +and if backups are not otherwise requested. +The backup file name is calculated as usual, +except that if the version control method is +.BR none , +a simple backup name is used. +This is the default unless the +.B POSIXLY_CORRECT +environment variable is set. +.TP +.B \*=no\-backup\-if\-mismatch +Do not back up a file if the patch does not match the file exactly +and if backups are not otherwise requested. +This is the default if the +.B POSIXLY_CORRECT +environment variable is set. +.TP \fB\-B\fP \fIpref\fP or \fB\*=prefix=\fP\fIpref\fP Prefix simple backup file names with .IR pref . @@ -249,20 +286,17 @@ the patch should be generated by \fB\-c\fP or \fB\*=context\fP Interpret the patch file as a ordinary context diff. .TP -\fB\*=verbose\fP -Output extra information about the work being done. -.TP \fB\-d\fP \fIdir\fP or \fB\*=directory=\fP\fIdir\fP Change to the directory .I dir immediately, before doing anything else. .TP -\fB\-D\fP \fIsym\fP or \fB\*=ifdef=\fP\fIsym\fP +\fB\-D\fP \fIdefine\fP or \fB\*=ifdef=\fP\fIdefine\fP Use the .BR #ifdef " .\|.\|. " #endif construct to mark changes, with -.I sym +.I define as the differentiating symbol. .TP .B "\*=dry\-run" @@ -277,7 +311,7 @@ script. Remove output files that are empty after the patches have been applied. Normally this option is unnecessary, since .B patch -can examine the timestamps on the header to determine whether a file +can examine the time stamps on the header to determine whether a file should exist after patching. However, if the input is not a context diff or if the .B POSIXLY_CORRECT @@ -300,7 +334,7 @@ This option does not suppress commentary; use .B \-s for that. .TP -\fB\-F\fP \fInumber\fP or \fB\*=fuzz=\fP\fInumber\fP +\fB\-F\fP \fInum\fP or \fB\*=fuzz=\fP\fInum\fP Set the maximum fuzz factor. This option only applies to diffs that have context, and causes .B patch @@ -309,19 +343,25 @@ Note that a larger fuzz factor increases the odds of a faulty patch. The default fuzz factor is 2, and it may not be set to more than the number of lines of context in the context diff, ordinarily 3. .TP -\fB\-g\fP or \fB\*=get\fP -If a file does not exist or is read-only and matches the default version, -get it from \s-1RCS\s0 if it is under \s-2RCS\s0 control; -similarly for \s-1SCCS\s0. -If the -.B PATCH_GET -environment variable is set, this is the default. -.TP -\fB\-G\fP or \fB\*=no\-get\fP -Do not get files from \s-1RCS\s0 or \s-2SCCS\s0. -This is the default unless the +\fB\-g\fP \fInum\fP or \fB\*=get=\fP\fInum\fP +This option controls +.BR patch 's +actions when a file is under \s-1RCS\s0 or \s-1SCCS\s0 control, +and does not exist or is read-only and matches the default version. +If +.I num +is positive, +.B patch +gets (or checks out) the file from the revision control system; if zero, +.B patch +ignores \s-1RCS\s0 and \s-1SCCS\s0 and does not get the file; and if negative, +.B patch +asks the user whether to get the file. +The default value of this option is given by the value of the .B PATCH_GET -environment variable is set. +environment variable if it is set; if not, the default value is zero if +.B POSIXLY_CORRECT +is set, negative otherwise. .TP .B "\*=help" Print a summary of options and exit. @@ -351,14 +391,14 @@ Ignore patches that seem to be reversed or already applied. See also .BR \-R . .TP -\fB\-o\fP \fIfile\fP or \fB\*=output=\fP\fIfile\fP +\fB\-o\fP \fIoutfile\fP or \fB\*=output=\fP\fIoutfile\fP Send output to -.I file +.I outfile instead of patching files in place. .TP -\fB\-p\fP\fInumber\fP or \fB\*=strip\fP\fB=\fP\fInumber\fP +\fB\-p\fP\fInum\fP or \fB\*=strip\fP\fB=\fP\fInum\fP Strip the smallest prefix containing -.I number +.I num leading slashes from each file name found in the patch file. A sequence of one or more adjacent slashes is counted as a single slash. This controls how file names found in the patch file are treated, in case @@ -389,19 +429,10 @@ Whatever you end up with is looked for either in the current directory, or the directory specified by the .B \-d option. -With \s-1GNU\s0 -.BR patch , -the two-argument -.BI "\-p " N -form of this option is equivalent to one-argument -.BI \-p N -form, but this is not true of traditional -.BR patch , -so the one-argument form is recommended for portability. .TP -\fB\-r\fP \fIfile\fP or \fB\*=reject\-file=\fP\fIfile\fP +\fB\-r\fP \fIrejectfile\fP or \fB\*=reject\-file=\fP\fIrejectfile\fP Put rejects into -.I file +.I rejectfile instead of the default .B \&.rej file. @@ -449,6 +480,19 @@ line in the patch; and assume that patches are reversed if they look like they are. .TP +\fB\-T\fP or \fB\*=set\-time\fP +Set the modification and access times of patched files from time stamps +given in context diff headers, assuming that the context diff headers +use local time. This option is not recommended, because patches using +local time cannot easily be used by people in other time zones, and +because local time stamps are ambiguous when local clocks move backwards +during daylight-saving time adjustments. Instead of using this option, +generate patches with \s-1UTC\s0 and use the +.B \-Z +or +.B \*=set\-utc +option instead. +.TP \fB\-u\fP or \fB\*=unified\fP Interpret the patch file as a unified context diff. .TP @@ -460,8 +504,8 @@ revision header and patch level, and exit. \fB\-V\fP \fImethod\fP or \fB\*=version\-control=\fP\fImethod\fP Use .I method -when creating -backup file names. The type of backups made can also be given in the +to determine +backup file names. The method can also be given by the .B PATCH_VERSION_CONTROL (or, if that's not set, the .BR VERSION_CONTROL ) @@ -484,7 +528,8 @@ Make numbered backups of files that already have them, otherwise simple backups. .TP \fBnone\fP -Do not make backups. +Do not make backups, unless backup-if-mismatch is in effect +and patches do not match files. This is the default. .TP \fBnumbered\fP or \fBt\fP @@ -497,9 +542,7 @@ where is the version number. .TP \fBsimple\fP or \fBnever\fP -Make simple backups. That is, when patching a file -.IR F , -rename or copy the original instead of removing it. +Make simple backups. The .B \-B or @@ -529,7 +572,10 @@ would make the name too long, then replaces the last character of the file name. .RE .TP -\fB\-x\fP \fInumber\fP or \fB\*=debug=\fP\fInumber\fP +\fB\*=verbose\fP +Output extra information about the work being done. +.TP +\fB\-x\fP \fInum\fP or \fB\*=debug=\fP\fInum\fP Set internal debugging flags of interest only to .B patch patchers. @@ -544,23 +590,72 @@ the backup file name for is .BR src/patch/.del/util.c . .TP -\fB\-z\fP \fIsuff\fP or \fB\*=suffix=\fP\fIsuff\fP +\fB\-z\fP \fIsuffix\fP or \fB\*=suffix=\fP\fIsuffix\fP Use -.I suff +.I suffix as the simple backup suffix. The backup extension may also be specified by the .B SIMPLE_BACKUP_SUFFIX environment variable, which is overridden by this option. +.TP +\fB\-Z\fP or \fB\*=set\-utc\fP +Set the modification and access times of patched files from time stamps +given in context diff headers, assuming that the context diff headers +use Coordinated Universal Time (\s-1UTC\s0, often known as \s-1GMT\s0). +Also see the +.B \-T +or +.B \*=set\-time +option. +.Sp +The +.B \-Z +or +.B \*=set\-utc +and +.B \-T +or +.B \*=set\-time +options normally refrain from setting a file's time if the file's original time +does not match the time given in the patch header, or if its +contents do not match the patch exactly. However, if the +.B \-f +or +.B \*=force +option is given, the file time is set regardless. +.Sp +Due to the limitations of +.B diff +output format, these options cannot update the times of files whose +contents have not changed. Also, if you use these options, you should remove +(e.g. with +.BR "make\ clean" ) +all files that depend on the patched files, so that later invocations of +.B make +do not get confused by the patched files' times. .SH ENVIRONMENT .TP 3 +\fBPATCH_GET\fP +This specifies whether +.B patch +gets missing or read-only files from \s-1RCS\s0 or \s-1SCCS\s0 +by default; see the +.B \-g +or +.B \*=get +option. +.TP .B POSIXLY_CORRECT If set, .B patch conforms more strictly to the \s-1POSIX\s0 standard: -it takes the first existing file when intuiting file names from diff headers, +it takes the first existing file from the list (old, new, index) +when intuiting file names from diff headers, it does not remove files that are empty after patching, -and it requires that all options precede the -files in the command line. +it does not ask whether to get files from \s-1RCS\s0 or \s-1SCCS\s0, +it requires that all options precede the +files in the command line, +and by default it does not make backup files. .TP .B SIMPLE_BACKUP_SUFFIX Extension to use for simple backup file names instead of @@ -575,33 +670,19 @@ it is normally .B /tmp on Unix hosts. .TP -\fBPATCH_VERSION_CONTROL\fP or \fBVERSION_CONTROL\fP +\fBVERSION_CONTROL\fP or \fBPATCH_VERSION_CONTROL\fP Selects version control style; see the .B \-v or .B \*=version\-control option. -.TP -\fBPATCH_GET\fP -If set, -.B patch -gets missing or read-only files from \s-1RCS\s0 or \s-1SCCS\s0 -by default; see the -.B \-g -or -.B \*= get -and the -.B \-G -or -.B \*= no\-get -options. .SH FILES .TP 3 .IB $TMPDIR "/p\(**" temporary files .TP .B /dev/tty -console; used to get answers to questions asked of the user +controlling terminal; used to get answers to questions asked of the user .SH "SEE ALSO" .BR diff (1), .BR ed (1) @@ -622,9 +703,18 @@ The names and .I new should not contain any slashes. -Here is an example: +The +.B diff +command's headers should have dates +and times in Universal Time using traditional Unix format, +so that patch recipients can use the +.B \-Z +or +.B \*=set\-utc +option. +Here is an example command, using Bourne shell syntax: .Sp - \fBdiff \-Naur version\-2.2 version\-2.3\fP + \fBLC_ALL=C TZ=UTC0 diff \-Naur gcc\-2.7 gcc\-2.8\fP .PP Tell your recipients how to apply the patch by telling them which directory to @@ -646,19 +736,14 @@ If you put a line in with the patch, it won't let them apply patches out of order without some warning. .PP -Make sure you've specified the file names right, either in a -context diff header, or with an -.B Index:\& -line. -.PP -You can create a file by sending out a diff that compares an -empty file (such as -.BR /dev/null ) +You can create a file by sending out a diff that compares +.B /dev/null +or an empty file dated the Epoch (1970-01-01 00:00:00 \s-1UTC\s0) to the file you want to create. This only works if the file you want to create doesn't exist already in the target directory. -Conversely, you can remove a file by sending out a diff that compares the -file to be deleted with an empty file. +Conversely, you can remove a file by sending out a context diff that compares +the file to be deleted with an empty file dated the Epoch. The file will be removed unless the .B POSIXLY_CORRECT environment variable is set and the @@ -669,6 +754,8 @@ option is not given. An easy way to generate patches that create and remove files is to use \s-1GNU\s0 .BR diff 's +.B \-N +or .B \*=new\-file option. .PP @@ -723,49 +810,14 @@ where there is a line in your makefile), since the recipient should be able to regenerate the derived files anyway. If you must send diffs of derived files, -ensure that the diffs for each derived file -follow the diffs for the files that it depends on, -so that the dependencies will be preserved as -.B patch -updates the files one by one. -Here is a sample shell script that output patches in an order that -should preserve dependencies: -.nf -.Sp -.ft B -.in +3n -#! /bin/sh -.Sp -.ne 2 -old=${1?} -new=${2?} -.Sp -.ne 10 -fs= -for f in ` - diff \-Nqr $old $new | - sed \-e "s,.\(** $new/,," \-e 's, differ$,,'` -do - if [ \-f $new/$f ] - then fs="$fs $f" - else diff \-au $old/$f /dev/null - fi -done -.Sp -.ne 10 -case $fs in -?\(**) - for f in `cd $new; ls \-rt $fs` - do - if [ \-f $old/$f ] - then diff \-au $old/$f $new/$f - else diff \-au /dev/null $new/$f - fi - done -esac -.in -.ft -.fi +generate the diffs using \s-1UTC\s0, +have the recipients apply the patch with the +.B \-Z +or +.B \*=set\-utc +option, and have them remove any unpatched files that depend on patched files +(e.g. with +.BR "make\ clean" ). .PP While you may be able to get away with putting 582 diff listings into one file, it may be wiser to group related patches into separate files in @@ -817,6 +869,150 @@ guessing. However, the results are guaranteed to be correct only when the patch is applied to exactly the same version of the file that the patch was generated from. +.SH "COMPATIBILITY ISSUES" +The \s-1POSIX\s0 standard specifies behavior that differs from +.BR patch 's +traditional behavior. +You should be aware of these differences if you must interoperate with +.B patch +versions 2.1 and earlier, which are not \s-1POSIX\s0-compliant. +.TP 3 +.B " \(bu" +In traditional +.BR patch , +the +.B \-p +option's operand was optional, and a bare +.B \-p +was equivalent to +.BR \-p0. +The +.B \-p +option now requires an operand, and +.B "\-p\ 0" +is now equivalent to +.BR \-p0 . +For maximum compatibility, use options like +.B \-p0 +and +.BR \-p1 . +.Sp +Also, +traditional +.B patch +simply counted slashes when stripping path prefixes; +.B patch +now counts pathname components. +That is, a sequence of one or more adjacent slashes +now counts as a single slash. +For maximum portability, avoid sending patches containing +.B // +in file names. +.TP +.B " \(bu" +In traditional +.BR patch , +simple backups were enabled by default. +This behavior is now enabled with the +.B \-b +or +.B \*=backup +option, or by setting the +.B VERSION_CONTROL +environment variable to +.BR simple . +.Sp +Conversely, in \s-1POSIX\s0 +.BR patch , +backups are never made, even when there is a mismatch. +In \s-1GNU\s0 +.BR patch , +this behavior is enabled with the +.B \*=no\-backup\-if\-mismatch +option or by setting the +.B POSIXLY_CORRECT +environment variable. +.Sp +The +.BI \-b " suffix" +option +of traditional +.B patch +is equivalent to the +.BI "\-b \-z" " suffix" +options of \s-1GNU\s0 +.BR patch . +.TP +.B " \(bu" +Traditional +.B patch +used a complicated (and incompletely documented) method +to intuit the name of the file to be patched from the patch header. +This method was not \s-1POSIX\s0-compliant, and had a few gotchas. +Now +.B patch +uses a different, equally complicated (but better documented) method +that is optionally \s-1POSIX\s0-compliant; we hope it has +fewer gotchas. The two methods are compatible if the +file names in the context diff header and the +.B Index:\& +line are all identical after prefix-stripping. +Your patch is normally compatible if each header's file names +all contain the same number of slashes. +.TP +.B " \(bu" +When traditional +.B patch +asked the user a question, it sent the question to standard error +and looked for an answer from +the first file in the following list that was a terminal: +standard error, standard output, +.BR /dev/tty , +and standard input. +Now +.B patch +sends questions to standard output and gets answers from +.BR /dev/tty . +Defaults for some answers have been changed so that +.B patch +never goes into an infinite loop when using default answers. +.TP +.B " \(bu" +Traditional +.B patch +exited with a status value that counted the number of bad hunks, +or with status 1 if there was real trouble. +Now +.B patch +exits with status 1 if some hunks failed, +or with 2 if there was real trouble. +.TP +.B " \(bu" +Limit yourself to the following options when sending instructions +meant to be executed by anyone running \s-1GNU\s0 +.BR patch , +traditional +.BR patch , +or a \s-1POSIX\s0-compliant +.BR patch . +Spaces are significant in the following list, and operands are required. +.Sp +.nf +.in +3 +.ne 11 +.B \-c +.BI \-d " dir" +.BI \-D " define" +.B \-e +.B \-l +.B \-n +.B \-N +.BI \-o " outfile" +.BI \-p num +.B \-R +.BI \-r " rejectfile" +.in +.fi .SH BUGS .B patch could be smarter about partial matches, excessively deviant offsets and @@ -860,7 +1056,8 @@ Larry Wall wrote the original version of .BR patch . Paul Eggert removed .BR patch 's -arbitrary limits, added support for binary files, +arbitrary limits; added support for binary files, +setting file times, and deleting files; and made it conform better to \s-1POSIX\s0. Other contributors include Wayne Davison, who added unidiff support, and David MacKenzie, who added configuration and backup support. diff --git a/pc/djgpp/config.h b/pc/djgpp/config.h deleted file mode 100644 index d2f6cb5..0000000 --- a/pc/djgpp/config.h +++ /dev/null @@ -1,139 +0,0 @@ -/* config.h for compiling `patch' with DJGPP for MS-DOS and MS-Windows. - Please keep this file as similar as possible to ../../config.h - to simplify maintenance later. */ - -/* This does most of the work; the rest of this file defines only those - symbols that <sys/config.h> doesn't define correctly. */ -#include <sys/config.h> - -/* Define if on AIX 3. - System headers sometimes define this. - We just want to avoid a redefinition error message. */ -#ifndef _ALL_SOURCE -/* #undef _ALL_SOURCE */ -#endif - -/* Define if the closedir function returns void instead of int. */ -/* #undef CLOSEDIR_VOID */ - -/* Define to empty if the keyword does not work. */ -/* #undef const */ - -/* Define if you don't have vprintf but do have _doprnt. */ -/* #undef HAVE_DOPRNT */ - -/* Define if you support file names longer than 14 characters. */ -#define HAVE_LONG_FILE_NAMES 1 - -/* Define if you have the vprintf function. */ -#define HAVE_VPRINTF 1 - -/* Define if on MINIX. */ -/* #undef _MINIX */ - -/* Define to `int' if <sys/types.h> doesn't define. */ -/* #undef mode_t */ - -/* Define to `long' if <sys/types.h> doesn't define. */ -/* #undef off_t */ - -/* Define if the system does not provide POSIX.1 features except - with this defined. */ -/* #undef _POSIX_1_SOURCE */ - -/* Define if you need to in order for stat and other things to work. */ -/* #undef _POSIX_SOURCE */ - -/* Define as the return type of signal handlers (int or void). */ -/* #undef RETSIGTYPE */ - -/* Define to `unsigned' if <sys/types.h> doesn't define. */ -/* #undef size_t */ - -/* Define if you have the ANSI C header files. */ -/* #undef STDC_HEADERS */ - -/* Define if there is a member named d_ino in the struct describing - directory headers. */ -/* #undef D_INO_IN_DIRENT */ - -/* Define if memchr works. */ -/* #undef HAVE_MEMCHR */ - -/* Define if you have the _doprintf function. */ -/* #undef HAVE__DOPRINTF */ - -/* Define if you have the isascii function. */ -/* #undef HAVE_ISASCII */ - -/* Define if you have the memchr function. */ -/* #undef HAVE_MEMCHR 1 */ - -/* Define if you have the memcmp function. */ -#define HAVE_MEMCMP 1 - -/* Define if you have the mkdir function. */ -/* #undef HAVE_MKDIR */ - -/* Define if you have the mktemp function. */ -#define HAVE_MKTEMP 1 - -/* Define if you have the pathconf function. */ -#define HAVE_PATHCONF 1 - -/* Define if you have the rename function. */ -/* #undef HAVE_RENAME */ - -/* Define if you have the sigaction function. */ -/* #undef HAVE_SIGACTION */ - -/* Define if you have the sigprocmask function. */ -#define HAVE_SIGPROCMASK 1 - -/* Define if you have the sigsetmask function. */ -/* #undef HAVE_SIGSETMASK */ - -/* Define if you have the <dirent.h> header file. */ -/* #undef HAVE_DIRENT_H */ - -/* Define if you have the <fcntl.h> header file. */ -/* #undef HAVE_FCNTL_H */ - -/* Define if you have the <limits.h> header file. */ -/* #undef HAVE_LIMITS_H */ - -/* Define if you have the <ndir.h> header file. */ -/* #undef HAVE_NDIR_H */ - -/* Define if you have the <string.h> header file. */ -/* #undef HAVE_STRING_H */ - -/* Define if you have the <sys/dir.h> header file. */ -/* #undef HAVE_SYS_DIR_H */ - -/* Define if you have the <sys/ndir.h> header file. */ -/* #undef HAVE_SYS_NDIR_H */ - -/* Define if you have the <unistd.h> header file. */ -/* #undef HAVE_UNISTD_H */ - -/* Define if you have the <varargs.h> header file. */ -/* #undef HAVE_VARARGS_H */ - - -/* PC-specific definitions */ - -#define chdir chdir_safer -int chdir_safer (char const *); - -#define FILESYSTEM_PREFIX_LEN(f) ((f)[0] && (f)[1] == ':' ? 2 : 0) -#define ISSLASH(c) ((c) == '/' || (c) == '\\') - -#define HAVE_DOS_FILE_NAMES 1 - -#define HAVE_SETMODE 1 -#ifdef WIN32 -# define setmode _setmode -#endif - -#define TMPDIR "c:" diff --git a/pc/djgpp/config.sed b/pc/djgpp/config.sed index cc449fd..f97d210 100644 --- a/pc/djgpp/config.sed +++ b/pc/djgpp/config.sed @@ -1,35 +1,38 @@ -# Edit Makefile.in to produce Makefile for DJGPP v2 -# $Id: config.sed,v 1.4 1997/05/26 17:52:29 eggert Exp $ +1c\ +/* config.h for compiling `patch' with DJGPP for MS-DOS and MS-Windows.\ + Please keep this file as similar as possible to ../../config.h\ + to simplify maintenance later. */\ +\ +/* This does most of the work; the rest of this file defines only those\ + symbols that <sys/config.h> doesn't define correctly. */\ +#include <sys/config.h> -1i\ -# Makefile generated by "configure.bat" for DJGPP v2\ +s/#undef HAVE_LONG_FILE_NAMES/#define HAVE_LONG_FILE_NAMES 1/ +s/#undef HAVE_MEMCMP/#define HAVE_MEMCMP 1/ +s/#undef HAVE_MKTEMP/#define HAVE_MKTEMP 1/ +s/#undef HAVE_PATHCONF/#define HAVE_PATHCONF 1/ +s/#undef HAVE_RAISE/#define HAVE_RAISE 1/ +s/#undef HAVE_SIGPROCMASK/#define HAVE_SIGPROCMASK 1/ +s/#undef HAVE_UTIME_H/#define HAVE_UTIME_H 1/ +s/#undef HAVE_STRUCT_UTIMBUF/#define HAVE_STRUCT_UTIMBUF 1/ +s/#undef HAVE_VPRINTF/#define HAVE_VPRINTF 1/ -/@SET_MAKE@/d - -s|@CC@|gcc|g -s|@ed_PROGRAM@|ed|g -s|@INSTALL@|${DJDIR}/bin/ginstall -c|g -s|@INSTALL_PROGRAM@|${INSTALL}|g -s|@INSTALL_DATA@|${INSTALL} -m 644|g - -s|@CFLAGS@|-g -O2|g -s|@CPPFLAGS@|-I$(srcdir)/pc/djgpp|g -s|@DEFS@|-DHAVE_CONFIG_H|g -s|@LDFLAGS@||g -s|@LIBOBJS@|getopt1.o getopt.o chdirsaf.o|g -s|@LIBS@||g -s|@PACKAGE@|patch|g -/@VERSION@/d - -s|@prefix@|${DJDIR}|g -s|@exec_prefix@|${prefix}|g - -/^CONFIG_HDRS *=/s|=.*|= pc/djgpp/config.h| -/^CONFIG_STATUS *=/s|=.*|= $(srcdir)/pc/djgpp/configure.bat| -/^ \$(SHELL) \$(CONFIG_STATUS) *$/s// $(CONFIG_STATUS) $(srcdir)/ +s,#undef.*,/* & */, $a\ -chdirsaf.o: chdirsaf.c\ -# Use sed instead of cp, since cp might not be installed.\ -chdirsaf.c: pc/chdirsaf.c; sed -e '' $? > $@\ -distclean::; rm -f chdirsaf.c +/* DGJPP-specific definitions */\ +\ +#define chdir chdir_safer\ +int chdir_safer (char const *);\ +\ +#define FILESYSTEM_PREFIX_LEN(f) ((f)[0] && (f)[1] == ':' ? 2 : 0)\ +#define ISSLASH(c) ((c) == '/' || (c) == '\\\\')\ +\ +#define HAVE_DOS_FILE_NAMES 1\ +\ +#define HAVE_SETMODE 1\ +#ifdef WIN32\ +# define setmode _setmode\ +#endif\ +\ +#define TMPDIR "c:" diff --git a/pc/djgpp/configure.bat b/pc/djgpp/configure.bat index c5313ea..c4e06d1 100644 --- a/pc/djgpp/configure.bat +++ b/pc/djgpp/configure.bat @@ -1,6 +1,6 @@ @echo off
Rem Configure patch for DJGPP v2.
-Rem $Id: configure.bat,v 1.3 1997/05/26 17:52:29 eggert Exp $
+Rem $Id: configure.bat,v 1.4 1997/06/17 06:52:12 eggert Exp $
Rem The DOS shell has fixed-size environment storage.
Rem When the environment is full, the shell prints
@@ -15,7 +15,7 @@ if not "%1" == "" set srcdir=%1 if not "%1" == "" if not "%srcdir%" == "%1" goto SmallEnv
Rem Create Makefile
-sed -f %srcdir%/pc/djgpp/config.sed -e "s,@srcdir@,%srcdir%,g" %srcdir%/Makefile.in >Makefile
+sed -f %srcdir%/pc/djgpp/configure.sed -e "s,@srcdir@,%srcdir%,g" %srcdir%/Makefile.in >Makefile
sed -n -e "/^VERSION/p" %srcdir%/configure.in >>Makefile
goto Exit
diff --git a/pc/djgpp/configure.sed b/pc/djgpp/configure.sed new file mode 100644 index 0000000..6f14c38 --- /dev/null +++ b/pc/djgpp/configure.sed @@ -0,0 +1,36 @@ +# Edit Makefile.in to produce Makefile for DJGPP v2 +# $Id: configure.sed,v 1.8 1997/06/18 06:26:43 eggert Exp $ + +1i\ +# Makefile generated by "configure.bat" for DJGPP v2\ + +/@SET_MAKE@/d + +s|@CC@|gcc|g +s|@ed_PROGRAM@|ed|g +s|@INSTALL@|${DJDIR}/bin/ginstall -c|g +s|@INSTALL_PROGRAM@|${INSTALL}|g +s|@INSTALL_DATA@|${INSTALL} -m 644|g +s|@program_transform_name@||g + +s|@CFLAGS@|-g -O2|g +s|@CPPFLAGS@|-I$(srcdir)/pc/djgpp|g +s|@DEFS@|-DHAVE_CONFIG_H|g +s|@LDFLAGS@||g +s|@LIBOBJS@|getopt1.o getopt.o chdirsaf.o|g +s|@LIBS@||g +s|@PACKAGE@|patch|g +/@VERSION@/d + +s|@prefix@|${DJDIR}|g +s|@exec_prefix@|${prefix}|g + +/^CONFIG_STATUS *=/s|=.*|= $(srcdir)/pc/djgpp/configure.bat| +/^ \$(SHELL) \$(CONFIG_STATUS) *$/s// $(CONFIG_STATUS) $(srcdir)/ + +$a\ +config.h: config.hin pc/djgpp/config.sed; sed -f $(srcdir)/pc/djgpp/config.sed $(srcdir)/config.hin >$@\ +chdirsaf.o: chdirsaf.c\ +# Use sed instead of cp, since cp might not be installed.\ +chdirsaf.c: pc/chdirsaf.c; sed -e '' $? > $@\ +distclean::; rm -f chdirsaf.c @@ -1,6 +1,6 @@ /* reading patches */ -/* $Id: pch.c,v 1.16 1997/05/26 17:52:29 eggert Exp $ */ +/* $Id: pch.c,v 1.23 1997/06/17 06:52:12 eggert Exp $ */ /* Copyright 1986, 1987, 1988 Larry Wall @@ -36,7 +36,9 @@ If not, write to the Free Software Foundation, /* Patch (diff listing) abstract type. */ static FILE *pfp; /* patch file pointer */ -static int p_says_nonexistent[2]; /* [0] for old file, [1] for new */ +static int p_says_nonexistent[2]; /* [0] for old file, [1] for new; + value is 0 for nonempty, 1 for empty, 2 for nonexistent */ +static time_t p_timestamp[2]; /* timestamps in patch headers */ static off_t p_filesize; /* size of the patch file */ static LINENUM p_first; /* 1st line number */ static LINENUM p_newfirst; /* 1st line number of replacement */ @@ -97,6 +99,7 @@ open_patch_file(filename) struct stat st; if (!filename || !*filename || strEQ (filename, "-")) { + file_offset stdin_pos; #if HAVE_SETMODE if (binary_transput) { @@ -107,10 +110,10 @@ open_patch_file(filename) #endif if (fstat (STDIN_FILENO, &st) != 0) pfatal ("fstat"); - if (S_ISREG (st.st_mode)) + if (S_ISREG (st.st_mode) && (stdin_pos = file_tell (stdin)) != -1) { pfp = stdin; - file_pos = file_tell (stdin); + file_pos = stdin_pos; } else { @@ -118,7 +121,9 @@ open_patch_file(filename) pfp = fopen (TMPPATNAME, "w+b"); if (!pfp) pfatal ("can't create `%s'", TMPPATNAME); - while ((charsread = fread (buf, 1, bufsize, stdin)) != 0) + for (st.st_size = 0; + (charsread = fread (buf, 1, bufsize, stdin)) != 0; + st.st_size += charsread) if (fwrite (buf, 1, charsread, pfp) != charsread) write_fatal (); if (ferror (stdin) || fclose (stdin) != 0) @@ -195,7 +200,11 @@ there_is_another_patch() return FALSE; } if (skip_rest_of_patch) + { + Fseek (pfp, p_start, SEEK_SET); + p_input_line = p_sline - 1; return TRUE; + } if (verbosity == VERBOSE) say (" %sooks like %s to me...\n", (p_base == 0 ? "L" : "The next patch l"), @@ -204,21 +213,32 @@ there_is_another_patch() diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" : diff_type == NORMAL_DIFF ? "a normal diff" : "an ed script" ); - if (p_indent && verbosity != SILENT) - say ("(Patch is indented %d space%s.)\n", p_indent, p_indent==1?"":"s"); + + if (verbosity != SILENT) + { + if (p_indent) + say ("(Patch is indented %d space%s.)\n", p_indent, p_indent==1?"":"s"); + if (! inname) + say ("can't find file to patch at input line %ld\n", + p_sline); + } + skip_to(p_start,p_sline); while (!inname) { if (force || batch) { - say ("No file to patch. Skipping...\n"); + say ("No file to patch. Skipping patch.\n"); skip_rest_of_patch = TRUE; return TRUE; } ask ("File to patch: "); - inname = fetchname (buf, 0, (int *) 0); + inname = fetchname (buf, 0, (time_t *) 0); if (inname) { if (stat (inname, &instat) == 0) - inerrno = 0; + { + inerrno = 0; + invc = -1; + } else { perror (inname); @@ -230,7 +250,7 @@ there_is_another_patch() ask ("Skip this patch? [y] "); if (*buf != 'n') { if (verbosity != SILENT) - say ("Skipping patch...\n"); + say ("Skipping patch.\n"); skip_rest_of_patch = TRUE; return TRUE; } @@ -259,11 +279,14 @@ intuit_diff_type() char *name[3]; struct stat st[3]; int stat_errno[3]; + int version_controlled[3]; register enum diff retval; - int head_says_nonexistent[2]; name[OLD] = name[NEW] = name[INDEX] = 0; - head_says_nonexistent[OLD] = head_says_nonexistent[NEW] = 0; + version_controlled[OLD] = -1; + version_controlled[NEW] = -1; + version_controlled[INDEX] = -1; + p_timestamp[OLD] = p_timestamp[NEW] = (time_t) -1; p_says_nonexistent[OLD] = p_says_nonexistent[NEW] = 0; Fseek (pfp, p_base, SEEK_SET); p_input_line = p_bline - 1; @@ -304,14 +327,14 @@ intuit_diff_type() p_indent = indent; /* assume this for now */ } if (!stars_last_line && strnEQ(s, "*** ", 4)) - name[OLD] = fetchname (s+4, strippath, &head_says_nonexistent[OLD]); + name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]); else if (strnEQ(s, "--- ", 4)) - name[NEW] = fetchname (s+4, strippath, &head_says_nonexistent[NEW]); + name[NEW] = fetchname (s+4, strippath, &p_timestamp[NEW]); else if (strnEQ(s, "+++ ", 4)) /* Swap with NEW below. */ - name[OLD] = fetchname (s+4, strippath, &head_says_nonexistent[OLD]); + name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]); else if (strnEQ(s, "Index:", 6)) - name[INDEX] = fetchname (s+6, strippath, (int *) 0); + name[INDEX] = fetchname (s+6, strippath, (time_t *) 0); else if (strnEQ(s, "Prereq:", 7)) { for (t = s + 7; ISSPACE ((unsigned char) *t); t++) continue; @@ -338,24 +361,32 @@ intuit_diff_type() } if ((diff_type == NO_DIFF || diff_type == UNI_DIFF) && strnEQ(s, "@@ -", 4)) { - s += 4; - /* `name' and `head_says_nonexistent' are backwards. - Swap the former, and interpret the latter backwards. */ + + /* `name' and `p_timestamp' are backwards; swap them. */ + time_t ti = p_timestamp[OLD]; + p_timestamp[OLD] = p_timestamp[NEW]; + p_timestamp[NEW] = ti; t = name[OLD]; name[OLD] = name[NEW]; name[NEW] = t; - if (head_says_nonexistent[NEW] && ! atol (s)) - p_says_nonexistent[OLD] = 1; + + s += 4; + if (! atol (s)) + p_says_nonexistent[OLD] = 1 + ! p_timestamp[OLD]; while (*s != ' ' && *s != '\n') s++; while (*s == ' ') s++; - if (head_says_nonexistent[OLD] && ! atol (s)) - p_says_nonexistent[NEW] = 1; + if (! atol (s)) + p_says_nonexistent[NEW] = 1 + ! p_timestamp[NEW]; p_indent = indent; p_start = this_line; p_sline = p_input_line; retval = UNI_DIFF; + if (! ((name[OLD] || ! p_timestamp[OLD]) + && (name[NEW] || ! p_timestamp[NEW]))) + say ("missing header for unified diff at line %ld of patch\n", + p_sline); goto scan_exit; } stars_this_line = strnEQ(s, "********", 8); @@ -364,8 +395,8 @@ intuit_diff_type() || diff_type == NEW_CONTEXT_DIFF) && stars_last_line && strnEQ (s, "*** ", 4)) { s += 4; - if (head_says_nonexistent[OLD] && ! atol (s)) - p_says_nonexistent[OLD] = 1; + if (! atol (s)) + p_says_nonexistent[OLD] = 1 + ! p_timestamp[OLD]; /* if this is a new context diff the character just before */ /* the newline is a '*'. */ while (*s != '\n') @@ -375,20 +406,23 @@ intuit_diff_type() p_sline = p_input_line - 1; retval = (*(s-1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF); - if (head_says_nonexistent[NEW]) - { - /* Scan the first hunk to see whether the file appears to - have been deleted. */ - file_offset saved_p_base = p_base; - LINENUM saved_p_bline = p_bline; - p_input_line = p_sline; - Fseek (pfp, previous_line, SEEK_SET); - if (another_hunk (retval, 0) - && ! p_repl_lines && p_newfirst == 1) - p_says_nonexistent[NEW] = 1; - next_intuit_at (saved_p_base, saved_p_bline); - } + { + /* Scan the first hunk to see whether the file contents + appear to have been deleted. */ + file_offset saved_p_base = p_base; + LINENUM saved_p_bline = p_bline; + Fseek (pfp, previous_line, SEEK_SET); + p_input_line -= 2; + if (another_hunk (retval, 0) + && ! p_repl_lines && p_newfirst == 1) + p_says_nonexistent[NEW] = 1 + ! p_timestamp[NEW]; + next_intuit_at (saved_p_base, saved_p_bline); + } + if (! ((name[OLD] || ! p_timestamp[OLD]) + && (name[NEW] || ! p_timestamp[NEW]))) + say ("missing header for context diff at line %ld of patch\n", + p_sline); goto scan_exit; } if ((diff_type == NO_DIFF || diff_type == NORMAL_DIFF) && @@ -409,12 +443,18 @@ intuit_diff_type() (with some modifications if posixly_correct is zero): - Take the old and new names from the context header if present, - and take the index name from the `Index:' line if present. + and take the index name from the `Index:' line if present and + if either the old and new names are both absent + or posixly_correct is nonzero. Consider the file names to be in the order (old, new, index). - If some named files exist, use the first one if posixly_correct is nonzero, the best one otherwise. - - If no named files exist, some names are given, posixly_correct is - zero, and the patch appears to create a file, then use the best name + - If patch_get is nonzero, and no named files exist, + but an RCS or SCCS master file exists, + use the first named file with an RCS or SCCS master. + - If no named files exist, no RCS or SCCS master was found, + some names are given, posixly_correct is zero, + and the patch appears to create a file, then use the best name requiring the creation of the fewest directories. - Otherwise, report failure by setting `inname' to 0; this causes our invoker to ask the user for a file name. */ @@ -425,6 +465,12 @@ intuit_diff_type() { enum nametype i0 = NONE; + if (! posixly_correct && (name[OLD] || name[NEW]) && name[INDEX]) + { + free (name[INDEX]); + name[INDEX] = 0; + } + for (i = OLD; i <= INDEX; i++) if (name[i]) { @@ -450,15 +496,57 @@ intuit_diff_type() { i = best_name (name, stat_errno); - if (p_says_nonexistent[reverse ^ (i == NONE)]) + if (i == NONE && patch_get) + { + enum nametype nope = NONE; + + for (i = OLD; i <= INDEX; i++) + if (name[i]) + { + char const *cs; + char *getbuf; + char *diffbuf; + int readonly = outfile && strcmp (outfile, name[i]) != 0; + + if (nope == NONE || strcmp (name[nope], name[i]) != 0) + { + cs = (version_controller + (name[i], readonly, (struct stat *) 0, + &getbuf, &diffbuf)); + version_controlled[i] = !! cs; + if (cs) + { + if (version_get (name[i], cs, 0, readonly, + getbuf, &st[i])) + stat_errno[i] = 0; + else + version_controlled[i] = 0; + + free (getbuf); + free (diffbuf); + + if (! stat_errno[i]) + break; + } + } + + nope = i; + } + } + + if (p_says_nonexistent[reverse ^ (i == NONE || st[i].st_size == 0)]) { assert (i0 != NONE); if (ok_to_reverse ("The next patch%s would %s the file `%s',\nwhich %s!", reverse ? ", when reversed," : "", - i == NONE ? "delete" : "create", - name[i == NONE ? i0 : i], - i == NONE ? "does not exist" : "already exists")) + (i == NONE ? "delete" + : st[i].st_size == 0 ? "empty out" + : "create"), + name[i == NONE || st[i].st_size == 0 ? i0 : i], + (i == NONE ? "does not exist" + : st[i].st_size == 0 ? "is already empty" + : "already exists"))) reverse ^= 1; } @@ -493,6 +581,7 @@ intuit_diff_type() inname = name[i]; name[i] = 0; inerrno = stat_errno[i]; + invc = version_controlled[i]; instat = st[i]; } @@ -1533,7 +1622,8 @@ pch_swap() return TRUE; } -/* Return whether file WHICH (0 = old, 1 = new) appears to be nonexistent. */ +/* Return whether file WHICH (0 = old, 1 = new) appears to nonexistent. + Return 1 for empty, 2 for nonexistent. */ bool pch_says_nonexistent (which) @@ -1542,6 +1632,16 @@ pch_says_nonexistent (which) return p_says_nonexistent[which]; } +/* Return timestamp of patch header for file WHICH (0 = old, 1 = new), + or -1 if there was no timestamp or an error in the timestamp. */ + +time_t +pch_timestamp (which) + int which; +{ + return p_timestamp[which]; +} + /* Return the specified line position in the old file of the old context. */ LINENUM @@ -1665,6 +1765,7 @@ do_ed_script (ofp) copy_file (inname, TMPOUTNAME, instat.st_mode); sprintf (buf, "%s %s%s", ed_program, verbosity == VERBOSE ? "" : "- ", TMPOUTNAME); + fflush (stdout); pipefp = popen(buf, binary_transput ? "wb" : "w"); if (!pipefp) pfatal ("can't open pipe to `%s'", buf); @@ -1,6 +1,6 @@ /* reading patches */ -/* $Id: pch.h,v 1.7 1997/05/19 06:52:03 eggert Exp $ */ +/* $Id: pch.h,v 1.8 1997/06/13 06:28:37 eggert Exp $ */ LINENUM pch_end PARAMS ((void)); LINENUM pch_first PARAMS ((void)); @@ -18,6 +18,7 @@ char pch_char PARAMS ((LINENUM)); int another_hunk PARAMS ((enum diff, int)); int pch_says_nonexistent PARAMS ((int)); size_t pch_line_len PARAMS ((LINENUM)); +time_t pch_timestamp PARAMS ((int)); void do_ed_script PARAMS ((FILE *)); void open_patch_file PARAMS ((char const *)); void re_patch PARAMS ((void)); @@ -1,6 +1,6 @@ /* utility functions for `patch' */ -/* $Id: util.c,v 1.17 1997/05/30 08:03:48 eggert Exp $ */ +/* $Id: util.c,v 1.22 1997/06/13 06:28:37 eggert Exp $ */ /* Copyright 1986 Larry Wall @@ -25,18 +25,22 @@ If not, write to the Free Software Foundation, #define XTERN extern #include <common.h> #include <backupfile.h> +#include <quotearg.h> #include <version.h> #undef XTERN #define XTERN #include <util.h> -#include <time.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> @@ -77,7 +81,7 @@ move_file (from, to, mode, backup) struct stat to_st; int to_errno = ! backup ? -1 : stat (to, &to_st) == 0 ? 0 : errno; - if (! to_errno) + if (backup) { int try_makedirs_errno = 0; char *bakname; @@ -110,15 +114,36 @@ move_file (from, to, mode, backup) memory_fatal (); } - if (debug & 4) - say ("renaming `%s' to `%s'\n", to, bakname); - while (rename (to, bakname) != 0) + if (to_errno) { - if (errno != try_makedirs_errno) - pfatal ("can't rename `%s' to `%s'", to, bakname); - makedirs (bakname); - try_makedirs_errno = 0; + 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); } @@ -218,6 +243,159 @@ copy_file (from, to, mode) 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 * @@ -339,7 +517,7 @@ pfatal (format, va_alist) vararg_start (args, format); vfprintf (stderr, format, args); va_end (args); - fflush (stderr); + fflush (stderr); /* perror bypasses stdio on some hosts. */ errno = errnum; perror (" "); fflush (stderr); @@ -388,21 +566,22 @@ ask (format, va_alist) if (ttyfd == -2) { - ttyfd = open ("/dev/tty", O_RDONLY); - if (ttyfd < 0) - { - close (ttyfd); - for (ttyfd = STDERR_FILENO; 0 <= ttyfd; ttyfd--) - if (isatty (ttyfd)) - break; - } + /* 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'; - r = 1; + buf[1] = '\0'; } else { @@ -420,13 +599,14 @@ ask (format, va_alist) printf ("EOF\n"); else if (r < 0) { + perror ("tty read"); + fflush (stderr); close (ttyfd); ttyfd = -1; r = 0; } + buf[s + r] = '\0'; } - - buf[r] = '\0'; } /* Return nonzero if it OK to reverse a patch. */ @@ -442,7 +622,7 @@ ok_to_reverse (format, va_alist) { int r = 0; - if (noreverse || ! batch || verbosity != SILENT) + if (noreverse || ! (force && verbosity == SILENT)) { va_list args; vararg_start (args, format); @@ -452,14 +632,19 @@ ok_to_reverse (format, va_alist) if (noreverse) { - printf (" Ignoring it.\n"); + printf (" Skipping patch.\n"); skip_rest_of_patch = TRUE; r = 0; } - else if (batch) + else if (force) { if (verbosity != SILENT) - say (reverse ? " Ignoring -R.\n" : " Assuming -R.\n"); + printf (" Applying it anyway.\n"); + r = 0; + } + else if (batch) + { + say (reverse ? " Ignoring -R.\n" : " Assuming -R.\n"); r = 1; } else @@ -470,7 +655,11 @@ ok_to_reverse (format, va_alist) { ask ("Apply anyway? [n] "); if (*buf != 'y') - skip_rest_of_patch = TRUE; + { + if (verbosity != SILENT) + say ("Skipping patch.\n"); + skip_rest_of_patch = TRUE; + } } } @@ -484,6 +673,9 @@ static int const sigs[] = { #ifdef SIGHUP SIGHUP, #endif +#ifdef SIGPIPE + SIGPIPE, +#endif #ifdef SIGTERM SIGTERM, #endif @@ -493,8 +685,7 @@ static int const sigs[] = { #ifdef SIGXFSZ SIGXFSZ, #endif - SIGINT, - SIGPIPE + SIGINT }; #if !HAVE_SIGPROCMASK @@ -616,7 +807,7 @@ exit_with_signal (sig) sigemptyset (&s); sigaddset (&s, sig); sigprocmask (SIG_UNBLOCK, &s, (sigset_t *) 0); - kill (getpid (), sig); + raise (sig); exit (2); } @@ -626,6 +817,7 @@ systemic (command) { if (debug & 8) say ("+ %s\n", command); + fflush (stdout); return system (command); } @@ -633,7 +825,6 @@ systemic (command) /* These mkdir and rmdir substitutes are good enough for `patch'; they are not general emulators. */ -#include <quotearg.h> static int doprogram PARAMS ((char const *, char const *)); static int mkdir PARAMS ((char const *, mode_t)); static int rmdir PARAMS ((char const *)); @@ -793,18 +984,16 @@ init_time () /* Make filenames more reasonable. */ char * -fetchname (at, strip_leading, head_says_nonexistent) +fetchname (at, strip_leading, pstamp) char *at; int strip_leading; -int *head_says_nonexistent; +time_t *pstamp; { char *name; register char *t; int sleading = strip_leading; - int says_nonexistent = 0; + time_t stamp = (time_t) -1; - if (!at) - return 0; while (ISSPACE ((unsigned char) *at)) at++; if (debug & 128) @@ -823,15 +1012,21 @@ int *head_says_nonexistent; } else if (ISSPACE ((unsigned char) *t)) { - /* 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. */ - time_t stamp = str2time (t, initial_time, -24L * 60 * 60); - if (0 <= stamp && stamp <= 2 * 24L * 60 * 60) - says_nonexistent = 1; + 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; } @@ -843,22 +1038,22 @@ int *head_says_nonexistent; /* Allow files to be created by diffing against /dev/null. */ if (strcmp (at, "/dev/null") == 0) { - if (head_says_nonexistent) - *head_says_nonexistent = 1; + if (pstamp) + *pstamp = 0; return 0; } - if (head_says_nonexistent) - *head_says_nonexistent = says_nonexistent; + if (pstamp) + *pstamp = stamp; return savestr (name); } -VOID * +GENERIC_OBJECT * xmalloc (size) size_t size; { - register VOID *p = malloc (size); + register GENERIC_OBJECT *p = malloc (size); if (!p) memory_fatal (); return p; @@ -1,6 +1,6 @@ /* utility functions for `patch' */ -/* $Id: util.h,v 1.12 1997/05/19 06:52:03 eggert Exp $ */ +/* $Id: util.h,v 1.14 1997/06/13 06:28:37 eggert Exp $ */ int ok_to_reverse PARAMS ((char const *, ...)) __attribute__ ((format (printf, 1, 2))); void ask PARAMS ((char const *, ...)) __attribute__ ((format (printf, 1, 2))); @@ -11,9 +11,11 @@ void fatal PARAMS ((char const *, ...)) void pfatal PARAMS ((char const *, ...)) __attribute__ ((noreturn, format (printf, 1, 2))); -char *fetchname PARAMS ((char *, int, int *)); +char *fetchname PARAMS ((char *, int, time_t *)); char *savebuf PARAMS ((char const *, size_t)); char *savestr PARAMS ((char const *)); +char const *version_controller PARAMS ((char const *, int, struct stat const *, char **, char **)); +int version_get PARAMS ((char const *, char const *, int, int, char const *, struct stat *)); int create_file PARAMS ((char const *, int, mode_t)); int systemic PARAMS ((char const *)); void Fseek PARAMS ((FILE *, file_offset, int)); |