summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@suse.de>2009-03-12 15:14:29 +0100
committerAndreas Gruenbacher <agruen@suse.de>2009-03-12 15:14:29 +0100
commit1adb4535a31d825f10a5bd1ef10b52a7425073bd (patch)
tree1a9a12d04c92d4d93a4b7d8a09af635a8f93fa63
parentbcce1233902dc7a94623b3a90cd7920c44f22474 (diff)
downloadpatch-2.3.tar.gz
Import of patch-2.3.tar.gzv2.3
-rw-r--r--ChangeLog401
-rw-r--r--Makefile.in57
-rw-r--r--NEWS51
-rw-r--r--README6
-rw-r--r--acconfig.h4
-rw-r--r--addext.c37
-rw-r--r--argmatch.c33
-rw-r--r--backupfile.c67
-rw-r--r--basename.c16
-rw-r--r--common.h59
-rw-r--r--config.hin7
-rwxr-xr-xconfigure253
-rw-r--r--configure.in67
-rw-r--r--getopt.c321
-rw-r--r--getopt.h31
-rw-r--r--getopt1.c52
-rw-r--r--inp.c223
-rw-r--r--maketime.c388
-rw-r--r--maketime.h39
-rw-r--r--partime.c742
-rw-r--r--partime.h67
-rw-r--r--patch.c332
-rw-r--r--patch.man309
-rw-r--r--pc/chdirsaf.c34
-rw-r--r--pc/djgpp/README19
-rw-r--r--pc/djgpp/config.h139
-rw-r--r--pc/djgpp/config.sed35
-rw-r--r--pc/djgpp/configure.bat27
-rw-r--r--pch.c561
-rw-r--r--pch.h5
-rw-r--r--quotearg.c125
-rw-r--r--quotearg.h9
-rw-r--r--rename.c87
-rw-r--r--util.c462
-rw-r--r--util.h17
-rw-r--r--version.c6
36 files changed, 4194 insertions, 894 deletions
diff --git a/ChangeLog b/ChangeLog
index 0ff3627..c460c90 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,404 @@
+1997-05-30 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (VERSION), NEWS: Version 2.3 released.
+ * patch.man: Fix two font typos.
+ * util.c (doprogram): Fix misspelled decl.
+
+1997-05-26 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (VERSION): Bump to 2.2.93.
+
+ * pch.c (open_patch_file):
+ Fatal error if binary_transput and stdin is a tty.
+
+ * pc/djgpp/config.sed (chdirsaf.c):
+ Use sed instead of cp, since cp might not be installed.
+ * pc/djgpp/configure.bat:
+ Prepend %srcdir% to pathname of config.sed, for crosscompiles.
+
+1997-05-25 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (VERSION): Bump to 2.2.92.
+ (D_INO_IN_DIRENT): New macro.
+ * pc/djgpp/config.h, acconfig.h (D_INO_IN_DIRENT): New macro.
+ * backupfile.c (REAL_DIR_ENTRY):
+ Depend on D_INO_IN_DIRENT, not _POSIX_VERSION.
+
+ * addext.c (addext): Adjust slen when adjusting s for DOS 8.3 limit.
+ Do not use xxx.h -> xxxh~ hack.
+
+ * util.c: (move_file): Avoid makedirs test when possible even
+ if FILESYSTEM_PREFIX_LEN (p) is nonzero. Don't play
+ case-changing tricks to come up with backup file name; it's
+ not portable to case-insensitive file systems.
+ * common.h (ISLOWER): Remove.
+
+ * inp.c (scan_input): Don't use Plan A if (debug & 16).
+
+ * patch.c (shortopts): Add -g, -G.
+ (longopts): --help now maps to 132, not 'h', to avoid confusion.
+ (get_some_switches): Likewise.
+ Don't invoke setmode on input if --binary; wait until needed.
+ Don't ever invoke setmode on stdout.
+ * pch.c (open_patch_file): Setmode stdin to binary if binary_transput.
+
+ * patch.man: Fix documentation of backup file name to match behavior.
+ Add advice for ordering of patches of derived files.
+ Add /dev/tty to list of files used.
+ * README: Adjust instructions for building on DOS.
+ * pc/djgpp/README: Remove tentative wording.
+ * NEWS: The DOS port is now tested.
+ Backup file names are no longer computed by switching case.
+
+ * pc/chdirsaf.c (ERANGE): Include <errno.h> to define it.
+ (restore_wd): chdir unconditionally.
+ (chdir_safer): Invoke atexit successfully at most once.
+ * pc/djgpp/config.sed: Use chdirsaf.o, not pc/chdirsaf.o.
+ Replace CONFIG_HDRS, don't append.
+ Use $(srcdir) in CONFIG_STATUS.
+ Don't apply $(SHELL) to $(CONFIG_STATUS).
+ Append rules for chdirsaf.o, chdirsaf.c; clean chdirsaf.c at the end.
+ * pc/djgpp/configure.bat: Append CR to each line; DOS needs this.
+ Don't use | as sed s delimiter; DOS can't handle it.
+
+1997-05-21 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (VERSION): Bump to 2.2.91.
+
+ * pch.c (another_hunk):
+ Fix bug with computing size of prefix and suffix context
+ with ordinary context diffs. Report malformed patch if a unified diff
+ has nothing but context.
+
+ * inp.c (get_input_file):
+ Use patch_get, not backup_type, to decide whether to
+ get from RCS or SCCS. Use the word `get' in diagnostics.
+ * patch.c (main): Initialize patch_get from PATCH_GET.
+ Omit DEFAULT_VERSION_CONTROL hook; it just leads to nonstandarization.
+ (longopts, option_help, get_some_switches): Add support for -g, -G.
+ (option_help): Add bug report address.
+ * common.h (patch_get): New decl.
+ * patch.man: Add -g and -G options; use `get' instead of `check out'.
+ Add PATCH_GET. Recommend -Naur instead of -raNU2 for diff.
+ * NEWS: Describe -g, -G, PATCH_GET.
+
+ * version.c (copyright_string): Use only most recent copyright year,
+ as per GNU standards.
+
+ * 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.
+ (AC_TYPE_MODE_T): Add.
+
+ * pch.h (another_hunk): New parameter REV.
+ * 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.
+
+ * util.h (create_file): New function.
+ (copy_file): Now takes mode, not struct stat.
+ (makedirs): No longer exported.
+ (move_file): Now takes mode, not struct stat.
+ * util.c (makedirs): No longer exported.
+ (move_file): Accept mode of destination, not struct stat.
+ All callers changed.
+ Quote file names in diagnostics.
+ Create parent dir of destination if necessary.
+ Don't use ENOTDIR.
+ Don't unlink source; it will be unlinked later.
+ Unlink destination if FROM is zero.
+ (create_file): New function.
+ (copy_file): Accept mode of destination, not struct stat.
+ All callers changed.
+ Use create_file to create file.
+ (ok_to_reverse): Moved here from patch.c. Now accepts format and args;
+ all callers changed.
+ (mkdir): 2nd arg is now mode_t, for better compatibility.
+ (replace_slashes): Ignore slashes at the end of the filename.
+
+ * 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.
+
+ * pc/djgpp/config.h: Add comment for mode_t.
+
+ * pc/djgpp/README: Note that it's not tested.
+
+ * patch.man: PATCH_VERSION_CONTROL overrides VERSION_CONTROL.
+
+1997-05-15 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in: Add AC_PREREQ(2.12).
+ (VERSION): Bump to 2.2.8.
+ (ed_PROGRAM): Rename from ED_PROGRAM.
+
+ * pch.c (prefix_components): Support DOS file names better.
+ Fix typo that caused fn to almost always yield 0.
+
+ * util.c (<time.h>, <maketime.h>): Include.
+ (move_file, copy_file): Add support for DOS filenames.
+ Preserve mode of input files when creating temp files.
+ Add binary file support.
+ (doprogram, rmdir): New functions.
+ (mkdir): Use doprogram.
+ (replace_slashes): Add support for DOS filenames.
+ (removedirs): New function.
+ (init_time)): New function.
+ (initial_time): New var.
+ (fetchname): Add support for deleted files, DOS filenames.
+
+ * basename.c (FILESYSTEM_PREFIX_LEN, ISSLASH):
+ New macros, for DOS port.
+ (base_name): Use them.
+
+ * addext.c (HAVE_DOS_FILE_NAMES): New macro.
+ <limits.h>: Include if HAVE_LIMITS_H.
+ (addext): Handle hosts with DOS file name limits.
+
+ * common.h (LONG_MIN): New macro.
+ (FILESYSTEM_PREFIX_LEN, ISSLASH): New macros, for DOS port.
+ (ok_to_create_file): Remove.
+ (reverse): Now int.
+ (ok_to_reverse): New function decl.
+ (O_WRONLY, _O_BINARY, O_BINARY, O_CREAT, O_TRUNC): New macros.
+ (binary_transput): New var decl.
+
+ * Makefile.in (ed_PROGRAM): Renamed from ED_PROGRAM.
+ (CONFIG_HDRS, CONFIG_STATUS): New vars.
+ (SRCS): Add maketime.c, partime.c.
+ (OBJS): Likewise.
+ (HDRS): Add maketime.h, partime.h.
+ (DISTFILES_PC, DISTFILES_PC_DJGPP): New vars.
+ (Makefile, config.status): Use CONFIG_STATUS, not config.status.
+ (clean): Remove */*.o.
+ (dist): Add pc and pc/djgpp subdirectories.
+ ($(OBJS)): Depend on $(CONFIG_HDRS) instead of config.h.
+ (maketime.o, partime.o): New rules.
+ (util.o): Depend on maketime.h.
+
+ * patch.c (main):
+ Call init_time. Add DEFAULT_VERSION_CONTROL hook for people who
+ prefer the old ways. Build temp file names before we might invoke cleanup.
+ Add support for deleted files and clean up the patch-swapping code a bit.
+ Delete empty ancestors of deleted files.
+ When creating temporaries, use file modes of original files.
+ (longopts, get_some_switches): New option --binary.
+ (get_some_switches): Report non-errno errors with `fatal', not `pfatal'.
+ (create_output_file): New function, which preserves modes of original files
+ and supports binary transput.
+ (init_output, init_reject): Use it.
+ (ok_to_reverse): New function.
+ (TMPDIR): New macro.
+ (make_temp): Use $TMPDIR, $TMP, $TEMP, or TMPDIR, whichever comes first.
+
+ * pch.c (p_says_nonexistent): New var.
+ (open_patch_file): Add binary transput support.
+ Apply stat to file names retrieved from user.
+ Reject them if they don't exist.
+ (intuit_diff_type): Add support for deleting files.
+ Don't treat trivial directories any differently.
+ Avoid stating the same file twice in common case of context diffs.
+ (prefix_components): Don't treat trivial directories any differently.
+ Add support for DOS filenames.
+ (pch_says_nonexistent): New function.
+ (do_ed_script): Preserve mode of input files when creating temp files.
+ Add support for binary transput.
+
+ * pch.h (pch_says_nonexistent): New decl.
+
+ * util.h (replace_slashes): No longer exported.
+ (fetchname): Add support for deleted files.
+ (copy_file, move_file): Add support for preserving file modes.
+ (init_time, removedirs): New functions.
+
+ * argmatch.c: Converge with fileutils.
+
+ * backupfile.c: Converge with fileutils.
+ (find_backup_file_name): Treat .~N~ suffix just like any other suffix
+ when handling file names that are too long.
+
+ * inp.c:
+ In messages, put quotes around file names and spaces around "--".
+ (get_input_file): Allow files to be deleted. Do the expense of
+ makedirs only if we can't create the file.
+ (plan_a, plan_b): Add support for binary transput.
+
+ * pc/chdirsaf.c, pc/djgpp/README, pc/djgpp/config.h, pc/djgpp/config.sed, pc/djgpp/configure.bat, pc/quotearg.c:
+ New file.
+
+ * NEWS:
+ New methods for removing files; adjust file name intuition again.
+ Add description of MS-DOS and MS-Windows ports.
+
+ * patch.man:
+ Simplify file name intuition slightly (no distinction for trivial dirs).
+ Add --binary. Describe how files and directories are deleted.
+ Suggest diff -a. Include caveats about what context diffs cannot represent.
+
+1997-05-06 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (VERSION): Now 2.2.7.
+ (CPPFLAGS, LDFLAGS, LIBS): If the user has not set any of these vars,
+ prefer support for large files if available.
+
+ * common.h (_LARGEFILE_SOURCE): Define.
+ (file_offset): New typedef.
+ (file_seek, file_tell): New macros.
+
+ * patch.c (main):
+ Remove empty files by default unless POSIXLY_CORRECT is set.
+
+ * util.c, util.h (Fseek):
+ Use file_offset instead of long, for portability to large-file hosts.
+
+ * pch.c: (p_base, p_start, next_intuit_at, skip_to, open_patch_file,
+ intuit_diff_type, another_hunk, incomplete_line, do_ed_script):
+ Use file_offset instead of long, for portability to large-file hosts.
+ (prefix_components): Renamed from path_name_components; count only
+ nontrivial prefix components, and take a 2nd EXISTING arg.
+ (existing_prefix_components): Remove; subsumed by prefix_components.
+ (intuit_diff_type): When creating files, try for the creation of the
+ fewest directories.
+
+ * configure.in (VERSION): Now 2.2.6.
+
+ * pch.c (existing_prefix_components): New function.
+ (intuit_diff_type): When creating a file, use a name whose existing
+ directory prefix contains the most nontrivial path name components.
+ (best_name): Don't check for null 2nd arg.
+
+ * util.h (replace_slashes): New decl.
+
+ * util.c (replace_slashes): Now external.
+ (fetchname): Don't assume chars are nonnegative.
+
+ * patch.man:
+ When creating a file, use a name whose existing directory prefix
+ contains the most nontrivial path name components.
+ Add advice for creating patches and applying them.
+
+1997-05-06 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (VERSION): Now 2.2.6.
+
+ * pch.c (existing_prefix_components): New function.
+ (intuit_diff_type): When creating a file, use a name whose existing
+ directory prefix contains the most nontrivial path name components.
+ (best_name): Don't check for null 2nd arg.
+
+ * util.h (replace_slashes): New decl.
+ * util.c (replace_slashes): Now external.
+ (fetchname): Don't assume chars are nonnegative.
+
+ * patch.man: Describe above change to pch.c.
+ Add advice for creating patches and applying them.
+
+1997-05-05 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (VERSION): Update to 2.2.5.
+
+ * quotearg.h, quotearg.c: New files.
+ * Makefile.in (SRCS, OBJS, HDRS): Mention new files.
+ (inp.o, util.o): Now depends on quotearg.h.
+ (quotearg.o): New makefile rule.
+
+ * common.h (posixly_correct): New var.
+ * patch.c (main): Initialize it.
+ If ! posixly_correct, default backup type is now `existing'.
+ SIMPLE_BACKUP_SUFFIX no longer affects backup type.
+ (backup): Remove var.
+
+ * util.h: (countdirs): Remove.
+ (systemic): New decl.
+ * util.c (move_file): Try making the parent directory of TO
+ if backup prefix or suffix contain a slash.
+ (ask): Remove arbitrary limit on size of result.
+ (systemic): New function.
+ (mkdir): Work even if arg contains shell metacharacters.
+ (replace_slashes): Return 0 if none were replaced.
+ Don't replace slash after . or .. since it's redundant.
+ (countdirs): Remove.
+ (makedirs): Ignore mkdir failures.
+
+ * NEWS, patch.man: More POSIXLY_CORRECT adjustments.
+ Describe new rules for how file names are intuited.
+
1997-04-17 Paul Eggert <eggert@twinsun.com>
* configure.in (VERSION): Version 2.2 released.
diff --git a/Makefile.in b/Makefile.in
index 38982aa..d517ed5 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -24,7 +24,7 @@ VPATH = @srcdir@
@SET_MAKE@
CC = @CC@
-ED_PROGRAM = @ED_PROGRAM@
+ed_PROGRAM = @ed_PROGRAM@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
@@ -48,21 +48,28 @@ man1dir = $(prefix)/man/man1
# Extension (not including `.') for the manual page filenames.
man1ext = .1
+# Hooks for nonstandard builds.
+CONFIG_HDRS = config.h
+CONFIG_STATUS = config.status
+
#### End of system configuration section. ####
SHELL = /bin/sh
LIBSRCS = getopt.c getopt1.c memchr.c rename.c
-SRCS = addext.c argmatch.c backupfile.c basename.c inp.c \
- patch.c pch.c util.c version.c $(LIBSRCS)
-OBJS = addext.o argmatch.o backupfile.o basename.o inp.o \
- patch.o pch.o util.o version.o $(LIBOBJS)
+SRCS = addext.c argmatch.c backupfile.c basename.c inp.c maketime.c \
+ partime.c patch.c pch.c quotearg.c util.c version.c $(LIBSRCS)
+OBJS = addext.o argmatch.o backupfile.o basename.o inp.o maketime.o \
+ partime.o patch.o pch.o quotearg.o util.o version.o $(LIBOBJS)
HDRS = argmatch.h backupfile.h common.h getopt.h \
- inp.h pch.h util.h version.h
+ inp.h maketime.h partime.h pch.h quotearg.h util.h version.h
MISC = COPYING ChangeLog INSTALL Makefile.in NEWS README \
acconfig.h config.hin configure configure.in \
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
all:: patch
@@ -70,7 +77,7 @@ info::
check::
installcheck::
-COMPILE = $(CC) -c $(CPPFLAGS) $(DEFS) -DED_PROGRAM=\"$(ED_PROGRAM)\" \
+COMPILE = $(CC) -c $(CPPFLAGS) $(DEFS) -Ded_PROGRAM=\"$(ed_PROGRAM)\" \
-I. -I$(srcdir) $(CFLAGS)
.c.o:
@@ -90,10 +97,10 @@ installdirs::
uninstall::
rm -f $(bindir)/patch $(man1dir)/patch$(man1ext)
-Makefile: Makefile.in config.status
- $(SHELL) config.status
+Makefile: Makefile.in $(CONFIG_STATUS)
+ $(SHELL) $(CONFIG_STATUS)
config.status: configure
- $(SHELL) config.status --recheck
+ $(SHELL) $(CONFIG_STATUS) --recheck
configure: configure.in
cd $(srcdir) && autoconf
config.hin: configure.in acconfig.h
@@ -106,13 +113,13 @@ TAGS: $(HDRS) patchlevel.h $(SRCS)
etags $(HDRS) patchlevel.h $(SRCS)
clean::
- rm -f patch *.o core
+ rm -f patch *.o */*.o core
mostlyclean:: clean
distclean:: clean
rm -f Makefile config.cache config.log config.status config.h
- rm -f patchlevel.h
+ rm -f patchlevel.h
maintainer-clean::
@echo "This command is intended for maintainers to use;"
@@ -120,22 +127,28 @@ maintainer-clean::
$(MAKE) distclean
rm -f TAGS
-dist:: $(DISTFILES)
- rm -rf $(PACKAGE)-$(VERSION)
- mkdir $(PACKAGE)-$(VERSION)
- ln $(DISTFILES) $(PACKAGE)-$(VERSION)
- tar -chf - $(PACKAGE)-$(VERSION) | \
- gzip -9 >$(PACKAGE)-$(VERSION).tar.gz
- rm -rf $(PACKAGE)-$(VERSION)
+PV = $(PACKAGE)-$(VERSION)
+
+dist:: $(DISTFILES) $(DISTFILES_PC) $(DISTFILES_PC_DJGPP)
+ rm -rf $(PV)
+ mkdir $(PV) $(PV)/pc $(PV)/pc/djgpp
+ ln $(DISTFILES) $(PV)
+ ln $(DISTFILES_PC) $(PV)/pc
+ ln $(DISTFILES_PC_DJGPP) $(PV)/pc/djgpp
+ tar -chf - $(PV) | gzip -9 >$(PV).tar.gz
+ rm -rf $(PV)
-$(OBJS): config.h
+$(OBJS): $(CONFIG_HDRS)
addext.o: backupfile.h
argmatch.o: argmatch.h
backupfile.o: argmatch.h backupfile.h
basename.o: backupfile.h
getopt.o getopt1.o: getopt.h
-inp.o: backupfile.h common.h inp.h util.h pch.h
+maketime.o: maketime.h partime.h
+inp.o: backupfile.h common.h inp.h pch.h quotearg.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
-util.o: backupfile.h common.h util.h version.h
+quotearg.o: quotearg.h
+util.o: backupfile.h common.h maketime.h quotearg.h util.h version.h
version.o: common.h patchlevel.h util.h version.h
diff --git a/NEWS b/NEWS
index 7022862..f708cef 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,57 @@ 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'.
+Changes in version 2.3:
+
+* Unless the POSIXLY_CORRECT environment variable is set:
+
+ - `patch' now distinguishes more accurately between empty and
+ 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.
+ - 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 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 new --binary option makes `patch' read and write files in binary mode.
+ This option has no effect on POSIX-compliant hosts;
+ it is useful only in on operating systems like DOS
+ that distinguish between text and binary I/O.
+
+* The environment variables TMP and TEMP are consulted for the name of
+ the temporary directory if TMPDIR is not set.
+
+* A port to MS-DOS and MS-Windows is available; see the `pc' directory.
+
+* Backup file names are no longer ever computed by uppercasing characters,
+ since this isn't portable to systems with case-insensitive file names.
+
Changes in version 2.2:
* Arbitrary limits removed (e.g. line length, file name length).
diff --git a/README b/README
index 609221b..e3aa259 100644
--- a/README
+++ b/README
@@ -14,9 +14,9 @@ for `patch' is obsolete; this should be fixed in diffutils 2.8.
In the mean time, see `patch --help', or consult the man page
in this distribution.
-See the file INSTALL for compilation and installation instructions for Unix.
-
-For non-Unix systems, copy config.hin to config.h and change
+For GNU and Unix build and installation instructions, see the file INSTALL.
+For MS-DOS using DJGPP tools, see the file pc/djgpp/README.
+For other systems, copy config.hin to config.h and change
#undef statements in it to #define as appropriate for your system,
and copy Makefile.in to Makefile and set the variables that are
enclosed in @ signs as appropriate for your system.
diff --git a/acconfig.h b/acconfig.h
index 4033163..f6fb072 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -3,5 +3,9 @@
the patch configure.in can define.
autoheader copies the comments into config.hin. */
+/* 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
diff --git a/addext.c b/addext.c
index b32a90d..56d0e4f 100644
--- a/addext.c
+++ b/addext.c
@@ -22,12 +22,22 @@
# include <config.h>
#endif
+#ifndef HAVE_DOS_FILE_NAMES
+#define HAVE_DOS_FILE_NAMES 0
+#endif
#ifndef HAVE_LONG_FILE_NAMES
#define HAVE_LONG_FILE_NAMES 0
#endif
#include <backupfile.h>
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+#ifndef _POSIX_NAME_MAX
+#define _POSIX_NAME_MAX 14
+#endif
+
#include <sys/types.h>
#if HAVE_STRING_H
# include <string.h>
@@ -53,10 +63,7 @@ addext (filename, ext, e)
long slen_max = -1;
#if HAVE_PATHCONF && defined _PC_NAME_MAX
-#ifndef _POSIX_NAME_MAX
-#define _POSIX_NAME_MAX 14
-#endif
- if (slen + extlen <= _POSIX_NAME_MAX)
+ if (slen + extlen <= _POSIX_NAME_MAX && ! HAVE_DOS_FILE_NAMES)
/* The file name is so short there's no need to call pathconf. */
slen_max = _POSIX_NAME_MAX;
else if (s == filename)
@@ -72,17 +79,27 @@ addext (filename, ext, e)
if (slen_max < 0)
slen_max = HAVE_LONG_FILE_NAMES ? 255 : 14;
+ if (HAVE_DOS_FILE_NAMES && slen_max <= 12)
+ {
+ /* Live within DOS's 8.3 limit. */
+ char *dot = strchr (s, '.');
+ if (dot)
+ {
+ slen -= dot + 1 - s;
+ s = dot + 1;
+ slen_max = 3;
+ }
+ else
+ slen_max = 8;
+ extlen = 9; /* Don't use EXT. */
+ }
+
if (slen + extlen <= slen_max)
strcpy (s + slen, ext);
else
{
- if (slen_max <= slen) {
- /* Try to preserve difference between .h .c etc. */
- if (slen == slen_max && s[slen - 2] == '.')
- s[slen - 2] = s[slen - 1];
-
+ if (slen_max <= slen)
slen = slen_max - 1;
- }
s[slen] = e;
s[slen + 1] = 0;
}
diff --git a/argmatch.c b/argmatch.c
index 51d8b95..aa55933 100644
--- a/argmatch.c
+++ b/argmatch.c
@@ -24,8 +24,9 @@
#include <argmatch.h>
-#include <stdio.h>
#include <sys/types.h>
+
+#include <stdio.h>
#if HAVE_STRING_H
# include <string.h>
#else
@@ -35,16 +36,17 @@
/* If ARG is an unambiguous match for an element of the
null-terminated array OPTLIST, return the index in OPTLIST
of the matched element, else -1 if it does not match any element
- or -2 if it is ambiguous (is a prefix of more than one element). */
+ or -2 if it is ambiguous (is a prefix of more than one element). */
int
argmatch (arg, optlist)
- char const *arg;
- char const * const *optlist;
+ const char *arg;
+ const char *const *optlist;
{
- int i; /* Temporary index in OPTLIST. */
- size_t arglen; /* Length of ARG. */
- int matchind = -1; /* Index of first nonexact match. */
+ int i; /* Temporary index in OPTLIST. */
+ size_t arglen; /* Length of ARG. */
+ int matchind = -1; /* Index of first nonexact match. */
+ int ambiguous = 0; /* If nonzero, multiple nonexact match(es). */
arglen = strlen (arg);
@@ -60,28 +62,31 @@ argmatch (arg, optlist)
/* First nonexact match found. */
matchind = i;
else
- /* Subsequent nonexact match found. */
- matchind = -2;
+ /* Second nonexact match found. */
+ ambiguous = 1;
}
}
- return matchind;
+ if (ambiguous)
+ return -2;
+ else
+ return matchind;
}
/* Error reporting for argmatch.
KIND is a description of the type of entity that was being matched.
VALUE is the invalid value that was given.
- PROBLEM is the return value from argmatch. */
+ PROBLEM is the return value from argmatch. */
void
invalid_arg (kind, value, problem)
- char const *kind;
- char const *value;
+ const char *kind;
+ const char *value;
int problem;
{
fprintf (stderr, "%s: ", program_name);
if (problem == -1)
fprintf (stderr, "invalid");
- else /* Assume -2. */
+ else /* Assume -2. */
fprintf (stderr, "ambiguous");
fprintf (stderr, " %s `%s'\n", kind, value);
}
diff --git a/backupfile.c b/backupfile.c
index 266d392..4b0f2ec 100644
--- a/backupfile.c
+++ b/backupfile.c
@@ -81,14 +81,20 @@ char *malloc ();
add 1 for integer division truncation; add 1 more for a minus sign. */
#define INT_STRLEN_BOUND(t) ((sizeof (t) * CHAR_BIT - 1) * 302 / 1000 + 2)
-#define ISDIGIT(c) (((unsigned) (c) - '0') <= 9)
-
-#ifdef _POSIX_VERSION
-/* POSIX does not require that the d_ino field be present, and some
- systems do not provide it. */
-# define REAL_DIR_ENTRY(dp) 1
-#else
+/* ISDIGIT differs from isdigit, as follows:
+ - Its arg may be any int or unsigned int; it need not be an unsigned char.
+ - It's guaranteed to evaluate its argument exactly once.
+ - It's typically faster.
+ Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
+ only '0' through '9' are digits. Prefer ISDIGIT to isdigit unless
+ it's important to use the locale's definition of `digit' even when the
+ host does not conform to Posix. */
+#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
+
+#if D_INO_IN_DIRENT
# define REAL_DIR_ENTRY(dp) ((dp)->d_ino != 0)
+#else
+# define REAL_DIR_ENTRY(dp) 1
#endif
/* Which type of backup file names are generated. */
@@ -96,10 +102,10 @@ enum backup_type backup_type = none;
/* The extension added to file names to produce a simple (as opposed
to numbered) backup file name. */
-char const *simple_backup_suffix = ".orig";
+const char *simple_backup_suffix = ".orig";
-static int max_backup_version __BACKUPFILE_P ((char const *, char const *));
-static int version_number __BACKUPFILE_P ((char const *, char const *, size_t));
+static int max_backup_version __BACKUPFILE_P ((const char *, const char *));
+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.
@@ -108,17 +114,20 @@ static int version_number __BACKUPFILE_P ((char const *, char const *, size_t));
char *
find_backup_file_name (file)
- char const *file;
+ const char *file;
{
size_t backup_suffix_size_max;
+ size_t file_len = strlen (file);
+ size_t numbered_suffix_size_max = INT_STRLEN_BOUND (int) + 4;
char *s;
+ const char *suffix = simple_backup_suffix;
/* Allow room for simple or `.~N~' backups. */
backup_suffix_size_max = strlen (simple_backup_suffix) + 1;
- if (HAVE_DIR && backup_suffix_size_max < INT_STRLEN_BOUND (int) + 4)
- backup_suffix_size_max = INT_STRLEN_BOUND (int) + 4;
+ if (HAVE_DIR && backup_suffix_size_max < numbered_suffix_size_max)
+ backup_suffix_size_max = numbered_suffix_size_max;
- s = malloc (strlen (file) + backup_suffix_size_max);
+ s = malloc (file_len + backup_suffix_size_max + numbered_suffix_size_max);
if (s)
{
strcpy (s, file);
@@ -133,14 +142,15 @@ find_backup_file_name (file)
highest_backup = max_backup_version (file + dir_len, s);
if (! (backup_type == numbered_existing && highest_backup == 0))
{
- sprintf (s, "%s.~%d~", file, highest_backup + 1);
- return s;
+ char *numbered_suffix = s + (file_len + backup_suffix_size_max);
+ sprintf (numbered_suffix, ".~%d~", highest_backup + 1);
+ suffix = numbered_suffix;
}
strcpy (s, file);
}
#endif /* HAVE_DIR */
- addext (s, simple_backup_suffix, '~');
+ addext (s, suffix, '~');
}
return s;
}
@@ -149,11 +159,13 @@ find_backup_file_name (file)
/* Return the number of the highest-numbered backup file for file
FILE in directory DIR. If there are no numbered backups
- of FILE in DIR, or an error occurs reading DIR, return 0. */
+ of FILE in DIR, or an error occurs reading DIR, return 0.
+ */
static int
max_backup_version (file, dir)
- char const *file, *dir;
+ const char *file;
+ const char *dir;
{
DIR *dirp;
struct dirent *dp;
@@ -177,22 +189,23 @@ max_backup_version (file, dir)
if (this_version > highest_version)
highest_version = this_version;
}
- if (CLOSEDIR (dirp) != 0)
+ if (CLOSEDIR (dirp))
return 0;
return highest_version;
}
/* If BACKUP is a numbered backup of BASE, return its version number;
- otherwise return 0. BASE_LENGTH is the length of BASE. */
+ otherwise return 0. BASE_LENGTH is the length of BASE.
+ */
static int
version_number (base, backup, base_length)
- char const *base;
- char const *backup;
+ const char *base;
+ const char *backup;
size_t base_length;
{
int version;
- char const *p;
+ const char *p;
version = 0;
if (strncmp (base, backup, base_length) == 0
@@ -208,12 +221,12 @@ version_number (base, backup, base_length)
}
#endif /* HAVE_DIR */
-static char const * const backup_args[] =
+static const char * const backup_args[] =
{
"never", "simple", "nil", "existing", "t", "numbered", 0
};
-static enum backup_type const backup_types[] =
+static const enum backup_type backup_types[] =
{
simple, simple, numbered_existing, numbered_existing, numbered, numbered
};
@@ -223,7 +236,7 @@ static enum backup_type const backup_types[] =
enum backup_type
get_version (version)
- char const *version;
+ const char *version;
{
int i;
diff --git a/basename.c b/basename.c
index 1cc7854..8d18a8f 100644
--- a/basename.c
+++ b/basename.c
@@ -6,6 +6,14 @@
#include <backupfile.h>
+#ifndef FILESYSTEM_PREFIX_LEN
+#define FILESYSTEM_PREFIX_LEN(f) 0
+#endif
+
+#ifndef ISSLASH
+#define ISSLASH(c) ((c) == '/')
+#endif
+
/* In general, we can't use the builtin `basename' function if available,
since it has different meanings in different environments.
In some environments the builtin `basename' modifies its argument. */
@@ -14,11 +22,11 @@ char *
base_name (name)
char const *name;
{
- char const *base = name;
+ char const *base = name += FILESYSTEM_PREFIX_LEN (name);
- while (*name)
- if (*name++ == '/')
- base = name;
+ for (; *name; name++)
+ if (ISSLASH (*name))
+ base = name + 1;
return (char *) base;
}
diff --git a/common.h b/common.h
index 4b67425..97fdc9a 100644
--- a/common.h
+++ b/common.h
@@ -1,6 +1,6 @@
/* common definitions for `patch' */
-/* $Id: common.h,v 1.10 1997/04/10 05:09:53 eggert Exp $ */
+/* $Id: common.h,v 1.16 1997/05/26 05:34:43 eggert Exp $ */
/*
Copyright 1986, 1988 Larry Wall
@@ -33,6 +33,12 @@ If not, write to the Free Software Foundation,
# define volatile
# endif
#endif
+
+/* Enable support for fseeko and ftello on hosts
+ where it is available but is turned off by default.
+ This must be defined before any system file is included. */
+#define _LARGEFILE_SOURCE 1
+
#include <config.h>
#include <assert.h>
@@ -80,6 +86,9 @@ If not, write to the Free Software Foundation,
#ifndef INT_MAX
#define INT_MAX 2147483647
#endif
+#ifndef LONG_MIN
+#define LONG_MIN (-1-2147483647L)
+#endif
#include <ctype.h>
/* CTYPE_DOMAIN (C) is nonzero if the unsigned char C can safely be given
@@ -89,9 +98,6 @@ If not, write to the Free Software Foundation,
#else
#define CTYPE_DOMAIN(c) ((unsigned) (c) <= 0177)
#endif
-#ifndef ISLOWER
-#define ISLOWER(c) (CTYPE_DOMAIN (c) && islower (c))
-#endif
#ifndef ISSPACE
#define ISSPACE(c) (CTYPE_DOMAIN (c) && isspace (c))
#endif
@@ -101,6 +107,15 @@ If not, write to the Free Software Foundation,
#endif
+#ifndef FILESYSTEM_PREFIX_LEN
+#define FILESYSTEM_PREFIX_LEN(f) 0
+#endif
+
+#ifndef ISSLASH
+#define ISSLASH(c) ((c) == '/')
+#endif
+
+
/* constants */
/* AIX predefines these. */
@@ -135,8 +150,8 @@ XTERN bool using_plan_a; /* try to keep everything in memory */
XTERN char *inname;
XTERN int inerrno;
XTERN struct stat instat;
-XTERN bool ok_to_create_file;
XTERN bool dry_run;
+XTERN bool posixly_correct;
XTERN char const *origprae;
XTERN char const *origbase;
@@ -152,11 +167,13 @@ XTERN int debug;
#endif
XTERN bool force;
XTERN bool batch;
-XTERN bool reverse;
+XTERN bool noreverse;
+XTERN int reverse;
XTERN enum { DEFAULT_VERBOSITY, SILENT, VERBOSE } verbosity;
XTERN bool skip_rest_of_patch;
XTERN int strippath;
XTERN bool canonicalize;
+XTERN int patch_get;
enum diff
{
@@ -235,6 +252,15 @@ off_t lseek ();
#ifndef STDERR_FILENO
#define STDERR_FILENO 2
#endif
+#if _LFS_LARGEFILE
+ typedef off_t file_offset;
+# define file_seek fseeko
+# define file_tell ftello
+#else
+ typedef long file_offset;
+# define file_seek fseek
+# define file_tell ftell
+#endif
#if HAVE_FCNTL_H
# include <fcntl.h>
@@ -242,6 +268,27 @@ off_t lseek ();
#ifndef O_RDONLY
#define O_RDONLY 0
#endif
+#ifndef O_WRONLY
+#define O_WRONLY 1
+#endif
#ifndef O_RDWR
#define O_RDWR 2
#endif
+#ifndef _O_BINARY
+#define _O_BINARY 0
+#endif
+#ifndef O_BINARY
+#define O_BINARY _O_BINARY
+#endif
+#ifndef O_CREAT
+#define O_CREAT 0
+#endif
+#ifndef O_TRUNC
+#define O_TRUNC 0
+#endif
+
+#if HAVE_SETMODE
+ XTERN int binary_transput; /* O_BINARY if binary i/o is desired */
+#else
+# define binary_transput 0
+#endif
diff --git a/config.hin b/config.hin
index 83c7fc5..50d722e 100644
--- a/config.hin
+++ b/config.hin
@@ -25,6 +25,9 @@
/* 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
@@ -44,6 +47,10 @@
/* 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
diff --git a/configure b/configure
index c234335..2905122 100755
--- a/configure
+++ b/configure
@@ -540,7 +540,7 @@ test "$program_transform_name" = "" && program_transform_name="s,x,x,"
PACKAGE=patch
-VERSION=2.2
+VERSION=2.3
@@ -881,43 +881,78 @@ else
SET_MAKE="MAKE=${MAKE-make}"
fi
+# Use ed_PROGRAM, not ED_PROGRAM,
+# because <errno.h> reserves symbols starting with `E'.
# Extract the first word of "ed", so it can be a program name with args.
set dummy ed; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:888: checking for $ac_word" >&5
-if eval "test \"`echo '$''{'ac_cv_path_ED_PROGRAM'+set}'`\" = set"; then
+echo "configure:890: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_ed_PROGRAM'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
- case "$ED_PROGRAM" in
+ case "$ed_PROGRAM" in
/*)
- ac_cv_path_ED_PROGRAM="$ED_PROGRAM" # Let the user override the test with a path.
+ ac_cv_path_ed_PROGRAM="$ed_PROGRAM" # Let the user override the test with a path.
;;
*)
IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
for ac_dir in $PATH; do
test -z "$ac_dir" && ac_dir=.
if test -f $ac_dir/$ac_word; then
- ac_cv_path_ED_PROGRAM="$ac_dir/$ac_word"
+ ac_cv_path_ed_PROGRAM="$ac_dir/$ac_word"
break
fi
done
IFS="$ac_save_ifs"
- test -z "$ac_cv_path_ED_PROGRAM" && ac_cv_path_ED_PROGRAM="ed"
+ test -z "$ac_cv_path_ed_PROGRAM" && ac_cv_path_ed_PROGRAM="ed"
;;
esac
fi
-ED_PROGRAM="$ac_cv_path_ED_PROGRAM"
-if test -n "$ED_PROGRAM"; then
- echo "$ac_t""$ED_PROGRAM" 1>&6
+ed_PROGRAM="$ac_cv_path_ed_PROGRAM"
+if test -n "$ed_PROGRAM"; then
+ echo "$ac_t""$ed_PROGRAM" 1>&6
else
echo "$ac_t""no" 1>&6
fi
+# If available, prefer support for large files unless the user specified
+# one of the CPPFLAGS, LDFLAGS, or LIBS variables.
+echo $ac_n "checking whether large file support needs explicit enabling""... $ac_c" 1>&6
+echo "configure:923: checking whether large file support needs explicit enabling" >&5
+ac_getconfs=''
+ac_result=yes
+ac_set=''
+ac_shellvars='CPPFLAGS LDFLAGS LIBS'
+for ac_shellvar in $ac_shellvars; do
+ case $ac_shellvar in
+ CPPFLAGS) ac_lfsvar=LFS_CFLAGS ;;
+ *) ac_lfsvar=LFS_$ac_shellvar ;;
+ esac
+ eval test '"${'$ac_shellvar'+set}"' = set && ac_set=$ac_shellvar
+ (getconf $ac_lfsvar) >/dev/null 2>&1 || { ac_result=no; break; }
+ ac_getconf=`getconf $ac_lfsvar`
+ ac_getconfs=$ac_getconfs$ac_getconf
+ eval ac_test_$ac_shellvar=\$ac_getconf
+done
+case "$ac_result$ac_getconfs" in
+yes) ac_result=no ;;
+esac
+case "$ac_result$ac_set" in
+yes?*) ac_result="yes, but $ac_set is already set, so use its settings"
+esac
+echo "$ac_t""$ac_result" 1>&6
+case $ac_result in
+yes)
+ for ac_shellvar in $ac_shellvars; do
+ eval $ac_shellvar=\$ac_test_$ac_shellvar
+ done ;;
+esac
+
echo $ac_n "checking for AIX""... $ac_c" 1>&6
-echo "configure:919: checking for AIX" >&5
+echo "configure:954: checking for AIX" >&5
cat > conftest.$ac_ext <<EOF
-#line 921 "configure"
+#line 956 "configure"
#include "confdefs.h"
#ifdef _AIX
yes
@@ -940,17 +975,17 @@ rm -f conftest*
ac_safe=`echo "minix/config.h" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6
-echo "configure:944: checking for minix/config.h" >&5
+echo "configure:979: checking for minix/config.h" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 949 "configure"
+#line 984 "configure"
#include "confdefs.h"
#include <minix/config.h>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:954: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:989: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out`
if test -z "$ac_err"; then
rm -rf conftest*
@@ -988,7 +1023,7 @@ EOF
fi
echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6
-echo "configure:992: checking for POSIXized ISC" >&5
+echo "configure:1027: checking for POSIXized ISC" >&5
if test -d /etc/conf/kconfig.d &&
grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1
then
@@ -1010,12 +1045,12 @@ fi
echo $ac_n "checking for working const""... $ac_c" 1>&6
-echo "configure:1014: checking for working const" >&5
+echo "configure:1049: checking for working const" >&5
if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1019 "configure"
+#line 1054 "configure"
#include "confdefs.h"
int main() {
@@ -1064,7 +1099,7 @@ ccp = (char const *const *) p;
; return 0; }
EOF
-if { (eval echo configure:1068: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1103: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_c_const=yes
else
@@ -1090,12 +1125,12 @@ for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
-echo "configure:1094: checking for $ac_hdr that defines DIR" >&5
+echo "configure:1129: checking for $ac_hdr that defines DIR" >&5
if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1099 "configure"
+#line 1134 "configure"
#include "confdefs.h"
#include <sys/types.h>
#include <$ac_hdr>
@@ -1103,7 +1138,7 @@ int main() {
DIR *dirp = 0;
; return 0; }
EOF
-if { (eval echo configure:1107: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1142: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
eval "ac_cv_header_dirent_$ac_safe=yes"
else
@@ -1128,7 +1163,7 @@ done
# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
if test $ac_header_dirent = dirent.h; then
echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
-echo "configure:1132: checking for opendir in -ldir" >&5
+echo "configure:1167: checking for opendir in -ldir" >&5
ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -1136,7 +1171,7 @@ else
ac_save_LIBS="$LIBS"
LIBS="-ldir $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 1140 "configure"
+#line 1175 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
@@ -1147,7 +1182,7 @@ int main() {
opendir()
; return 0; }
EOF
-if { (eval echo configure:1151: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:1186: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -1169,7 +1204,7 @@ fi
else
echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
-echo "configure:1173: checking for opendir in -lx" >&5
+echo "configure:1208: checking for opendir in -lx" >&5
ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -1177,7 +1212,7 @@ else
ac_save_LIBS="$LIBS"
LIBS="-lx $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 1181 "configure"
+#line 1216 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
@@ -1188,7 +1223,7 @@ int main() {
opendir()
; return 0; }
EOF
-if { (eval echo configure:1192: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:1227: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -1211,12 +1246,12 @@ fi
fi
echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
-echo "configure:1215: checking for ANSI C header files" >&5
+echo "configure:1250: checking for ANSI C header files" >&5
if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1220 "configure"
+#line 1255 "configure"
#include "confdefs.h"
#include <stdlib.h>
#include <stdarg.h>
@@ -1224,7 +1259,7 @@ else
#include <float.h>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1228: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1263: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out`
if test -z "$ac_err"; then
rm -rf conftest*
@@ -1241,7 +1276,7 @@ rm -f conftest*
if test $ac_cv_header_stdc = yes; then
# SunOS 4.x string.h does not declare mem*, contrary to ANSI.
cat > conftest.$ac_ext <<EOF
-#line 1245 "configure"
+#line 1280 "configure"
#include "confdefs.h"
#include <string.h>
EOF
@@ -1259,7 +1294,7 @@ fi
if test $ac_cv_header_stdc = yes; then
# ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
cat > conftest.$ac_ext <<EOF
-#line 1263 "configure"
+#line 1298 "configure"
#include "confdefs.h"
#include <stdlib.h>
EOF
@@ -1280,7 +1315,7 @@ if test "$cross_compiling" = yes; then
:
else
cat > conftest.$ac_ext <<EOF
-#line 1284 "configure"
+#line 1319 "configure"
#include "confdefs.h"
#include <ctype.h>
#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
@@ -1291,7 +1326,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
exit (0); }
EOF
-if { (eval echo configure:1295: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1330: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
then
:
else
@@ -1318,17 +1353,17 @@ for ac_hdr in fcntl.h limits.h string.h unistd.h varargs.h
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:1322: checking for $ac_hdr" >&5
+echo "configure:1357: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1327 "configure"
+#line 1362 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1332: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1367: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out`
if test -z "$ac_err"; then
rm -rf conftest*
@@ -1355,13 +1390,46 @@ fi
done
+echo $ac_n "checking for mode_t""... $ac_c" 1>&6
+echo "configure:1395: checking for mode_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_mode_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1400 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "mode_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_mode_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_mode_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_mode_t" 1>&6
+if test $ac_cv_type_mode_t = no; then
+ cat >> confdefs.h <<\EOF
+#define mode_t int
+EOF
+
+fi
+
echo $ac_n "checking for off_t""... $ac_c" 1>&6
-echo "configure:1360: checking for off_t" >&5
+echo "configure:1428: checking for off_t" >&5
if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1365 "configure"
+#line 1433 "configure"
#include "confdefs.h"
#include <sys/types.h>
#if STDC_HEADERS
@@ -1389,12 +1457,12 @@ EOF
fi
echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
-echo "configure:1393: checking return type of signal handlers" >&5
+echo "configure:1461: checking return type of signal handlers" >&5
if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1398 "configure"
+#line 1466 "configure"
#include "confdefs.h"
#include <sys/types.h>
#include <signal.h>
@@ -1411,7 +1479,7 @@ int main() {
int i;
; return 0; }
EOF
-if { (eval echo configure:1415: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1483: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_type_signal=void
else
@@ -1430,12 +1498,12 @@ EOF
echo $ac_n "checking for size_t""... $ac_c" 1>&6
-echo "configure:1434: checking for size_t" >&5
+echo "configure:1502: checking for size_t" >&5
if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1439 "configure"
+#line 1507 "configure"
#include "confdefs.h"
#include <sys/types.h>
#if STDC_HEADERS
@@ -1465,7 +1533,7 @@ 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:1469: checking for working memchr" >&5
+echo "configure:1537: 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
@@ -1474,12 +1542,12 @@ else
ac_cv_func_memchr=no
else
cat > conftest.$ac_ext <<EOF
-#line 1478 "configure"
+#line 1546 "configure"
#include "confdefs.h"
#include <string.h>
main () { exit (memchr ("", 0, 0) != 0 || memchr ("", 1, 0) != 0); }
EOF
-if { (eval echo configure:1483: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1551: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
then
ac_cv_func_memchr=yes
else
@@ -1501,12 +1569,12 @@ EOF
fi
echo $ac_n "checking for getopt_long""... $ac_c" 1>&6
-echo "configure:1505: checking for getopt_long" >&5
+echo "configure:1573: 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 1510 "configure"
+#line 1578 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char getopt_long(); below. */
@@ -1529,7 +1597,7 @@ getopt_long();
; return 0; }
EOF
-if { (eval echo configure:1533: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:1601: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_func_getopt_long=yes"
else
@@ -1553,12 +1621,12 @@ fi
for ac_func in _doprintf isascii memcmp mkdir mktemp pathconf sigaction sigprocmask sigsetmask
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:1557: checking for $ac_func" >&5
+echo "configure:1625: 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 1562 "configure"
+#line 1630 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */
@@ -1581,7 +1649,7 @@ $ac_func();
; return 0; }
EOF
-if { (eval echo configure:1585: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:1653: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
@@ -1608,12 +1676,12 @@ done
for ac_func in memchr rename
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:1612: checking for $ac_func" >&5
+echo "configure:1680: 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 1617 "configure"
+#line 1685 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */
@@ -1636,7 +1704,7 @@ $ac_func();
; return 0; }
EOF
-if { (eval echo configure:1640: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:1708: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
@@ -1663,7 +1731,7 @@ done
echo $ac_n "checking whether closedir returns void""... $ac_c" 1>&6
-echo "configure:1667: checking whether closedir returns void" >&5
+echo "configure:1735: 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
@@ -1671,13 +1739,13 @@ else
ac_cv_func_closedir_void=yes
else
cat > conftest.$ac_ext <<EOF
-#line 1675 "configure"
+#line 1743 "configure"
#include "confdefs.h"
#include <sys/types.h>
#include <$ac_header_dirent>
int closedir(); main() { exit(closedir(opendir(".")) != 0); }
EOF
-if { (eval echo configure:1681: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1749: \"$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
@@ -1700,12 +1768,12 @@ EOF
fi
echo $ac_n "checking for vprintf""... $ac_c" 1>&6
-echo "configure:1704: checking for vprintf" >&5
+echo "configure:1772: 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 1709 "configure"
+#line 1777 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char vprintf(); below. */
@@ -1728,7 +1796,7 @@ vprintf();
; return 0; }
EOF
-if { (eval echo configure:1732: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:1800: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_func_vprintf=yes"
else
@@ -1752,12 +1820,12 @@ fi
if test "$ac_cv_func_vprintf" != yes; then
echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
-echo "configure:1756: checking for _doprnt" >&5
+echo "configure:1824: 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 1761 "configure"
+#line 1829 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char _doprnt(); below. */
@@ -1780,7 +1848,7 @@ _doprnt();
; return 0; }
EOF
-if { (eval echo configure:1784: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:1852: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_func__doprnt=yes"
else
@@ -1806,7 +1874,7 @@ fi
echo $ac_n "checking for long file names""... $ac_c" 1>&6
-echo "configure:1810: checking for long file names" >&5
+echo "configure:1878: 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
@@ -1850,6 +1918,55 @@ EOF
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
+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"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#if HAVE_DIRENT_H
+# include <dirent.h>
+#else
+# define dirent direct
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+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
+ rm -rf conftest*
+ patch_cv_sys_d_ino_in_dirent=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ patch_cv_sys_d_ino_in_dirent=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$patch_cv_sys_d_ino_in_dirent" 1>&6
+if test $patch_cv_sys_d_ino_in_dirent = yes; then
+ cat >> confdefs.h <<\EOF
+#define D_INO_IN_DIRENT 1
+EOF
+
+fi
+
trap '' 1 2 15
cat > confcache <<\EOF
# This file is a shell script that caches the results of configure
@@ -1988,7 +2105,7 @@ s%@CPP@%$CPP%g
s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
s%@INSTALL_DATA@%$INSTALL_DATA%g
s%@SET_MAKE@%$SET_MAKE%g
-s%@ED_PROGRAM@%$ED_PROGRAM%g
+s%@ed_PROGRAM@%$ed_PROGRAM%g
s%@LIBOBJS@%$LIBOBJS%g
CEOF
diff --git a/configure.in b/configure.in
index 3c674ec..902f83f 100644
--- a/configure.in
+++ b/configure.in
@@ -2,12 +2,13 @@
# Copyright 1993, 1997 Free Software Foundation, Inc.
dnl Process this file with autoconf to produce a configure script.
+AC_PREREQ(2.12)
AC_INIT(patch.c)
AC_CONFIG_HEADER(config.h:config.hin)
AC_ARG_PROGRAM
PACKAGE=patch
-VERSION=2.2
+VERSION=2.3
AC_SUBST(PACKAGE)
AC_SUBST(VERSION)
@@ -15,7 +16,41 @@ AC_PROG_CC
AC_PROG_CPP
AC_PROG_INSTALL
AC_PROG_MAKE_SET
-AC_PATH_PROG(ED_PROGRAM, ed, ed)
+# Use ed_PROGRAM, not ED_PROGRAM,
+# because <errno.h> reserves symbols starting with `E'.
+AC_PATH_PROG(ed_PROGRAM, ed, ed)
+
+# If available, prefer support for large files unless the user specified
+# one of the CPPFLAGS, LDFLAGS, or LIBS variables.
+AC_MSG_CHECKING(whether large file support needs explicit enabling)
+ac_getconfs=''
+ac_result=yes
+ac_set=''
+ac_shellvars='CPPFLAGS LDFLAGS LIBS'
+for ac_shellvar in $ac_shellvars; do
+ case $ac_shellvar in
+ CPPFLAGS) ac_lfsvar=LFS_CFLAGS ;;
+ *) ac_lfsvar=LFS_$ac_shellvar ;;
+ esac
+ eval test '"${'$ac_shellvar'+set}"' = set && ac_set=$ac_shellvar
+ (getconf $ac_lfsvar) >/dev/null 2>&1 || { ac_result=no; break; }
+ ac_getconf=`getconf $ac_lfsvar`
+ ac_getconfs=$ac_getconfs$ac_getconf
+ eval ac_test_$ac_shellvar=\$ac_getconf
+done
+case "$ac_result$ac_getconfs" in
+yes) ac_result=no ;;
+esac
+case "$ac_result$ac_set" in
+yes?*) ac_result="yes, but $ac_set is already set, so use its settings"
+esac
+AC_MSG_RESULT($ac_result)
+case $ac_result in
+yes)
+ for ac_shellvar in $ac_shellvars; do
+ eval $ac_shellvar=\$ac_test_$ac_shellvar
+ done ;;
+esac
AC_AIX
AC_MINIX
@@ -27,6 +62,7 @@ AC_HEADER_DIRENT
AC_HEADER_STDC
AC_CHECK_HEADERS(fcntl.h limits.h string.h unistd.h varargs.h)
+AC_TYPE_MODE_T
AC_TYPE_OFF_T
AC_TYPE_SIGNAL
AC_TYPE_SIZE_T
@@ -54,4 +90,31 @@ AC_FUNC_VPRINTF
AC_SYS_LONG_FILE_NAMES
+AC_MSG_CHECKING([for d_ino member in directory struct])
+AC_CACHE_VAL(patch_cv_sys_d_ino_in_dirent,
+[AC_TRY_LINK([
+#include <sys/types.h>
+#if HAVE_DIRENT_H
+# include <dirent.h>
+#else
+# define dirent direct
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+],
+ [struct dirent dp; dp.d_ino = 0;],
+ patch_cv_sys_d_ino_in_dirent=yes,
+ patch_cv_sys_d_ino_in_dirent=no)])
+AC_MSG_RESULT($patch_cv_sys_d_ino_in_dirent)
+if test $patch_cv_sys_d_ino_in_dirent = yes; then
+ AC_DEFINE(D_INO_IN_DIRENT)
+fi
+
AC_OUTPUT(Makefile)
diff --git a/getopt.c b/getopt.c
index 56ab9f2..300f86d 100644
--- a/getopt.c
+++ b/getopt.c
@@ -3,23 +3,26 @@
"Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
before changing it!
- Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 1996
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97
Free Software Foundation, Inc.
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
+NOTE: The canonical source of this file is maintained with the GNU C Library.
+Bugs can be reported to bug-glibc@prep.ai.mit.edu.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- USA. */
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+USA. */
/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
Ditto for AIX 3.2 and <stdlib.h>. */
@@ -49,7 +52,15 @@
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
-#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#ifndef ELIDE_CODE
/* This needs to come after some library #include
@@ -68,7 +79,7 @@
#endif
#endif
-#if defined (_WIN32) && !defined (__CYGWIN32__)
+#if defined (WIN32) && !defined (__CYGWIN32__)
/* It's not Unix, really. See? Capital letters. */
#include <windows.h>
#define getpid() GetCurrentProcessId()
@@ -115,14 +126,20 @@ char *optarg = NULL;
On entry to `getopt', zero means this is the first call; initialize.
- When `getopt' returns EOF, this is the index of the first of the
+ When `getopt' returns -1, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
-/* XXX 1003.2 says this must be 1 before any call. */
-int optind = 0;
+/* 1003.2 says this must be 1 before any call. */
+int optind = 1;
+
+/* Formerly, initialization of getopt depended on optind==0, which
+ causes problems with re-calling getopt as programs generally don't
+ know that. */
+
+int __getopt_initialized = 0;
/* The next char to be scanned in the option-element
in which the last option character we returned was found.
@@ -171,7 +188,7 @@ int optopt = '?';
The special argument `--' forces an end of option-scanning regardless
of the value of `ordering'. In the case of RETURN_IN_ORDER, only
- `--' can cause `getopt' to return EOF with `optind' != ARGC. */
+ `--' can cause `getopt' to return -1 with `optind' != ARGC. */
static enum
{
@@ -232,12 +249,46 @@ extern int strlen (const char *);
static int first_nonopt;
static int last_nonopt;
+#ifdef _LIBC
/* Bash 2.0 gives us an environment variable containing flags
indicating ARGV elements that should not be considered arguments. */
-static const char *nonoption_flags;
+/* Defined in getopt_init.c */
+extern char *__getopt_nonoption_flags;
+
+static int nonoption_flags_max_len;
static int nonoption_flags_len;
+static int original_argc;
+static char *const *original_argv;
+
+extern pid_t __libc_pid;
+
+/* Make sure the environment variable bash 2.0 puts in the environment
+ is valid for the getopt call we must make sure that the ARGV passed
+ to getopt is that one passed to the process. */
+static void
+__attribute__ ((unused))
+store_args_and_env (int argc, char *const *argv)
+{
+ /* XXX This is no good solution. We should rather copy the args so
+ that we can compare them later. But we must not use malloc(3). */
+ original_argc = argc;
+ original_argv = argv;
+}
+text_set_element (__libc_subinit, store_args_and_env);
+
+# define SWAP_FLAGS(ch1, ch2) \
+ if (nonoption_flags_len > 0) \
+ { \
+ char __tmp = __getopt_nonoption_flags[ch1]; \
+ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \
+ __getopt_nonoption_flags[ch2] = __tmp; \
+ }
+#else /* !_LIBC */
+# define SWAP_FLAGS(ch1, ch2)
+#endif /* _LIBC */
+
/* Exchange two adjacent subsequences of ARGV.
One subsequence is elements [first_nonopt,last_nonopt)
which contains all the non-options that have been skipped so far.
@@ -265,6 +316,28 @@ exchange (argv)
It leaves the longer segment in the right place overall,
but it consists of two parts that need to be swapped next. */
+#ifdef _LIBC
+ /* First make sure the handling of the `__getopt_nonoption_flags'
+ string can work normally. Our top argument must be in the range
+ of the string. */
+ if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len)
+ {
+ /* We must extend the array. The user plays games with us and
+ presents new arguments. */
+ char *new_str = malloc (top + 1);
+ if (new_str == NULL)
+ nonoption_flags_len = nonoption_flags_max_len = 0;
+ else
+ {
+ memcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len);
+ memset (&new_str[nonoption_flags_max_len], '\0',
+ top + 1 - nonoption_flags_max_len);
+ nonoption_flags_max_len = top + 1;
+ __getopt_nonoption_flags = new_str;
+ }
+ }
+#endif
+
while (top > middle && middle > bottom)
{
if (top - middle > middle - bottom)
@@ -279,6 +352,7 @@ exchange (argv)
tem = argv[bottom + i];
argv[bottom + i] = argv[top - (middle - bottom) + i];
argv[top - (middle - bottom) + i] = tem;
+ SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
}
/* Exclude the moved bottom segment from further swapping. */
top -= len;
@@ -295,6 +369,7 @@ exchange (argv)
tem = argv[bottom + i];
argv[bottom + i] = argv[middle + i];
argv[middle + i] = tem;
+ SWAP_FLAGS (bottom + i, middle + i);
}
/* Exclude the moved top segment from further swapping. */
bottom += len;
@@ -310,17 +385,19 @@ exchange (argv)
/* Initialize the internal data when the first call is made. */
#if defined (__STDC__) && __STDC__
-static const char *_getopt_initialize (const char *);
+static const char *_getopt_initialize (int, char *const *, const char *);
#endif
static const char *
-_getopt_initialize (optstring)
+_getopt_initialize (argc, argv, optstring)
+ int argc;
+ char *const *argv;
const char *optstring;
{
/* Start processing options with ARGV-element 1 (since ARGV-element 0
is the program name); the sequence of previously skipped
non-option ARGV-elements is empty. */
- first_nonopt = last_nonopt = optind = 1;
+ first_nonopt = last_nonopt = optind;
nextchar = NULL;
@@ -343,20 +420,38 @@ _getopt_initialize (optstring)
else
ordering = PERMUTE;
- if (posixly_correct == NULL)
+#ifdef _LIBC
+ if (posixly_correct == NULL
+ && argc == original_argc && argv == original_argv)
{
- /* Bash 2.0 puts a special variable in the environment for each
- command it runs, specifying which ARGV elements are the results of
- file name wildcard expansion and therefore should not be
- considered as options. */
- char var[100];
- sprintf (var, "_%d_GNU_nonoption_argv_flags_", getpid ());
- nonoption_flags = getenv (var);
- if (nonoption_flags == NULL)
- nonoption_flags_len = 0;
- else
- nonoption_flags_len = strlen (nonoption_flags);
+ if (nonoption_flags_max_len == 0)
+ {
+ if (__getopt_nonoption_flags == NULL
+ || __getopt_nonoption_flags[0] == '\0')
+ nonoption_flags_max_len = -1;
+ else
+ {
+ const char *orig_str = __getopt_nonoption_flags;
+ int len = nonoption_flags_max_len = strlen (orig_str);
+ if (nonoption_flags_max_len < argc)
+ nonoption_flags_max_len = argc;
+ __getopt_nonoption_flags =
+ (char *) malloc (nonoption_flags_max_len);
+ if (__getopt_nonoption_flags == NULL)
+ nonoption_flags_max_len = -1;
+ else
+ {
+ memcpy (__getopt_nonoption_flags, orig_str, len);
+ memset (&__getopt_nonoption_flags[len], '\0',
+ nonoption_flags_max_len - len);
+ }
+ }
+ }
+ nonoption_flags_len = nonoption_flags_max_len;
}
+ else
+ nonoption_flags_len = 0;
+#endif
return optstring;
}
@@ -374,7 +469,7 @@ _getopt_initialize (optstring)
updating `optind' and `nextchar' so that the next call to `getopt' can
resume the scan with the following option character or ARGV-element.
- If there are no more option characters, `getopt' returns `EOF'.
+ If there are no more option characters, `getopt' returns -1.
Then `optind' is the index in ARGV of the first ARGV-element
that is not an option. (The ARGV-elements have been permuted
so that those that are not options now come last.)
@@ -428,18 +523,25 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
{
optarg = NULL;
- if (optind == 0)
+ if (optind == 0 || !__getopt_initialized)
{
- optstring = _getopt_initialize (optstring);
- optind = 1; /* Don't scan ARGV[0], the program name. */
+ if (optind == 0)
+ optind = 1; /* Don't scan ARGV[0], the program name. */
+ optstring = _getopt_initialize (argc, argv, optstring);
+ __getopt_initialized = 1;
}
/* Test whether ARGV[optind] points to a non-option argument.
Either it does not have option syntax, or there is an environment flag
- from the shell indicating it is not an option. */
+ from the shell indicating it is not an option. The later information
+ is only used when the used in the GNU libc. */
+#ifdef _LIBC
#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \
|| (optind < nonoption_flags_len \
- && nonoption_flags[optind] == '1'))
+ && __getopt_nonoption_flags[optind] == '1'))
+#else
+#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#endif
if (nextchar == NULL || *nextchar == '\0')
{
@@ -497,7 +599,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
that we previously skipped, so the caller will digest them. */
if (first_nonopt != last_nonopt)
optind = first_nonopt;
- return EOF;
+ return -1;
}
/* If we have come to a non-option and did not permute it,
@@ -506,7 +608,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
if (NONOPTION_P)
{
if (ordering == REQUIRE_ORDER)
- return EOF;
+ return -1;
optarg = argv[optind++];
return 1;
}
@@ -542,7 +644,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
const struct option *pfound = NULL;
int exact = 0;
int ambig = 0;
- int indfound;
+ int indfound = -1;
int option_index;
for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
@@ -553,7 +655,8 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp (p->name, nextchar, nameend - nextchar))
{
- if (nameend - nextchar == strlen (p->name))
+ if ((unsigned int) (nameend - nextchar)
+ == (unsigned int) strlen (p->name))
{
/* Exact match found. */
pfound = p;
@@ -689,6 +792,130 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
optopt = c;
return '?';
}
+ /* Convenience. Treat POSIX -W foo same as long option --foo */
+ if (temp[0] == 'W' && temp[1] == ';')
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = 0;
+ int option_index;
+
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, _("%s: option requires an argument -- %c\n"),
+ argv[0], c);
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ return c;
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+
+ /* optarg is now the argument, see if it's in the
+ table of longopts. */
+
+ for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, nextchar, nameend - nextchar))
+ {
+ if ((unsigned int) (nameend - nextchar) == strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = nameend + 1;
+ else
+ {
+ if (opterr)
+ fprintf (stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf (stderr,
+ _("%s: option `%s' requires an argument\n"),
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ nextchar = NULL;
+ return 'W'; /* Let the application handle it. */
+ }
if (temp[1] == ':')
{
if (temp[2] == ':')
@@ -751,7 +978,7 @@ getopt (argc, argv, optstring)
0);
}
-#endif /* _LIBC or not __GNU_LIBRARY__. */
+#endif /* Not ELIDE_CODE. */
#ifdef TEST
@@ -771,7 +998,7 @@ main (argc, argv)
int this_option_optind = optind ? optind : 1;
c = getopt (argc, argv, "abc:d:0123456789");
- if (c == EOF)
+ if (c == -1)
break;
switch (c)
diff --git a/getopt.h b/getopt.h
index 0de1881..69256fd 100644
--- a/getopt.h
+++ b/getopt.h
@@ -1,20 +1,23 @@
/* Declarations for getopt.
- Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
+ Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc.
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
+NOTE: The canonical source of this file is maintained with the GNU C Library.
+Bugs can be reported to bug-glibc@prep.ai.mit.edu.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- USA. */
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+USA. */
#ifndef _GETOPT_H
#define _GETOPT_H 1
@@ -37,7 +40,7 @@ extern char *optarg;
On entry to `getopt', zero means this is the first call; initialize.
- When `getopt' returns EOF, this is the index of the first of the
+ When `getopt' returns -1, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
diff --git a/getopt1.c b/getopt1.c
index 9d394e6..6507ba1 100644
--- a/getopt1.c
+++ b/getopt1.c
@@ -1,21 +1,23 @@
/* getopt_long and getopt_long_only entry points for GNU getopt.
- Copyright (C) 1987, 88, 89, 90, 91, 92, 1993, 1994
- Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- USA. */
+ Copyright (C) 1987,88,89,90,91,92,93,94,96,97 Free Software Foundation, Inc.
+
+NOTE: The canonical source of this file is maintained with the GNU C Library.
+Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+USA. */
#ifdef HAVE_CONFIG_H
#include <config.h>
@@ -41,15 +43,21 @@
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
-#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#ifndef ELIDE_CODE
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
#include <stdlib.h>
-#else
-char *getenv ();
#endif
#ifndef NULL
@@ -84,7 +92,7 @@ getopt_long_only (argc, argv, options, long_options, opt_index)
}
-#endif /* _LIBC or not __GNU_LIBRARY__. */
+#endif /* Not ELIDE_CODE. */
#ifdef TEST
@@ -115,7 +123,7 @@ main (argc, argv)
c = getopt_long (argc, argv, "abc:d:0123456789",
long_options, &option_index);
- if (c == EOF)
+ if (c == -1)
break;
switch (c)
diff --git a/inp.c b/inp.c
index 7bf497f..3db5f59 100644
--- a/inp.c
+++ b/inp.c
@@ -1,6 +1,6 @@
/* inputting files to be patched */
-/* $Id: inp.c,v 1.9 1997/04/17 16:15:48 eggert Exp $ */
+/* $Id: inp.c,v 1.14 1997/05/26 05:34:43 eggert Exp $ */
/*
Copyright 1986, 1988 Larry Wall
@@ -26,20 +26,24 @@ 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>
-#define SCCSPREFIX "s."
-#define GET "get '%s'"
-#define GET_LOCKED "get -e '%s'"
-#define SCCSDIFF "get -p '%s' | diff - '%s%s' >/dev/null"
+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";
-#define RCSSUFFIX ",v"
-#define CHECKOUT "co '%s%s'"
-#define CHECKOUT_LOCKED "co -l '%s%s'"
-#define RCSDIFF "rcsdiff '%s%s' > /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 */
@@ -81,13 +85,13 @@ re_input()
}
}
-/* Constuct the line index, somehow or other. */
+/* Construct the line index, somehow or other. */
void
scan_input(filename)
char *filename;
{
- using_plan_a = plan_a (filename);
+ using_plan_a = ! (debug & 16) && plan_a (filename);
if (!using_plan_a)
plan_b(filename);
switch (verbosity)
@@ -96,12 +100,12 @@ char *filename;
break;
case VERBOSE:
- say ("Patching file %s using Plan %s...\n",
+ say ("Patching file `%s' using Plan %s...\n",
filename, using_plan_a ? "A" : "B");
break;
case DEFAULT_VERBOSITY:
- say ("patching file %s\n", filename);
+ say ("patching file `%s'\n", filename);
break;
}
}
@@ -120,17 +124,17 @@ report_revision (found_revision)
else if (force)
{
if (verbosity != SILENT)
- say ("Warning: this file doesn't appear to be the %s version--patching anyway.\n",
+ say ("Warning: this file doesn't appear to be the %s version -- patching anyway.\n",
revision);
}
else if (batch)
{
- fatal ("this file doesn't appear to be the %s version--aborting.",
+ fatal ("This file doesn't appear to be the %s version -- aborting.",
revision);
}
else
{
- ask ("This file doesn't appear to be the %s version--patch anyway? [n] ",
+ ask ("This file doesn't appear to be the %s version -- patch anyway? [n] ",
revision);
if (*buf != 'y')
fatal ("aborted");
@@ -144,59 +148,40 @@ get_input_file (filename, outname)
char const *outname;
{
int elsewhere = strcmp (filename, outname);
- char const *dotslash;
if (inerrno == -1)
inerrno = stat (inname, &instat) == 0 ? 0 : errno;
- if (inerrno && ok_to_create_file) {
- int fd;
- if (verbosity == VERBOSE)
- say ("(Creating file %s...)\n", inname);
- if (dry_run) {
- inerrno = 0;
- instat.st_mode = 0;
- instat.st_size = 0;
- return;
- }
- makedirs (inname);
- fd = creat (inname, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
- if (fd < 0)
- inerrno = errno;
- else {
- inerrno = fstat (fd, &instat) == 0 ? 0 : errno;
- if (close (fd) != 0)
- inerrno = errno;
- }
- }
- /* For nonexistent or read-only files, look for RCS or SCCS versions. */
- if (backup_type == numbered_existing
+ /* Perhaps look for RCS or SCCS versions. */
+ if (patch_get
&& (inerrno
|| (! elsewhere
&& (/* No one can write to it. */
(instat.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) == 0
- /* I can't write to it. */
+ /* Only the owner (who's not me) can write to it. */
|| ((instat.st_mode & (S_IWGRP|S_IWOTH)) == 0
- && instat.st_uid != getuid ()))))) {
- register char *s;
+ && instat.st_uid != geteuid ()))))) {
struct stat cstat;
char const *cs = 0;
- char const *filebase;
- size_t dir_len;
- char *lbuf = xmalloc (strlen (filename) + 100);
-
- strcpy (lbuf, filename);
- dir_len = base_name (lbuf) - lbuf;
- filebase = filename + dir_len;
-
- /* Put any leading path into `s'.
- Leave room in lbuf for the diff command. */
- s = lbuf + 20;
- memcpy (s, filename, dir_len);
- dotslash = *filename=='-' ? "./" : "";
-
-#define try1(f,a1) (sprintf (s + dir_len, f, a1), stat (s, &cstat) == 0)
-#define try2(f,a1,a2) (sprintf (s + dir_len, f, a1,a2), stat (s, &cstat) == 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))
@@ -204,35 +189,65 @@ get_input_file (filename, outname)
/* 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)))) {
- sprintf (buf, elsewhere ? CHECKOUT : CHECKOUT_LOCKED,
- dotslash, filename);
- sprintf (lbuf, RCSDIFF, dotslash, filename);
+ || 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)) {
- sprintf (buf, elsewhere ? GET : GET_LOCKED, s);
- sprintf (lbuf, SCCSDIFF, s, dotslash, filename);
+
+ 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)
- fatal ("can't find %s", filename);
+
+ } 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) {
if (!inerrno) {
- if ((instat.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) != 0)
- /* The owner can write to it. */
- fatal ("file %s seems to be locked by somebody else under %s",
+ if (!elsewhere
+ && (instat.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) != 0)
+ /* Somebody can write to it. */
+ fatal ("file `%s' seems to be locked by somebody else under %s",
filename, cs);
/* It might be checked out unlocked. See if it's safe to
check out the default version locked. */
if (verbosity == VERBOSE)
- say ("Comparing file %s to default %s version...\n",
+ say ("Comparing file `%s' to default %s version...\n",
filename, cs);
- if (system (lbuf) != 0)
+ if (systemic (diffbuf) != 0)
{
- say ("warning: patching file %s, which does not match default %s version\n",
+ say ("warning: patching file `%s', which does not match default %s version\n",
filename, cs);
cs = 0;
}
@@ -242,23 +257,30 @@ get_input_file (filename, outname)
if (dry_run)
{
if (inerrno)
- fatal ("Cannot dry run on nonexistent version-controlled file `%s'; invoke `%s' and try again.",
+ fatal ("can't do dry run on nonexistent version-controlled file `%s'; invoke `%s' and try again",
filename, buf);
}
else
{
if (verbosity == VERBOSE)
- say ("Checking out file %s from %s...\n", filename, cs);
- if (system (buf) != 0 || stat (filename, &instat) != 0)
- fatal ("can't check out file %s from %s", filename, cs);
+ 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 (lbuf);
+ free (trybuf);
}
- if (!S_ISREG (instat.st_mode))
- fatal ("%s is not a regular file--can't patch", filename);
+
+ if (inerrno)
+ {
+ instat.st_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
+ instat.st_size = 0;
+ }
+ else if (! S_ISREG (instat.st_mode))
+ fatal ("`%s' is not a regular file -- can't patch", filename);
}
@@ -288,19 +310,30 @@ plan_a(filename)
buffer = (char *) (ptr + (size + 2));
/* Read the input file, but don't bother reading it if it's empty.
- During dry runs, empty files may not actually exist. */
+ When creating files, the files do not actually exist. */
if (size)
{
- int ifd = open (filename, O_RDONLY);
+ int ifd = open (filename, O_RDONLY|binary_transput);
+ size_t buffered = 0, n;
if (ifd < 0)
- pfatal ("can't open file %s", filename);
- if (read (ifd, buffer, size) != size)
+ pfatal ("can't open file `%s'", filename);
+ while (size - buffered != 0
+ && (n = read (ifd, buffer + buffered, size - buffered)) != 0)
{
- /* Perhaps size is too large for this host. */
- close (ifd);
- free (ptr);
- return FALSE;
+ if (n == -1)
+ {
+ /* Perhaps size is too large for this host. */
+ close (ifd);
+ free (ptr);
+ return FALSE;
+ }
+ buffered += n;
}
+
+ /* Some non-POSIX hosts exaggerate st_size in text mode;
+ or the file may have shrunk! */
+ size = buffered;
+
if (close (ifd) != 0)
read_fatal ();
}
@@ -363,13 +396,11 @@ plan_b(filename)
register size_t revlen;
register LINENUM line;
- if (dry_run)
+ if (instat.st_size == 0)
filename = "/dev/null";
- if (! (ifp = fopen (filename, "r")))
- pfatal ("can't open file %s", filename);
- tifd = creat (TMPINNAME, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
- if (tifd < 0)
- pfatal ("can't open file %s", TMPINNAME);
+ 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);
i = 0;
len = 0;
maxlen = 1;
@@ -448,10 +479,6 @@ plan_b(filename)
if (write (tifd, tibuf[0], tibufsize) != tibufsize)
write_fatal ();
input_lines = line - 1;
- if (close (tifd) != 0)
- write_fatal ();
- if ((tifd = open (TMPINNAME, O_RDONLY)) < 0)
- pfatal ("can't reopen file %s", TMPINNAME);
}
/* Fetch a line from the input file. */
diff --git a/maketime.c b/maketime.c
new file mode 100644
index 0000000..263a4da
--- /dev/null
+++ b/maketime.c
@@ -0,0 +1,388 @@
+/* Convert struct partime into time_t. */
+
+/* Copyright 1992, 1993, 1994, 1995, 1997 Paul Eggert
+ Distributed under license by the Free Software Foundation, Inc.
+
+ This file is part of RCS.
+
+ RCS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ RCS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with RCS; see the file COPYING.
+ If not, write to the Free Software Foundation,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Report problems and direct all questions to:
+
+ rcs-bugs@cs.purdue.edu
+
+ */
+
+#if has_conf_h
+# include <conf.h>
+#else
+# if HAVE_CONFIG_H
+# include <config.h>
+# else
+# ifndef __STDC__
+# define const
+# endif
+# endif
+# if HAVE_LIMITS_H
+# include <limits.h>
+# endif
+# ifndef LONG_MIN
+# define LONG_MIN (-1-2147483647L)
+# endif
+# if STDC_HEADERS
+# include <stdlib.h>
+# endif
+# include <time.h>
+# ifdef __STDC__
+# define P(x) x
+# else
+# define P(x) ()
+# endif
+#endif
+
+#include <partime.h>
+#include <maketime.h>
+
+char const maketId[] =
+ "$Id: maketime.c,v 5.13 1997/05/15 17:33:14 eggert Exp $";
+
+static int isleap P ((int));
+static int month_days P ((struct tm const *));
+static time_t maketime P ((struct partime const *, time_t));
+
+/* For maximum portability, use only localtime and gmtime.
+ Make no assumptions about the time_t epoch or the range of time_t values.
+ Avoid mktime because it's not universal and because there's no easy,
+ portable way for mktime to yield the inverse of gmtime. */
+
+#define TM_YEAR_ORIGIN 1900
+
+static int
+isleap (y)
+ int y;
+{
+ return (y & 3) == 0 && (y % 100 != 0 || y % 400 == 0);
+}
+
+/* days in year before start of months 0-12 */
+static int const month_yday[] =
+{
+ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
+};
+
+/* Yield the number of days in TM's month. */
+static int
+month_days (tm)
+ struct tm const *tm;
+{
+ int m = tm->tm_mon;
+ return (month_yday[m + 1] - month_yday[m]
+ + (m == 1 && isleap (tm->tm_year + TM_YEAR_ORIGIN)));
+}
+
+/* Convert UNIXTIME to struct tm form.
+ Use gmtime if available and if !LOCALZONE, localtime otherwise. */
+struct tm *
+time2tm (unixtime, localzone)
+ time_t unixtime;
+ int localzone;
+{
+ struct tm *tm;
+#if TZ_must_be_set
+ static char const *TZ;
+ if (!TZ && !(TZ = getenv ("TZ")))
+ faterror ("The TZ environment variable is not set; please set it to your timezone");
+#endif
+ if (localzone || !(tm = gmtime (&unixtime)))
+ tm = localtime (&unixtime);
+ return tm;
+}
+
+/* Yield A - B, measured in seconds. */
+time_t
+difftm (a, b)
+ struct tm const *a, *b;
+{
+ int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
+ int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
+ int ac = ay / 100 - (ay % 100 < 0);
+ int bc = by / 100 - (by % 100 < 0);
+ int difference_in_day_of_year = a->tm_yday - b->tm_yday;
+ int intervening_leap_days = (((ay >> 2) - (by >> 2))
+ - (ac - bc)
+ + ((ac >> 2) - (bc >> 2)));
+ time_t difference_in_years = ay - by;
+ time_t difference_in_days
+ = (difference_in_years * 365
+ + (intervening_leap_days + difference_in_day_of_year));
+ return (((((difference_in_days * 24
+ + (a->tm_hour - b->tm_hour))
+ * 60)
+ + (a->tm_min - b->tm_min))
+ * 60)
+ + (a->tm_sec - b->tm_sec));
+}
+
+/*
+ * Adjust time T by adding SECONDS. SECONDS must be at most 24 hours' worth.
+ * Adjust only T's year, mon, mday, hour, min and sec members;
+ * plus adjust wday if it is defined.
+ */
+void
+adjzone (t, seconds)
+ register struct tm *t;
+ long seconds;
+{
+ /*
+ * This code can be off by a second if SECONDS is not a multiple of 60,
+ * if T is local time, and if a leap second happens during this minute.
+ * But this bug has never occurred, and most likely will not ever occur.
+ * Liberia, the last country for which SECONDS % 60 was nonzero,
+ * switched to UTC in May 1972; the first leap second was in June 1972.
+ */
+ int leap_second = t->tm_sec == 60;
+ long sec = seconds + (t->tm_sec - leap_second);
+ if (sec < 0)
+ {
+ if ((t->tm_min -= (59 - sec) / 60) < 0)
+ {
+ if ((t->tm_hour -= (59 - t->tm_min) / 60) < 0)
+ {
+ t->tm_hour += 24;
+ if (TM_DEFINED (t->tm_wday) && --t->tm_wday < 0)
+ t->tm_wday = 6;
+ if (--t->tm_mday <= 0)
+ {
+ if (--t->tm_mon < 0)
+ {
+ --t->tm_year;
+ t->tm_mon = 11;
+ }
+ t->tm_mday = month_days (t);
+ }
+ }
+ t->tm_min += 24 * 60;
+ }
+ sec += 24L * 60 * 60;
+ }
+ else if (60 <= (t->tm_min += sec / 60))
+ if (24 <= (t->tm_hour += t->tm_min / 60))
+ {
+ t->tm_hour -= 24;
+ if (TM_DEFINED (t->tm_wday) && ++t->tm_wday == 7)
+ t->tm_wday = 0;
+ if (month_days (t) < ++t->tm_mday)
+ {
+ if (11 < ++t->tm_mon)
+ {
+ ++t->tm_year;
+ t->tm_mon = 0;
+ }
+ t->tm_mday = 1;
+ }
+ }
+ t->tm_min %= 60;
+ t->tm_sec = (int) (sec % 60) + leap_second;
+}
+
+/*
+ * Convert TM to time_t, using localtime if LOCALZONE and gmtime otherwise.
+ * Use only TM's year, mon, mday, hour, min, and sec members.
+ * Ignore TM's old tm_yday and tm_wday, but fill in their correct values.
+ * Yield -1 on failure (e.g. a member out of range).
+ * Posix 1003.1-1990 doesn't allow leap seconds, but some implementations
+ * have them anyway, so allow them if localtime/gmtime does.
+ */
+time_t
+tm2time (tm, localzone)
+ struct tm *tm;
+ int localzone;
+{
+ /* Cache the most recent t,tm pairs; 1 for gmtime, 1 for localtime. */
+ static time_t t_cache[2];
+ static struct tm tm_cache[2];
+
+ time_t d, gt;
+ struct tm const *gtm;
+ /*
+ * The maximum number of iterations should be enough to handle any
+ * combinations of leap seconds, time zone rule changes, and solar time.
+ * 4 is probably enough; we use a bigger number just to be safe.
+ */
+ int remaining_tries = 8;
+
+ /* Avoid subscript errors. */
+ if (12 <= (unsigned) tm->tm_mon)
+ return -1;
+
+ tm->tm_yday = month_yday[tm->tm_mon] + tm->tm_mday
+ - (tm->tm_mon < 2 || !isleap (tm->tm_year + TM_YEAR_ORIGIN));
+
+ /* Make a first guess. */
+ gt = t_cache[localzone];
+ gtm = gt ? &tm_cache[localzone] : time2tm (gt, localzone);
+
+ /* Repeatedly use the error from the guess to improve the guess. */
+ while ((d = difftm (tm, gtm)) != 0)
+ {
+ if (--remaining_tries == 0)
+ return -1;
+ gt += d;
+ gtm = time2tm (gt, localzone);
+ }
+
+ /*
+ * Check that the guess actually matches;
+ * overflow can cause difftm to yield 0 even on differing times,
+ * or tm may have members out of range (e.g. bad leap seconds).
+ */
+#define TM_DIFFER(a,b) \
+ ( \
+ ((a)->tm_year ^ (b)->tm_year) | \
+ ((a)->tm_mon ^ (b)->tm_mon) | \
+ ((a)->tm_mday ^ (b)->tm_mday) | \
+ ((a)->tm_hour ^ (b)->tm_hour) | \
+ ((a)->tm_min ^ (b)->tm_min) | \
+ ((a)->tm_sec ^ (b)->tm_sec) \
+ )
+ if (TM_DIFFER (tm, gtm))
+ {
+ /*
+ * If gt is a leap second, try gt+1; if it is one greater than
+ * a leap second, try gt-1; otherwise, it doesn't matter.
+ * Leap seconds always fall at month end.
+ */
+ int yd = tm->tm_year - gtm->tm_year;
+ gt += yd + (yd ? 0 : tm->tm_mon - gtm->tm_mon);
+ gtm = time2tm (gt, localzone);
+ if (TM_DIFFER (tm, gtm))
+ return -1;
+ }
+ t_cache[localzone] = gt;
+ tm_cache[localzone] = *gtm;
+
+ tm->tm_wday = gtm->tm_wday;
+ return gt;
+}
+
+/*
+ * Check *PT and convert it to time_t.
+ * If it is incompletely specified, use DEFAULT_TIME to fill it out.
+ * Use localtime if PT->zone is the special value TM_LOCAL_ZONE.
+ * Yield -1 on failure.
+ * ISO 8601 day-of-year and week numbers are not yet supported.
+ */
+static time_t
+maketime (pt, default_time)
+ struct partime const *pt;
+ time_t default_time;
+{
+ int localzone, wday;
+ struct tm tm;
+ struct tm *tm0 = 0;
+ time_t r;
+
+ tm0 = 0; /* Keep gcc -Wall happy. */
+ localzone = pt->zone == TM_LOCAL_ZONE;
+
+ tm = pt->tm;
+
+ if (TM_DEFINED (pt->ymodulus) || !TM_DEFINED (tm.tm_year))
+ {
+ /* Get tm corresponding to default time. */
+ tm0 = time2tm (default_time, localzone);
+ if (!localzone)
+ adjzone (tm0, pt->zone);
+ }
+
+ if (TM_DEFINED (pt->ymodulus))
+ tm.tm_year +=
+ (tm0->tm_year + TM_YEAR_ORIGIN) / pt->ymodulus * pt->ymodulus;
+ else if (!TM_DEFINED (tm.tm_year))
+ {
+ /* Set default year, month, day from current time. */
+ tm.tm_year = tm0->tm_year + TM_YEAR_ORIGIN;
+ if (!TM_DEFINED (tm.tm_mon))
+ {
+ tm.tm_mon = tm0->tm_mon;
+ if (!TM_DEFINED (tm.tm_mday))
+ tm.tm_mday = tm0->tm_mday;
+ }
+ }
+
+ /* Convert from partime year (Gregorian) to Posix year. */
+ tm.tm_year -= TM_YEAR_ORIGIN;
+
+ /* Set remaining default fields to be their minimum values. */
+ if (!TM_DEFINED (tm.tm_mon))
+ tm.tm_mon = 0;
+ if (!TM_DEFINED (tm.tm_mday))
+ tm.tm_mday = 1;
+ if (!TM_DEFINED (tm.tm_hour))
+ tm.tm_hour = 0;
+ if (!TM_DEFINED (tm.tm_min))
+ tm.tm_min = 0;
+ if (!TM_DEFINED (tm.tm_sec))
+ tm.tm_sec = 0;
+
+ if (!localzone)
+ adjzone (&tm, -pt->zone);
+ wday = tm.tm_wday;
+
+ /* Convert and fill in the rest of the tm. */
+ r = tm2time (&tm, localzone);
+
+ /* Check weekday. */
+ if (r != -1 && TM_DEFINED (wday) && wday != tm.tm_wday)
+ return -1;
+
+ return r;
+}
+
+/* Parse a free-format date in SOURCE, yielding a Unix format time. */
+time_t
+str2time (source, default_time, default_zone)
+ char const *source;
+ time_t default_time;
+ long default_zone;
+{
+ struct partime pt;
+
+ if (*partime (source, &pt))
+ return -1;
+ if (pt.zone == TM_UNDEFINED_ZONE)
+ pt.zone = default_zone;
+ return maketime (&pt, default_time);
+}
+
+#if TEST
+#include <stdio.h>
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ time_t default_time = time ((time_t *) 0);
+ long default_zone = argv[1] ? atol (argv[1]) : 0;
+ char buf[1000];
+ while (fgets (buf, sizeof (buf), stdin))
+ {
+ time_t t = str2time (buf, default_time, default_zone);
+ printf ("%s", asctime (gmtime (&t)));
+ }
+ return 0;
+}
+#endif
diff --git a/maketime.h b/maketime.h
new file mode 100644
index 0000000..3948eda
--- /dev/null
+++ b/maketime.h
@@ -0,0 +1,39 @@
+/* Yield time_t from struct partime yielded by partime. */
+
+/* Copyright 1993, 1994, 1995 Paul Eggert
+ Distributed under license by the Free Software Foundation, Inc.
+
+ This file is part of RCS.
+
+ RCS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ RCS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with RCS; see the file COPYING.
+ If not, write to the Free Software Foundation,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Report problems and direct all questions to:
+
+ rcs-bugs@cs.purdue.edu
+
+ */
+
+#if defined __STDC__ || has_prototypes
+# define __MAKETIME_P(x) x
+#else
+# define __MAKETIME_P(x) ()
+#endif
+
+struct tm *time2tm __MAKETIME_P ((time_t, int));
+time_t difftm __MAKETIME_P ((struct tm const *, struct tm const *));
+time_t str2time __MAKETIME_P ((char const *, time_t, long));
+time_t tm2time __MAKETIME_P ((struct tm *, int));
+void adjzone __MAKETIME_P ((struct tm *, long));
diff --git a/partime.c b/partime.c
new file mode 100644
index 0000000..ce87109
--- /dev/null
+++ b/partime.c
@@ -0,0 +1,742 @@
+/* Parse a string, yielding a struct partime that describes it. */
+
+/* Copyright 1993, 1994, 1995, 1997 Paul Eggert
+ Distributed under license by the Free Software Foundation, Inc.
+
+ This file is part of RCS.
+
+ RCS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ RCS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with RCS; see the file COPYING.
+ If not, write to the Free Software Foundation,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Report problems and direct all questions to:
+
+ rcs-bugs@cs.purdue.edu
+
+ */
+
+#if has_conf_h
+# include <conf.h>
+#else
+# if HAVE_CONFIG_H
+# include <config.h>
+# else
+# ifndef __STDC__
+# define const
+# endif
+# endif
+# if HAVE_LIMITS_H
+# include <limits.h>
+# endif
+# ifndef LONG_MIN
+# define LONG_MIN (-1-2147483647L)
+# endif
+# if STDC_HEADERS
+# include <stdlib.h>
+# endif
+# include <time.h>
+# ifdef __STDC__
+# define P(x) x
+# else
+# define P(x) ()
+# endif
+#endif
+
+#include <ctype.h>
+#if STDC_HEADERS
+# define CTYPE_DOMAIN(c) 1
+#else
+# define CTYPE_DOMAIN(c) ((unsigned) (c) <= 0177)
+#endif
+#define ISALNUM(c) (CTYPE_DOMAIN (c) && isalnum (c))
+#define ISALPHA(c) (CTYPE_DOMAIN (c) && isalpha (c))
+#define ISSPACE(c) (CTYPE_DOMAIN (c) && isspace (c))
+#define ISUPPER(c) (CTYPE_DOMAIN (c) && isupper (c))
+#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
+
+#include <partime.h>
+
+char const partimeId[] =
+ "$Id: partime.c,v 5.16 1997/05/19 06:33:53 eggert Exp $";
+
+
+/* Lookup tables for names of months, weekdays, time zones. */
+
+#define NAME_LENGTH_MAXIMUM 4
+
+struct name_val
+ {
+ char name[NAME_LENGTH_MAXIMUM];
+ int val;
+ };
+
+
+static char const *parse_decimal P ((char const *, int, int, int, int, int *, int *));
+static char const *parse_fixed P ((char const *, int, int *));
+static char const *parse_pattern_letter P ((char const *, int, struct partime *));
+static char const *parse_prefix P ((char const *, struct partime *, int *));
+static char const *parse_ranged P ((char const *, int, int, int, int *));
+static int lookup P ((char const *, struct name_val const[]));
+static int merge_partime P ((struct partime *, struct partime const *));
+static void undefine P ((struct partime *));
+
+
+static struct name_val const month_names[] =
+{
+ {"jan", 0},
+ {"feb", 1},
+ {"mar", 2},
+ {"apr", 3},
+ {"may", 4},
+ {"jun", 5},
+ {"jul", 6},
+ {"aug", 7},
+ {"sep", 8},
+ {"oct", 9},
+ {"nov", 10},
+ {"dec", 11},
+ {"", TM_UNDEFINED}
+};
+
+static struct name_val const weekday_names[] =
+{
+ {"sun", 0},
+ {"mon", 1},
+ {"tue", 2},
+ {"wed", 3},
+ {"thu", 4},
+ {"fri", 5},
+ {"sat", 6},
+ {"", TM_UNDEFINED}
+};
+
+#define hr60nonnegative(t) ((t)/100 * 60 + (t)%100)
+#define hr60(t) ((t)<0 ? -hr60nonnegative(-(t)) : hr60nonnegative(t))
+#define zs(t,s) {s, hr60(t)}
+#define zd(t,s,d) zs(t, s), zs((t)+100, d)
+
+static struct name_val const zone_names[] =
+{
+ zs (-1000, "hst"), /* Hawaii */
+ zd (-1000, "hast", "hadt"), /* Hawaii-Aleutian */
+ zd (- 900, "akst", "akdt"), /* Alaska */
+ zd (- 800, "pst" , "pdt" ), /* Pacific */
+ zd (- 700, "mst" , "mdt" ), /* Mountain */
+ zd (- 600, "cst" , "cdt" ), /* Central */
+ zd (- 500, "est" , "edt" ), /* Eastern */
+ zd (- 400, "ast" , "adt" ), /* Atlantic */
+ zd (- 330, "nst" , "ndt" ), /* Newfoundland */
+ zs ( 000, "utc" ), /* Coordinated Universal */
+ zs ( 000, "uct" ), /* " */
+ zs ( 000, "cut" ), /* " */
+ zs ( 000, "ut"), /* Universal */
+ zs ( 000, "z"), /* Zulu (required by ISO 8601) */
+ zd ( 000, "gmt" , "bst" ), /* Greenwich Mean, British Summer */
+ zd ( 000, "wet" , "west"), /* Western European */
+ zd ( 100, "cet" , "cest"), /* Central European */
+ zd ( 100, "met" , "mest"), /* Middle European (bug in old tz versions) */
+ zd ( 100, "mez" , "mesz"), /* Mittel-Europaeische Zeit */
+ zd ( 200, "eet" , "eest"), /* Eastern European */
+ zs ( 530, "ist" ), /* India */
+ zd ( 900, "jst" , "jdt" ), /* Japan */
+ zd ( 900, "kst" , "kdt" ), /* Korea */
+ zd ( 1200, "nzst", "nzdt"), /* New Zealand */
+ {"lt", 1},
+#if 0
+ /* The following names are duplicates or are not well attested.
+ There are lots more where these came from. */
+ zs (-1100, "sst" ), /* Samoan */
+ zd (- 900, "yst" , "ydt" ), /* Yukon - name is no longer used */
+ zd (- 500, "ast" , "adt" ), /* Acre */
+ zd (- 400, "wst" , "wdt" ), /* Western Brazil */
+ zd (- 400, "cst" , "cdt" ), /* Chile */
+ zd (- 200, "fst" , "fdt" ), /* Fernando de Noronha */
+ zs ( 000, "wat" ), /* West African */
+ zs ( 100, "cat" ), /* Central African */
+ zs ( 200, "sat" ), /* South African */
+ zd ( 200, "ist" , "idt" ), /* Israel */
+ zs ( 300, "eat" ), /* East African */
+ zd ( 300, "msk" , "msd" ), /* Moscow */
+ zd ( 330, "ist" , "idt" ), /* Iran */
+ zs ( 800, "hkt" ), /* Hong Kong */
+ zs ( 800, "sgt" ), /* Singapore */
+ zd ( 800, "cst" , "cdt" ), /* China */
+ zd ( 800, "wst" , "wst" ), /* Western Australia */
+ zd ( 930, "cst" , "cst" ), /* Central Australia */
+ zs ( 1000, "gst" ), /* Guam */
+ zd ( 1000, "est" , "est" ), /* Eastern Australia */
+#endif
+ {"", -1}
+};
+
+/* Look for a prefix of S in TABLE, returning val for first matching entry. */
+static int
+lookup (s, table)
+ char const *s;
+ struct name_val const table[];
+{
+ int j;
+ char buf[NAME_LENGTH_MAXIMUM];
+
+ for (j = 0; j < NAME_LENGTH_MAXIMUM; j++)
+ {
+ unsigned char c = *s++;
+ if (! ISALPHA (c))
+ {
+ buf[j] = '\0';
+ break;
+ }
+ buf[j] = ISUPPER (c) ? tolower (c) : c;
+ }
+
+ for (;; table++)
+ for (j = 0; ; j++)
+ if (j == NAME_LENGTH_MAXIMUM || ! table[0].name[j])
+ return table[0].val;
+ else if (buf[j] != table[0].name[j])
+ break;
+}
+
+
+/* Set *T to ``undefined'' values. */
+static void
+undefine (t)
+ struct partime *t;
+{
+ t->tm.tm_sec = t->tm.tm_min = t->tm.tm_hour = t->tm.tm_mday = t->tm.tm_mon
+ = t->tm.tm_year = t->tm.tm_wday = t->tm.tm_yday
+ = t->ymodulus = t->yweek
+ = TM_UNDEFINED;
+ t->zone = TM_UNDEFINED_ZONE;
+}
+
+/* Array of patterns to look for in a date string.
+ Order is important: we look for the first matching pattern
+ whose values do not contradict values that we already know about.
+ See `parse_pattern_letter' below for the meaning of the pattern codes. */
+static char const *const patterns[] =
+{
+ /* These traditional patterns must come first,
+ to prevent an ISO 8601 format from misinterpreting their prefixes. */
+ "E_n_y", "x", /* RFC 822 */
+ "E_n", "n_E", "n", "t:m:s_A", "t:m_A", "t_A", /* traditional */
+ "y/N/D$", /* traditional RCS */
+
+ /* ISO 8601:1988 formats, generalized a bit. */
+ "y-N-D$", "4ND$", "Y-N$",
+ "RND$", "-R=N$", "-R$", "--N=D$", "N=DT",
+ "--N$", "---D$", "DT",
+ "Y-d$", "4d$", "R=d$", "-d$", "dT",
+ "y-W-X", "yWX", "y=W",
+ "-r-W-X", "r-W-XT", "-rWX", "rWXT", "-W=X", "W=XT", "-W",
+ "-w-X", "w-XT", "---X$", "XT", "4$",
+ "T",
+ "h:m:s$", "hms$", "h:m$", "hm$", "h$", "-m:s$", "-ms$", "-m$", "--s$",
+ "Y", "Z",
+
+ 0
+};
+
+/* Parse an initial prefix of STR, setting *T accordingly.
+ Return the first character after the prefix, or 0 if it couldn't be parsed.
+ Start with pattern *PI; if success, set *PI to the next pattern to try.
+ Set *PI to -1 if we know there are no more patterns to try;
+ if *PI is initially negative, give up immediately. */
+static char const *
+parse_prefix (str, t, pi)
+ char const *str;
+ struct partime *t;
+ int *pi;
+{
+ int i = *pi;
+ char const *pat;
+ unsigned char c;
+
+ if (i < 0)
+ return 0;
+
+ /* Remove initial noise. */
+ while (! ISALNUM (c = *str) && c != '-' && c != '+')
+ {
+ if (! c)
+ {
+ undefine (t);
+ *pi = -1;
+ return str;
+ }
+ str++;
+ }
+
+ /* Try a pattern until one succeeds. */
+ while ((pat = patterns[i++]) != 0)
+ {
+ char const *s = str;
+ undefine (t);
+ do
+ {
+ if (! (c = *pat++))
+ {
+ *pi = i;
+ return s;
+ }
+ }
+ while ((s = parse_pattern_letter (s, c, t)) != 0);
+ }
+
+ return 0;
+}
+
+/* Parse an initial prefix of S of length DIGITS; it must be a number.
+ Store the parsed number into *RES.
+ Return the first character after the prefix, or 0 if it wasn't parsed. */
+static char const *
+parse_fixed (s, digits, res)
+ char const *s;
+ int digits, *res;
+{
+ int n = 0;
+ char const *lim = s + digits;
+ while (s < lim)
+ {
+ unsigned d = *s++ - '0';
+ if (9 < d)
+ return 0;
+ n = 10 * n + d;
+ }
+ *res = n;
+ return s;
+}
+
+/* Parse an initial prefix of S of length DIGITS;
+ it must be a number in the range LO through HI.
+ Store the parsed number into *RES.
+ Return the first character after the prefix, or 0 if it wasn't parsed. */
+static char const *
+parse_ranged (s, digits, lo, hi, res)
+ char const *s;
+ int digits, lo, hi, *res;
+{
+ s = parse_fixed (s, digits, res);
+ return s && lo <= *res && *res <= hi ? s : 0;
+}
+
+/* Parse an initial prefix of S of length DIGITS;
+ it must be a number in the range LO through HI
+ and it may be followed by a fraction to be computed using RESOLUTION.
+ Store the parsed number into *RES; store the fraction times RESOLUTION,
+ rounded to the nearest integer, into *FRES.
+ Return the first character after the prefix, or 0 if it wasn't parsed. */
+static char const *
+parse_decimal (s, digits, lo, hi, resolution, res, fres)
+ char const *s;
+ int digits, lo, hi, resolution, *res, *fres;
+{
+ s = parse_fixed (s, digits, res);
+ if (s && lo <= *res && *res <= hi)
+ {
+ int f = 0;
+ if ((s[0] == ',' || s[0] == '.') && ISDIGIT (s[1]))
+ {
+ char const *s1 = ++s;
+ int num10 = 0, denom10 = 10, product;
+ while (ISDIGIT (*++s))
+ {
+ int d = denom10 * 10;
+ if (d / 10 != denom10)
+ return 0; /* overflow */
+ denom10 = d;
+ }
+ s = parse_fixed (s1, (int) (s - s1), &num10);
+ product = num10 * resolution;
+ f = (product + (denom10 >> 1)) / denom10;
+ f -= f & (product % denom10 == denom10 >> 1); /* round to even */
+ if (f < 0 || product/resolution != num10)
+ return 0; /* overflow */
+ }
+ *fres = f;
+ return s;
+ }
+ return 0;
+}
+
+/* Parse an initial prefix of S; it must denote a time zone.
+ Set *ZONE to the number of seconds east of GMT,
+ or to TM_LOCAL_ZONE if it is the local time zone.
+ Return the first character after the prefix, or 0 if it wasn't parsed. */
+char *
+parzone (s, zone)
+ char const *s;
+ long *zone;
+{
+ char sign;
+ int hh, mm, ss;
+ int minutesEastOfUTC;
+ long offset, z;
+
+ /* The formats are LT, n, n DST, nDST, no, o
+ where n is a time zone name
+ and o is a time zone offset of the form [-+]hh[:mm[:ss]]. */
+ switch (*s)
+ {
+ case '-':
+ case '+':
+ z = 0;
+ break;
+
+ default:
+ minutesEastOfUTC = lookup (s, zone_names);
+ if (minutesEastOfUTC == -1)
+ return 0;
+
+ /* Don't bother to check rest of spelling. */
+ while (ISALPHA ((unsigned char) *s))
+ s++;
+
+ /* Don't modify LT. */
+ if (minutesEastOfUTC == 1)
+ {
+ *zone = TM_LOCAL_ZONE;
+ return (char *) s;
+ }
+
+ z = minutesEastOfUTC * 60L;
+
+ /* Look for trailing " DST". */
+ if ((s[-1] == 'T' || s[-1] == 't')
+ && (s[-2] == 'S' || s[-2] == 's')
+ && (s[-3] == 'D' || s[-3] == 'd'))
+ goto trailing_dst;
+ while (ISSPACE ((unsigned char) *s))
+ s++;
+ if ((s[0] == 'D' || s[0] == 'd')
+ && (s[1] == 'S' || s[1] == 's')
+ && (s[2] == 'T' || s[2] == 't'))
+ {
+ s += 3;
+ trailing_dst:
+ *zone = z + 60*60;
+ return (char *) s;
+ }
+
+ switch (*s)
+ {
+ case '-':
+ case '+':
+ break;
+
+ default:
+ *zone = z;
+ return (char *) s;
+ }
+
+ break;
+ }
+
+ sign = *s++;
+
+ if (! (s = parse_ranged (s, 2, 0, 23, &hh)))
+ return 0;
+ mm = ss = 0;
+ if (*s == ':')
+ s++;
+ if (ISDIGIT (*s))
+ {
+ if (! (s = parse_ranged (s, 2, 0, 59, &mm)))
+ return 0;
+ if (*s == ':' && s[-3] == ':' && ISDIGIT (s[1])
+ && ! (s = parse_ranged (s + 1, 2, 0, 59, &ss)))
+ return 0;
+ }
+ if (ISDIGIT (*s))
+ return 0;
+ offset = (hh * 60 + mm) * 60L + ss;
+ *zone = z + (sign == '-' ? -offset : offset);
+ /* ?? Are fractions allowed here? If so, they're not implemented. */
+ return (char *) s;
+}
+
+/* Parse an initial prefix of S, matching the pattern whose code is C.
+ Set *T accordingly.
+ Return the first character after the prefix, or 0 if it wasn't parsed. */
+static char const *
+parse_pattern_letter (s, c, t)
+ char const *s;
+ int c;
+ struct partime *t;
+{
+ switch (c)
+ {
+ case '$': /* The next character must be a non-digit. */
+ if (ISDIGIT (*s))
+ return 0;
+ break;
+
+ case '-':
+ case '/':
+ case ':':
+ /* These characters stand for themselves. */
+ if (*s++ != c)
+ return 0;
+ break;
+
+ case '4': /* 4-digit year */
+ s = parse_fixed (s, 4, &t->tm.tm_year);
+ break;
+
+ case '=': /* optional '-' */
+ s += *s == '-';
+ break;
+
+ case 'A': /* AM or PM */
+ /* This matches the regular expression [AaPp][Mm]?.
+ It must not be followed by a letter or digit;
+ otherwise it would match prefixes of strings like "PST". */
+ switch (*s++)
+ {
+ case 'A':
+ case 'a':
+ if (t->tm.tm_hour == 12)
+ t->tm.tm_hour = 0;
+ break;
+
+ case 'P':
+ case 'p':
+ if (t->tm.tm_hour != 12)
+ t->tm.tm_hour += 12;
+ break;
+
+ default:
+ return 0;
+ }
+ switch (*s)
+ {
+ case 'M':
+ case 'm':
+ s++;
+ break;
+ }
+ if (ISALNUM ((unsigned char) *s))
+ return 0;
+ break;
+
+ case 'D': /* day of month [01-31] */
+ s = parse_ranged (s, 2, 1, 31, &t->tm.tm_mday);
+ break;
+
+ case 'd': /* day of year [001-366] */
+ s = parse_ranged (s, 3, 1, 366, &t->tm.tm_yday);
+ t->tm.tm_yday--;
+ break;
+
+ case 'E': /* extended day of month [1-9, 01-31] */
+ s = parse_ranged (s, (ISDIGIT (s[0]) && ISDIGIT (s[1])) + 1, 1, 31,
+ &t->tm.tm_mday);
+ break;
+
+ case 'h': /* hour [00-23 followed by optional fraction] */
+ {
+ int frac;
+ s = parse_decimal (s, 2, 0, 23, 60 * 60, &t->tm.tm_hour, &frac);
+ t->tm.tm_min = frac / 60;
+ t->tm.tm_sec = frac % 60;
+ }
+ break;
+
+ case 'm': /* minute [00-59 followed by optional fraction] */
+ s = parse_decimal (s, 2, 0, 59, 60, &t->tm.tm_min, &t->tm.tm_sec);
+ break;
+
+ case 'n': /* month name [e.g. "Jan"] */
+ if (! TM_DEFINED (t->tm.tm_mon = lookup (s, month_names)))
+ return 0;
+ /* Don't bother to check rest of spelling. */
+ while (ISALPHA ((unsigned char) *s))
+ s++;
+ break;
+
+ case 'N': /* month [01-12] */
+ s = parse_ranged (s, 2, 1, 12, &t->tm.tm_mon);
+ t->tm.tm_mon--;
+ break;
+
+ case 'r': /* year % 10 (remainder in origin-0 decade) [0-9] */
+ s = parse_fixed (s, 1, &t->tm.tm_year);
+ t->ymodulus = 10;
+ break;
+
+ case_R:
+ case 'R': /* year % 100 (remainder in origin-0 century) [00-99] */
+ s = parse_fixed (s, 2, &t->tm.tm_year);
+ t->ymodulus = 100;
+ break;
+
+ case 's': /* second [00-60 followed by optional fraction] */
+ {
+ int frac;
+ s = parse_decimal (s, 2, 0, 60, 1, &t->tm.tm_sec, &frac);
+ t->tm.tm_sec += frac;
+ }
+ break;
+
+ case 'T': /* 'T' or 't' */
+ switch (*s++)
+ {
+ case 'T':
+ case 't':
+ break;
+ default:
+ return 0;
+ }
+ break;
+
+ case 't': /* traditional hour [1-9 or 01-12] */
+ s = parse_ranged (s, (ISDIGIT (s[0]) && ISDIGIT (s[1])) + 1, 1, 12,
+ &t->tm.tm_hour);
+ break;
+
+ case 'w': /* 'W' or 'w' only (stands for current week) */
+ switch (*s++)
+ {
+ case 'W':
+ case 'w':
+ break;
+ default:
+ return 0;
+ }
+ break;
+
+ case 'W': /* 'W' or 'w', followed by a week of year [00-53] */
+ switch (*s++)
+ {
+ case 'W':
+ case 'w':
+ break;
+ default:
+ return 0;
+ }
+ s = parse_ranged (s, 2, 0, 53, &t->yweek);
+ break;
+
+ case 'X': /* weekday (1=Mon ... 7=Sun) [1-7] */
+ s = parse_ranged (s, 1, 1, 7, &t->tm.tm_wday);
+ t->tm.tm_wday--;
+ break;
+
+ case 'x': /* weekday name [e.g. "Sun"] */
+ if (! TM_DEFINED (t->tm.tm_wday = lookup (s, weekday_names)))
+ return 0;
+ /* Don't bother to check rest of spelling. */
+ while (ISALPHA ((unsigned char) *s))
+ s++;
+ break;
+
+ case 'y': /* either R or Y */
+ if (ISDIGIT (s[0]) && ISDIGIT (s[1]) && ! ISDIGIT (s[2]))
+ goto case_R;
+ /* fall into */
+ case 'Y': /* year in full [4 or more digits] */
+ {
+ int len = 0;
+ while (ISDIGIT (s[len]))
+ len++;
+ if (len < 4)
+ return 0;
+ s = parse_fixed (s, len, &t->tm.tm_year);
+ }
+ break;
+
+ case 'Z': /* time zone */
+ s = parzone (s, &t->zone);
+ break;
+
+ case '_': /* possibly empty sequence of non-alphanumerics */
+ while (! ISALNUM ((unsigned char) *s) && *s)
+ s++;
+ break;
+
+ default: /* bad pattern */
+ return 0;
+ }
+
+ return s;
+}
+
+/* If there is no conflict, merge into *T the additional information in *U
+ and return 0. Otherwise do nothing and return -1. */
+static int
+merge_partime (t, u)
+ struct partime *t;
+ struct partime const *u;
+{
+# define conflict(a,b) ((a) != (b) && TM_DEFINED (a) && TM_DEFINED (b))
+ if (conflict (t->tm.tm_sec, u->tm.tm_sec)
+ || conflict (t->tm.tm_min, u->tm.tm_min)
+ || conflict (t->tm.tm_hour, u->tm.tm_hour)
+ || conflict (t->tm.tm_mday, u->tm.tm_mday)
+ || conflict (t->tm.tm_mon, u->tm.tm_mon)
+ || conflict (t->tm.tm_year, u->tm.tm_year)
+ || conflict (t->tm.tm_wday, u->tm.tm_yday)
+ || conflict (t->ymodulus, u->ymodulus)
+ || conflict (t->yweek, u->yweek)
+ || (t->zone != u->zone
+ && t->zone != TM_UNDEFINED_ZONE
+ && u->zone != TM_UNDEFINED_ZONE))
+ return -1;
+# undef conflict
+# define merge_(a,b) if (TM_DEFINED (b)) (a) = (b);
+ merge_ (t->tm.tm_sec, u->tm.tm_sec)
+ merge_ (t->tm.tm_min, u->tm.tm_min)
+ merge_ (t->tm.tm_hour, u->tm.tm_hour)
+ merge_ (t->tm.tm_mday, u->tm.tm_mday)
+ merge_ (t->tm.tm_mon, u->tm.tm_mon)
+ merge_ (t->tm.tm_year, u->tm.tm_year)
+ merge_ (t->tm.tm_wday, u->tm.tm_yday)
+ merge_ (t->ymodulus, u->ymodulus)
+ merge_ (t->yweek, u->yweek)
+# undef merge_
+ if (u->zone != TM_UNDEFINED_ZONE)
+ t->zone = u->zone;
+ return 0;
+}
+
+/* Parse a date/time prefix of S, putting the parsed result into *T.
+ Return the first character after the prefix.
+ The prefix may contain no useful information;
+ in that case, *T will contain only undefined values. */
+char *
+partime (s, t)
+ char const *s;
+ struct partime *t;
+{
+ struct partime p;
+
+ undefine (t);
+
+ while (*s)
+ {
+ int i = 0;
+ char const *s1;
+
+ do
+ {
+ if (! (s1 = parse_prefix (s, &p, &i)))
+ return (char *) s;
+ }
+ while (merge_partime (t, &p) != 0);
+
+ s = s1;
+ }
+
+ return (char *) s;
+}
diff --git a/partime.h b/partime.h
new file mode 100644
index 0000000..bcc8165
--- /dev/null
+++ b/partime.h
@@ -0,0 +1,67 @@
+/* Parse a string, yielding a struct partime that describes it. */
+
+/* Copyright 1993, 1994, 1995, 1997 Paul Eggert
+ Distributed under license by the Free Software Foundation, Inc.
+
+ This file is part of RCS.
+
+ RCS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ RCS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with RCS; see the file COPYING.
+ If not, write to the Free Software Foundation,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Report problems and direct all questions to:
+
+ rcs-bugs@cs.purdue.edu
+
+ */
+
+#define TM_UNDEFINED (-1)
+#define TM_DEFINED(x) (0 <= (x))
+
+/* #include <limits.h> if you want to use these symbols. */
+#define TM_LOCAL_ZONE LONG_MIN
+#define TM_UNDEFINED_ZONE (LONG_MIN + 1)
+
+struct partime
+ {
+ /* This structure describes the parsed time.
+ Only the following tm_* values in it are used:
+ sec, min, hour, mday, mon, year, wday, yday.
+ If TM_UNDEFINED (value), the parser never found the value.
+ The tm_year field is the actual year, not the year - 1900;
+ but see ymodulus below. */
+ struct tm tm;
+
+ /* If !TM_UNDEFINED (ymodulus),
+ then tm.tm_year is actually modulo ymodulus. */
+ int ymodulus;
+
+ /* Week of year, ISO 8601 style.
+ If TM_UNDEFINED (yweek), the parser never found yweek.
+ Weeks start on Mondays.
+ Week 1 includes Jan 4. */
+ int yweek;
+
+ /* Seconds east of UTC; or TM_LOCAL_ZONE or TM_UNDEFINED_ZONE. */
+ long zone;
+ };
+
+#if defined __STDC__ || has_prototypes
+# define __PARTIME_P(x) x
+#else
+# define __PARTIME_P(x) ()
+#endif
+
+char *partime __PARTIME_P ((char const *, struct partime *));
+char *parzone __PARTIME_P ((char const *, long *));
diff --git a/patch.c b/patch.c
index daf6342..7e196ce 100644
--- a/patch.c
+++ b/patch.c
@@ -1,6 +1,6 @@
/* patch - a program to apply diffs to original files */
-/* $Id: patch.c,v 1.11 1997/04/14 05:32:30 eggert Exp $ */
+/* $Id: patch.c,v 1.17 1997/05/26 05:34:43 eggert Exp $ */
/*
Copyright 1984, 1985, 1986, 1987, 1988 Larry Wall
@@ -36,7 +36,8 @@ If not, write to the Free Software Foundation,
/* procedures */
-static LINENUM locate_hunk PARAMS ((LINENUM, LINENUM));
+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 patch_match PARAMS ((LINENUM, LINENUM, LINENUM, LINENUM));
@@ -52,15 +53,11 @@ static void init_reject PARAMS ((char const *));
static void reinitialize_almost_everything PARAMS ((void));
static void usage PARAMS ((FILE *, int)) __attribute__((noreturn));
-/* TRUE if -E was specified on command line. */
static int remove_empty_files;
/* TRUE if -R was specified on command line. */
static int reverse_flag_specified;
-static bool backup;
-static bool noreverse;
-
/* how many input lines have been irretractably output */
static LINENUM last_frozen_line;
@@ -99,6 +96,8 @@ char **argv;
{
bool somefailed = FALSE;
+ init_time ();
+
setbuf(stderr, serrbuf);
bufsize = 8 * 1024;
@@ -106,32 +105,35 @@ char **argv;
strippath = INT_MAX;
+ patch_get = getenv ("PATCH_GET") != 0;
+ posixly_correct = getenv ("POSIXLY_CORRECT") != 0;
+
{
char const *v;
v = getenv ("SIMPLE_BACKUP_SUFFIX");
if (v && *v)
- {
- simple_backup_suffix = v;
- backup = TRUE;
- }
- v = getenv ("VERSION_CONTROL");
+ simple_backup_suffix = v;
+
+ v = getenv ("PATCH_VERSION_CONTROL");
+ if (! v)
+ v = getenv ("VERSION_CONTROL");
if (v && *v)
- backup = TRUE;
- backup_type = get_version (v); /* OK to pass NULL. */
+ backup_type = get_version (v);
}
- /* parse switches */
- Argc = argc;
- Argv = argv;
- get_some_switches();
-
- /* Cons up the names of the global temporary files. */
+ /* Cons up the names of the global temporary files.
+ Do this before `cleanup' can possibly be called (e.g. by `pfatal'). */
TMPOUTNAME = make_temp ('o');
TMPINNAME = make_temp ('i');
TMPREJNAME = make_temp ('r');
TMPPATNAME = make_temp ('p');
+ /* parse switches */
+ Argc = argc;
+ Argv = argv;
+ get_some_switches();
+
if (output)
init_output (output);
@@ -145,7 +147,7 @@ char **argv;
) { /* for each patch in patch file */
int hunk = 0;
int failed = 0;
- char const *outname = output ? output : inname;
+ char *outname = output ? output : inname;
if (!skip_rest_of_patch)
get_input_file (inname, outname);
@@ -155,7 +157,7 @@ char **argv;
do_ed_script (ofp);
} else {
int got_hunk;
- bool rev_okayed = FALSE;
+ int apply_anyway = 0;
bool after_newline = TRUE;
/* initialize the patched file */
@@ -173,76 +175,50 @@ char **argv;
/* might misfire and we can't catch it easily */
/* apply each hunk of patch */
- while (0 < (got_hunk = another_hunk (diff_type))) {
+ while (0 < (got_hunk = another_hunk (diff_type, reverse))) {
LINENUM where = 0; /* Pacify `gcc -Wall'. */
LINENUM newwhere;
LINENUM fuzz = 0;
- LINENUM max_prefix_fuzz = pch_prefix_context ();
- LINENUM max_suffix_fuzz = pch_suffix_context ();
+ LINENUM prefix_context = pch_prefix_context ();
+ LINENUM suffix_context = pch_suffix_context ();
+ LINENUM context = (prefix_context < suffix_context
+ ? suffix_context : prefix_context);
+ LINENUM mymaxfuzz = (maxfuzz < context ? maxfuzz : context);
hunk++;
- if (maxfuzz < max_prefix_fuzz)
- max_prefix_fuzz = maxfuzz;
- if (maxfuzz < max_suffix_fuzz)
- max_suffix_fuzz = maxfuzz;
if (!skip_rest_of_patch) {
do {
- LINENUM prefix_fuzz =
- fuzz < max_prefix_fuzz ? fuzz : max_prefix_fuzz;
- LINENUM suffix_fuzz =
- fuzz < max_suffix_fuzz ? fuzz : max_suffix_fuzz;
- where = locate_hunk (prefix_fuzz, suffix_fuzz);
- if (hunk == 1 && !where && !(force|rev_okayed)) {
+ where = locate_hunk(fuzz);
+ if (hunk == 1 && !where && !(force|apply_anyway)) {
/* dwim for reversed patch? */
if (!pch_swap()) {
- if (!fuzz)
- say (
+ say (
"Not enough memory to try swapped hunk! Assuming unswapped.\n");
continue;
}
- reverse = !reverse;
/* Try again. */
- where = locate_hunk (prefix_fuzz, suffix_fuzz);
- if (!where) { /* didn't find it swapped */
- if (!pch_swap()) /* put it back to normal */
- fatal ("lost hunk on alloc error!");
- reverse = !reverse;
- }
- else if (noreverse) {
- if (!pch_swap()) /* put it back to normal */
- fatal ("lost hunk on alloc error!");
- reverse = !reverse;
- say (
-"Ignoring previously applied (or reversed) patch.\n");
- skip_rest_of_patch = TRUE;
- }
- else if (batch) {
- if (verbosity != SILENT)
- say (
-"%seversed (or previously applied) patch detected! %s -R.\n",
- reverse ? "R" : "Unr",
- reverse ? "Assuming" : "Ignoring");
- }
- else {
- ask (
-"%seversed (or previously applied) patch detected! %s -R? [y] ",
- reverse ? "R" : "Unr",
- reverse ? "Assume" : "Ignore");
- if (*buf == 'n') {
- ask ("Apply anyway? [n] ");
- if (*buf == 'y')
- rev_okayed = TRUE;
- else
- skip_rest_of_patch = TRUE;
+ where = locate_hunk (fuzz);
+ if (where
+ && (ok_to_reverse
+ ("%s patch detected!",
+ (reverse
+ ? "Unreversed"
+ : "Reversed (or previously applied)"))))
+ reverse ^= 1;
+ else
+ {
+ /* Put it back to normal. */
+ if (! pch_swap ())
+ fatal ("lost hunk on alloc error!");
+ if (where)
+ {
+ apply_anyway = 1;
+ fuzz--; /* Undo `++fuzz' below. */
where = 0;
- reverse = !reverse;
- if (!pch_swap()) /* put it back to normal */
- fatal ("lost hunk on alloc error!");
- }
- }
+ }
+ }
}
} while (!skip_rest_of_patch && !where
- && (++fuzz <= max_prefix_fuzz
- || fuzz <= max_suffix_fuzz));
+ && ++fuzz <= mymaxfuzz);
if (skip_rest_of_patch) { /* just got decided */
if (ofp && !output)
@@ -261,7 +237,8 @@ char **argv;
say ("Hunk #%d ignored at %ld.\n", hunk, newwhere);
}
else if (!where
- || (where == 1 && ok_to_create_file && input_lines)) {
+ || (where == 1 && pch_says_nonexistent (reverse)
+ && input_lines)) {
if (where)
say ("\nPatch attempted to create file `%s', which already exists.\n", inname);
abort_hunk();
@@ -290,7 +267,7 @@ char **argv;
if (got_hunk < 0 && using_plan_a) {
if (output)
fatal ("out of memory using Plan A");
- say ("\n\nRan out of memory using Plan A--trying again...\n\n");
+ say ("\n\nRan out of memory using Plan A -- trying again...\n\n");
if (ofp)
{
fclose (ofp);
@@ -300,11 +277,12 @@ char **argv;
continue;
}
- assert(hunk);
-
/* finish spewing out the new file */
if (!skip_rest_of_patch)
- skip_rest_of_patch = ! spew_output (&after_newline);
+ {
+ assert (hunk);
+ skip_rest_of_patch = ! spew_output (&after_newline);
+ }
}
/* and put the output where desired */
@@ -312,21 +290,29 @@ char **argv;
if (!skip_rest_of_patch && !output) {
struct stat statbuf;
- if (remove_empty_files
+ if ((remove_empty_files
+ || (pch_says_nonexistent (reverse ^ 1) && !posixly_correct))
&& stat (TMPOUTNAME, &statbuf) == 0
&& statbuf.st_size == 0)
{
if (verbosity == VERBOSE)
- say ("Removing %s (empty after patching).\n", outname);
+ say ("Removing file `%s'%s.\n", outname,
+ dry_run ? " and any empty ancestor directories" : "");
if (! dry_run)
- unlink (outname);
+ {
+ move_file ((char *) 0, outname, (mode_t) 0,
+ backup_type != none);
+ removedirs (outname);
+ }
}
else
{
if (! dry_run)
{
- move_file (TMPOUTNAME, outname, backup);
- chmod (outname, instat.st_mode);
+ move_file (TMPOUTNAME, outname, instat.st_mode,
+ backup_type != none);
+ if (! inerrno && chmod (outname, instat.st_mode) != 0)
+ pfatal ("can't set permissions on file `%s'", outname);
}
}
}
@@ -344,9 +330,16 @@ char **argv;
strcpy (rej, outname);
addext (rej, ".rej", '#');
}
- say ("--saving rejects to %s", rej);
+ say (" -- saving rejects to %s", rej);
if (! dry_run)
- move_file (TMPREJNAME, rej, FALSE);
+ {
+ move_file (TMPREJNAME, rej, instat.st_mode, FALSE);
+ if (! inerrno
+ && (chmod (rej, (instat.st_mode
+ & ~(S_IXUSR|S_IXGRP|S_IXOTH)))
+ != 0))
+ pfatal ("can't set permissions on file `%s'", rej);
+ }
if (!rejname)
free (rej);
}
@@ -392,7 +385,7 @@ reinitialize_almost_everything()
skip_rest_of_patch = FALSE;
}
-static char const shortopts[] = "bB:cd:D:eEfF:i:lnNo:p:r:RstuvV:x:Y:z:";
+static char const shortopts[] = "bB:cd:D:eEfF:gGi:lnNo:p:r:RstuvV:x:Y:z:";
static struct option const longopts[] =
{
{"backup", no_argument, NULL, 'b'},
@@ -404,7 +397,8 @@ static struct option const longopts[] =
{"remove-empty-files", no_argument, NULL, 'E'},
{"force", no_argument, NULL, 'f'},
{"fuzz", required_argument, NULL, 'F'},
- {"help", no_argument, NULL, 'h'},
+ {"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'},
@@ -424,10 +418,13 @@ static struct option const longopts[] =
{"suffix", required_argument, NULL, 'z'},
{"dry-run", no_argument, NULL, 129},
{"verbose", no_argument, NULL, 130},
+ {"binary", no_argument, NULL, 131},
+ {"help", no_argument, NULL, 132},
{NULL, no_argument, NULL, 0}
};
-static char const * const option_help[] = {
+static char const *const option_help[] =
+{
"Input options:",
"",
" -p NUM --strip=NUM Strip NUM leading components from file names.",
@@ -452,7 +449,7 @@ 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.",
"",
-"Backup file options:",
+"Backup and version control options:",
"",
" -V STYLE --version-control=STYLE Use STYLE version control.",
" STYLE is either 'simple', 'numbered', or 'existing'.",
@@ -462,6 +459,9 @@ static char const * const option_help[] = {
" -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.",
+"",
"Miscellaneous options:",
"",
" -t --batch Ask no questions; skip bad-Prereq patches; assume reversed.",
@@ -471,9 +471,16 @@ static char const * const option_help[] = {
" --dry-run Do not actually change any files; just print what would happen.",
"",
" -d DIR --directory=DIR Change the working directory to DIR first.",
+#if HAVE_SETMODE
+" --binary Read and write data in binary mode.",
+#else
+" --binary Read and write data in binary mode (no effect on this platform).",
+#endif
"",
" -v --version Output version info.",
" --help Output this help.",
+"",
+"Report bugs to <bug-gnu-utils@prep.ai.mit.edu>.",
0
};
@@ -531,14 +538,12 @@ get_some_switches()
optarg, optarg);
goto case_z;
}
- backup = TRUE;
backup_type = simple;
break;
case 'B':
if (!*optarg)
- pfatal ("backup prefix is empty");
+ fatal ("backup prefix is empty");
origprae = savestr (optarg);
- backup = TRUE;
backup_type = simple;
break;
case 'c':
@@ -546,7 +551,7 @@ get_some_switches()
break;
case 'd':
if (chdir(optarg) < 0)
- pfatal ("can't cd to %s", optarg);
+ pfatal ("can't change directory to `%s'", optarg);
break;
case 'D':
do_defines = savestr (optarg);
@@ -563,8 +568,12 @@ get_some_switches()
case 'F':
maxfuzz = numeric_optarg ("fuzz factor");
break;
- case 'h':
- usage (stdout, 0);
+ case 'g':
+ patch_get = 1;
+ break;
+ case 'G':
+ patch_get = 0;
+ break;
case 'i':
patchname = savestr (optarg);
break;
@@ -579,7 +588,7 @@ get_some_switches()
break;
case 'o':
if (strcmp (optarg, "-") == 0)
- fatal ("cannot output patches to standard output");
+ fatal ("can't output patches to standard output");
output = savestr (optarg);
break;
case 'p':
@@ -589,8 +598,8 @@ get_some_switches()
rejname = savestr (optarg);
break;
case 'R':
- reverse = TRUE;
- reverse_flag_specified = TRUE;
+ reverse = 1;
+ reverse_flag_specified = 1;
break;
case 's':
verbosity = SILENT;
@@ -606,7 +615,6 @@ get_some_switches()
exit (0);
break;
case 'V':
- backup = TRUE;
backup_type = get_version (optarg);
break;
#if DEBUGGING
@@ -616,17 +624,15 @@ get_some_switches()
#endif
case 'Y':
if (!*optarg)
- pfatal ("backup basename prefix is empty");
+ fatal ("backup basename prefix is empty");
origbase = savestr (optarg);
- backup = TRUE;
backup_type = simple;
break;
case 'z':
case_z:
if (!*optarg)
- pfatal ("backup suffix is empty");
+ fatal ("backup suffix is empty");
simple_backup_suffix = savestr (optarg);
- backup = TRUE;
backup_type = simple;
break;
case 129:
@@ -635,6 +641,13 @@ get_some_switches()
case 130:
verbosity = VERBOSE;
break;
+ case 131:
+#if HAVE_SETMODE
+ binary_transput = O_BINARY;
+#endif
+ break;
+ case 132:
+ usage (stdout, 0);
default:
usage (stderr, 2);
}
@@ -687,47 +700,76 @@ numeric_optarg (argtype_msgid)
/* Attempt to find the right place to apply this hunk of patch. */
static LINENUM
-locate_hunk (prefix_fuzz, suffix_fuzz)
- LINENUM prefix_fuzz;
- LINENUM suffix_fuzz;
+locate_hunk(fuzz)
+LINENUM fuzz;
{
register LINENUM first_guess = pch_first () + last_offset;
register LINENUM offset;
LINENUM pat_lines = pch_ptrn_lines();
- register LINENUM max_pos_offset
- = input_lines - first_guess - pat_lines + 1;
- register LINENUM max_neg_offset
- = first_guess - last_frozen_line - 1 + pch_prefix_context ();
+ LINENUM prefix_context = pch_prefix_context ();
+ LINENUM suffix_context = pch_suffix_context ();
+ LINENUM context = (prefix_context < suffix_context
+ ? suffix_context : prefix_context);
+ LINENUM prefix_fuzz = fuzz + prefix_context - context;
+ LINENUM suffix_fuzz = fuzz + suffix_context - context;
+ LINENUM max_where = input_lines - (pat_lines - suffix_fuzz) + 1;
+ LINENUM min_where = last_frozen_line + 1 - (prefix_context - prefix_fuzz);
+ LINENUM max_pos_offset = max_where - first_guess;
+ LINENUM max_neg_offset = first_guess - min_where;
+ LINENUM max_offset = (max_pos_offset < max_neg_offset
+ ? max_neg_offset : max_pos_offset);
if (!pat_lines) /* null range matches always */
return first_guess;
- if (max_neg_offset >= first_guess) /* do not try lines < 0 */
+
+ /* Do not try lines <= 0. */
+ if (first_guess <= max_neg_offset)
max_neg_offset = first_guess - 1;
- if (first_guess <= input_lines
- && patch_match (first_guess, (LINENUM) 0, prefix_fuzz, suffix_fuzz))
- return first_guess;
- for (offset = 1; ; offset++) {
- register bool check_after = offset <= max_pos_offset;
- register bool check_before = offset <= max_neg_offset;
- if (check_after
+ if (prefix_fuzz < 0)
+ {
+ /* Can only match start of file. */
+
+ if (suffix_fuzz < 0)
+ /* Can only match entire file. */
+ if (pat_lines != input_lines || prefix_context < last_frozen_line)
+ return 0;
+
+ offset = 1 - first_guess;
+ return
+ ((last_frozen_line <= prefix_context
+ && offset <= max_pos_offset
+ && patch_match (first_guess, offset, (LINENUM) 0, suffix_fuzz))
+ ? first_guess : 0);
+ }
+
+ if (suffix_fuzz < 0)
+ {
+ /* Can only match end of file. */
+ offset = first_guess - (input_lines - pat_lines + 1);
+ return
+ ((offset <= max_neg_offset
+ && patch_match (first_guess, -offset, prefix_fuzz, (LINENUM) 0))
+ ? first_guess : 0);
+ }
+
+ for (offset = 0; offset <= max_offset; offset++) {
+ if (offset <= max_pos_offset
&& patch_match (first_guess, offset, prefix_fuzz, suffix_fuzz)) {
if (debug & 1)
say ("Offset changing from %ld to %ld\n", last_offset, offset);
last_offset = offset;
return first_guess+offset;
}
- else if (check_before
- && patch_match (first_guess, -offset,
- prefix_fuzz, suffix_fuzz)) {
+ if (0 < offset && offset <= max_neg_offset
+ && patch_match (first_guess, -offset, prefix_fuzz, suffix_fuzz)) {
if (debug & 1)
say ("Offset changing from %ld to %ld\n", last_offset, -offset);
last_offset = -offset;
return first_guess-offset;
}
- else if (!check_before && !check_after)
- return 0;
}
+ return 0;
}
/* We did not find the pattern, dump out the hunk so they can handle it. */
@@ -845,7 +887,7 @@ LINENUM where;
if (debug & 1)
say ("oldchar = '%c', newchar = '%c'\n",
pch_char (old), pch_char (new));
- fatal ("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?",
+ fatal ("Out-of-sync patch, lines %ld,%ld -- mangled text or line numbers, maybe?",
pch_hunk_beg() + old,
pch_hunk_beg() + new);
}
@@ -932,15 +974,26 @@ LINENUM where;
return TRUE;
}
+/* Create an output file. */
+
+static FILE *
+create_output_file (name)
+ char const *name;
+{
+ int fd = create_file (name, O_WRONLY | binary_transput, instat.st_mode);
+ FILE *f = fdopen (fd, binary_transput ? "wb" : "w");
+ if (! f)
+ pfatal ("can't create `%s'", name);
+ return f;
+}
+
/* Open the new file. */
static void
init_output(name)
char const *name;
{
- ofp = fopen(name, "w");
- if (! ofp)
- pfatal ("can't create %s", name);
+ ofp = create_output_file (name);
}
/* Open a file to put hunks we can't locate. */
@@ -949,9 +1002,7 @@ static void
init_reject(name)
char const *name;
{
- rejfp = fopen(name, "w");
- if (!rejfp)
- pfatal ("can't create %s", name);
+ rejfp = create_output_file (name);
}
/* Copy input file to output, up to wherever hunk is to be applied. */
@@ -1081,17 +1132,22 @@ similar (a, alen, b, blen)
char *mktemp PARAMS ((char *));
#endif
+#ifndef TMPDIR
+#define TMPDIR "/tmp"
+#endif
+
static char const *
make_temp (letter)
int letter;
{
char *r;
#if HAVE_MKTEMP
- char const *tmpdir = getenv ("TMPDIR");
- if (!tmpdir)
- tmpdir = "/tmp";
- r = xmalloc (strlen (tmpdir) + 14);
- sprintf (r, "%s/patch%cXXXXXX", tmpdir, letter);
+ char const *tmpdir = getenv ("TMPDIR"); /* Unix tradition */
+ if (!tmpdir) tmpdir = getenv ("TMP"); /* DOS tradition */
+ if (!tmpdir) tmpdir = getenv ("TEMP"); /* another DOS tradition */
+ if (!tmpdir) tmpdir = TMPDIR;
+ r = xmalloc (strlen (tmpdir) + 10);
+ sprintf (r, "%s/p%cXXXXXX", tmpdir, letter);
mktemp (r);
if (!*r)
pfatal ("mktemp");
diff --git a/patch.man b/patch.man
index 6b2fcfb..a145cf9 100644
--- a/patch.man
+++ b/patch.man
@@ -2,7 +2,7 @@
.de Id
.ds Dt \\$4
..
-.Id $Id: patch.man,v 1.8 1997/04/17 17:08:15 eggert Exp $
+.Id $Id: patch.man,v 1.16 1997/05/30 08:03:48 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" "number"
.BI < patchfile
.SH DESCRIPTION
.B patch
@@ -94,12 +94,16 @@ cannot find a place to install that hunk of the patch, it puts the
hunk out to a reject file, which normally is the name of the output file
plus a
.B \&.rej
-suffix
-(or
+suffix, or
.B #
if
.B \&.rej
-would generate a file name that is too long).
+would generate a file name that is too long
+(if even appending the single character
+.B #
+makes the file name too long, then
+.B #
+replaces the file name's last character).
(The rejected hunk comes out in ordinary context diff form regardless of
the input patch's form.
If the input was a normal diff, many of the contexts are simply null.)
@@ -132,24 +136,37 @@ tries to figure out from the leading garbage what the name of the file
to edit is.
If the header is that of a context diff,
.B patch
-tests for the existence of the old and new files named in the header.
-If there is an
-.B Index:
+takes the old and new file names in the header,
+and if there is an
+.B Index:\&
line in the leading garbage,
.B patch
-tests for the existence of the file named in that line.
-If none of the file names refer to existing files, but the patch appears
-to create a file, then
+obtains the name in that line; any
+.B /dev/null
+names are ignored.
+These names are considered to be in the order (old, new, index),
+regardless of the order that they appear in the header.
+If some of the named files exist,
.B patch
-tries the same file names again, this time testing only for the
-existence of the file names' directory prefix;
+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,
+.B POSIXLY_CORRECT
+is not set, and the patch appears to create a file,
.B patch
-uses the first name with the longest existing prefix.
-If no file name can be intuited from the leading garbage, you are asked
+uses the best name requiring the creation of the fewest directories.
+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,
+.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;
+of those, it then takes all the shortest names;
+finally, it takes the first remaining name.
.PP
Additionally, if the leading garbage contains a
-.B Prereq:
+.B Prereq:\&
line,
.B patch
takes the first word from the prerequisites line (normally a version
@@ -158,8 +175,10 @@ If not,
.B patch
asks for confirmation before proceeding.
.PP
-If the original file cannot be found or is read-only, but a suitable
+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
@@ -169,7 +188,7 @@ option)
is set to
.BR existing ,
.B patch
-attempts to check out and lock the file.
+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
@@ -218,6 +237,15 @@ the simple backup file name for
is
.BR /junk/src/patch/util.c .
.TP
+\fB\*=binary\fP
+Read and write all files in binary mode,
+except for standard output and
+.BR /dev/tty .
+This option has no effect on \s-1POSIX\s0-compliant systems.
+On systems like \s-1DOS\s0 where this option makes a difference,
+the patch should be generated by
+.BR "diff\ \-a\ \*=binary" .
+.TP
\fB\-c\fP or \fB\*=context\fP
Interpret the patch file as a ordinary context diff.
.TP
@@ -232,7 +260,7 @@ anything else.
.TP
\fB\-D\fP \fIsym\fP or \fB\*=ifdef=\fP\fIsym\fP
Use the
-.B "#ifdef .\|.\|. #endif"
+.BR #ifdef " .\|.\|. " #endif
construct to mark changes, with
.I sym
as the differentiating symbol.
@@ -247,13 +275,25 @@ script.
.TP
\fB\-E\fP or \fB\*=remove\-empty\-files\fP
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
+should exist after patching.
+However, if the input is not a context diff or if the
+.B POSIXLY_CORRECT
+environment variable is set,
+.B patch
+does not remove empty patched files unless this option is given.
+When
+.B patch
+removes a file, it also attempts to remove any empty ancestor directories.
.TP
\fB\-f\fP or \fB\*=force\fP
Assume that the user knows exactly what he or she is doing, and do not
ask any questions. Skip patches whose headers
do not say which file is to be patched; patch files even though they have the
wrong version for the
-.B Prereq:
+.B Prereq:\&
line in the patch; and assume that
patches are not reversed even if they look like they are.
This option does not suppress commentary; use
@@ -269,6 +309,20 @@ 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
+.B PATCH_GET
+environment variable is set.
+.TP
.B "\*=help"
Print a summary of options and exit.
.TP
@@ -295,7 +349,7 @@ Interpret the patch file as a normal diff.
\fB\-N\fP or \fB\*=forward\fP
Ignore patches that seem to be reversed or already applied.
See also
-.B \-R .
+.BR \-R .
.TP
\fB\-o\fP \fIfile\fP or \fB\*=output=\fP\fIfile\fP
Send output to
@@ -335,7 +389,7 @@ Whatever you end up with is looked for either in the current directory,
or the directory specified by the
.B \-d
option.
-With GNU
+With \s-1GNU\s0
.BR patch ,
the two-argument
.BI "\-p " N
@@ -390,7 +444,7 @@ Suppress questions like
but make some different assumptions:
skip patches whose headers do not contain file names (the same as \fB\-f\fP);
skip patches for which the file has the wrong version for the
-.B Prereq:
+.B Prereq:\&
line
in the patch; and assume that patches are reversed if they look like
they are.
@@ -408,12 +462,14 @@ Use
.I method
when creating
backup file names. The type of backups made can also be given in the
-.B VERSION_CONTROL
+.B PATCH_VERSION_CONTROL
+(or, if that's not set, the
+.BR VERSION_CONTROL )
environment variable, which is overridden by this option.
.Sp
The value of
.I method
-is like the GNU
+is like the \s-1GNU\s0
Emacs `version-control' variable;
.B patch
also recognizes synonyms that
@@ -426,9 +482,6 @@ accepted):
\fBexisting\fP or \fBnil\fP
Make numbered backups of files that already have them,
otherwise simple backups.
-If a file is read-only or does not exist,
-check it out from \s-1RCS\s0 if it is under \s-2RCS\s0 control;
-similarly for \s-1SCCS\s0.
.TP
\fBnone\fP
Do not make backups.
@@ -467,13 +520,13 @@ environment variable if set, and is
otherwise.
.PP
With numbered or simple backups,
-if the backup file name is just another name for the original file,
-.B patch
-creates a new backup file name by changing the first lowercase letter
-in the last component of the file's name into uppercase. If there are
-no more lowercase letters in the name, it removes the first character
-from the name. It repeats this process until it fails, or comes up with a
-backup file that is not just another name for the original file.
+if the backup file name is too long, the backup suffix
+.B ~
+is used instead; if even appending
+.B ~
+would make the name too long, then
+.B ~
+replaces the last character of the file name.
.RE
.TP
\fB\-x\fP \fInumber\fP or \fB\*=debug=\fP\fInumber\fP
@@ -498,35 +551,57 @@ 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.
-If the backup suffix would create a file name that is too long,
-the backup suffix
-.B ~
-is used instead.
.SH ENVIRONMENT
.TP 3
.B POSIXLY_CORRECT
If set,
.B patch
-conforms more strictly to the Posix standard:
-i.e. it requires that all options precede the
+conforms more strictly to the \s-1POSIX\s0 standard:
+it takes the first existing file 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.
.TP
-.B TMPDIR
-Directory to put temporary files in; default is
-.BR /tmp .
-.TP
.B SIMPLE_BACKUP_SUFFIX
Extension to use for simple backup file names instead of
.BR \&.orig .
.TP
-.B VERSION_CONTROL
+\fBTMPDIR\fP, \fBTMP\fP, \fBTEMP\fP
+Directory to put temporary files in;
+.B patch
+uses the first environment variable in this list that is set.
+If none are set, the default is system-dependent;
+it is normally
+.B /tmp
+on Unix hosts.
+.TP
+\fBPATCH_VERSION_CONTROL\fP or \fBVERSION_CONTROL\fP
Selects version control style; see the
.B \-v
or
-.B \*=version_control
+.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
-.IB $TMPDIR "/patch\(**"
+.TP 3
+.IB $TMPDIR "/p\(**"
+temporary files
+.TP
+.B /dev/tty
+console; used to get answers to questions asked of the user
.SH "SEE ALSO"
.BR diff (1),
.BR ed (1)
@@ -534,35 +609,46 @@ option.
There are several things you should bear in mind if you are going to
be sending out patches.
.PP
-Tell your recipients how to apply the patches.
-This should include which directory to
+Create your patch systematically.
+A good method is the command
+.BI "diff\ \-Naur\ " "old\ new"
+where
+.I old
+and
+.I new
+identify the old and new directories.
+The names
+.I old
+and
+.I new
+should not contain any slashes.
+Here is an example:
+.Sp
+ \fBdiff \-Naur version\-2.2 version\-2.3\fP
+.PP
+Tell your recipients how to apply the patch
+by telling them which directory to
.B cd
to, and which
.B patch
-options to use. Normally you should specify the
-.BI \-p N
-option with the proper value of
-.IR N .
-The
-.B \-E
-and
-.B \-N
-options are also common.
+options to use. The option string
+.B "\-Np1"
+is recommended.
Test your procedure by pretending to be a recipient and applying
-your patches to a copy of the original files.
+your patch to a copy of the original files.
.PP
You can save people a lot of grief by keeping a
.B patchlevel.h
file which is patched to increment the patch level
as the first diff in the patch file you send out.
If you put a
-.B Prereq:
+.B Prereq:\&
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:
+.B Index:\&
line.
.PP
You can create a file by sending out a diff that compares an
@@ -573,12 +659,15 @@ 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.
-The file will be left empty, but not actually be removed unless the
+The file will be removed unless the
+.B POSIXLY_CORRECT
+environment variable is set and the
.B \-E
or
.B \*=remove\-empty\-files
-option is given.
-An easy way to generate patches that create and remove files is to use GNU
+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 \*=new\-file
option.
@@ -588,11 +677,12 @@ If the recipient is supposed to use the
option, do not send output that looks like this:
.Sp
.ft B
- diff \-uNR v2.0.29/prog/README prog/README
+.ne 3
+ diff \-Naur v2.0.29/prog/README prog/README
.br
- \-\-\- v2.0.29/prog/README Mon Mar 10 15:13:12 1997
+ \-\^\-\^\- v2.0.29/prog/README Mon Mar 10 15:13:12 1997
.br
- +++ prog/README Mon Mar 17 14:58:22 1997
+ +\^+\^+ prog/README Mon Mar 17 14:58:22 1997
.ft
.Sp
because the two file names have different numbers of slashes,
@@ -602,19 +692,83 @@ interpret the file names differently.
To avoid confusion, send output that looks like this instead:
.Sp
.ft B
- diff \-uNR v2.0.29/prog/README v2.0.30/prog/README
+.ne 3
+ diff \-Naur v2.0.29/prog/README v2.0.30/prog/README
.br
- \-\-\- v2.0.29/prog/README Mon Mar 10 15:13:12 1997
+ \-\^\-\^\- v2.0.29/prog/README Mon Mar 10 15:13:12 1997
.br
- +++ v2.0.30/prog/README Mon Mar 17 14:58:22 1997
+ +\^+\^+ v2.0.30/prog/README Mon Mar 17 14:58:22 1997
.ft
.Sp
.PP
+Avoid sending patches that compare backup file names like
+.BR README.orig ,
+since this might confuse
+.B patch
+into patching a backup file instead of the real file.
+Instead, send patches that compare the same base file names
+in different directories, e.g.\&
+.B old/README
+and
+.BR new/README .
+.PP
Take care not to send out reversed patches, since it makes people wonder
whether they already applied the patch.
.PP
+Try not to have your patch modify derived files
+(e.g. the file
+.B configure
+where there is a line
+.B "configure: configure.in"
+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
+.PP
While you may be able to get away with putting 582 diff listings into
-one file, it is probably wiser to group related patches into separate files in
+one file, it may be wiser to group related patches into separate files in
case something goes haywire.
.SH DIAGNOSTICS
Diagnostics generally indicate that
@@ -639,6 +793,13 @@ and 2 if there is more serious trouble.
When applying a set of patches in a loop it behooves you to check this
exit status so you don't apply a later patch to a partially patched file.
.SH CAVEATS
+Context diffs cannot reliably represent the creation or deletion of
+empty files, empty directories, or special files such as symbolic links.
+Nor can they represent changes to file metadata like ownership, permissions,
+or whether one file is a hard link to another.
+If changes like these are also required, separate instructions
+(e.g. a shell script) to accomplish them should accompany the patch.
+.PP
.B patch
cannot tell if the line numbers are off in an
.B ed
@@ -662,7 +823,7 @@ could be smarter about partial matches, excessively deviant offsets and
swapped code, but that would take an extra pass.
.PP
If code has been duplicated (for instance with
-.BR "#ifdef OLDCODE .\|.\|. #else .\|.\|. #endif" ),
+\fB#ifdef OLDCODE\fP .\|.\|. \fB#else .\|.\|. #endif\fP),
.B patch
is incapable of patching both versions, and, if it works at all, will likely
patch the wrong one, and tell you that it succeeded to boot.
@@ -700,6 +861,6 @@ Larry Wall wrote the original version of
Paul Eggert removed
.BR patch 's
arbitrary limits, added support for binary files,
-and made it conform better to Posix.
+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/chdirsaf.c b/pc/chdirsaf.c
new file mode 100644
index 0000000..0598f78
--- /dev/null
+++ b/pc/chdirsaf.c
@@ -0,0 +1,34 @@
+/* A safer version of chdir, which returns back to the
+ initial working directory when the program exits. */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static char *initial_wd;
+
+static void
+restore_wd (void)
+{
+ chdir (initial_wd);
+}
+
+int
+chdir_safer (char const *dir)
+{
+ if (! initial_wd)
+ {
+ size_t s;
+ for (s = 256; ! (initial_wd = getcwd (0, s)); s *= 2)
+ if (errno != ERANGE)
+ return -1;
+ if (atexit (restore_wd) != 0)
+ {
+ free (initial_wd);
+ initial_wd = 0;
+ return -1;
+ }
+ }
+
+ return chdir (dir);
+}
diff --git a/pc/djgpp/README b/pc/djgpp/README
new file mode 100644
index 0000000..ef1cba7
--- /dev/null
+++ b/pc/djgpp/README
@@ -0,0 +1,19 @@
+To configure `patch' for DJGPP, issue these commands from the
+`patch' source directory:
+
+ pc\djgpp\configure
+ make
+
+To build `patch' in a directory other than where the sources are,
+add a parameter that specifies the source directory, e.g.:
+
+ e:\gnu\patch-2.3\pc\djgpp\configure e:/gnu/patch-2.3
+
+You MUST use forward slashes to specify the source directory.
+
+Running configure.bat requires a port of `sed'.
+You can find one on the usual DJGPP archive sites.
+
+
+Thanks to Eli Zaretskii <eliz@is.elta.co.il> for
+suggestions and ideas for this DJGPP port.
diff --git a/pc/djgpp/config.h b/pc/djgpp/config.h
new file mode 100644
index 0000000..d2f6cb5
--- /dev/null
+++ b/pc/djgpp/config.h
@@ -0,0 +1,139 @@
+/* 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
new file mode 100644
index 0000000..cc449fd
--- /dev/null
+++ b/pc/djgpp/config.sed
@@ -0,0 +1,35 @@
+# Edit Makefile.in to produce Makefile for DJGPP v2
+# $Id: config.sed,v 1.4 1997/05/26 17:52:29 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|@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)/
+
+$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
diff --git a/pc/djgpp/configure.bat b/pc/djgpp/configure.bat
new file mode 100644
index 0000000..c5313ea
--- /dev/null
+++ b/pc/djgpp/configure.bat
@@ -0,0 +1,27 @@
+@echo off
+Rem Configure patch for DJGPP v2.
+Rem $Id: configure.bat,v 1.3 1997/05/26 17:52:29 eggert Exp $
+
+Rem The DOS shell has fixed-size environment storage.
+Rem When the environment is full, the shell prints
+Rem "Out of environment space" and truncates the string at will.
+Rem Since people often ignore these messages,
+Rem test whether the environment variable got the correct value.
+
+Rem Where is our source directory?
+set srcdir=.
+if not "%srcdir%" == "." goto SmallEnv
+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 -n -e "/^VERSION/p" %srcdir%/configure.in >>Makefile
+
+goto Exit
+
+:SmallEnv
+echo Your environment size is too small. Please enlarge it and run me again.
+
+:Exit
+set srcdir=
diff --git a/pch.c b/pch.c
index f9d2d73..38eaf03 100644
--- a/pch.c
+++ b/pch.c
@@ -1,6 +1,6 @@
/* reading patches */
-/* $Id: pch.c,v 1.7 1997/04/14 05:32:30 eggert Exp $ */
+/* $Id: pch.c,v 1.16 1997/05/26 17:52:29 eggert Exp $ */
/*
Copyright 1986, 1987, 1988 Larry Wall
@@ -24,6 +24,7 @@ If not, write to the Free Software Foundation,
#define XTERN extern
#include <common.h>
+#include <backupfile.h>
#include <inp.h>
#include <util.h>
#undef XTERN
@@ -35,6 +36,7 @@ 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 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 */
@@ -48,23 +50,28 @@ static LINENUM p_input_line; /* current line # from patch file */
static char **p_line; /* the text of the hunk */
static size_t *p_len; /* line length including \n if any */
static char *p_Char; /* +, -, and ! */
-static size_t hunkmax = INITHUNKMAX; /* size of above arrays */
+static LINENUM hunkmax = INITHUNKMAX; /* size of above arrays */
static int p_indent; /* indent to patch */
-static long p_base; /* where to intuit this time */
+static file_offset p_base; /* where to intuit this time */
static LINENUM p_bline; /* line # of p_base */
-static long p_start; /* where intuit found a patch */
+static file_offset p_start; /* where intuit found a patch */
static LINENUM p_sline; /* and the line number for it */
static LINENUM p_hunk_beg; /* line number of current hunk */
static LINENUM p_efake = -1; /* end of faked up lines--don't free */
static LINENUM p_bfake = -1; /* beg of faked up lines */
+enum nametype { OLD, NEW, INDEX, NONE };
+
static enum diff intuit_diff_type PARAMS ((void));
+static enum nametype best_name PARAMS ((char * const *, int const *));
+static int prefix_components PARAMS ((char *, int));
static size_t pget_line PARAMS ((int));
static size_t get_line PARAMS ((void));
static bool incomplete_line PARAMS ((void));
static bool grow_hunkmax PARAMS ((void));
-static void next_intuit_at PARAMS ((long, LINENUM));
-static void skip_to PARAMS ((long, LINENUM));
+static void malformed PARAMS ((void));
+static void next_intuit_at PARAMS ((file_offset, LINENUM));
+static void skip_to PARAMS ((file_offset, LINENUM));
/* Prepare to look for the next patch in the patch file. */
@@ -86,41 +93,49 @@ void
open_patch_file(filename)
char const *filename;
{
- long file_pos = 0;
+ file_offset file_pos = 0;
struct stat st;
if (!filename || !*filename || strEQ (filename, "-"))
{
+#if HAVE_SETMODE
+ if (binary_transput)
+ {
+ if (isatty (STDIN_FILENO))
+ fatal ("cannot read binary data from tty on this platform");
+ setmode (STDIN_FILENO, O_BINARY);
+ }
+#endif
if (fstat (STDIN_FILENO, &st) != 0)
pfatal ("fstat");
if (S_ISREG (st.st_mode))
{
pfp = stdin;
- file_pos = ftell (stdin);
- filename = 0;
+ file_pos = file_tell (stdin);
}
else
{
size_t charsread;
- pfp = fopen (TMPPATNAME, "w");
+ pfp = fopen (TMPPATNAME, "w+b");
if (!pfp)
- pfatal ("can't create %s", TMPPATNAME);
+ pfatal ("can't create `%s'", TMPPATNAME);
while ((charsread = fread (buf, 1, bufsize, stdin)) != 0)
if (fwrite (buf, 1, charsread, pfp) != charsread)
write_fatal ();
if (ferror (stdin) || fclose (stdin) != 0)
read_fatal ();
- if (fclose (pfp) != 0)
+ if (fflush (pfp) != 0
+ || file_seek (pfp, (file_offset) 0, SEEK_SET) != 0)
write_fatal ();
- filename = TMPPATNAME;
}
}
- if (filename) {
- pfp = fopen (filename, "r");
+ else
+ {
+ pfp = fopen (filename, binary_transput ? "rb" : "r");
if (!pfp)
- pfatal ("patch file %s not found", filename);
+ pfatal ("can't open patch file `%s'", filename);
if (fstat (fileno (pfp), &st) != 0)
pfatal ("fstat");
- }
+ }
p_filesize = st.st_size;
next_intuit_at (file_pos, (LINENUM) 1);
set_hunkmax();
@@ -179,6 +194,8 @@ there_is_another_patch()
: " I can't seem to find a patch in there anywhere.\n");
return FALSE;
}
+ if (skip_rest_of_patch)
+ return TRUE;
if (verbosity == VERBOSE)
say (" %sooks like %s to me...\n",
(p_base == 0 ? "L" : "The next patch l"),
@@ -197,16 +214,26 @@ there_is_another_patch()
return TRUE;
}
ask ("File to patch: ");
- inname = fetchname (buf, 0);
+ inname = fetchname (buf, 0, (int *) 0);
+ if (inname)
+ {
+ if (stat (inname, &instat) == 0)
+ inerrno = 0;
+ else
+ {
+ perror (inname);
+ free (inname);
+ inname = 0;
+ }
+ }
if (!inname) {
ask ("Skip this patch? [y] ");
- if (*buf == 'n') {
- continue;
+ if (*buf != 'n') {
+ if (verbosity != SILENT)
+ say ("Skipping patch...\n");
+ skip_rest_of_patch = TRUE;
+ return TRUE;
}
- if (verbosity != SILENT)
- say ("Skipping patch...\n");
- skip_rest_of_patch = TRUE;
- return TRUE;
}
}
return TRUE;
@@ -220,30 +247,31 @@ intuit_diff_type()
register char *s;
register char *t;
register int indent;
- register long this_line = 0;
- register long previous_line;
- register long first_command_line = -1;
+ register file_offset this_line = 0;
+ register file_offset previous_line;
+ register file_offset first_command_line = -1;
LINENUM fcl_line = 0; /* Pacify `gcc -W'. */
register bool last_line_was_command = FALSE;
register bool this_is_a_command = FALSE;
register bool stars_last_line = FALSE;
register bool stars_this_line = FALSE;
- enum nametype { OLD, NEW, INDEX, NONE } i;
+ enum nametype i;
char *name[3];
struct stat st[3];
int stat_errno[3];
- int dir_count[3];
register enum diff retval;
+ int head_says_nonexistent[2];
name[OLD] = name[NEW] = name[INDEX] = 0;
- ok_to_create_file = FALSE;
+ head_says_nonexistent[OLD] = head_says_nonexistent[NEW] = 0;
+ p_says_nonexistent[OLD] = p_says_nonexistent[NEW] = 0;
Fseek (pfp, p_base, SEEK_SET);
p_input_line = p_bline - 1;
for (;;) {
previous_line = this_line;
last_line_was_command = this_is_a_command;
stars_last_line = stars_this_line;
- this_line = ftell(pfp);
+ this_line = file_tell (pfp);
indent = 0;
if (! pget_line (0)) {
if (first_command_line >= 0) {
@@ -276,13 +304,14 @@ intuit_diff_type()
p_indent = indent; /* assume this for now */
}
if (!stars_last_line && strnEQ(s, "*** ", 4))
- name[OLD] = fetchname (s+4, strippath);
+ name[OLD] = fetchname (s+4, strippath, &head_says_nonexistent[OLD]);
else if (strnEQ(s, "--- ", 4))
- name[NEW] = fetchname (s+4, strippath);
+ name[NEW] = fetchname (s+4, strippath, &head_says_nonexistent[NEW]);
else if (strnEQ(s, "+++ ", 4))
- name[OLD] = fetchname (s+4, strippath); /* Swap with NEW below. */
+ /* Swap with NEW below. */
+ name[OLD] = fetchname (s+4, strippath, &head_says_nonexistent[OLD]);
else if (strnEQ(s, "Index:", 6))
- name[INDEX] = fetchname (s+6, strippath);
+ name[INDEX] = fetchname (s+6, strippath, (int *) 0);
else if (strnEQ(s, "Prereq:", 7)) {
for (t = s + 7; ISSPACE ((unsigned char) *t); t++)
continue;
@@ -309,23 +338,24 @@ intuit_diff_type()
}
if ((diff_type == NO_DIFF || diff_type == UNI_DIFF)
&& strnEQ(s, "@@ -", 4)) {
- s += 3;
- if (reverse)
- {
- while (*s != ' ' && *s != '\n')
- s++;
- while (*s == ' ')
- s++;
- }
- if (!atol(s))
- ok_to_create_file = TRUE;
+ s += 4;
+ /* `name' and `head_says_nonexistent' are backwards.
+ Swap the former, and interpret the latter backwards. */
+ t = name[OLD];
+ name[OLD] = name[NEW];
+ name[NEW] = t;
+ if (head_says_nonexistent[NEW] && ! atol (s))
+ p_says_nonexistent[OLD] = 1;
+ while (*s != ' ' && *s != '\n')
+ s++;
+ while (*s == ' ')
+ s++;
+ if (head_says_nonexistent[OLD] && ! atol (s))
+ p_says_nonexistent[NEW] = 1;
p_indent = indent;
p_start = this_line;
p_sline = p_input_line;
retval = UNI_DIFF;
- t = name[OLD];
- name[OLD] = name[NEW];
- name[NEW] = t;
goto scan_exit;
}
stars_this_line = strnEQ(s, "********", 8);
@@ -333,9 +363,9 @@ intuit_diff_type()
|| diff_type == CONTEXT_DIFF
|| diff_type == NEW_CONTEXT_DIFF)
&& stars_last_line && strnEQ (s, "*** ", 4)) {
- if (! reverse)
- if (! atol (s + 4))
- ok_to_create_file = TRUE;
+ s += 4;
+ if (head_says_nonexistent[OLD] && ! atol (s))
+ p_says_nonexistent[OLD] = 1;
/* if this is a new context diff the character just before */
/* the newline is a '*'. */
while (*s != '\n')
@@ -344,19 +374,21 @@ intuit_diff_type()
p_start = previous_line;
p_sline = p_input_line - 1;
retval = (*(s-1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);
- if (reverse)
+
+ if (head_says_nonexistent[NEW])
{
- /* If the patch is a reversed context diff,
- scan the entire first hunk to see whether
- it's OK to create the file. */
- long saved_p_base = p_base;
+ /* 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) && ! p_ptrn_lines && p_first == 1)
- ok_to_create_file = TRUE;
+ 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);
}
+
goto scan_exit;
}
if ((diff_type == NO_DIFF || diff_type == NORMAL_DIFF) &&
@@ -372,40 +404,86 @@ intuit_diff_type()
scan_exit:
- /* Use algorithm specified by POSIX 1003.2b/D11 to deduce `inname',
- the name of the file to patch; except that if the patch syntactically
- can create a file, before asking the user for a file name
- redo the earlier steps in sequence, this time ignoring the
- nonexistence of a file if the path length of the existing directory
- in the file name is a maximum among all the candidate file names. */
+ /* To intuit `inname', the name of the file to patch,
+ use the algorithm specified by POSIX 1003.2b/D11 section 5.22.7.2
+ (with some modifications if posixly_correct is zero):
- for (i = OLD; i <= INDEX; i++)
- if (!inname && name[i])
- {
- if (stat (name[i], &st[i]) != 0)
- stat_errno[i] = errno;
- else
- {
- stat_errno[i] = 0;
- break;
- }
- }
+ - 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 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
+ 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. */
+
+ i = NONE;
- if (i == NONE && !inname && ok_to_create_file)
+ if (!inname)
{
- int dir_count_max = 0;
+ enum nametype i0 = NONE;
for (i = OLD; i <= INDEX; i++)
if (name[i])
{
- dir_count[i] = countdirs (name[i]);
- if (dir_count_max < dir_count[i])
- dir_count_max = dir_count[i];
+ if (i0 != NONE && strcmp (name[i0], name[i]) == 0)
+ {
+ /* It's the same name as before; reuse stat results. */
+ stat_errno[i] = stat_errno[i0];
+ if (! stat_errno[i])
+ st[i] = st[i0];
+ }
+ else if (stat (name[i], &st[i]) != 0)
+ stat_errno[i] = errno;
+ else
+ {
+ stat_errno[i] = 0;
+ if (posixly_correct)
+ break;
+ }
+ i0 = i;
}
- for (i = OLD; i <= INDEX; i++)
- if (name[i] && dir_count[i] == dir_count_max)
- break;
+ if (! posixly_correct)
+ {
+ i = best_name (name, stat_errno);
+
+ if (p_says_nonexistent[reverse ^ (i == NONE)])
+ {
+ 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"))
+ reverse ^= 1;
+ }
+
+ if (i == NONE && p_says_nonexistent[reverse])
+ {
+ int newdirs[3];
+ int newdirs_min = INT_MAX;
+ int distance_from_minimum[3];
+
+ for (i = OLD; i <= INDEX; i++)
+ if (name[i])
+ {
+ newdirs[i] = (prefix_components (name[i], 0)
+ - prefix_components (name[i], 1));
+ if (newdirs[i] < newdirs_min)
+ newdirs_min = newdirs[i];
+ }
+
+ for (i = OLD; i <= INDEX; i++)
+ if (name[i])
+ distance_from_minimum[i] = newdirs[i] - newdirs_min;
+
+ i = best_name (name, distance_from_minimum);
+ }
+ }
}
if (i == NONE)
@@ -425,11 +503,91 @@ intuit_diff_type()
return retval;
}
+/* Count the path name components in FILENAME's prefix.
+ If CHECKDIRS is nonzero, count only existing directories. */
+static int
+prefix_components (filename, checkdirs)
+ char *filename;
+ int checkdirs;
+{
+ int count = 0;
+ struct stat stat_buf;
+ int stat_result;
+ char *f = filename + FILESYSTEM_PREFIX_LEN (filename);
+
+ if (*f)
+ while (*++f)
+ if (ISSLASH (f[0]) && ! ISSLASH (f[-1]))
+ {
+ if (checkdirs)
+ {
+ *f = '\0';
+ stat_result = stat (filename, &stat_buf);
+ *f = '/';
+ if (! (stat_result == 0 && S_ISDIR (stat_buf.st_mode)))
+ break;
+ }
+
+ count++;
+ }
+
+ return count;
+}
+
+/* Return the index of the best of NAME[OLD], NAME[NEW], and NAME[INDEX].
+ Ignore null names, and ignore NAME[i] if IGNORE[i] is nonzero.
+ Return NONE if all names are ignored. */
+static enum nametype
+best_name (name, ignore)
+ char *const *name;
+ int const *ignore;
+{
+ enum nametype i;
+ int components[3];
+ int components_min = INT_MAX;
+ size_t basename_len[3];
+ size_t basename_len_min = (size_t) -1;
+ size_t len[3];
+ size_t len_min = (size_t) -1;
+
+ for (i = OLD; i <= INDEX; i++)
+ if (name[i] && !ignore[i])
+ {
+ /* Take the names with the fewest prefix components. */
+ components[i] = prefix_components (name[i], 0);
+ if (components_min < components[i])
+ continue;
+ components_min = components[i];
+
+ /* Of those, take the names with the shortest basename. */
+ basename_len[i] = strlen (base_name (name[i]));
+ if (basename_len_min < basename_len[i])
+ continue;
+ basename_len_min = basename_len[i];
+
+ /* Of those, take the shortest names. */
+ len[i] = strlen (name[i]);
+ if (len_min < len[i])
+ continue;
+ len_min = len[i];
+ }
+
+ /* Of those, take the first name. */
+ for (i = OLD; i <= INDEX; i++)
+ if (name[i] && !ignore[i]
+ && components[i] == components_min
+ && basename_len[i] == basename_len_min
+ && len[i] == len_min)
+ break;
+
+ return i;
+}
+
/* Remember where this patch ends so we know where to start up again. */
static void
next_intuit_at(file_pos,file_line)
-long file_pos;
+file_offset file_pos;
LINENUM file_line;
{
p_base = file_pos;
@@ -440,7 +598,7 @@ LINENUM file_line;
static void
skip_to(file_pos,file_line)
-long file_pos;
+file_offset file_pos;
LINENUM file_line;
{
register FILE *i = pfp;
@@ -452,7 +610,7 @@ LINENUM file_line;
Fseek (i, p_base, SEEK_SET);
say ("The text leading up to this was:\n--------------------------\n");
- while (ftell (i) < file_pos)
+ while (file_tell (i) < file_pos)
{
putc ('|', o);
do
@@ -483,8 +641,9 @@ malformed ()
0 if not; -1 if ran out of memory. */
int
-another_hunk (difftype)
+another_hunk (difftype, rev)
enum diff difftype;
+ int rev;
{
register char *s;
register LINENUM context = 0;
@@ -502,7 +661,7 @@ another_hunk (difftype)
p_max = hunkmax; /* gets reduced when --- found */
if (difftype == CONTEXT_DIFF || difftype == NEW_CONTEXT_DIFF) {
- long line_beginning = ftell(pfp);
+ file_offset line_beginning = file_tell (pfp);
/* file pos of the current line */
LINENUM repl_beginning = 0; /* index of --- line */
register LINENUM fillcnt = 0; /* #lines of missing ptrn or repl */
@@ -512,10 +671,13 @@ another_hunk (difftype)
bool some_context = FALSE; /* (perhaps internal) context seen */
register bool repl_could_be_missing = TRUE;
bool repl_missing = FALSE; /* we are now backtracking */
- long repl_backtrack_position = 0;
+ file_offset repl_backtrack_position = 0;
/* file pos of first repl line */
LINENUM repl_patch_line; /* input line number for same */
LINENUM repl_context; /* context for same */
+ LINENUM ptrn_prefix_context = -1; /* lines in pattern prefix context */
+ LINENUM ptrn_suffix_context = -1; /* lines in pattern suffix context */
+ LINENUM repl_prefix_context = -1; /* lines in replac. prefix context */
register LINENUM ptrn_copiable = 0;
/* # of copiable lines in ptrn */
@@ -529,7 +691,6 @@ another_hunk (difftype)
next_intuit_at(line_beginning,p_input_line);
return chars_read == (size_t) -1 ? -1 : 0;
}
- p_prefix_context = -1;
p_hunk_beg = p_input_line + 1;
while (p_end < p_max) {
chars_read = get_line ();
@@ -609,85 +770,86 @@ another_hunk (difftype)
p_max = hunkmax;
break;
case '-':
- if (buf[1] == '-') {
- if (p_prefix_context == -1)
- p_prefix_context = context;
- if (repl_beginning ||
- (p_end != p_ptrn_lines + 1 + (p_Char[p_end-1] == '\n')))
- {
- if (p_end == 1) {
- /* `old' lines were omitted - set up to fill */
- /* them in from 'new' context lines. */
- p_end = p_ptrn_lines + 1;
- fillsrc = p_end + 1;
- filldst = 1;
- fillcnt = p_ptrn_lines;
- }
- else {
- if (repl_beginning) {
- if (repl_could_be_missing){
- repl_missing = TRUE;
- goto hunk_done;
- }
- fatal (
-"duplicate \"---\" at line %ld--check line numbers at line %ld",
- p_input_line, p_hunk_beg + repl_beginning);
- }
- else {
- fatal (
-"%s \"---\" at line %ld--check line numbers at line %ld",
- (p_end <= p_ptrn_lines
- ? "Premature"
- : "Overdue" ),
- p_input_line, p_hunk_beg);
- }
- }
- }
- repl_beginning = p_end;
- repl_backtrack_position = ftell(pfp);
- repl_patch_line = p_input_line;
- repl_context = context;
- p_len[p_end] = strlen (buf);
- if (! (p_line[p_end] = savestr (buf))) {
- p_end--;
- return -1;
- }
- p_Char[p_end] = '=';
- for (s = buf; *s && !ISDIGIT (*s); s++)
- continue;
- if (!*s)
- malformed ();
- p_newfirst = (LINENUM) atol(s);
- while (ISDIGIT (*s))
- s++;
- if (*s == ',') {
- do
- {
- if (!*++s)
- malformed ();
- }
- while (!ISDIGIT (*s));
- p_repl_lines = ((LINENUM)atol(s)) - p_newfirst + 1;
- }
- else if (p_newfirst)
- p_repl_lines = 1;
- else {
- p_repl_lines = 0;
- p_newfirst = 1;
- }
- p_max = p_repl_lines + p_end;
- while (p_max >= hunkmax)
- if (! grow_hunkmax ())
- return -1;
- if (p_repl_lines != ptrn_copiable
- && (p_prefix_context != 0
- || context != 0
- || p_repl_lines != 1))
- repl_could_be_missing = FALSE;
- context = 0;
- break;
- }
- goto change_line;
+ if (buf[1] != '-')
+ goto change_line;
+ if (ptrn_prefix_context == -1)
+ ptrn_prefix_context = context;
+ ptrn_suffix_context = context;
+ if (repl_beginning
+ || (p_end
+ != p_ptrn_lines + 1 + (p_Char[p_end - 1] == '\n')))
+ {
+ if (p_end == 1)
+ {
+ /* `Old' lines were omitted. Set up to fill
+ them in from `new' context lines. */
+ p_end = p_ptrn_lines + 1;
+ ptrn_prefix_context = ptrn_suffix_context = -1;
+ fillsrc = p_end + 1;
+ filldst = 1;
+ fillcnt = p_ptrn_lines;
+ }
+ else if (! repl_beginning)
+ fatal ("%s `---' at line %ld; check line numbers at line %ld",
+ (p_end <= p_ptrn_lines
+ ? "Premature"
+ : "Overdue"),
+ p_input_line, p_hunk_beg);
+ else if (! repl_could_be_missing)
+ fatal ("duplicate `---' at line %ld; check line numbers at line %ld",
+ p_input_line, p_hunk_beg + repl_beginning);
+ else
+ {
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ }
+ repl_beginning = p_end;
+ repl_backtrack_position = file_tell (pfp);
+ repl_patch_line = p_input_line;
+ repl_context = context;
+ p_len[p_end] = strlen (buf);
+ if (! (p_line[p_end] = savestr (buf)))
+ {
+ p_end--;
+ return -1;
+ }
+ p_Char[p_end] = '=';
+ for (s = buf; *s && ! ISDIGIT (*s); s++)
+ continue;
+ if (!*s)
+ malformed ();
+ p_newfirst = (LINENUM) atol (s);
+ while (ISDIGIT (*s))
+ s++;
+ if (*s == ',')
+ {
+ do
+ {
+ if (!*++s)
+ malformed ();
+ }
+ while (! ISDIGIT (*s));
+ p_repl_lines = (LINENUM) atol (s) - p_newfirst + 1;
+ }
+ else if (p_newfirst)
+ p_repl_lines = 1;
+ else
+ {
+ p_repl_lines = 0;
+ p_newfirst = 1;
+ }
+ p_max = p_repl_lines + p_end;
+ while (p_max >= hunkmax)
+ if (! grow_hunkmax ())
+ return -1;
+ if (p_repl_lines != ptrn_copiable
+ && (p_prefix_context != 0
+ || context != 0
+ || p_repl_lines != 1))
+ repl_could_be_missing = FALSE;
+ context = 0;
+ break;
case '+': case '!':
repl_could_be_missing = FALSE;
change_line:
@@ -704,8 +866,16 @@ another_hunk (difftype)
repl_missing = TRUE;
goto hunk_done;
}
- if (p_prefix_context == -1)
- p_prefix_context = context;
+ if (! repl_beginning)
+ {
+ if (ptrn_prefix_context == -1)
+ ptrn_prefix_context = context;
+ }
+ else
+ {
+ if (repl_prefix_context == -1)
+ repl_prefix_context = context;
+ }
chars_read -=
(1 < chars_read
&& p_end == (repl_beginning ? p_max : p_ptrn_lines)
@@ -785,7 +955,7 @@ another_hunk (difftype)
hunk_done:
if (p_end >=0 && !repl_beginning)
- fatal ("no --- found in patch at line %ld", pch_hunk_beg ());
+ fatal ("no `---' found in patch at line %ld", pch_hunk_beg ());
if (repl_missing) {
@@ -821,7 +991,14 @@ another_hunk (difftype)
p_ptrn_lines = 0;
}
- p_suffix_context = context;
+ p_prefix_context = ((repl_prefix_context == -1
+ || (ptrn_prefix_context != -1
+ && ptrn_prefix_context < repl_prefix_context))
+ ? ptrn_prefix_context : repl_prefix_context);
+ p_suffix_context = ((ptrn_suffix_context != -1
+ && ptrn_suffix_context < context)
+ ? ptrn_suffix_context : context);
+ assert (p_prefix_context != -1 && p_suffix_context != -1);
if (difftype == CONTEXT_DIFF
&& (fillcnt
@@ -829,7 +1006,7 @@ another_hunk (difftype)
&& p_prefix_context + p_suffix_context < ptrn_copiable))) {
if (verbosity == VERBOSE)
say ("%s\n%s\n%s\n",
-"(Fascinating--this is really a new-style context diff but without",
+"(Fascinating -- this is really a new-style context diff but without",
"the telltale extra asterisks on the *** line that usually indicate",
"the new style...)");
diff_type = difftype = NEW_CONTEXT_DIFF;
@@ -866,7 +1043,7 @@ another_hunk (difftype)
}
}
else if (difftype == UNI_DIFF) {
- long line_beginning = ftell(pfp);
+ file_offset line_beginning = file_tell (pfp);
/* file pos of the current line */
register LINENUM fillsrc; /* index of old lines */
register LINENUM filldst; /* index of new lines */
@@ -1018,13 +1195,15 @@ another_hunk (difftype)
context = 0;
}
}/* while */
+ if (p_prefix_context == -1)
+ malformed ();
p_suffix_context = context;
}
else { /* normal diff--fake it up */
char hunk_type;
register int i;
LINENUM min, max;
- long line_beginning = ftell(pfp);
+ file_offset line_beginning = file_tell (pfp);
p_prefix_context = p_suffix_context = 0;
chars_read = get_line ();
@@ -1131,7 +1310,7 @@ another_hunk (difftype)
p_Char[i] = '+';
}
}
- if (reverse) /* backwards patch? */
+ if (rev) /* backwards patch? */
if (!pch_swap())
say ("Not enough memory to swap next hunk!\n");
if (debug & 2) {
@@ -1237,7 +1416,7 @@ incomplete_line ()
{
register FILE *fp = pfp;
register int c;
- register long line_beginning = ftell (fp);
+ register file_offset line_beginning = file_tell (fp);
if (getc (fp) == '\\')
{
@@ -1354,6 +1533,15 @@ pch_swap()
return TRUE;
}
+/* Return whether file WHICH (0 = old, 1 = new) appears to be nonexistent. */
+
+bool
+pch_says_nonexistent (which)
+ int which;
+{
+ return p_says_nonexistent[which];
+}
+
/* Return the specified line position in the old file of the old context. */
LINENUM
@@ -1464,24 +1652,25 @@ void
do_ed_script (ofp)
FILE *ofp;
{
- static char const ed_program[] = ED_PROGRAM;
+ static char const ed_program[] = ed_PROGRAM;
register char *t;
- register long beginning_of_this_line;
+ register file_offset beginning_of_this_line;
register bool this_line_is_command = FALSE;
register FILE *pipefp = 0;
register size_t chars_read;
if (!skip_rest_of_patch) {
- copy_file (inname, TMPOUTNAME);
+ assert (! inerrno);
+ copy_file (inname, TMPOUTNAME, instat.st_mode);
sprintf (buf, "%s %s%s", ed_program, verbosity == VERBOSE ? "" : "- ",
TMPOUTNAME);
- pipefp = popen(buf, "w");
+ pipefp = popen(buf, binary_transput ? "wb" : "w");
if (!pipefp)
- pfatal (buf);
+ pfatal ("can't open pipe to `%s'", buf);
}
for (;;) {
- beginning_of_this_line = ftell(pfp);
+ beginning_of_this_line = file_tell (pfp);
chars_read = get_line ();
if (! chars_read) {
next_intuit_at(beginning_of_this_line,p_input_line);
@@ -1520,10 +1709,10 @@ do_ed_script (ofp)
if (ofp)
{
- FILE *ifp = fopen (TMPOUTNAME, "r");
+ FILE *ifp = fopen (TMPOUTNAME, binary_transput ? "rb" : "r");
int c;
if (!ifp)
- pfatal (TMPOUTNAME);
+ pfatal ("can't open `%s'", TMPOUTNAME);
while ((c = getc (ifp)) != EOF)
if (putc (c, ofp) == EOF)
write_fatal ();
diff --git a/pch.h b/pch.h
index d2c645b..947e1c3 100644
--- a/pch.h
+++ b/pch.h
@@ -1,6 +1,6 @@
/* reading patches */
-/* $Id: pch.h,v 1.5 1997/04/07 01:07:00 eggert Exp $ */
+/* $Id: pch.h,v 1.7 1997/05/19 06:52:03 eggert Exp $ */
LINENUM pch_end PARAMS ((void));
LINENUM pch_first PARAMS ((void));
@@ -15,7 +15,8 @@ bool pch_write_line PARAMS ((LINENUM, FILE *));
bool there_is_another_patch PARAMS ((void));
char *pfetch PARAMS ((LINENUM));
char pch_char PARAMS ((LINENUM));
-int another_hunk PARAMS ((enum diff));
+int another_hunk PARAMS ((enum diff, int));
+int pch_says_nonexistent PARAMS ((int));
size_t pch_line_len PARAMS ((LINENUM));
void do_ed_script PARAMS ((FILE *));
void open_patch_file PARAMS ((char const *));
diff --git a/quotearg.c b/quotearg.c
new file mode 100644
index 0000000..e4926e4
--- /dev/null
+++ b/quotearg.c
@@ -0,0 +1,125 @@
+/* Shell command argument quoting.
+ Copyright (C) 1994, 1995, 1997 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING.
+ If not, write to the Free Software Foundation,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Paul Eggert <eggert@twinsun.com> */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <quotearg.h>
+
+/* Place into QUOTED a quoted version of ARG suitable for `system'.
+ Return the length of the resulting string (which is not null-terminated).
+ If QUOTED is null, return the length without any side effects. */
+
+size_t
+quote_system_arg (quoted, arg)
+ char *quoted;
+ char const *arg;
+{
+ char const *a;
+ size_t len = 0;
+
+ /* Scan ARG, copying it to QUOTED if QUOTED is not null,
+ looking for shell metacharacters. */
+
+ for (a = arg; ; a++)
+ {
+ char c = *a;
+ switch (c)
+ {
+ case 0:
+ /* ARG has no shell metacharacters. */
+ return len;
+
+ case '=':
+ if (*arg == '-')
+ break;
+ /* Fall through. */
+ case '\t': case '\n': case ' ':
+ case '!': case '"': case '#': case '$': case '%': case '&': case '\'':
+ case '(': case ')': case '*': case ';':
+ case '<': case '>': case '?': case '[': case '\\':
+ case '^': case '`': case '|': case '~':
+ {
+ /* ARG has a shell metacharacter.
+ Start over, quoting it this time. */
+
+ len = 0;
+ c = *arg++;
+
+ /* If ARG is an option, quote just its argument.
+ This is not necessary, but it looks nicer. */
+ if (c == '-' && arg < a)
+ {
+ c = *arg++;
+
+ if (quoted)
+ {
+ quoted[len] = '-';
+ quoted[len + 1] = c;
+ }
+ len += 2;
+
+ if (c == '-')
+ while (arg < a)
+ {
+ c = *arg++;
+ if (quoted)
+ quoted[len] = c;
+ len++;
+ if (c == '=')
+ break;
+ }
+ c = *arg++;
+ }
+
+ if (quoted)
+ quoted[len] = '\'';
+ len++;
+
+ for (; c; c = *arg++)
+ {
+ if (c == '\'')
+ {
+ if (quoted)
+ {
+ quoted[len] = '\'';
+ quoted[len + 1] = '\\';
+ quoted[len + 2] = '\'';
+ }
+ len += 3;
+ }
+ if (quoted)
+ quoted[len] = c;
+ len++;
+ }
+
+ if (quoted)
+ quoted[len] = '\'';
+ return len + 1;
+ }
+ }
+
+ if (quoted)
+ quoted[len] = c;
+ len++;
+ }
+}
diff --git a/quotearg.h b/quotearg.h
new file mode 100644
index 0000000..f32f919
--- /dev/null
+++ b/quotearg.h
@@ -0,0 +1,9 @@
+/* quote.h -- declarations for quoting system arguments */
+
+#if defined __STDC__ || __GNUC__
+# define __QUOTEARG_P(args) args
+#else
+# define __QUOTEARG_P(args) ()
+#endif
+
+size_t quote_system_arg __QUOTEARG_P ((char *, char const *));
diff --git a/rename.c b/rename.c
index e11c60b..d04a8bc 100644
--- a/rename.c
+++ b/rename.c
@@ -1,5 +1,5 @@
-/* rename.c -- BSD compatible directory function for System V
- Copyright (C) 1988, 1990, 1992 Free Software Foundation, Inc.
+/* BSD compatible rename and directory rename function for System V.
+ Copyright (C) 1988, 1990 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -12,16 +12,28 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
-#ifndef STDC_HEADERS
+#ifndef errno
extern int errno;
#endif
+#if STAT_MACROS_BROKEN
+# undef S_ISDIR
+#endif
+
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
/* Rename file FROM to file TO.
Return 0 if successful, -1 if not. */
@@ -30,22 +42,71 @@ rename (from, to)
char *from;
char *to;
{
- struct stat from_stats;
+ struct stat from_stats, to_stats;
+ int pid, status;
if (stat (from, &from_stats))
return -1;
- if (unlink (to) && errno != ENOENT)
- return -1;
+ /* Be careful not to unlink `from' if it happens to be equal to `to' or
+ (on filesystems that silently truncate filenames after 14 characters)
+ if `from' and `to' share the significant characters. */
+ if (stat (to, &to_stats))
+ {
+ if (errno != ENOENT)
+ return -1;
+ }
+ else
+ {
+ if ((from_stats.st_dev == to_stats.st_dev)
+ && (from_stats.st_ino == to_stats.st_ino))
+ /* `from' and `to' designate the same file on that filesystem. */
+ return 0;
- if (link (from, to))
- return -1;
+ if (unlink (to) && errno != ENOENT)
+ return -1;
+ }
+
+#ifdef MVDIR
- if (unlink (from) && errno != ENOENT)
+/* If MVDIR is defined, it should be the full filename of a setuid root
+ program able to link and unlink directories. If MVDIR is not defined,
+ then the capability of renaming directories may be missing. */
+
+ if (S_ISDIR (from_stats.st_mode))
{
- unlink (to);
- return -1;
+ /* Need a setuid root process to link and unlink directories. */
+ pid = fork ();
+ switch (pid)
+ {
+ case -1: /* Error. */
+ error (1, errno, "cannot fork");
+
+ case 0: /* Child. */
+ execl (MVDIR, "mvdir", from, to, (char *) 0);
+ error (255, errno, "cannot run `%s'", MVDIR);
+
+ default: /* Parent. */
+ while (wait (&status) != pid)
+ /* Do nothing. */ ;
+
+ errno = 0; /* mvdir printed the system error message. */
+ if (status)
+ return -1;
+ }
}
+ else
+
+#endif /* MVDIR */
+ {
+ if (link (from, to))
+ return -1;
+ if (unlink (from) && errno != ENOENT)
+ {
+ unlink (to);
+ return -1;
+ }
+ }
return 0;
}
diff --git a/util.c b/util.c
index fb8183c..6bbf8d5 100644
--- a/util.c
+++ b/util.c
@@ -1,6 +1,6 @@
/* utility functions for `patch' */
-/* $Id: util.c,v 1.9 1997/04/14 05:32:30 eggert Exp $ */
+/* $Id: util.c,v 1.17 1997/05/30 08:03:48 eggert Exp $ */
/*
Copyright 1986 Larry Wall
@@ -30,6 +30,9 @@ If not, write to the Free Software Foundation,
#define XTERN
#include <util.h>
+#include <time.h>
+#include <maketime.h>
+
#include <signal.h>
#if !defined SIGCHLD && defined SIGCLD
#define SIGCHLD SIGCLD
@@ -51,20 +54,33 @@ If not, write to the Free Software Foundation,
# endif
#endif
-/* Rename a file, copying it if necessary. */
+static void makedirs PARAMS ((char *));
+
+/* Move a file FROM to TO, renaming it if possible and copying it if necessary.
+ If we must create TO, use MODE to create it.
+ If FROM is null, remove TO (ignoring FROMSTAT).
+ Back up TO if BACKUP is nonzero. */
+#ifdef __STDC__
+/* If mode_t doesn't promote to itself, we can't use old-style definition. */
+void
+move_file (char const *from, char *to, mode_t mode, int backup)
+#else
void
-move_file (from, to, backup)
- char const *from, *to;
+move_file (from, to, mode, backup)
+ char const *from;
+ char *to;
+ mode_t mode;
int backup;
+#endif
{
- register char *s;
- register char *bakname;
- struct stat tost, bakst;
+ struct stat to_st;
+ int to_errno = ! backup ? -1 : stat (to, &to_st) == 0 ? 0 : errno;
- if (backup && stat (to, &tost) == 0)
+ if (! to_errno)
{
- char *simplename;
+ int try_makedirs_errno = 0;
+ char *bakname;
if (origprae || origbase)
{
@@ -80,6 +96,12 @@ move_file (from, to, backup)
memcpy (bakname + plen, to, tlen);
memcpy (bakname + plen + tlen, b, blen);
memcpy (bakname + plen + tlen + blen, o, osize);
+ for (p += FILESYSTEM_PREFIX_LEN (p); *p; p++)
+ if (ISSLASH (*p))
+ {
+ try_makedirs_errno = ENOENT;
+ break;
+ }
}
else
{
@@ -88,70 +110,109 @@ move_file (from, to, backup)
memory_fatal ();
}
- simplename = base_name (bakname);
- /* Find a backup name that is not the same file.
- Change the first lowercase char into uppercase;
- if that doesn't suffice, chop off the first char and try again. */
- while (stat (bakname, &bakst) == 0
- && tost.st_dev == bakst.st_dev
- && tost.st_ino == bakst.st_ino)
+ if (debug & 4)
+ say ("renaming `%s' to `%s'\n", to, bakname);
+ while (rename (to, bakname) != 0)
{
- /* Skip initial non-lowercase chars. */
- for (s=simplename; *s && !ISLOWER ((unsigned char) *s); s++)
- continue;
- if (*s)
- *s = toupper ((unsigned char) *s);
- else
- remove_prefix (simplename, 1);
+ if (errno != try_makedirs_errno)
+ pfatal ("can't rename `%s' to `%s'", to, bakname);
+ makedirs (bakname);
+ try_makedirs_errno = 0;
}
- if (debug & 4)
- say ("Moving %s to %s.\n", to, bakname);
- if (rename (to, bakname) != 0)
- pfatal ("Can't rename `%s' to `%s'", to, bakname);
free (bakname);
}
- if (debug & 4)
- say ("Moving %s to %s.\n", from, to);
-
- if (rename (from, to) != 0)
+ if (from)
{
-#ifdef EXDEV
- if (errno == EXDEV)
+ if (debug & 4)
+ say ("renaming `%s' to `%s'\n", from, to);
+
+ if (rename (from, to) != 0)
{
- if (! backup && unlink (to) != 0
- && errno != ENOENT && errno != ENOTDIR)
- pfatal ("Can't remove `%s'", to);
- copy_file (from, to);
- if (unlink (from) != 0)
- pfatal ("Can't remove `%s'", from);
- return;
- }
+ if (errno == ENOENT
+ && (to_errno == -1 || to_errno == ENOENT))
+ {
+ makedirs (to);
+ if (rename (from, to) == 0)
+ return;
+ }
+
+#ifdef EXDEV
+ if (errno == EXDEV)
+ {
+ if (! backup && unlink (to) != 0 && errno != ENOENT)
+ pfatal ("can't remove `%s'", to);
+ copy_file (from, to, mode);
+ return;
+ }
#endif
- pfatal ("Can't rename `%s' to `%s'", from, to);
+ pfatal ("can't rename `%s' to `%s'", from, to);
+ }
+ }
+ else if (! backup)
+ {
+ if (debug & 4)
+ say ("removing `%s'\n", to);
+ if (unlink (to) != 0)
+ pfatal ("can't remove `%s'", to);
}
}
+/* Create FILE with OPEN_FLAGS, and with MODE adjusted so that
+ we can read and write the file and that the file is not executable.
+ Return the file descriptor. */
+#ifdef __STDC__
+/* If mode_t doesn't promote to itself, we can't use old-style definition. */
+int
+create_file (char const *file, int open_flags, mode_t mode)
+#else
+int
+create_file (file, open_flags, mode)
+ char const *file;
+ int open_flags;
+ mode_t mode;
+#endif
+{
+ int fd;
+ mode |= S_IRUSR | S_IWUSR;
+ mode &= ~ (S_IXUSR | S_IXGRP | S_IXOTH);
+ if (! (O_CREAT && O_TRUNC))
+ close (creat (file, mode));
+ fd = open (file, O_CREAT | O_TRUNC | open_flags, mode);
+ if (fd < 0)
+ pfatal ("can't create `%s'", file);
+ return fd;
+}
+
/* Copy a file. */
+#ifdef __STDC__
+/* If mode_t doesn't promote to itself, we can't use old-style definition. */
void
-copy_file(from,to)
+copy_file (char const *from, char const *to, mode_t mode)
+#else
+void
+copy_file (from, to, mode)
char const *from;
char const *to;
+ mode_t mode;
+#endif
{
int tofd;
- int fromfd = open (from, O_RDONLY);
- long i;
-
- if (fromfd < 0)
- pfatal ("can't reopen %s", from);
- tofd = creat (to, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
- if (tofd < 0)
- pfatal ("can't create %s", to);
- while ((i = read (fromfd, buf, bufsize)) > 0)
- if (write (tofd, buf, (size_t) i) != i)
- write_fatal ();
- if (i < 0 || close (fromfd) != 0)
+ int fromfd;
+ size_t i;
+
+ if ((fromfd = open (from, O_RDONLY | O_BINARY)) < 0)
+ pfatal ("can't reopen `%s'", from);
+ tofd = create_file (to, O_WRONLY | O_BINARY, mode);
+ while ((i = read (fromfd, buf, bufsize)) != 0)
+ {
+ if (i == -1)
+ read_fatal ();
+ if (write (tofd, buf, i) != i)
+ write_fatal ();
+ }
+ if (close (fromfd) != 0)
read_fatal ();
if (close (tofd) != 0)
write_fatal ();
@@ -345,7 +406,16 @@ ask (format, va_alist)
}
else
{
- r = read (ttyfd, buf, bufsize - 1);
+ size_t s = 0;
+ while ((r = read (ttyfd, buf + s, bufsize - 1 - s)) == bufsize - 1 - s
+ && buf[bufsize - 2] != '\n')
+ {
+ s = bufsize - 1;
+ bufsize *= 2;
+ buf = realloc (buf, bufsize);
+ if (!buf)
+ memory_fatal ();
+ }
if (r == 0)
printf ("EOF\n");
else if (r < 0)
@@ -359,6 +429,54 @@ ask (format, va_alist)
buf[r] = '\0';
}
+/* Return nonzero if it OK to reverse a patch. */
+
+#ifdef __STDC__
+int
+ok_to_reverse (char const *format, ...)
+#else
+ok_to_reverse (format, va_alist)
+ char const *format;
+ va_dcl
+#endif
+{
+ int r = 0;
+
+ if (noreverse || ! batch || verbosity != SILENT)
+ {
+ va_list args;
+ vararg_start (args, format);
+ vfprintf (stdout, format, args);
+ va_end (args);
+ }
+
+ if (noreverse)
+ {
+ printf (" Ignoring it.\n");
+ skip_rest_of_patch = TRUE;
+ r = 0;
+ }
+ else if (batch)
+ {
+ if (verbosity != SILENT)
+ say (reverse ? " Ignoring -R.\n" : " Assuming -R.\n");
+ r = 1;
+ }
+ else
+ {
+ ask (reverse ? " Ignore -R? [y] " : " Assume -R? [y] ");
+ r = *buf != 'n';
+ if (! r)
+ {
+ ask ("Apply anyway? [n] ");
+ if (*buf != 'y')
+ skip_rest_of_patch = TRUE;
+ }
+ }
+
+ return r;
+}
+
/* How to handle certain events when not in a critical region. */
#define NUM_SIGS (sizeof (sigs) / sizeof (*sigs))
@@ -502,134 +620,192 @@ exit_with_signal (sig)
exit (2);
}
+int
+systemic (command)
+ char const *command;
+{
+ if (debug & 8)
+ say ("+ %s\n", command);
+ return system (command);
+}
+
#if !HAVE_MKDIR
-/* This is good enough for `patch'; it's not a general emulator. */
-static int mkdir PARAMS ((char const *, int));
+/* 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 *));
+
+static int
+doprogram (program, arg)
+ char const *program;
+ char const *arg;
+{
+ int result;
+ static char const DISCARD_OUTPUT[] = " 2>/dev/null";
+ size_t program_len = strlen (program);
+ char *cmd = xmalloc (program_len + 1 + quote_system_arg (0, arg)
+ + sizeof DISCARD_OUTPUT);
+ char *p = cmd;
+ strcpy (p, program);
+ p += program_len;
+ *p++ = ' ';
+ p += quote_system_arg (p, arg);
+ strcpy (p, DISCARD_OUTPUT);
+ result = systemic (cmd);
+ free (cmd);
+ return result;
+}
+
+#ifdef __STDC__
+/* If mode_t doesn't promote to itself, we can't use old-style definition. */
+static int
+mkdir (char const *path, mode_t mode)
+#else
static int
mkdir (path, mode)
char const *path;
- int mode; /* ignored */
+ mode_t mode; /* ignored */
+#endif
{
- char *cmd = xmalloc (strlen (path) + 9);
- int r;
- sprintf (cmd, "mkdir '%s'", path);
- r = system (cmd);
- free (cmd);
- return r;
+ return doprogram ("mkdir", path);
+}
+
+static int
+rmdir (path)
+ char const *path;
+{
+ int result = doprogram ("rmdir", path);
+ errno = EEXIST;
+ return result;
}
#endif
/* Replace '/' with '\0' in FILENAME if it marks a place that
needs testing for the existence of directory. Return the address
- of the last location replaced, or FILENAME if none were replaced. */
+ of the last location replaced, or 0 if none were replaced. */
static char *replace_slashes PARAMS ((char *));
static char *
replace_slashes (filename)
char *filename;
{
char *f;
- for (f = filename; *f == '/'; f++)
+ char *last_location_replaced = 0;
+ char const *component_start;
+
+ for (f = filename + FILESYSTEM_PREFIX_LEN (filename); ISSLASH (*f); f++)
continue;
+
+ component_start = f;
+
for (; *f; f++)
- if (*f == '/')
+ if (ISSLASH (*f))
{
- *f = '\0';
- while (f[1] == '/')
- f++;
- }
- while (filename != f && *--f)
- continue;
- return f;
-}
+ char *slash = f;
-/* Count the number of path name components in the existing leading prefix
- of `filename'. Do not count the last element, or the root dir. */
-int
-countdirs (filename)
- char *filename;
-{
- int count = 0;
+ /* Treat multiple slashes as if they were one slash. */
+ while (ISSLASH (f[1]))
+ f++;
- if (*filename)
- {
- register char *f;
- register char *flim = replace_slashes (filename);
+ /* Ignore slashes at the end of the path. */
+ if (! f[1])
+ break;
- /* Now turn the '\0's back to '/'s, calling stat as we go. */
- for (f = filename; f <= flim; f++)
- if (!*f)
+ /* "." and ".." need not be tested. */
+ if (! (slash - component_start <= 2
+ && component_start[0] == '.' && slash[-1] == '.'))
{
- struct stat sbuf;
- if (stat (filename, &sbuf) != 0)
- break;
- count++;
- *f = '/';
+ *slash = '\0';
+ last_location_replaced = slash;
}
- for (; f <= flim; f++)
- if (!*f)
- *f = '/';
- }
+ component_start = f + 1;
+ }
- return count;
+ return last_location_replaced;
}
/* Make sure we'll have the directories to create a file.
Ignore the last element of `filename'. */
-void
+static void
makedirs (filename)
register char *filename;
{
- if (*filename)
- {
- register char *f;
- register char *flim = replace_slashes (filename);
+ register char *f;
+ register char *flim = replace_slashes (filename);
- /* Now turn the NULs back to '/'s; stop when the path doesn't exist. */
- errno = 0;
+ if (flim)
+ {
+ /* Create any missing directories, replacing NULs by '/'s.
+ Ignore errors. We may have to keep going even after an EEXIST,
+ since the path may contain ".."s; and when there is an EEXIST
+ failure the system may return some other error number.
+ Any problems will eventually be reported when we create the file. */
for (f = filename; f <= flim; f++)
if (!*f)
{
- struct stat sbuf;
- if (stat (filename, &sbuf) != 0)
- break;
+ mkdir (filename,
+ S_IRUSR|S_IWUSR|S_IXUSR
+ |S_IRGRP|S_IWGRP|S_IXGRP
+ |S_IROTH|S_IWOTH|S_IXOTH);
*f = '/';
}
+ }
+}
- /* Create the missing directories, replacing NULs by '/'s. */
- if (errno == ENOENT)
- for (; f <= flim; f++)
- if (!*f)
- {
- if (mkdir (filename,
- S_IRUSR|S_IWUSR|S_IXUSR
- |S_IRGRP|S_IWGRP|S_IXGRP
- |S_IROTH|S_IWOTH|S_IXOTH) != 0)
- break;
- *f = '/';
- }
+/* Remove empty ancestor directories of FILENAME.
+ Ignore errors, since the path may contain ".."s, and when there
+ is an EEXIST failure the system may return some other error number. */
+void
+removedirs (filename)
+ char *filename;
+{
+ size_t i;
+
+ for (i = strlen (filename); i != 0; i--)
+ if (ISSLASH (filename[i])
+ && ! (ISSLASH (filename[i - 1])
+ || (filename[i - 1] == '.'
+ && (i == 1
+ || ISSLASH (filename[i - 2])
+ || (filename[i - 2] == '.'
+ && (i == 2
+ || ISSLASH (filename[i - 3])))))))
+ {
+ filename[i] = '\0';
+ if (rmdir (filename) == 0 && verbosity == VERBOSE)
+ say ("Removed empty directory `%s'.\n", filename);
+ filename[i] = '/';
+ }
+}
- for (; f <= flim; f++)
- if (!*f)
- *f = '/';
- }
+static time_t initial_time;
+
+void
+init_time ()
+{
+ time (&initial_time);
}
/* Make filenames more reasonable. */
char *
-fetchname (at, strip_leading)
+fetchname (at, strip_leading, head_says_nonexistent)
char *at;
int strip_leading;
+int *head_says_nonexistent;
{
char *name;
register char *t;
int sleading = strip_leading;
+ int says_nonexistent = 0;
if (!at)
return 0;
- while (ISSPACE (*at))
+ while (ISSPACE ((unsigned char) *at))
at++;
if (debug & 128)
say ("fetchname %s %d\n", at, strip_leading);
@@ -637,25 +813,43 @@ int strip_leading;
name = at;
/* Strip off up to `sleading' leading slashes and null terminate. */
for (t = at; *t; t++)
- if (*t == '/')
+ {
+ if (ISSLASH (*t))
{
- while (t[1] == '/')
+ while (ISSLASH (t[1]))
t++;
if (--sleading >= 0)
name = t+1;
}
- else if (ISSPACE (*t))
+ 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;
*t = '\0';
break;
}
+ }
if (!*name)
return 0;
/* Allow files to be created by diffing against /dev/null. */
if (strcmp (at, "/dev/null") == 0)
- return 0;
+ {
+ if (head_says_nonexistent)
+ *head_says_nonexistent = 1;
+ return 0;
+ }
+
+ if (head_says_nonexistent)
+ *head_says_nonexistent = says_nonexistent;
return savestr (name);
}
@@ -673,9 +867,9 @@ xmalloc (size)
void
Fseek (stream, offset, ptrname)
FILE *stream;
- long offset;
+ file_offset offset;
int ptrname;
{
- if (fseek (stream, offset, ptrname) != 0)
+ if (file_seek (stream, offset, ptrname) != 0)
pfatal ("fseek");
}
diff --git a/util.h b/util.h
index 0bc44ad..92a48f7 100644
--- a/util.h
+++ b/util.h
@@ -1,7 +1,8 @@
/* utility functions for `patch' */
-/* $Id: util.h,v 1.7 1997/04/14 05:32:30 eggert Exp $ */
+/* $Id: util.h,v 1.12 1997/05/19 06:52:03 eggert Exp $ */
+int ok_to_reverse PARAMS ((char const *, ...)) __attribute__ ((format (printf, 1, 2)));
void ask PARAMS ((char const *, ...)) __attribute__ ((format (printf, 1, 2)));
void say PARAMS ((char const *, ...)) __attribute__ ((format (printf, 1, 2)));
@@ -10,18 +11,20 @@ void fatal PARAMS ((char const *, ...))
void pfatal PARAMS ((char const *, ...))
__attribute__ ((noreturn, format (printf, 1, 2)));
-char *fetchname PARAMS ((char *, int));
+char *fetchname PARAMS ((char *, int, int *));
char *savebuf PARAMS ((char const *, size_t));
char *savestr PARAMS ((char const *));
-int countdirs PARAMS ((char *));
-void Fseek PARAMS ((FILE *, long, int));
-void copy_file PARAMS ((char const *, char const *));
+int create_file PARAMS ((char const *, int, mode_t));
+int systemic PARAMS ((char const *));
+void Fseek PARAMS ((FILE *, file_offset, int));
+void copy_file PARAMS ((char const *, char const *, mode_t));
void exit_with_signal PARAMS ((int)) __attribute__ ((noreturn));
void ignore_signals PARAMS ((void));
-void makedirs PARAMS ((char *));
+void init_time PARAMS ((void));
void memory_fatal PARAMS ((void));
-void move_file PARAMS ((char const *, char const *, int));
+void move_file PARAMS ((char const *, char *, mode_t, int));
void read_fatal PARAMS ((void));
void remove_prefix PARAMS ((char *, size_t));
+void removedirs PARAMS ((char *));
void set_signals PARAMS ((int));
void write_fatal PARAMS ((void));
diff --git a/version.c b/version.c
index 5e52939..ea08437 100644
--- a/version.c
+++ b/version.c
@@ -1,6 +1,6 @@
/* Print the version number. */
-/* $Id: version.c,v 1.4 1997/04/07 01:07:00 eggert Exp $ */
+/* $Id: version.c,v 1.5 1997/05/21 18:29:20 eggert Exp $ */
#define XTERN extern
#include <common.h>
@@ -10,8 +10,8 @@
#include <version.h>
static char const copyright_string[] = "\
-Copyright 1984, 1985, 1986, 1987, 1988 Larry Wall\n\
-Copyright 1989, 1990, 1991, 1992, 1993, 1997 Free Software Foundation, Inc.";
+Copyright 1988 Larry Wall\n\
+Copyright 1997 Free Software Foundation, Inc.";
static char const free_software_msgid[] = "\
This program comes with NO WARRANTY, to the extent permitted by law.\n\