aboutsummaryrefslogtreecommitdiff
path: root/contrib/patch
diff options
context:
space:
mode:
authorSteve Price <steve@FreeBSD.org>1997-06-29 06:55:02 +0000
committerSteve Price <steve@FreeBSD.org>1997-06-29 06:55:02 +0000
commit511633a2fe6a28e37e7c367915d4b6c131ded5a1 (patch)
treeb91e93b575aeb975e736e614eaf2a0d0f8ea461a /contrib/patch
downloadsrc-511633a2fe6a28e37e7c367915d4b6c131ded5a1.tar.gz
src-511633a2fe6a28e37e7c367915d4b6c131ded5a1.zip
Notes
Diffstat (limited to 'contrib/patch')
-rw-r--r--contrib/patch/COPYING340
-rw-r--r--contrib/patch/ChangeLog1627
-rw-r--r--contrib/patch/NEWS158
-rw-r--r--contrib/patch/README52
-rw-r--r--contrib/patch/acconfig.h14
-rw-r--r--contrib/patch/addext.c106
-rw-r--r--contrib/patch/argmatch.c92
-rw-r--r--contrib/patch/argmatch.h12
-rw-r--r--contrib/patch/backupfile.c251
-rw-r--r--contrib/patch/backupfile.h50
-rw-r--r--contrib/patch/basename.c32
-rw-r--r--contrib/patch/common.h307
-rw-r--r--contrib/patch/getopt.c1053
-rw-r--r--contrib/patch/getopt.h133
-rw-r--r--contrib/patch/getopt1.c189
-rw-r--r--contrib/patch/inp.c442
-rw-r--r--contrib/patch/inp.h10
-rw-r--r--contrib/patch/maketime.c391
-rw-r--r--contrib/patch/maketime.h39
-rw-r--r--contrib/patch/memchr.c199
-rw-r--r--contrib/patch/partime.c742
-rw-r--r--contrib/patch/partime.h67
-rw-r--r--contrib/patch/patch.11063
-rw-r--r--contrib/patch/patch.c1293
-rw-r--r--contrib/patch/pch.c1823
-rw-r--r--contrib/patch/pch.h25
-rw-r--r--contrib/patch/quotearg.c125
-rw-r--r--contrib/patch/quotearg.h9
-rw-r--r--contrib/patch/rename.c112
-rw-r--r--contrib/patch/util.c1070
-rw-r--r--contrib/patch/util.h32
-rw-r--r--contrib/patch/version.c30
-rw-r--r--contrib/patch/version.h5
33 files changed, 11893 insertions, 0 deletions
diff --git a/contrib/patch/COPYING b/contrib/patch/COPYING
new file mode 100644
index 000000000000..60549be514af
--- /dev/null
+++ b/contrib/patch/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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 of the License, 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/contrib/patch/ChangeLog b/contrib/patch/ChangeLog
new file mode 100644
index 000000000000..ea9ed3da6af8
--- /dev/null
+++ b/contrib/patch/ChangeLog
@@ -0,0 +1,1627 @@
+1997-06-19 Paul Eggert <eggert@pogo.gnu.ai.mit.edu>
+
+ * configure.in (VERSION): Version 2.4 released.
+ * NEWS: Patch is now verbose when patches do not match exactly.
+
+1997-06-17 Paul Eggert <eggert@twinsun.com>
+
+ * pc/djgpp/configure.sed (config.h): Remove redundant $(srcdir).
+
+ * configure.in (VERSION): Bump to 2.3.9.
+ * patch.c (main): By default, warn about hunks that succeed
+ with nonzero offset.
+ * patch.man: Add LC_ALL=C advice for making patches.
+ * pc/djgpp/configure.sed (config.h): Fix paths to dependent files.
+
+1997-06-17 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (VERSION): Bump to 2.3.8.
+
+ * pch.c (open_patch_file): Test stdin for fseekability.
+ (intuit_diff_type): Missing context diff headers are now warnings,
+ not errors; some people use patches with them (e.g. when retrying
+ rejects).
+
+ * patch.c (struct outstate):
+ New type, collecting together some output state vars.
+ (apply_hunk, copy_till, spew_output, init_output): Use it.
+ Keep track of whether some output has been generated.
+ (backup_if_mismatch): New var.
+ (ofp): Remove, in favor of local struct outstate vars.
+ (main): Use struct outstate. Initialize backup_if_mismatch to
+ be the inverse of posixly_correct. Keep track of whether mismatches
+ occur, and use this to implement backup_if_mismatch.
+ Report files that are not empty after patching, but should be.
+ (longopts, option_help, get_some_switches): New options
+ --backup-if-mismatch, --no-backup-if-mismatch.
+ (get_some_switches): -B, -Y, -z no longer set backup_type.
+ * backupfile.c (find_backup_file_name):
+ Treat backup_type == none like simple.
+
+ * Makefile.in (CONFIG_HDRS):
+ Remove var; no longer needed by djgpp port.
+ (DISTFILES_PC_DJGPP): Rename pc/djgpp/config.sed to
+ pc/djgpp/configure.sed; remove pc/djgpp/config.h in favor of
+ new file that edits it, called pc/djgpp/config.sed.
+ * pc/djgpp/configure.bat: Rename config.sed to configure.sed.
+ * pc/djgpp/configure.sed (CONFIG_HDRS): Remove.
+ (config.h): Add rule to build this from config.hin and
+ pc/djgpp/config.sed.
+ * pc/djgpp/config.sed:
+ Convert from .h file to .sed script that generates .h file.
+
+ * NEWS: Describe --backup-if-mismatch, --no-backup-if-mismatch.
+ * patch.man:
+ Describe new options --backup-if-mismatch, --no-backup-if-mismatch
+ and their ramifications. Use unreadable backup to represent
+ nonexistent file.
+
+1997-06-12 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (VERSION): Bump to 2.3.7.
+ (AC_CHECK_FUNCS): Add `raise'.
+
+ * Makefile.in (inp.o): No longer depends on quotearg.h.
+
+ * common.h (outfile): New decl (was private var named `output').
+ (invc): New decl.
+ (GENERIC_OBJECT): Renamed from VOID.
+ (NULL_DEVICE, TTY_DEVICE): New macros.
+
+ * patch.c (output): Remove; renamed to `outfile' and moved to common.h.
+ (main): `failed' is count, not boolean.
+ Say "Skipping patch." when deciding to skip patch.
+ (get_some_switches): Set invc when setting inname.
+
+ * inp.c: Do not include <quotearg.h>.
+ (SCCSPREFIX, GET, GET_LOCKED, SCCSDIFF1, SCCSDIFF2, SCCSDIFF3,
+ RCSSUFFIX, CHECKOUT, CHECKOUT_LOCKED, RCSDIFF1, RCSDIFF2):
+ Move to util.c.
+ (get_input_file): Invoke new functions version_controller and
+ version_get to simplify this code.
+ (plan_b): "/dev/tty" -> NULL_DEVICE
+
+ * pch.h (pch_timestamp): New decl.
+ * pch.c (p_timestamp): New var; takes over from global timestamp array.
+ (pch_timestamp): New function to export p_timestamp.
+ (there_is_another_patch): Use blander wording when you can't intuit
+ the file name.
+ Say "Skipping patch." when deciding to skip patch.
+ (intuit_diff_type): Look for version-controlled but nonexistent files
+ when intuiting file names; set invc accordingly.
+ Ignore Index: line if either old or new line is present, and if
+ POSIXLY_CORRECT is not set.
+ (do_ed_script): Flush stdout before invoking popen, since it may
+ send output to stdout.
+
+ * util.h (version_controller, version_get): New decls.
+ * util.c: Include <quotearg.h> earlier.
+ (raise): New macro, if ! HAVE_RAISE.
+ (move_file): Create empty unreadable file when backing up a nonexistent
+ file.
+ (DEV_NULL): New constant.
+ (SCCSPREFIX, GET. GET_LOCKED, SCCSDIFF1, SCCSDIFF2,
+ RCSSUFFIX, CHECKOUT, CHECKOUT_LOCKED, RCSDIFF1): Moved here from inp.c.
+ (version_controller, version_get): New functions.
+ (ask): Look only at /dev/tty for answers; and when standard output is
+ not a terminal and ! posixly_correct, don't even look there.
+ Remove unnecessary fflushes of stdout.
+ (ok_to_reverse): Say "Skipping patch." when deciding to skip patch..
+ (sigs): SIGPIPE might not be defined.
+ (exit_with_signal): Use `raise' instead of `kill'.
+ (systemic): fflush stdout before invoking subsidiary command.
+
+ * patch.man: Document recent changes.
+ Add "COMPATIBILITY ISSUES" section.
+
+ * NEWS: New COMPATIBILITY ISSUES for man page.
+ Changed verbosity when fuzz is found.
+ File name intuition is changed, again.
+ Backups are made unreadable when the file did not exist.
+
+ * pc/djgpp/config.h (HAVE_STRUCT_UTIMBUF): Define.
+ (HAVE_RAISE): New macro.
+ (HAVE_UTIME_H): Define.
+ (TZ_is_unset): Do not define; it's not a serious problem with `patch'
+ to have TZ be unset in DOS.
+
+1997-06-08 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (VERSION): Bump to 2.3.6.
+ (AC_CHECK_HEADERS): Add utime.h.
+ * acconfig.h, configure.in, pc/djgpp/config.h (HAVE_STRUCT_UTIMBUF):
+ New macro.
+ * pc/djgpp/config.h (HAVE_UTIME_H, TZ_is_unset): New macros.
+
+ * NEWS, patch.man: Describe new -Z, -T options, new numeric
+ option for -G, retired -G, and more verbose default behavior
+ with fuzz.
+
+ * pch.c (intuit_diff_type): Record times reported for files in headers.
+ Remove head_says_nonexistent[x], since it's now equivalent to
+ !timestamp[x].
+ * util.h (fetchname): Change argument head_says_nonexistent to
+ timestamp.
+ * util.c: #include <partime.h> for TM_LOCAL_ZONE.
+ Don't include <time.h> since common.h now includes it.
+ (ok_to_reverse): noreverse and batch cases now output regardless of
+ verbosity.
+ (fetchname): Change argument head_says_nonexistent to pstamp, and
+ store header timestamp into *pstamp.
+ If -T or -Z option is given, match time stamps more precisely.
+ (ask): Remove unnecessary close of ttyfd.
+ When there is no terminal at all, output a newline to make the
+ output look nicer. After reporting EOF, flush stdout;
+ when an input error, report the error type.
+
+ * inp.c (get_input_file):
+ Ask user whether to get file if patch_get is negative.
+
+ * Makefile.in (clean): Don't clean */*.o; clean core* and *core.
+
+1997-06-04 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (VERSION): Bump to 2.3.5.
+
+ * util.c (ok_to_reverse):
+ Be less chatty if verbosity is SILENT and we don't
+ have to ask the user. If force is nonzero, apply the patch anyway.
+
+ * pch.c (there_is_another_patch):
+ Before skipping rest of patch, skip to
+ the patch start, so that another_hunk can skip it properly.
+ (intuit_diff_type): Slight wording change for missing headers, to
+ regularize with other diagnostics. Fix off-by-one error when setting
+ p_input_line when scanning the first hunk to check for deleted files.
+
+1997-06-03 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (VERSION): Bump to 2.3.4.
+
+ * NEWS: Now matches more generously against nonexistent or empty files.
+
+ * pch.c (there_is_another_patch): Move warning about not being
+ able to intuit file names here from skip_to.
+ (intuit_diff_type): Fatal error if we find a headless unified
+ or context diff.
+
+ * util.c (ask): Null-terminate buffer properly even if it grew.
+ (fetchname): No need to test for null first argument.
+
+1997-06-02 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (VERSION): Bump to 2.3.3.
+ * pch.c (p_says_nonexistent, pch_says_nonexistent): Is now 1 for empty,
+ 2 for nonexistent.
+ (intuit_diff_type): Set p_says_nonexistent according to new meaning.
+ Treat empty files like nonexistent files when reversing.
+ (skip_to): Output better diagnostic when we can't intuit a file name.
+ * patch.c (main):
+ Count bytes, not lines, when testing whether a file is empty,
+ since it may contain only non-newline chars.
+ pch_says_nonexistent now returns 2 for nonexistent files.
+
+1997-06-01 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (VERSION): Bump to 2.3.2.
+ * pch.c (open_patch_file):
+ Fix bug when computing size of patch read from a pipe.
+
+1997-05-30 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (VERSION): Bump to 2.3.1.
+
+ * Makefile.in (transform, patch_name): New vars,
+ for proper implementation of AC_ARG_PROGRAM.
+ (install, uninstall): Use them.
+ (install-strip): New rule.
+ * pc/djgpp/config.sed (program_transform_name): Set to empty.
+
+1997-05-30 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (VERSION), NEWS: Version 2.3 released.
+ * 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@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.
+
+ * Makefile.in (config.hin):
+ Remove before building; we always want the timestamp updated.
+
+ * inp.c (get_input_file):
+ Look for RCS files only if backup_type == numbered_existing.
+
+ * NEWS, patch.man:
+ Remove mention of never-implemented -V rcs and -V sccs options.
+ * patch.man: `pathname' -> `file name'
+ Correct the description of how file names are found in diff headers.
+ Clarify the distinction between ordinary and unified context diffs.
+
+1997-04-13 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (VERSION): Update to 2.1.7.
+
+ * patch.c (numeric_optarg): New function.
+ (get_some_switches): Use it.
+
+ * pch.c (intuit_diff_type): When creating a file, prefer a name whose
+ existing dir prefix is the longest.
+
+ * util.h (countdirs): New function.
+ * util.c (replace_slashes, countdirs): New functions.
+ (makedirs): Use replace_slashes, to be more like countdirs.
+
+ * patch.man: Explain -pN vs -p N. Recommend --new-file.
+ Explain possible incompatibility with strip count.
+
+1997-04-10 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (VERSION): Bump to 2.1.6.
+ (AC_CHECK_HEADERS): Remove stdlib.h (i.e. remove HAVE_STDLIB_H).
+
+ * Makefile.in: (HDRS, patchlevel.h, TAGS, distclean, maintainer-clean):
+ Don't distribute patchlevel.h; let the user do it.
+ This works around some obscure (possibly nonexistent?) `make' bugs.
+
+ * common.h (program_name): extern, not XTERN.
+ (<stdlib.h>): Include if STDC_HEADERS, not if HAVE_STDLIB_H.
+ (atol, getenv, malloc, realloc): Don't worry whether they're #defined.
+
+ * patch.c (get_some_switches):
+ Add special hack for backwards compatibility with CVS 1.9.
+ (-B, -Y, -z): Now set backup_type = simple.
+
+ * NEWS: Fix misspellings; minor reformatting.
+ * README: Report POSIX.2 compliance.
+
+1997-04-06 Paul Eggert <eggert@twinsun.com>
+
+ Move all old RCS $Log entries into ChangeLog.
+ #include all files with < >, not " ".
+
+ * addext.c, argmatch.c, argmatch.h, memchr.c, install-sh:
+ New files.
+ * EXTERN.h, INTERN.h: Removed.
+ * config.hin: Renamed from config.h.in.
+
+ * acconfig.h (NODIR): Remove.
+ (HAVE_MEMCHR): Add.
+
+ * configure.in (AC_ARG_PROGRAM, AC_PROG_MAKE_SET, HAVE_MEMCHR): Add.
+ (AC_CHECK_HEADERS): Replaces obsolescent AC_HAVE_HEADERS.
+ Add stdlib.h, string.h, unistd.h, varargs.h.
+ Delete obsolete call to AC_UNISTD_H.
+ (AC_CONFIG_HEADER): Rename config.h.in to config.hin.
+ (AC_C_CONST): Replaces obsolescent AC_CONST.
+ (AC_CHECK_FUNC): Check for getopt_long; define LIBOBJS and substitute
+ for it accordingly.
+ (AC_CHECK_FUNCS): Replaces obsolescent AC_HAVE_FUNCS.
+ Add _doprintf, isascii, mktemp, sigaction, sigprocmask, sigsetmask.
+ Remove strerror.
+ (AC_FUNC_CLOSEDIR_VOID, AC_FUNC_VPRINTF): Add.
+ (AC_HEADER_DIRENT): Replaces obsolescent AC_DIR_HEADER.
+ (AC_HEADER_STDC): Replaces obsolescent AC_STDC_HEADERS.
+ (AC_SYS_LONG_FILE_NAMES): Replaces obsolescent AC_LONG_FILE_NAMES.
+ (AC_TYPE_OFF_T): Replaces obsolescent AC_OFF_T.
+ (AC_TYPE_SIGNAL): Replaces obsolescent AC_RETSIGTYPE.
+ (AC_TYPE_SIZE_T): Replaces obsolescent AC_SIZE_T.
+ (AC_XENIX_DIR): Remove.
+ (ED_PROGRAM): New var.
+ (NODIR): Remove.
+ (PACKAGE, VERSION): New vars; substitute them with AC_SUBST.
+
+ * Makefile.in: Conform to current GNU build standards.
+ Redo dependencies. Use library getopt_long if available.
+ Use `&&' instead of `;' inside shell commands where applicable;
+ GNU make requires this.
+ Use double-colon rules for actions that do not build files.
+ (@SET_MAKE@): Added.
+ (CFLAGS, LDFLAGS, prefix, exec_prefix): Base on @ versions of symbols.
+ (COMPILE, CPPFLAGS, DEFS, ED_PROGRAM, LIBOBJS, LIBSRCS, PACKAGE,
+ VERSION): New symbols.
+ (SRCS, OBJS, HDRS, MISC): Add new files.
+ (man1dir): Renamed from mandir.
+ (man1ext): Renamed from manext.
+ (patch): Put -o first.
+ (install): Use $(transform) to allow program to be renamed by configure.
+ (patchlevel.h): Build from $(VERSION).
+ (dist): Get version number from $(VERSION) and package name from
+ $(PACKAGE).
+ (TAGS): Scan $(HDRS).
+ (maintainer-clean): Renamed from realclean. Remove patchlevel.h.
+
+ * backupfile.h (simple_backup_suffix): Now const *.
+ (find_backup_file_name, base_name, get_version): Args are now const *.
+ (base_name): New decl.
+ * backupfile.c (<config.h>): Include only if HAVE_CONFIG_H.
+ (<argmatch.h>): Include.
+ (<string.h>): Include if HAVE_STRING_H, not if STDC_HEADERS.
+ (<strings.h>): Include if !HAVE_STRING_H.
+ (<unistd.h>): Do not include.
+ (<dirent.h>): Redo include as per current autoconf standards.
+ (<limits.h>): Include if HAVE_LIMITS_H. Define CHAR_BIT if not defined.
+ (NLENGTH): Now returns size_t.
+ (CLOSEDIR, INT_STRLEN_BOUND): New macros.
+ (ISDIGIT): Use faster method.
+ (find_backup_file_name): No longer depends on NODIR.
+ Remove redundant code.
+ (make_version_name): Remove; do it more portably.
+ (max_backup_version): Args are now const *.
+ (version_number): Simplify digit checking.
+ (basename, concat, dirname): Remove.
+ (argmatch, invalid_arg): Move to argmatch.c. Simplify test for
+ ambiguous args. When reporting an error, use program_name not "patch".
+ (addext): Move to addext.c. Treat all negative values from pathconf
+ like -1. Always use long extension if it fits, even if the filesystem
+ does not support long file names.
+ (backup_types): Now const.
+
+ * common.h, inp.h (XTERN): Renamed from EXT to avoid collision
+ with errno.h reserved name space.
+
+ * common.h (DEBUGGING): Now an integer; default is 1.
+ (enum diff): New type.
+ (diff_type): Use it instead of small integers.
+ (CONTEXT_DIFF, NORMAL_DIFF, ED_DIFF, NEW_CONTEXT_DIFF, UNI_DIFF):
+ Now enumerated values instead of macros.
+ (NO_DIFF): New enumerated value (used instead of 0).
+ (volatile): Default to the empty string if __STDC__ is not defined.
+ (<signal.h>): Do not include.
+ (Chmod, Close, Fclose, Fflush, Fputc, Signal, Sprintf, Strcat,
+ Strcpy, Unlink, Write): Remove these macros; casts to void are
+ not needed for GNU coding standards.
+ (INITHUNKMAX): Move to pch.c.
+ (malloc, realloc, INT_MIN, MAXLINELEN, strNE, strnNE,
+ Reg1, Reg2, Reg3, Reg4, Reg5, Reg6, Reg7, Reg8, Reg9, Reg10, Reg11,
+ Reg12, Reg13, Reg14, Reg15, Reg16): Remove these macros.
+ (S_IXOTH, S_IWOTH, S_IROTH, S_IXGRP, S_IWGRP,
+ S_IRGRP, S_IXUSR, S_IWUSR, S_IRUSR, O_RDONLY, O_RDWR):
+ Define these macros, if not defined.
+ (CTYPE_DOMAIN, ISLOWER, ISSPACE, ISDIGIT, PARAMS): New macros.
+ (instat): Renamed from filestat; used for input file now.
+ (bufsize, using_plan_a, debug, strippath): Not statically initialized.
+ (debug): #define to 0 if not DEBUGGING, so that users of `debug'
+ no longer need to be surrounded by `#if DEBUGGING'.
+ (out_of_mem, filec, filearg, outname, toutkeep, trejkeep): Remove.
+ (inname, inerrno, dry_run, origbase): New variables.
+ (origprae): Now const*.
+ (TMPOUTNAME, TMPINNAME, TMPPATNAME): Now const*volatile.
+ (verbosity): New variable; subsumes `verbose'.
+ (DEFAULT_VERBOSITY, SILENT, VERBOSE): Values in a new enum.
+ (verbose): Removed.
+ (VOID): Use `#ifdef __STDC__' instead of`#if __STDC__',
+ for consistency elsewhere.
+ (__attribute__): New macro (empty if not a recent GCC).
+ (fatal_exit): Renamed from my_exit.
+ (errno): Don't define if STDC_HEADERS.
+ (<string.h>): Include if either STDC_HEADERS or HAVE_STRING_H.
+ (memcmp, memcpy): Define if !STDC_HEADERS && !HAVE_STRING_H
+ && !HAVE_MEMCHR.
+ (<stdlib.h>): Include if HAVE_STDLIB_H, not if STDC_HEADERS.
+ (atol, getenv, malloc, realloc, lseek): Declare only if not defined
+ as a macro.
+ (popen, strcpy, strcat, mktemp): Do not declare.
+ (lseek): Declare to yield off_t, not long.
+ (<fcntl.h>): Include only if HAVE_FCNTL_H.
+
+ * inp.h (get_input_file): New decl.
+ * inp.c (SCCSPREFIX, GET, GET_LOCKED, SCCSDIFF, RCSSUFFIX, CHECKOUT,
+ CHECKOUT_LOCKED, RCSDIFF): Moved here from common.h.
+ (i_ptr): Now char const **.
+ (i_size): Remove.
+ (TIBUFSIZE_MINIMUM): Define only if not already defined.
+ (plan_a, plan_b): Arg is now const *.
+ (report_revision): Declare before use. It's now the caller's
+ responsibility to test whether revision is 0.
+ (scan_input, report_revision, get_input_file):
+ Be less chatty unless --verbose.
+ (get_input_file): New function, split off from plan_a.
+ Reuse file status gotten by pch if possible. Allow for dry run.
+ Use POSIX bits for creat, not number. Check for creation and
+ close failure, and use fstat not stat. Use memcpy not strncpy.
+ (plan_a): Rewrite for speed.
+ Caller now assigns result to using_plan_a.
+ Don't bother reading empty files; during dry runs they might not exist.
+ Use ISSPACE, not isspace.
+ (plan_b): Allow for dry runs. Use ISSPACE, and handle sign extension
+ correctly on arg. Use POSIX symbol for open arg.
+
+ * patch.c (backup, output, patchname, program_name): New vars.
+ (last_frozen_line): Moved here from inp.h.
+ (TMPREJNAME): Moved here from common.h.
+ (optind_last): Removed.
+ (do_defines, if_defined, not_defined, else_defined, end_defined):
+ Now char const. Prepend with \n (except for not_defined) to
+ allow for files ending in non-newline.
+ (Argv): Now char*const*.
+ (main, get_some_switches): Exit status 0 means success,
+ 1 means hunks were rejected, 2 means trouble.
+ (main, locate_hunk, patch_match): Keep track of patch prefix context
+ separately from suffix context; this fixes several bugs.
+ (main): Initialize bufsize, strippath.
+ Be less chatty unless --verbose.
+ No more NODIR; always have version control available.
+ Require environment variables to be nonempty to have effect.
+ Add support for --dry-run, --output, --verbose.
+ Invoke get_input_file first, before deciding among do_ed_script,
+ plan_a, or plan_b.
+ Clear ofp after closing it, to keep discipline that ofp is either
+ 0 or open, to avoid file descriptor leaks. Conversely, rejfp doesn't
+ need this trick since static analysis is enough to show when it
+ needs to be closed.
+ Don't allow file-creation patches to be applied to existing files.
+ Misordered hunks are now not fatal errors; just go on to the next file.
+ It's a fatal error to fall back on plan B when --output is given,
+ since the moving hand has writ.
+ Add support for binary files.
+ Check for I/O errors.
+ chmod output file ourselves, rather than letting move_file do it;
+ this saves global state.
+ Use better grammar when outputting hunks messages, e.g. avoid
+ `1 hunks'.
+ (main, reinitialize_almost_everything):
+ Remove support for multiple file arguments.
+ Move get_some_switches call from reinitialize_almost_everything
+ to main.
+ (reinitialize_almost_everything): No need to reinitialize things
+ that are no longer global variables, e.g. outname.
+ (shortopts): Remove leading "-"; it's no longer important to
+ return options and arguments in order. '-b' no longer takes operand.
+ -p's operand is no longer optional. Add -i, -Y, -z. Remove -S.
+ (longopts): --suffix is now pared with -z, not -b. --backup now
+ means -b. Add --input, --basename-prefix, --dry-run, --verbose.
+ Remove --skip. --strip's operand is now required.
+ (option_help): New variable. Use style of current coding standards.
+ Change to match current option set.
+ (usage): Use it.
+ (get_some_switches): Get all switches, since `+' is defunct.
+ New options -i, -Y, -z, --verbose, --dry-run.
+ Option -S removed.
+ -b now means backup (backup_type == simple), not simple_backup_suffix.
+ -B now implies backup, and requires nonempty operand.
+ -D no longer requires first char of argument to be an identifier.
+ `-o -' is now disallowed (formerly output to regular file named "-").
+ -p operand is now required.
+ -v no longer needs to cleanup (no temp files can exist at that point).
+ -V now implies backup.
+ Set inname, patchname from file name arguments, if any;
+ do not set filearg. It's now an error if extra operands are given.
+ (abort_junk): Check for write errors in reject file.
+ (apply_hunk, copy_till): Return error flag, so that failure to apply
+ out-of-order hunk is no longer fatal.
+ (apply_hunk): New arg after_newline,
+ for patching files not ending in newline.
+ Cache ofp for speed. Check for write errors.
+ (OUTSIDE, IN_IFNDEF, IN_IFDEF, IN_ELSE): Now part of an enumerated type
+ instead of being #defined to small integers.
+ Change while-do to do-while when copying !-part for R_do_defines,
+ since condition is always true the first time through the loop.
+ (init_output, init_reject): Arg is now const *.
+ (copy_till, spew_output): Do not insert ``missing'' newlines;
+ propagate them via new after_newline argument.
+ (spew_output): Nothing to copy if last_frozen_line == input lines.
+ Do not close (ofp) if it's null.
+ (dump_line): Remove.
+ (similar): Ignore presence or absence of trailing newlines.
+ Check for only ' ' or '\t', not isspace (as per POSIX.2).
+ (make_temp): Use tmpnam if mktemp is not available.
+ (cleanup): New function.
+ (fatal_exit): Use it. Renamed from my_exit.
+ Take signal to exit with, not exit status (which is now always 2).
+
+ * pch.h, pch.c (pch_prefix_context, pch_suffix_context):
+ New fns replacing pch_context.
+ (another_hunk): Now yields int, not bool; -1 means out of memory.
+ Now takes difftype as argument.
+ (pch_write_line): Now returns boolean indicating whether we're after
+ a newline just after the write, for supporting non-text files.
+ * pch.c (isdigit): Remove; use ISDIGIT instead.
+ (INITHUNKMAX): Moved here from common.h.
+ (p_context): Removed. We need to keep track of the pre- and post-
+ context separately, in:
+ (p_prefix_context, p_suffix_context): New variables.
+ (bestguess): Remove.
+ (open_patch_file): Arg is now char const *.
+ Copy file a buffer at a time, not a char at a time, for speed.
+ (grow_hunkmax): Now returns success indicator.
+ (there_is_another_patch, skip_to, another_hunk, do_ed_script):
+ Be less chatty unless --verbose.
+ (there_is_another_patch):
+ Avoid infinite loop if user input keeps yielding EOF.
+ (intuit_diff_type): New returns enum diff, not int.
+ Strip paths as they're being fetched.
+ Set ok_to_create_file correctly even if patch is reversed.
+ Set up file names correctly with unidiff output.
+ Use algorithm specified by POSIX 1003.2b/D11 to deduce
+ name of file to patch, with the exception of patches
+ that can create files.
+ (skip_to): Be verbose if !inname, since we're about to ask the
+ user for a file name and the context will help the user choose.
+ (another_hunk): Keep context as LINENUM, not int.
+ If the replacement is missing, calculate its context correctly.
+ Don't assume input ends in newline.
+ Keep track of patch prefix context separately from suffix context;
+ this fixes several bugs.
+ Don't assume blank lines got chopped if the replacement is missing.
+ Report poorly-formed hunks instead of aborting.
+ Do not use strcpy on overlapping strings; it's not portable.
+ Work even if lines are incomplete.
+ Fix bugs associated with context-less context hunks,
+ particularly when patching in reverse.
+ (pget_line): Now takes just 1 arg; instead of second arg,
+ just examine using_plan_a global. Return -1 if we ran out
+ of memory.
+ (do_ed_script): Now takes output FILE * argument.
+ Take name of editor from ED_PROGRAM instead of hardwiring /bin/ed.
+ Don't bother unlinking TMPOUTNAME.
+ Check for popen failure.
+ Flush pipe to check for output errors.
+ If ofp is nonzero, copy result to it, instead of trying to
+ move the result.
+
+ * util.h, util.c (say1, say2, say3, say4, fatal1, fatal2, fatal3,
+ fatal4, pfatal1, pfatal2, pfatal3, pfatal4, ask1, ask2, ask3, ask4):
+ Remove; replaced with following.
+ (ask, say, fatal, pfatal): New stdarg functions.
+ (fetchname): Remove last, `assume_exists' parameter.
+ (savebuf, savestr, move_file, copy_file): Args are now const *.
+ (exit_with_signal): New function, for proper process status if
+ a signal is received as per POSIX.2.
+ (basename): Rename to `base_name' and move to backupfile.
+ * util.c (<signal.h>): Include here, not in common.h.
+ (vararg_start): New macro.
+ (va_dcl, va_start, va_arg, va_end): Define if neither <stdarg.h>
+ nor <varargs.h> are available.
+ (SIGCHLD): Define to SIGCLD if SIGCLD is defined and
+ SIGCHLD isn't.
+ (private_strerror): Remove.
+ (move_file): Remove option of moving to stdout.
+ Add support for -Y, -z.
+ Don't assume chars in file name are nonnegative.
+ Use copy_file if rename fails due to EXDEV;
+ report failure if rename fails for any other reason.
+ (copy_file, makedirs): Use POSIX symbols for permissions.
+ (copy_file): Open source before destination.
+ (remove_prefix): New function.
+ (vfprintf): New function, if !HAVE_VPRINTF.
+ (afatal, apfatal, zfatal, zpfatal, errnum): Remove.
+ (fatal, pfatal, say): New functions that use stdarg.
+ All callers changed.
+ (zask): Renamed from `ask'. Now uses stdarg. Output to stdout,
+ and read from /dev/tty, or if that cannot be opened, from
+ stderr, stdout, stdin, whichever is first a tty.
+ Print "EOF" when an EOF is read. Do not echo input.
+ (sigs): New array.
+ (sigset_t, sigemptyset, sigmask, sigaddset, sigismember, SIG_BLOCK,
+ SIG_UNBLOCK, SIG_SETMASK, sigprocmask, sigblock, sigsetmask):
+ Define substitutes if not available.
+ (initial_signal_mask, signals_to_block): New vars.
+ (fatal_exit_handler): New function, if !HAVE_SIGACTION.
+ (set_signals, ignore_signals): Use sigaction and sigprocmask style
+ signal-handling if possible; it doesn't lose signals.
+ (set_signals): Default SIGCHLD to work around SysV fork+wait bug.
+ (mkdir): First arg is now const *.
+ (makedirs): Handle multiple adjacent slashes correctly.
+ (fetchname): Do not worry about whether the file exists
+ (that is now the caller's responsibility).
+ Treat a sequence of one or more slashes like one slash.
+ Do not unstrip leading directories if they all exist and if
+ no -p option was given; POSIX doesn't allow this.
+ (memcmp): Remove (now a macro in common.h).
+
+ * version.c (copyright_string, free_software_msgid, authorship_msgid):
+ New constants.
+ (version): Use them. Use program_name instead of hardwiring it.
+
+ * patch.man: Generate date from RCS Id.
+ Rewrite to match the above changes.
+
+Fri Jul 30 02:02:51 1993 Paul Eggert (eggert@twinsun.com)
+
+ * configure.in (AC_HAVE_FUNCS): Add mkdir.
+
+ * common.h (Chmod, Fputc, Write, VOID): New macros.
+ (malloc, realloc): Yield `VOID *', not `char *'.
+
+ * util.h (makedirs): Omit `striplast' argument. Remove `aask'.
+
+ * inp.c (plan_a): Remove fixed internal buffer. Remove lint.
+
+ * util.c (set_signals, ignore_signals): Trap SIGTERM, too.
+ (makedirs): Removed fixed internal buffer. Omit `striplast' argument.
+ (mkdir): New function, if !HAVE_MKDIR.
+ (fetchname): Remove fixed internal buffer.
+ Remove lint from various functions.
+
+ * patch.c, pch.c: Remove lint.
+
+Thu Jul 29 20:52:07 1993 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu)
+
+ * Makefile.in (config.status): Run config.status --recheck, not
+ configure, to get the right args passed.
+
+Thu Jul 29 07:46:16 1993 Paul Eggert (eggert@twinsun.com)
+
+ * The following changes remove all remaining fixed limits on memory,
+ and fix bugs in patch's handling of null bytes and files that do not
+ end in newline. `Patch' now works on binary files.
+
+ * backupfile.c (find_backup_file_name): Don't dump core if malloc fails.
+
+ * EXTERN.h, INTERN.h (EXITING): New macro.
+ * backupfile.[ch], patch.c, pch.c: Add PARAMS to function declarations.
+
+ * common.h (bool): Change to int, so ANSI C prototype promotion works.
+ (CANVARARG): Remove varargs hack; it wasn't portable.
+ (filearg): Now a pointer, not an array, so that it can be reallocated.
+ (GET*, SCCSDIFF, CHECKOUT*, RCSDIFF): Quote operands to commands.
+ (my_exit): Declare here.
+ (BUFFERSIZE, Ctl, filemode, Fseek, Fstat, Lseek, MAXFILEC, MAXHUNKSIZE,
+ Mktemp, myuid, Null, Nullch, Nullfp, Nulline, Pclose, VOIDUSED): Remove.
+ All invokers changed.
+ (Argc, Argv, *define[sd], last_offset, maxfuzz, noreverse, ofp,
+ optind_last, rejfp, rejname): No longer externally visible; all
+ definers changed.
+ (INT_MAX, INT_MIN, STD*_FILENO, SEEK_SET): Define if the underlying
+ system doesn't. Include <limits.h> for this.
+
+ * configure.in: Add limits.h, memcmp. Delete getline.
+
+ * inp.c (tibufsize): New variable; buffers grow as needed.
+ (TIBUFSIZE_MINIMUM): New macro.
+ (report_revision): New function.
+ (plan_a): Do not search patch as a big string, since that fails
+ if it contains null bytes.
+ Prepend `./' to filenames starting with `-', for RCS and SCCS.
+ If file does not match default RCS/SCCS version, go ahead and patch
+ it anyway; warn about the problem but do not report a fatal error.
+ (plan_b): Do not use a fixed buffer to read lines; read byte by byte
+ instead, so that the lines can be arbitrarily long. Do not search
+ lines as strings, since they may contain null bytes.
+ (plan_a, plan_b): Report I/O errors.
+
+ * inp.c, inp.h (rev_in_string): Remove.
+ (ifetch): Yield size of line too, since strlen no longer applies.
+ (plan_a, plan_b): No longer exported.
+
+ * patch.c (abort_hunk, apply_hunk, patch_match, similar):
+ Lines may contain NUL and need not end in newline.
+ (copy_till, dump_line): Insert newline if appending after partial line.
+ All invokers changed.
+ (main, get_some_switches, apply_hunk): Allocate *_define[ds], filearg,
+ rejname dynamically.
+ (make_temp): New function.
+ (main): Use it.
+ (main, spew_output, dump_line) Check for I/O errors.
+
+ * pch.c (open_patch_file): Don't copy stdin to a temporary file if
+ it's a regular file, since we can seek on it directly.
+ (open_patch_file, skip_to, another_hunk): The patch file may contain
+ NULs.
+ (another_hunk): The patch file may contain lines starting with '\',
+ which means the preceding line lacked a trailing newline.
+ (pgetline): Rename to pget_line.
+ (get_line, incomplete_line, pch_write_line): New functions.
+ (pch_line_len): Return size_t, not short; lines may be very long.
+ (do_ed_script): Check for I/O errors. Allow scripts to contain
+ 'i' and 's' commands, too.
+
+ * pch.h (pfp, grow_hunkmax, intuit_diff_type, next_intuit_at, skip_to,
+ pfetch, pgetline): No longer exported.
+ (pch_write_line): New declaration.
+ (getline): Removed.
+
+ * util.c (move_file, fetchname): Use private stat buffer, so that
+ filestat isn't lost. Check for I/O errors.
+ (savestr): Use savebuf.
+ (zask): Use STD*_FILENO instead of 0, 1, 2.
+ (fetchname): strip_leading defaults to INT_MAX instead of 957 (!).
+ (memcmp): Define if !HAVE_MEMCMP.
+
+ * util.c, util.h (say*, fatal*, pfatal*, ask*): Delete; these
+ pseudo-varargs functions weren't ANSI C. Replace by macros
+ that invoke [fs]printf directly, and invoke new functions
+ [az]{say,fatal,pfatal,ask} before and after.
+ (savebuf, read_fatal, write_fatal, memory_fatal, Fseek): New functions.
+ (fatal*): Output trailing newline after message. All invokers changed.
+
+ * version.c (version): Don't exit.
+
+ * Makefile.in (SRCS): Remove getline.c.
+
+Thu Jul 22 15:24:24 1993 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
+
+ * EXTERN.h, INTERN.h (PARAMS): Define.
+ * backupfile.h, common.h, inp.h, pch.h, util.h: Use.
+ * backupfile.c: Include EXTERN.h.
+
+Wed Jul 21 13:14:05 1993 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
+
+ * getline.c: New file.
+ * configure.in: Check for getline (GNU libc has it).
+ * pch.c: Use it instead of fgets.
+ (pgetline): Renamed from pgets. Change callers.
+ * pch.h: Change decl.
+
+ * pch.c (pgets): Tab adjusts by 8 - (indent % 8), not % 7.
+ Be consistent with similar code in pch.c::intuit_diff_type.
+
+ * common.h (MEM): Typedef removed.
+ inp.c, pch.c, util.c: Use size_t instead of MEM.
+ inp.c, pch.c: Use off_t.
+ configure.in: Add AC_SIZE_T and AC_OFF_T.
+
+ * common.h: Make buf a pointer and add a bufsize variable.
+ * util.c, pch.c, inp.c: Replace sizeof buf with bufsize.
+ * patch.c: malloc buf to bufsize bytes.
+
+Tue Jul 20 20:40:03 1993 Paul Eggert (eggert@twinsun.com)
+
+ * common.h (BUFFERSIZE): Grow it to 8k too, just in case.
+ (buf): Turn `buf' back into an array; making it a pointer broke
+ things seriously.
+ * patch.c (main): Likewise.
+
+Tue Jul 20 20:02:40 1993 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
+
+ * Move Reg[1-16] and CANVARARG decls from config.h.in to common.h.
+ * acconfig.h: New file.
+ * Makefile (HDRS): Add it.
+
+Tue Jul 20 16:35:27 1993 Paul Eggert (eggert@twinsun.com)
+
+ * Makefile.in: Remove alloca.[co]; getopt no longer needs it.
+ * configure.in (AC_ALLOCA): Remove.
+
+ * util.c (set_signals, ignore_signals): Do nothing if SIGHUP
+ and SIGINT aren't defined.
+
+Tue Jul 20 17:59:56 1993 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
+
+ * patch.c (main): Call xmalloc, not malloc. xmalloc buf.
+ * common.h: Declare xmalloc. Make buf a pointer, not an array.
+
+ * util.c (xmalloc): Call fatal1, not fatal.
+
+ * common.h [MAXLINELEN]: Bump from 1k to 8k.
+
+Thu Jul 8 19:56:16 1993 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
+
+ * Makefile.in (installdirs): New target.
+ (install): Use it.
+ (Makefile, config.status, configure): New targets.
+
+Wed Jul 7 13:25:40 1993 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
+
+ * patch.c (get_some_switches, longopts): Recognize --help
+ option, and call usage.
+ (usage): New function.
+
+Fri Jun 25 07:49:45 1993 Paul Eggert (eggert@twinsun.com)
+
+ * backupfile.c (find_backup_file_name): Don't use .orig if
+ numbered_existing with no existing numbered backup.
+ (addext): Don't use ext if !HAVE_LONG_FILE_NAMES,
+ even if it would fit. This matches patch's historical behavior.
+ (simple_backup_suffix): Default to ".orig".
+ * patch.c (main): Just use that default.
+
+Tue Jun 15 22:32:14 1993 Paul Eggert (eggert@twinsun.com)
+
+ * config.h.in (HAVE_ALLOCA_H): This #undef was missing.
+ * Makefile.in (info, check, installcheck): New rules.
+
+Sun Jun 13 14:31:29 1993 Paul Eggert (eggert@twinsun.com)
+
+ * config.h.in (index, rindex): Remove unused macro
+ definitions; they get in the way when porting to AIX.
+ * config.h.in, configure.in (HAVE_STRING_H): Remove unused defn.
+
+Thu Jun 10 21:13:47 1993 Paul Eggert (eggert@twinsun.com)
+
+ * patchlevel.h: PATCH_VERSION 2.1.
+ (The name `patch-2.0.12g12' is too long for traditional Unix.)
+
+ * patchlevel.h (PATCH_VERSION): Renamed from PATCHLEVEL.
+ Now contains the entire patch version number.
+ * version.c (version): Use it.
+
+Wed Jun 9 21:43:23 1993 Paul Eggert (eggert@twinsun.com)
+
+ * common.h: Remove declarations of index and rindex.
+ * backupfile.c: Likewise.
+ (addext, basename, dirname): Avoid rindex.
+
+Tue Jun 8 15:24:14 1993 Paul Eggert (eggert@twinsun.com)
+
+ * inp.c (plan_a): Check that RCS and working files are not the
+ same. This check is needed on hosts that do not report file
+ name length limits and have short limits.
+
+Sat Jun 5 22:56:07 1993 Paul Eggert (eggert@twinsun.com)
+
+ * Makefile.in (.c.o): Put $(CFLAGS) after other options.
+ (dist): Switch from .z to .gz.
+
+Wed Jun 2 10:37:15 1993 Paul Eggert (eggert@twinsun.com)
+
+ * backupfile.c (find_backup_file_name): Initialize copy of
+ file name properly.
+
+Mon May 31 21:55:21 1993 Paul Eggert (eggert@twinsun.com)
+
+ * patchlevel.h: Patch level 12g11.
+
+ * pch.c (p_Char): Renamed from p_char, which is a system type
+ in Tex XD88's <sys/types.h>.
+
+ * backupfile.c: Include "config.h" first, so that `const' is
+ treated consistently in system headers.
+
+Mon May 31 16:06:23 1993 Paul Eggert (eggert@twinsun.com)
+
+ * patchlevel.h: Patch level 12g10.
+
+ * configure.in: Add AC_CONST.
+ * config.h.in: Add `const'.
+ * Makefile.in (.c.o): Add -DHAVE_CONFIG_H.
+ (getopt.o getopt1.o): Depend on config.h.
+
+ * util.c (xmalloc): New function; alloca.c needs this.
+
+Mon May 31 00:49:40 1993 Paul Eggert (eggert@twinsun.com)
+
+ * patchlevel.h: PATCHLEVEL 12g9.
+
+ * backupfile.c, backupfile.h (addext): New function.
+ It uses pathconf(), if available, to determine maximum file
+ name length.
+ * patch.c (main): Use it for reject file name.
+ * common.h (ORIGEXT): Moved to patch.c.
+ * config.h.in (HAVE_PATHCONF): New macro.
+ * configure.in: Define it.
+
+ * Makefile.in (dist): Use gzip, not compress.
+
+Sat May 29 09:42:18 1993 Paul Eggert (eggert@twinsun.com)
+
+ * patch.c (main): Use pathconf to decide reject file name.
+ * common.h (REJEXT): Remove.
+
+ * inp.c (plan_a): Don't lock the checked-out file if `patch -o'
+ redirected the output elsewhere.
+ * common.h (CHECKOUT_LOCKED, GET_LOCKED): New macros. GET and
+ CHECKOUT now just checkout unlocked copies.
+
+Fri May 28 08:44:50 1993 Paul Eggert (eggert@twinsun.com)
+
+ * backupfile.c (basename): Define even if NODIR isn't defined.
+ * patch.c (main): Ask just once to apply a reversed patch.
+
+Tue Nov 24 08:09:04 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
+
+ * config.h.in, common.h: Use HAVE_FCNTL_H and HAVE_STRING_H
+ instead of USG.
+
+ * backupfile.c: Use SYSDIR and NDIR instead of USG.
+ Define direct as dirent, not vice-versa.
+
+Wed Sep 16 17:11:48 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * patch.c (get_some_switches): optc should be int, not char.
+
+Tue Sep 15 00:36:46 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * patchlevel.h: PATCHLEVEL 12g8.
+
+Mon Sep 14 22:01:23 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * Makefile.in: Add uninstall target.
+
+ * util.c (fatal, pfatal): Add some asterisks to make fatal
+ messages stand out more.
+
+Tue Aug 25 22:13:36 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * patch.c (main, get_some_switches), common.h, inp.c (plan_a,
+ plan_b), pch.c (there_is_another_patch): Add -t --batch
+ option, similar to -f --force.
+
+Mon Jul 27 11:27:07 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * common.h: Define SCCSDIFF and RCSDIFF.
+ * inp.c (plan_a): Use them to make sure it's safe to check out
+ the default RCS or SCCS version.
+ From Paul Eggert.
+
+Mon Jul 20 14:10:32 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * util.h: Declare basename.
+ * inp.c (plan_a), util.c (fetchname): Use it to isolate the
+ leading path when testing for RCS and SCCS files.
+
+Fri Jul 10 16:03:23 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * util.c (makedirs): Only make the directories that don't exist.
+ From chip@tct.com (Chip Salzenberg).
+
+Wed Jul 8 01:20:56 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * patch.c (main): Open ofp after checking for ed script.
+ Close ofp and rejfp before trying plan B.
+ From epang@sfu.ca (Eugene Pang).
+
+ * util.c (fatal, pfatal): Print "patch: " before message.
+ * pch.c, inp.c, patch.c, util.c: Remove "patch: " from the
+ callers that had it.
+
+ * common.h (myuid): New variable.
+ * patch.c (main): Initialize it.
+ * inp.c (myuid): Function removed.
+ (plan_a): Use the variable, not the function.
+
+ * patch.c: Add back -E --remove-empty-files option.
+
+Tue Jul 7 23:19:28 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * inp.c (myuid): New function.
+ (plan_a): Call it. Optimize stat calls. Be smarter about
+ detecting checked out RCS and SCCS files.
+ From Paul Eggert (eggert@twinsun.com).
+
+ * inp.c, util.c, patch.c: Don't bother checking for stat() > 0.
+
+Mon Jul 6 13:01:52 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * util.c (move_file): Use rename instead of link and copying.
+
+ * util.c (pfatal): New function.
+ * util.h: Declare it and pfatal[1-4] macros.
+ * various files: Use it instead of fatal where appropriate.
+
+ * common.h, patch.c: Replace Arg[cv]_last with optind_last.
+
+ * patch.c (main, get_some_switches): Use getopt_long. Update
+ usage message.
+ (nextarg): Function removed.
+
+ * Rename FLEXFILENAMES to HAVE_LONG_FILE_NAMES,
+ VOIDSIG to RETSIGTYPE.
+
+ * backupfile.c, common.h: Use STDC header files if available.
+ backupfile.h: Declare get_version.
+
+ * COPYING, COPYING.LIB, INSTALL, Makefile.in, alloca.c,
+ config.h.in, configure, configure.in, getopt.[ch], getopt1.c,
+ rename.c: New files.
+ * Configure, MANIFEST, Makefile.SH, config.H, config.h.SH,
+ malloc.c: Files removed.
+
+ * version.c (version): Don't print the RCS stuff, since we're
+ not updating it regularly.
+
+ * patchlevel.h: PATCHLEVEL 12u7.
+
+ * Makefile.SH (dist): New target.
+ Makedist: File removed.
+
+ * inp.c (plan_a): Check whether the user can write to the
+ file, not whether anyone can write to the file.
+
+Sat Jul 4 00:06:58 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * inp.c (plan_a): Try to check out read-only files from RCS or SCCS.
+
+ * util.c (move_file): If backing up by linking fails, try copying.
+ From cek@sdc.boeing.com (Conrad Kimball).
+
+ * patch.c (get_some_switches): Eliminate -E option; always
+ remove empty output files.
+
+ * util.c (fetchname): Only undo slash removal for relative
+ paths if -p was not given.
+
+ * Makefile.sh: Add mostlyclean target.
+
+Fri Jul 3 23:48:14 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * util.c (fetchname): Accept whitespace between `Index:' and filename.
+ Also plug a small memory leak for diffs against /dev/null.
+ From eggert@twinsun.com (Paul Eggert).
+
+ * common.h: Don't define TRUE and FALSE if already defined.
+ From phk@data.fls.dk (Poul-Henning Kamp).
+
+Wed Apr 29 10:19:33 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
+
+ * backupfile.c (get_version): Exit if given a bad backup type.
+
+Fri Mar 27 09:57:14 1992 Karl Berry (karl at hayley)
+
+ * common.h (S_ISDIR, S_ISREG): define these.
+ * inp.c (plan_a): use S_ISREG, not S_IFREG.
+ * util.c (fetchname): use S_ISDIR, not S_IFDIR.
+
+Mon Mar 16 14:10:42 1992 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu)
+
+ * patchlevel.h: PATCHLEVEL 12u6.
+
+Sat Mar 14 13:13:29 1992 David J. MacKenzie (djm at frob.eng.umd.edu)
+
+ * Configure, config.h.SH: Check for directory header and unistd.h.
+
+ * patch.c (main): If -E was given and output file is empty after
+ patching, remove it.
+ (get_some_switches): Recognize -E option.
+
+ * patch.c (copy_till): Make garbled output an error, not a warning
+ that doesn't change the exit status.
+
+ * common.h: Protect against system declarations of malloc and realloc.
+
+ * Makedist: Add backupfile.[ch].
+
+ * Configure: Look for C library where NeXT and SVR4 put it.
+ Look in /usr/ucb after /bin and /usr/bin for utilities,
+ and look in /usr/ccs/bin, to make SVR4 happier.
+ Recognize m68k predefine.
+
+ * util.c (fetchname): Test of stat return value was backward.
+ From csss@scheme.cs.ubc.ca.
+
+ * version.c (version): Exit with status 0, not 1.
+
+ * Makefile.SH: Add backupfile.[cho].
+ * patch.c (main): Initialize backup file generation.
+ (get_some_switches): Add -V option.
+ * common.h, util,c, patch.c: Replace origext with simple_backup_suffix.
+ * util.c (move_file): Use find_backup_file_name.
+
+Tue Dec 3 11:27:16 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * patchlevel.h: PATCHLEVEL 12u5.
+
+ * Makefile.SH: Change clean, distclean, and realclean targets a
+ little so they agree with the GNU coding standards.
+ Add Makefile to addedbyconf, so distclean removes it.
+
+ * Configure: Recognize Domain/OS C library in /lib/libc.
+ From mmuegel@mot.com (Michael S. Muegel).
+
+ * pch.c: Fixes from Wayne Davison:
+ Patch now accepts no-context context diffs that are
+ specified with an assumed one line hunk (e.g. "*** 10 ****").
+ Fixed a bug in both context and unified diff processing that would
+ put a zero-context hunk in the wrong place (one line too soon).
+ Fixed a minor problem with p_max in unified diffs where it would
+ set p_max to hunkmax unnecessarily (the only adverse effect was to
+ not supply empty lines at eof by assuming they were truncated).
+
+Tue Jul 2 03:25:51 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
+
+ * Configure: Check for signal declaration in
+ /usr/include/sys/signal.h as well as /usr/include/signal.h.
+
+ * Configure, common.h, config.h.SH: Comment out the sprintf
+ declaration and tests to determine its return value type. It
+ conflicts with ANSI C systems' prototypes in stdio.h and the
+ return value of sprintf is never used anyway -- it's always cast
+ to void.
+
+Thu Jun 27 13:05:32 1991 David J. MacKenzie (djm at churchy.gnu.ai.mit.edu)
+
+ * patchlevel.h: PATCHLEVEL 12u4.
+
+Thu Feb 21 15:18:14 1991 David J. MacKenzie (djm at geech.ai.mit.edu)
+
+ * pch.c (another_hunk): Fix off by 1 error. From
+ iverson@xstor.com (Tim Iverson).
+
+Sun Jan 20 20:18:58 1991 David J. MacKenzie (djm at geech.ai.mit.edu)
+
+ * Makefile.SH (all): Don't make a dummy `all' file.
+
+ * patchlevel.h: PATCHLEVEL 12u3.
+
+ * patch.c (nextarg): New function.
+ (get_some_switches): Use it, to prevent dereferencing a null
+ pointer if an option that takes an arg is not given one (is last
+ on the command line). From Paul Eggert.
+
+ * pch.c (another_hunk): Fix from Wayne Davison to recognize
+ single-line hunks in unified diffs (with a single line number
+ instead of a range).
+
+ * inp.c (rev_in_string): Don't use `s' before defining it. From
+ Wayne Davison.
+
+Mon Jan 7 06:25:11 1991 David J. MacKenzie (djm at geech.ai.mit.edu)
+
+ * patchlevel.h: PATCHLEVEL 12u2.
+
+ * pch.c (intuit_diff_type): Recognize `+++' in diff headers, for
+ unified diff format. From unidiff patch 1.
+
+Mon Dec 3 00:14:25 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
+
+ * patch.c (get_some_switches): Make the usage message more
+ informative.
+
+Sun Dec 2 23:20:18 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
+
+ * Configure: When checking for C preprocessor, look for 'abc.*xyz'
+ instead of 'abc.xyz', so ANSI C preprocessors work.
+
+ * Apply fix for -D from ksb@mentor.cc.purdue.edu (Kevin Braunsdorf).
+
+1990-05-01 Wayne Davison <davison@dri.com>
+ * patch.c, pch.c: unidiff support added
+
+Wed Mar 7 23:47:25 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu)
+
+ * pch.c: Call malformed instead of goto malformed
+ (just allows easier debugging).
+
+Tue Jan 23 21:27:00 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu)
+
+ * common.h (TMP*NAME): Make these char *, not char [].
+ patch.c (main): Use TMPDIR (if present) to set TMP*NAME.
+ common.h: Declare getenv.
+
+Sun Dec 17 17:29:48 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * patch.c (reverse_flag_specified): New variable.
+ (get_some_switches, reinitialize_almost_everything): Use it.
+
+1988-06-22 Larry Wall <sdcrdcf!lwall>
+ patch12:
+ * common.h: sprintf was declared wrong
+ * patch.c: rindex() wasn't declared
+ * patch.man: now avoids Bell System Logo
+
+1988-06-03 Larry Wall <sdcrdcf!lwall>
+ patch10:
+ * common.h: support for shorter extensions.
+ * inp.c: made a little smarter about sccs files
+ * patch.c: exit code improved.
+ better support for non-flexfilenames.
+ * patch.man: -B switch was contributed.
+ * pch.c: Can now find patches in shar scripts.
+ Hunks that swapped and then swapped back could core dump.
+
+1987-06-04 Larry Wall <sdcrdcf!lwall>
+ * pch.c: pch_swap didn't swap p_bfake and p_efake.
+
+1987-02-16 Larry Wall <sdcrdcf!lwall>
+ * patch.c: Short replacement caused spurious "Out of sync" message.
+
+1987-01-30 Larry Wall <sdcrdcf!lwall>
+ * patch.c: Improved diagnostic on sync error.
+ Moved do_ed_script() to pch.c.
+ * pch.c: Improved responses to mangled patches.
+ * pch.h: Added do_ed_script().
+
+1987-01-05 Larry Wall <sdcrdcf!lwall>
+ * pch.c: New-style context diffs caused double call to free().
+
+1986-11-21 Larry Wall <sdcrdcf!lwall>
+ * patch.c: Fuzz factor caused offset of installed lines.
+
+1986-11-14 Larry Wall <sdcrdcf!lwall>
+ * pch.c: Fixed problem where a long pattern wouldn't grow the hunk.
+ Also restored p_input_line when backtracking so error messages are
+ right.
+
+1986-11-03 Larry Wall <sdcrdcf!lwall>
+ * pch.c: New-style delete triggers spurious assertion error.
+
+1986-10-29 Larry Wall <sdcrdcf!lwall>
+ * patch.c: Backwards search could terminate prematurely.
+ * pch.c: Could falsely report new-style context diff.
+
+1986-09-17 Larry Wall <sdcrdcf!lwall>
+ * common.h, inp.c, inp.h, patch.c, patch.man, pch.c, pch.h,
+ util.h, version.c, version.h: Baseline for netwide release.
+
+1986-08-01 Larry Wall <sdcrdcf!lwall>
+ * patch.c: Fixes for machines that can't vararg.
+ Added fuzz factor. Generalized -p. General cleanup.
+ Changed some %d's to %ld's. Linted.
+ * patch.man: Documented -v, -p, -F.
+ Added notes to patch senders.
+
+1985-08-15 van%ucbmonet@berkeley
+ Changes for 4.3bsd diff -c.
+
+1985-03-26 Larry Wall <sdcrdcf!lwall>
+ * patch.c: Frozen.
+ * patch.man: Frozen.
+
+1985-03-12 Larry Wall <sdcrdcf!lwall>
+ * patch.c: Now checks for normalness of file to patch.
+ Check i_ptr and i_womp to make sure they aren't null before freeing.
+ Also allow ed output to be suppressed.
+ Changed pfp->_file to fileno(pfp).
+ Added -p option from jromine@uci-750a.
+ Added -D (#ifdef) option from joe@fluke.
+ * patch.man: Documented -p, -D.
+
+1984-12-06 Larry Wall <sdcrdcf!lwall>
+ * patch.c: Made smarter about SCCS subdirectories.
+
+1984-12-05 Larry Wall <sdcrdcf!lwall>
+ * patch.c: Added -l switch to do loose string comparison.
+ * patch.man: Added -l switch, and noted bistability bug.
+
+1984-12-04 Larry Wall <sdcrdcf!lwall>
+ Branch for sdcrdcf changes.
+ * patch.c: Failed hunk count not reset on multiple patch file.
+ * patch.man: Baseline version.
+
+1984-11-29 Larry Wall <sdcrdcf!lwall>
+ * patch.c: Linted. Identifiers uniquified. Fixed i_ptr malloc() bug.
+ Fixed multiple calls to mktemp(). Will now work on machines that can
+ only read 32767 chars. Added -R option for diffs with new and old
+ swapped. Various cosmetic changes.
+
+1984-11-09 Larry Wall <sdcrdcf!lwall>
+ * patch.c: Initial revision
+
+Local Variables:
+mode: indented-text
+left-margin: 8
+version-control: never
+end:
diff --git a/contrib/patch/NEWS b/contrib/patch/NEWS
new file mode 100644
index 000000000000..de0f75727bf9
--- /dev/null
+++ b/contrib/patch/NEWS
@@ -0,0 +1,158 @@
+Known problems:
+
+* The diffutils 2.7 documentation for `patch' is obsolete; this should be
+ fixed in diffutils 2.8. Until then, see `patch --help' or `man patch'.
+
+Change in version 2.4:
+
+* New options:
+ -Z or --set-utc sets times of patched files, assuming diff uses UTC (GMT).
+ -T or --set-time is similar, assuming local time (not recommended).
+ --backup-if-mismatch makes a backup if the patch does not match exactly
+ --no-backup-if-mismatch makes a backup only if otherwise requested
+
+* The default is now --backup-if-mismatch unless POSIXLY_CORRECT is set.
+
+* The -B or --prefix, -Y or --basename-prefix, and -z or --suffix options
+ no longer affect whether backups are made (as they did in patch 2.2 and 2.3);
+ they now merely specify the file names used when simple backups are made.
+
+* When patching a nonexistent file and making backups, an empty backup file
+ is now made (just as with traditional patch); but the backup file is
+ unreadable, as a way of indicating that it represents a nonexistent file.
+
+* `patch' now matches against empty and nonexistent files more generously.
+ A patch against an empty file applies to a nonexistent file, and vice versa.
+
+* -g or --get and PATCH_GET now have a numeric value that specifies
+ whether `patch' is getting files.
+ If the value is positive, working files are gotten from RCS or SCCS files;
+ if zero, `patch' ignores RCS and SCCS and working files are not gotten;
+ and if negative, `patch' asks the user whether to get each file.
+ The default is normally negative, but it is zero if POSIXLY_CORRECT is set.
+
+* The -G or --no-get option introduced in GNU patch 2.3 has been removed;
+ use -g0 instead.
+
+* The method used to intuit names of files to be patched is changed again:
+ `Index:' lines are normally ignored for context diffs,
+ and RCS and SCCS files are normally looked for when files do not exist.
+ The complete new method is described in the man page.
+
+* By default, `patch' is now more verbose when patches do not match exactly.
+
+* The manual page has a new COMPATIBILITY ISSUES section.
+
+Changes in version 2.3:
+
+* Unless the POSIXLY_CORRECT environment variable is set:
+
+ - `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
+ looks like it might be equivalent to 1970-01-01 00:00:00 UTC.
+ - Files that ``become nonexistent'' after patching are now removed.
+ When a file is removed, any empty ancestor directories are also removed.
+
+* Files are now automatically gotten from RCS and SCCS
+ if the -g or --get option is specified.
+ (The -G or --no-get option, also introduced in 2.3, was withdrawn in 2.4.)
+
+* If the PATCH_VERSION_CONTROL environment variable is set,
+ it overrides the VERSION_CONTROL environment variable.
+
+* The method used to intuit names of files to be patched is changed.
+ (It was further revised in 2.4; see above.)
+
+* The new --binary option makes `patch' read and write files in binary mode.
+ This option has no effect on POSIX-compliant hosts;
+ 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).
+
+* On POSIX.1-compliant hosts, you can now patch binary files using the output
+ of GNU `diff -a'.
+
+* New options:
+ --dry-run
+ --help
+ --verbose
+ -i FILE or --input=FILE
+ -y PREF or --basename-prefix=PREF
+
+* patch is now quieter by default; use --verbose for the old chatty behavior.
+
+* Patch now complies better with POSIX.2 if your host complies with POSIX.1.
+
+ Therefore:
+ - By default, no backups are made.
+ (But this was changed again in patch 2.4; see above.)
+ - The simple backup file name for F defaults to F.orig
+ regardless of whether the file system supports long file names,
+ and F~ is used only if F.orig is too long for that particular file.
+ - Similarly for the reject file names F.rej and F#.
+
+ Also:
+ - The pseudo-option `+' has been withdrawn.
+ - -b is equivalent to --version-control=simple;
+ `-z SUFF' has the meaning that `-b SUFF' used to.
+ - Names of files to be patched are taken first from *** line and then from
+ --- line of context diffs; then from Index: line; /dev/tty is
+ consulted if none of the above files exist. However, if the patch
+ appears to create a file, the file does not have to exist: instead,
+ the first name with the longest existing directory prefix is taken.
+ (These rules were changed again in patch 2.3 and 2.4; see above.)
+ - Exit status 0 means success, 1 means hunks were rejected, 2 means trouble.
+ - `-l' ignores changes only in spaces and tabs, not in other white space.
+ - If no `-p' option is given, `-pINFINITY' is assumed, instead of trying
+ to guess the proper value.
+ - `-p' now requires an operand; use `-p 0' to get the effect of the old plain
+ `-p' option.
+ - `-p' treats two or more adjacent slashes as if it were one slash.
+ - The TERM signal is caught.
+ - New option `-i F' reads patch from F instead of stdin.
+
+* The `patch' options and build procedure conform to current GNU standards.
+ For example, the `--version' option now outputs copyright information.
+
+* When the patch is creating a file, but a nonempty file of that name already
+ exists, `patch' now asks for confirmation before patching.
+
+* RCS is used only if the version control method is `existing'
+ and there is already an RCS file. Similarly for SCCS.
+ (But this was changed again in patch 2.3 and 2.4; see above.)
+
+* Copyright notices have been clarified. Every file in this version of `patch'
+ can be distributed under the GNU General Public License. See README for
+ details.
+
+Changes in version 2.1:
+
+* A few more portability bugs have been fixed. The version number has
+ been changed from 2.0.12g11 to 2.1, because the name
+ `patch-2.0.12g10' was too long for traditional Unix file systems.
+
+Versions 2.0.12g9 through 2.0.12g11 fix various portability bugs.
+
+Changes in version 2.0.12g8:
+
+* Start of the 12g series, with a GNU-style configure script and
+ long-named options.
+* Added the -t --batch option, similar to -f.
+* Improved detection of files that are locked under RCS or SCCS.
+* Reinstate the -E option to remove output files that are empty after
+ being patched.
+* Print the system error message when system calls fail.
+* Fixed various bugs and portability problems.
diff --git a/contrib/patch/README b/contrib/patch/README
new file mode 100644
index 000000000000..e3aa259d9696
--- /dev/null
+++ b/contrib/patch/README
@@ -0,0 +1,52 @@
+This version of `patch' has many changes made by the Free Software Foundation.
+They add support for:
+ * handling arbitrary binary data and large files
+ * the unified context diff format that GNU diff can produce
+ * making GNU Emacs-style backup files
+ * improved interaction with RCS and SCCS
+ * the GNU conventions for option parsing and configuring and compilation.
+ * better POSIX.2 compliance
+They also fix some bugs. See the NEWS and ChangeLog files for details.
+
+Tutorial-style documentation for patch is included in the GNU
+diffutils package. Unfortunately, the diffutils 2.7 documentation
+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.
+
+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.
+
+Please send bug reports for this version of patch to
+bug-gnu-utils@prep.ai.mit.edu.
+
+The Free Software Foundation is distributing this version of patch
+independently because as of this writing, Larry Wall has not released a
+new version of patch since mid-1988. We have heard that he has been
+too busy working on other things, like Perl. He has graciously agreed
+to let GNU `patch' be distributed under the terms of the GNU General
+Public License.
+
+------
+
+Copyright 1984, 1985, 1986, 1987, 1988 Larry Wall
+Copyright 1989, 1990, 1991, 1992, 1993, 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 file; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
diff --git a/contrib/patch/acconfig.h b/contrib/patch/acconfig.h
new file mode 100644
index 000000000000..42e3e60df748
--- /dev/null
+++ b/contrib/patch/acconfig.h
@@ -0,0 +1,14 @@
+/* Local acconfig.h for autoheader.
+ Descriptive text for the C preprocessor macros that
+ 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
+
+/* Define if `struct utimbuf' is declared -- usually in <utime.h>. */
+#undef HAVE_STRUCT_UTIMBUF
diff --git a/contrib/patch/addext.c b/contrib/patch/addext.c
new file mode 100644
index 000000000000..56d0e4f4af6a
--- /dev/null
+++ b/contrib/patch/addext.c
@@ -0,0 +1,106 @@
+/* addext.c -- add an extension to a file name
+ Copyright (C) 1990, 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 David MacKenzie <djm@gnu.ai.mit.edu> and Paul Eggert */
+
+#if HAVE_CONFIG_H
+# 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>
+#else
+# include <strings.h>
+#endif
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+/* Append to FILENAME the extension EXT, unless the result would be too long,
+ in which case just append the character E. */
+
+void
+addext (filename, ext, e)
+ char *filename;
+ char const *ext;
+ int e;
+{
+ char *s = base_name (filename);
+ size_t slen = strlen (s), extlen = strlen (ext);
+ long slen_max = -1;
+
+#if HAVE_PATHCONF && defined _PC_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)
+ slen_max = pathconf (".", _PC_NAME_MAX);
+ else
+ {
+ char c = *s;
+ *s = 0;
+ slen_max = pathconf (filename, _PC_NAME_MAX);
+ *s = c;
+ }
+#endif
+ 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)
+ slen = slen_max - 1;
+ s[slen] = e;
+ s[slen + 1] = 0;
+ }
+}
diff --git a/contrib/patch/argmatch.c b/contrib/patch/argmatch.c
new file mode 100644
index 000000000000..aa5593329765
--- /dev/null
+++ b/contrib/patch/argmatch.c
@@ -0,0 +1,92 @@
+/* argmatch.c -- find a match for a string in an array
+ Copyright (C) 1990, 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 David MacKenzie <djm@gnu.ai.mit.edu> */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <argmatch.h>
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#if HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+/* 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). */
+
+int
+argmatch (arg, 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 ambiguous = 0; /* If nonzero, multiple nonexact match(es). */
+
+ arglen = strlen (arg);
+
+ /* Test all elements for either exact match or abbreviated matches. */
+ for (i = 0; optlist[i]; i++)
+ {
+ if (!strncmp (optlist[i], arg, arglen))
+ {
+ if (strlen (optlist[i]) == arglen)
+ /* Exact match found. */
+ return i;
+ else if (matchind == -1)
+ /* First nonexact match found. */
+ matchind = i;
+ else
+ /* Second nonexact match found. */
+ ambiguous = 1;
+ }
+ }
+ 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. */
+
+void
+invalid_arg (kind, value, problem)
+ const char *kind;
+ const char *value;
+ int problem;
+{
+ fprintf (stderr, "%s: ", program_name);
+ if (problem == -1)
+ fprintf (stderr, "invalid");
+ else /* Assume -2. */
+ fprintf (stderr, "ambiguous");
+ fprintf (stderr, " %s `%s'\n", kind, value);
+}
diff --git a/contrib/patch/argmatch.h b/contrib/patch/argmatch.h
new file mode 100644
index 000000000000..e95ff62e24c0
--- /dev/null
+++ b/contrib/patch/argmatch.h
@@ -0,0 +1,12 @@
+/* argmatch.h -- declarations for matching arguments against option lists */
+
+#if defined __STDC__ || __GNUC__
+# define __ARGMATCH_P(args) args
+#else
+# define __ARGMATCH_P(args) ()
+#endif
+
+int argmatch __ARGMATCH_P ((const char *, const char * const *));
+void invalid_arg __ARGMATCH_P ((const char *, const char *, int));
+
+extern char const program_name[];
diff --git a/contrib/patch/backupfile.c b/contrib/patch/backupfile.c
new file mode 100644
index 000000000000..3b91be04c5a9
--- /dev/null
+++ b/contrib/patch/backupfile.c
@@ -0,0 +1,251 @@
+/* backupfile.c -- make Emacs style backup file names
+ Copyright (C) 1990,1991,1992,1993,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 David MacKenzie <djm@gnu.ai.mit.edu>.
+ Some algorithms adapted from GNU Emacs. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <argmatch.h>
+#include <backupfile.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#if HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+# define NLENGTH(direct) strlen ((direct)->d_name)
+#else
+# define dirent direct
+# define NLENGTH(direct) ((size_t) (direct)->d_namlen)
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+#if CLOSEDIR_VOID
+/* Fake a return value. */
+# define CLOSEDIR(d) (closedir (d), 0)
+#else
+# define CLOSEDIR(d) closedir (d)
+#endif
+
+#if STDC_HEADERS
+# include <stdlib.h>
+#else
+char *malloc ();
+#endif
+
+#if HAVE_DIRENT_H || HAVE_NDIR_H || HAVE_SYS_DIR_H || HAVE_SYS_NDIR_H
+# define HAVE_DIR 1
+#else
+# define HAVE_DIR 0
+#endif
+
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+/* Upper bound on the string length of an integer converted to string.
+ 302 / 1000 is ceil (log10 (2.0)). Subtract 1 for the sign bit;
+ 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)
+
+/* 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. */
+enum backup_type backup_type = none;
+
+/* The extension added to file names to produce a simple (as opposed
+ to numbered) backup file name. */
+const char *simple_backup_suffix = ".orig";
+
+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.
+ FILE must not end with a '/' unless it is the root directory. */
+
+char *
+find_backup_file_name (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 < numbered_suffix_size_max)
+ backup_suffix_size_max = numbered_suffix_size_max;
+
+ s = malloc (file_len + backup_suffix_size_max + numbered_suffix_size_max);
+ if (s)
+ {
+ strcpy (s, file);
+
+#if HAVE_DIR
+ if (backup_type != simple && backup_type != none)
+ {
+ int highest_backup;
+ size_t dir_len = base_name (s) - s;
+
+ strcpy (s + dir_len, ".");
+ highest_backup = max_backup_version (file + dir_len, s);
+ if (! (backup_type == numbered_existing && highest_backup == 0))
+ {
+ 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, suffix, '~');
+ }
+ return s;
+}
+
+#if HAVE_DIR
+
+/* 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.
+ */
+
+static int
+max_backup_version (file, dir)
+ const char *file;
+ const char *dir;
+{
+ DIR *dirp;
+ struct dirent *dp;
+ int highest_version;
+ int this_version;
+ size_t file_name_length;
+
+ dirp = opendir (dir);
+ if (!dirp)
+ return 0;
+
+ highest_version = 0;
+ file_name_length = strlen (file);
+
+ while ((dp = readdir (dirp)) != 0)
+ {
+ if (!REAL_DIR_ENTRY (dp) || NLENGTH (dp) < file_name_length + 4)
+ continue;
+
+ this_version = version_number (file, dp->d_name, file_name_length);
+ if (this_version > highest_version)
+ highest_version = this_version;
+ }
+ 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.
+ */
+
+static int
+version_number (base, backup, base_length)
+ const char *base;
+ const char *backup;
+ size_t base_length;
+{
+ int version;
+ const char *p;
+
+ version = 0;
+ if (strncmp (base, backup, base_length) == 0
+ && backup[base_length] == '.'
+ && backup[base_length + 1] == '~')
+ {
+ for (p = &backup[base_length + 2]; ISDIGIT (*p); ++p)
+ version = version * 10 + *p - '0';
+ if (p[0] != '~' || p[1])
+ version = 0;
+ }
+ return version;
+}
+#endif /* HAVE_DIR */
+
+static const char * const backup_args[] =
+{
+ "never", "simple", "nil", "existing", "t", "numbered", 0
+};
+
+static const enum backup_type backup_types[] =
+{
+ simple, simple, numbered_existing, numbered_existing, numbered, numbered
+};
+
+/* Return the type of backup indicated by VERSION.
+ Unique abbreviations are accepted. */
+
+enum backup_type
+get_version (version)
+ const char *version;
+{
+ int i;
+
+ if (version == 0 || *version == 0)
+ return numbered_existing;
+ i = argmatch (version, backup_args);
+ if (i < 0)
+ {
+ invalid_arg ("version control type", version, i);
+ exit (2);
+ }
+ return backup_types[i];
+}
diff --git a/contrib/patch/backupfile.h b/contrib/patch/backupfile.h
new file mode 100644
index 000000000000..dad19843f597
--- /dev/null
+++ b/contrib/patch/backupfile.h
@@ -0,0 +1,50 @@
+/* backupfile.h -- declarations for making Emacs style backup file names
+ Copyright (C) 1990, 1991, 1992, 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. */
+
+/* When to make backup files. */
+enum backup_type
+{
+ /* Never make backups. */
+ none,
+
+ /* Make simple backups of every file. */
+ simple,
+
+ /* Make numbered backups of files that already have numbered backups,
+ and simple backups of the others. */
+ numbered_existing,
+
+ /* Make numbered backups of every file. */
+ numbered
+};
+
+extern enum backup_type backup_type;
+extern char const *simple_backup_suffix;
+
+#ifndef __BACKUPFILE_P
+# if defined __STDC__ || __GNUC__
+# define __BACKUPFILE_P(args) args
+# else
+# define __BACKUPFILE_P(args) ()
+# endif
+#endif
+
+char *base_name __BACKUPFILE_P ((char const *));
+char *find_backup_file_name __BACKUPFILE_P ((char const *));
+enum backup_type get_version __BACKUPFILE_P ((char const *));
+void addext __BACKUPFILE_P ((char *, char const *, int));
diff --git a/contrib/patch/basename.c b/contrib/patch/basename.c
new file mode 100644
index 000000000000..8d18a8fab3b5
--- /dev/null
+++ b/contrib/patch/basename.c
@@ -0,0 +1,32 @@
+/* basename.c -- return the last element in a path */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#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. */
+
+char *
+base_name (name)
+ char const *name;
+{
+ char const *base = name += FILESYSTEM_PREFIX_LEN (name);
+
+ for (; *name; name++)
+ if (ISSLASH (*name))
+ base = name + 1;
+
+ return (char *) base;
+}
diff --git a/contrib/patch/common.h b/contrib/patch/common.h
new file mode 100644
index 000000000000..b2895d474870
--- /dev/null
+++ b/contrib/patch/common.h
@@ -0,0 +1,307 @@
+/* common definitions for `patch' */
+
+/* $Id: common.h,v 1.18 1997/06/13 06:28:37 eggert Exp $ */
+
+/*
+Copyright 1986, 1988 Larry Wall
+Copyright 1990, 1991, 1992, 1993, 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.
+*/
+
+#ifndef DEBUGGING
+#define DEBUGGING 1
+#endif
+
+/* We must define `volatile' and `const' first (the latter inside config.h),
+ so that they're used consistently in all system includes. */
+#ifndef __STDC__
+# ifndef volatile
+# 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>
+#include <stdio.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <sys/stat.h>
+#if ! defined S_ISDIR && defined S_IFDIR
+# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+#if ! defined S_ISREG && defined S_IFREG
+# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH 1
+#endif
+#ifndef S_IWOTH
+#define S_IWOTH 2
+#endif
+#ifndef S_IROTH
+#define S_IROTH 4
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP (S_IXOTH << 3)
+#endif
+#ifndef S_IWGRP
+#define S_IWGRP (S_IWOTH << 3)
+#endif
+#ifndef S_IRGRP
+#define S_IRGRP (S_IROTH << 3)
+#endif
+#ifndef S_IXUSR
+#define S_IXUSR (S_IXOTH << 6)
+#endif
+#ifndef S_IWUSR
+#define S_IWUSR (S_IWOTH << 6)
+#endif
+#ifndef S_IRUSR
+#define S_IRUSR (S_IROTH << 6)
+#endif
+
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+#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
+ as an argument to <ctype.h> macros like `isspace'. */
+#if STDC_HEADERS
+#define CTYPE_DOMAIN(c) 1
+#else
+#define CTYPE_DOMAIN(c) ((unsigned) (c) <= 0177)
+#endif
+#ifndef ISSPACE
+#define ISSPACE(c) (CTYPE_DOMAIN (c) && isspace (c))
+#endif
+
+#ifndef ISDIGIT
+#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
+#endif
+
+
+#ifndef FILESYSTEM_PREFIX_LEN
+#define FILESYSTEM_PREFIX_LEN(f) 0
+#endif
+
+#ifndef ISSLASH
+#define ISSLASH(c) ((c) == '/')
+#endif
+
+
+/* constants */
+
+/* AIX predefines these. */
+#ifdef TRUE
+#undef TRUE
+#endif
+#ifdef FALSE
+#undef FALSE
+#endif
+#define TRUE 1
+#define FALSE 0
+
+/* handy definitions */
+
+#define strEQ(s1,s2) (!strcmp(s1, s2))
+#define strnEQ(s1,s2,l) (!strncmp(s1, s2, l))
+
+/* typedefs */
+
+typedef int bool; /* must promote to itself */
+typedef long LINENUM; /* must be signed */
+
+/* globals */
+
+extern char const program_name[];
+
+XTERN char *buf; /* general purpose buffer */
+XTERN size_t bufsize; /* allocated size of buf */
+
+XTERN bool using_plan_a; /* try to keep everything in memory */
+
+XTERN char *inname;
+XTERN char *outfile;
+XTERN int inerrno;
+XTERN int invc;
+XTERN struct stat instat;
+XTERN bool dry_run;
+XTERN bool posixly_correct;
+
+XTERN char const *origprae;
+XTERN char const *origbase;
+
+XTERN char const * volatile TMPOUTNAME;
+XTERN char const * volatile TMPINNAME;
+XTERN char const * volatile TMPPATNAME;
+
+#ifdef DEBUGGING
+XTERN int debug;
+#else
+# define debug 0
+#endif
+XTERN bool force;
+XTERN bool batch;
+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;
+XTERN int set_time;
+XTERN int set_utc;
+
+enum diff
+ {
+ NO_DIFF,
+ CONTEXT_DIFF,
+ NORMAL_DIFF,
+ ED_DIFF,
+ NEW_CONTEXT_DIFF,
+ UNI_DIFF
+ };
+
+XTERN enum diff diff_type;
+
+XTERN char *revision; /* prerequisite revision, if any */
+
+#ifdef __STDC__
+# define GENERIC_OBJECT void
+#else
+# define GENERIC_OBJECT char
+#endif
+
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 6) || __STRICT_ANSI__
+# define __attribute__(x)
+#endif
+
+#ifndef PARAMS
+# ifdef __STDC__
+# define PARAMS(args) args
+# else
+# define PARAMS(args) ()
+# endif
+#endif
+
+GENERIC_OBJECT *xmalloc PARAMS ((size_t));
+void fatal_exit PARAMS ((int)) __attribute__ ((noreturn));
+
+#include <errno.h>
+#if !STDC_HEADERS && !defined errno
+extern int errno;
+#endif
+
+#if STDC_HEADERS || HAVE_STRING_H
+# include <string.h>
+#else
+# if !HAVE_MEMCHR
+# define memcmp(s1, s2, n) bcmp (s1, s2, n)
+# define memcpy(d, s, n) bcopy (s, d, n)
+GENERIC_OBJECT *memchr ();
+# endif
+#endif
+
+#if STDC_HEADERS
+# include <stdlib.h>
+#else
+long atol ();
+char *getenv ();
+GENERIC_OBJECT *malloc ();
+GENERIC_OBJECT *realloc ();
+#endif
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifndef lseek
+off_t lseek ();
+#endif
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
+#endif
+#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>
+#endif
+#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
+
+#ifndef NULL_DEVICE
+#define NULL_DEVICE "/dev/null"
+#endif
+
+#ifndef TTY_DEVICE
+#define TTY_DEVICE "/dev/tty"
+#endif
diff --git a/contrib/patch/getopt.c b/contrib/patch/getopt.c
new file mode 100644
index 000000000000..300f86de3ebd
--- /dev/null
+++ b/contrib/patch/getopt.c
@@ -0,0 +1,1053 @@
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "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, 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. */
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+ Ditto for AIX 3.2 and <stdlib.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if !defined (__STDC__) || !__STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ 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. */
+
+#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__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+#include <stdlib.h>
+#include <unistd.h>
+#endif /* GNU C library. */
+
+#ifdef VMS
+#include <unixlib.h>
+#if HAVE_STRING_H - 0
+#include <string.h>
+#endif
+#endif
+
+#if defined (WIN32) && !defined (__CYGWIN32__)
+/* It's not Unix, really. See? Capital letters. */
+#include <windows.h>
+#define getpid() GetCurrentProcessId()
+#endif
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages.
+ When compiling libc, the _ macro is predefined. */
+#ifdef HAVE_LIBINTL_H
+# include <libintl.h>
+# define _(msgid) gettext (msgid)
+#else
+# define _(msgid) (msgid)
+#endif
+#endif
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ 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. */
+
+/* 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.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ 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 -1 with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable. */
+static char *posixly_correct;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+#include <string.h>
+#define my_index strchr
+#else
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+ const char *str;
+ int chr;
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+ If not using GCC, it is ok not to declare it. */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+ That was relevant to code that was here before. */
+#if !defined (__STDC__) || !__STDC__
+/* gcc with -traditional declares the built-in strlen to return int,
+ and has done so at least since version 2.4.5. -- rms. */
+extern int strlen (const char *);
+#endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+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. */
+
+/* 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.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+#if defined (__STDC__) && __STDC__
+static void exchange (char **);
+#endif
+
+static void
+exchange (argv)
+ char **argv;
+{
+ int bottom = first_nonopt;
+ int middle = last_nonopt;
+ int top = optind;
+ char *tem;
+
+ /* Exchange the shorter segment with the far end of the longer segment.
+ That puts the shorter segment into the right place.
+ 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)
+ {
+ /* Bottom segment is the short one. */
+ int len = middle - bottom;
+ register int i;
+
+ /* Swap it with the top part of the top segment. */
+ for (i = 0; i < len; i++)
+ {
+ 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;
+ }
+ else
+ {
+ /* Top segment is the short one. */
+ int len = top - middle;
+ register int i;
+
+ /* Swap it with the bottom part of the bottom segment. */
+ for (i = 0; i < len; i++)
+ {
+ 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;
+ }
+ }
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (optind - last_nonopt);
+ last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made. */
+
+#if defined (__STDC__) && __STDC__
+static const char *_getopt_initialize (int, char *const *, const char *);
+#endif
+static const char *
+_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;
+
+ nextchar = NULL;
+
+ posixly_correct = getenv ("POSIXLY_CORRECT");
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (posixly_correct != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+
+#ifdef _LIBC
+ if (posixly_correct == NULL
+ && argc == original_argc && argv == original_argv)
+ {
+ 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;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ 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 -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.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+ const struct option *longopts;
+ int *longind;
+ int long_only;
+{
+ optarg = NULL;
+
+ if (optind == 0 || !__getopt_initialized)
+ {
+ 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. 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 \
+ && __getopt_nonoption_flags[optind] == '1'))
+#else
+#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#endif
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ /* Advance to the next ARGV-element. */
+
+ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+ moved back by the user (who may also have changed the arguments). */
+ if (last_nonopt > optind)
+ last_nonopt = optind;
+ if (first_nonopt > optind)
+ first_nonopt = optind;
+
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc && NONOPTION_P)
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* The special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp (argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return -1;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if (NONOPTION_P)
+ {
+ if (ordering == REQUIRE_ORDER)
+ return -1;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Skip the initial punctuation. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ /* Decode the current option-ARGV-element. */
+
+ /* Check whether the ARGV-element is a long option.
+
+ If long_only and the ARGV-element has the form "-f", where f is
+ a valid short option, don't consider it an abbreviated form of
+ a long option that starts with f. Otherwise there would be no
+ way to give the -f short option.
+
+ On the other hand, if there's a long option "fubar" and
+ the ARGV-element is "-fu", do consider that an abbreviation of
+ the long option, just like "--fu", and not "-f" with arg "u".
+
+ This distinction seems to be the most useful approach. */
+
+ if (longopts != NULL
+ && (argv[optind][1] == '-'
+ || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = -1;
+ int option_index;
+
+ for (nameend = nextchar; *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)
+ == (unsigned int) 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 `%s' is ambiguous\n"),
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ optopt = 0;
+ return '?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ optind++;
+ 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)
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ _("%s: option `--%s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ _("%s: option `%c%s' doesn't allow an argument\n"),
+ argv[0], argv[optind - 1][0], pfound->name);
+
+ nextchar += strlen (nextchar);
+
+ optopt = pfound->val;
+ 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);
+ optopt = pfound->val;
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+ || my_index (optstring, *nextchar) == NULL)
+ {
+ if (opterr)
+ {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ optopt = 0;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next short option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (opterr)
+ {
+ if (posixly_correct)
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, _("%s: illegal option -- %c\n"),
+ argv[0], c);
+ else
+ fprintf (stderr, _("%s: invalid option -- %c\n"),
+ argv[0], c);
+ }
+ 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] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = NULL;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* 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 = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+getopt (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ return _getopt_internal (argc, argv, optstring,
+ (const struct option *) 0,
+ (int *) 0,
+ 0);
+}
+
+#endif /* Not ELIDE_CODE. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt (argc, argv, "abc:d:0123456789");
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/contrib/patch/getopt.h b/contrib/patch/getopt.h
new file mode 100644
index 000000000000..69256fd38647
--- /dev/null
+++ b/contrib/patch/getopt.h
@@ -0,0 +1,133 @@
+/* Declarations for getopt.
+ Copyright (C) 1989,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. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ 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. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+#if defined (__STDC__) && __STDC__
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#if defined (__STDC__) && __STDC__
+#ifdef __GNU_LIBRARY__
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/contrib/patch/getopt1.c b/contrib/patch/getopt1.c
new file mode 100644
index 000000000000..6507ba1b1f63
--- /dev/null
+++ b/contrib/patch/getopt1.c
@@ -0,0 +1,189 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+ 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>
+#endif
+
+#include "getopt.h"
+
+#if !defined (__STDC__) || !__STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ 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. */
+
+#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>
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+ If an option that starts with '-' (not '--') doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* Not ELIDE_CODE. */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] =
+ {
+ {"add", 1, 0, 0},
+ {"append", 0, 0, 0},
+ {"delete", 1, 0, 0},
+ {"verbose", 0, 0, 0},
+ {"create", 0, 0, 0},
+ {"file", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long (argc, argv, "abc:d:0123456789",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case 0:
+ printf ("option %s", long_options[option_index].name);
+ if (optarg)
+ printf (" with arg %s", optarg);
+ printf ("\n");
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case 'd':
+ printf ("option d with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/contrib/patch/inp.c b/contrib/patch/inp.c
new file mode 100644
index 000000000000..ebc2a0323d9e
--- /dev/null
+++ b/contrib/patch/inp.c
@@ -0,0 +1,442 @@
+/* inputting files to be patched */
+
+/* $Id: inp.c,v 1.16 1997/06/13 06:28:37 eggert Exp $ */
+
+/*
+Copyright 1986, 1988 Larry Wall
+Copyright 1991, 1992, 1993, 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.
+*/
+
+#define XTERN extern
+#include <common.h>
+#include <backupfile.h>
+#include <pch.h>
+#include <util.h>
+#undef XTERN
+#define XTERN
+#include <inp.h>
+
+/* Input-file-with-indexable-lines abstract type */
+
+static char const **i_ptr; /* pointers to lines in plan A buffer */
+
+static size_t tibufsize; /* size of plan b buffers */
+#ifndef TIBUFSIZE_MINIMUM
+#define TIBUFSIZE_MINIMUM (8 * 1024) /* minimum value for tibufsize */
+#endif
+static int tifd = -1; /* plan b virtual string array */
+static char *tibuf[2]; /* plan b buffers */
+static LINENUM tiline[2] = {-1, -1}; /* 1st line in each buffer */
+static LINENUM lines_per_buf; /* how many lines per buffer */
+static size_t tireclen; /* length of records in tmp file */
+static size_t last_line_size; /* size of last input line */
+
+static bool plan_a PARAMS ((char const *));/* yield FALSE if memory runs out */
+static void plan_b PARAMS ((char const *));
+static void report_revision PARAMS ((int));
+
+/* New patch--prepare to edit another file. */
+
+void
+re_input()
+{
+ if (using_plan_a) {
+ if (i_ptr) {
+ free (i_ptr);
+ i_ptr = 0;
+ }
+ }
+ else {
+ close (tifd);
+ tifd = -1;
+ free(tibuf[0]);
+ tibuf[0] = 0;
+ tiline[0] = tiline[1] = -1;
+ tireclen = 0;
+ }
+}
+
+/* Construct the line index, somehow or other. */
+
+void
+scan_input(filename)
+char *filename;
+{
+ using_plan_a = ! (debug & 16) && plan_a (filename);
+ if (!using_plan_a)
+ plan_b(filename);
+ switch (verbosity)
+ {
+ case SILENT:
+ break;
+
+ case VERBOSE:
+ say ("Patching file `%s' using Plan %s...\n",
+ filename, using_plan_a ? "A" : "B");
+ break;
+
+ case DEFAULT_VERBOSITY:
+ say ("patching file `%s'\n", filename);
+ break;
+ }
+}
+
+/* Report whether a desired revision was found. */
+
+static void
+report_revision (found_revision)
+ int found_revision;
+{
+ if (found_revision)
+ {
+ if (verbosity == VERBOSE)
+ say ("Good. This file appears to be the %s version.\n", revision);
+ }
+ else if (force)
+ {
+ if (verbosity != SILENT)
+ 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.",
+ revision);
+ }
+ else
+ {
+ ask ("This file doesn't appear to be the %s version -- patch anyway? [n] ",
+ revision);
+ if (*buf != 'y')
+ fatal ("aborted");
+ }
+}
+
+
+void
+get_input_file (filename, outname)
+ char const *filename;
+ char const *outname;
+{
+ int elsewhere = strcmp (filename, outname);
+ char const *cs;
+ char *diffbuf;
+ char *getbuf;
+
+ if (inerrno == -1)
+ inerrno = stat (inname, &instat) == 0 ? 0 : errno;
+
+ /* Perhaps look for RCS or SCCS versions. */
+ if (patch_get
+ && invc != 0
+ && (inerrno
+ || (! elsewhere
+ && (/* No one can write to it. */
+ (instat.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) == 0
+ /* Only the owner (who's not me) can write to it. */
+ || ((instat.st_mode & (S_IWGRP|S_IWOTH)) == 0
+ && instat.st_uid != geteuid ()))))
+ && (invc = !! (cs = (version_controller
+ (filename, elsewhere,
+ inerrno ? (struct stat *) 0 : &instat,
+ &getbuf, &diffbuf))))) {
+
+ if (!inerrno) {
+ if (!elsewhere
+ && (instat.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) != 0)
+ /* 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",
+ filename, cs);
+ if (systemic (diffbuf) != 0)
+ {
+ say ("warning: patching file `%s', which does not match default %s version\n",
+ filename, cs);
+ cs = 0;
+ }
+ }
+
+ if (cs && version_get (filename, cs, ! inerrno, elsewhere, getbuf,
+ &instat))
+ inerrno = 0;
+
+ free (getbuf);
+ free (diffbuf);
+
+ } else if (inerrno && !pch_says_nonexistent (reverse))
+ {
+ errno = inerrno;
+ pfatal ("can't find file `%s'", filename);
+ }
+
+ if (inerrno)
+ {
+ 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);
+}
+
+
+/* Try keeping everything in memory. */
+
+static bool
+plan_a(filename)
+ char const *filename;
+{
+ register char const *s;
+ register char const *lim;
+ register char const **ptr;
+ register char *buffer;
+ register LINENUM iline;
+ size_t size = instat.st_size;
+ size_t allocated_bytes_per_input_byte = sizeof *i_ptr + sizeof (char);
+ size_t allocated_bytes = (size + 2) * allocated_bytes_per_input_byte;
+
+ /* Fail if arithmetic overflow occurs during size calculations,
+ or if storage isn't available. */
+ if (size != instat.st_size
+ || size + 2 < 2
+ || allocated_bytes / allocated_bytes_per_input_byte != size + 2
+ || ! (ptr = (char const **) malloc (allocated_bytes)))
+ return FALSE;
+
+ buffer = (char *) (ptr + (size + 2));
+
+ /* Read the input file, but don't bother reading it if it's empty.
+ When creating files, the files do not actually exist. */
+ if (size)
+ {
+ int ifd = open (filename, O_RDONLY|binary_transput);
+ size_t buffered = 0, n;
+ if (ifd < 0)
+ pfatal ("can't open file `%s'", filename);
+ while (size - buffered != 0
+ && (n = read (ifd, buffer + buffered, size - buffered)) != 0)
+ {
+ 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 ();
+ }
+
+ /* Scan the buffer and build array of pointers to lines. */
+ iline = 0;
+ lim = buffer + size;
+ for (s = buffer; ; s++)
+ {
+ ptr[++iline] = s;
+ if (! (s = (char *) memchr (s, '\n', lim - s)))
+ break;
+ }
+ if (size && lim[-1] != '\n')
+ ptr[++iline] = lim;
+ input_lines = iline - 1;
+
+ if (revision)
+ {
+ char const *rev = revision;
+ int rev0 = rev[0];
+ int found_revision = 0;
+ size_t revlen = strlen (rev);
+
+ if (revlen <= size)
+ {
+ char const *limrev = lim - revlen;
+
+ for (s = buffer; (s = (char *) memchr (s, rev0, limrev - s)); s++)
+ if (memcmp (s, rev, revlen) == 0
+ && (s == buffer || ISSPACE ((unsigned char) s[-1]))
+ && (s + 1 == limrev || ISSPACE ((unsigned char) s[revlen])))
+ {
+ found_revision = 1;
+ break;
+ }
+ }
+
+ report_revision (found_revision);
+ }
+
+ /* Plan A will work. */
+ i_ptr = ptr;
+ return TRUE;
+}
+
+/* Keep (virtually) nothing in memory. */
+
+static void
+plan_b(filename)
+ char const *filename;
+{
+ register FILE *ifp;
+ register int c;
+ register size_t len;
+ register size_t maxlen;
+ register int found_revision;
+ register size_t i;
+ register char const *rev;
+ register size_t revlen;
+ register LINENUM line;
+
+ if (instat.st_size == 0)
+ filename = NULL_DEVICE;
+ if (! (ifp = fopen (filename, binary_transput ? "rb" : "r")))
+ pfatal ("can't open file `%s'", filename);
+ tifd = create_file (TMPINNAME, O_RDWR | O_BINARY, (mode_t) 0);
+ i = 0;
+ len = 0;
+ maxlen = 1;
+ rev = revision;
+ found_revision = !rev;
+ revlen = rev ? strlen (rev) : 0;
+
+ while ((c = getc (ifp)) != EOF)
+ {
+ len++;
+
+ if (c == '\n')
+ {
+ if (maxlen < len)
+ maxlen = len;
+ len = 0;
+ }
+
+ if (!found_revision)
+ {
+ if (i == revlen)
+ {
+ found_revision = ISSPACE ((unsigned char) c);
+ i = (size_t) -1;
+ }
+ else if (i != (size_t) -1)
+ i = rev[i]==c ? i + 1 : (size_t) -1;
+
+ if (i == (size_t) -1 && ISSPACE ((unsigned char) c))
+ i = 0;
+ }
+ }
+
+ if (revision)
+ report_revision (found_revision);
+ Fseek (ifp, (off_t) 0, SEEK_SET); /* rewind file */
+ for (tibufsize = TIBUFSIZE_MINIMUM; tibufsize < maxlen; tibufsize <<= 1)
+ continue;
+ lines_per_buf = tibufsize / maxlen;
+ tireclen = maxlen;
+ tibuf[0] = xmalloc (2 * tibufsize);
+ tibuf[1] = tibuf[0] + tibufsize;
+
+ for (line = 1; ; line++)
+ {
+ char *p = tibuf[0] + maxlen * (line % lines_per_buf);
+ char const *p0 = p;
+ if (! (line % lines_per_buf)) /* new block */
+ if (write (tifd, tibuf[0], tibufsize) != tibufsize)
+ write_fatal ();
+ if ((c = getc (ifp)) == EOF)
+ break;
+
+ for (;;)
+ {
+ *p++ = c;
+ if (c == '\n')
+ {
+ last_line_size = p - p0;
+ break;
+ }
+
+ if ((c = getc (ifp)) == EOF)
+ {
+ last_line_size = p - p0;
+ line++;
+ goto EOF_reached;
+ }
+ }
+ }
+ EOF_reached:
+ if (ferror (ifp) || fclose (ifp) != 0)
+ read_fatal ();
+
+ if (line % lines_per_buf != 0)
+ if (write (tifd, tibuf[0], tibufsize) != tibufsize)
+ write_fatal ();
+ input_lines = line - 1;
+}
+
+/* Fetch a line from the input file. */
+
+char const *
+ifetch (line, whichbuf, psize)
+register LINENUM line;
+int whichbuf; /* ignored when file in memory */
+size_t *psize;
+{
+ register char const *q;
+ register char const *p;
+
+ if (line < 1 || line > input_lines) {
+ *psize = 0;
+ return "";
+ }
+ if (using_plan_a) {
+ p = i_ptr[line];
+ *psize = i_ptr[line + 1] - p;
+ return p;
+ } else {
+ LINENUM offline = line % lines_per_buf;
+ LINENUM baseline = line - offline;
+
+ if (tiline[0] == baseline)
+ whichbuf = 0;
+ else if (tiline[1] == baseline)
+ whichbuf = 1;
+ else {
+ tiline[whichbuf] = baseline;
+ if (lseek (tifd, (off_t) (baseline/lines_per_buf * tibufsize),
+ SEEK_SET) == -1
+ || read (tifd, tibuf[whichbuf], tibufsize) < 0)
+ read_fatal ();
+ }
+ p = tibuf[whichbuf] + (tireclen*offline);
+ if (line == input_lines)
+ *psize = last_line_size;
+ else {
+ for (q = p; *q++ != '\n'; )
+ continue;
+ *psize = q - p;
+ }
+ return p;
+ }
+}
diff --git a/contrib/patch/inp.h b/contrib/patch/inp.h
new file mode 100644
index 000000000000..fd636bf75fdd
--- /dev/null
+++ b/contrib/patch/inp.h
@@ -0,0 +1,10 @@
+/* inputting files to be patched */
+
+/* $Id: inp.h,v 1.4 1997/04/07 01:07:00 eggert Exp $ */
+
+XTERN LINENUM input_lines; /* how long is input file in lines */
+
+char const *ifetch PARAMS ((LINENUM, int, size_t *));
+void get_input_file PARAMS ((char const *, char const *));
+void re_input PARAMS ((void));
+void scan_input PARAMS ((char *));
diff --git a/contrib/patch/maketime.c b/contrib/patch/maketime.c
new file mode 100644
index 000000000000..e66f9df0c375
--- /dev/null
+++ b/contrib/patch/maketime.c
@@ -0,0 +1,391 @@
+/* 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
+ /* MIPS RISCOS4.52 defines time_t in <sys/types.h> not <time.h>. */
+# include <sys/types.h>
+# if HAVE_LIMITS_H
+# include <limits.h>
+# endif
+# 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.15 1997/06/17 16:54:36 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;
+#ifdef TZ_is_unset
+ static char const *TZ;
+ if (!TZ && !(TZ = getenv ("TZ")))
+ TZ_is_unset ("The TZ environment variable is not set; please set it to your timezone");
+#endif
+ if (localzone || !(tm = gmtime (&unixtime)))
+ tm = localtime (&unixtime);
+ return tm;
+}
+
+/* Yield A - B, measured in seconds. */
+time_t
+difftm (a, b)
+ struct tm const *a;
+ struct tm const *b;
+{
+ int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
+ int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
+ 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/contrib/patch/maketime.h b/contrib/patch/maketime.h
new file mode 100644
index 000000000000..3948eda257f6
--- /dev/null
+++ b/contrib/patch/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/contrib/patch/memchr.c b/contrib/patch/memchr.c
new file mode 100644
index 000000000000..c75217fd9777
--- /dev/null
+++ b/contrib/patch/memchr.c
@@ -0,0 +1,199 @@
+/* Copyright (C) 1991, 1993, 1996 Free Software Foundation, Inc.
+ Based on strlen implementation by Torbjorn Granlund (tege@sics.se),
+ with help from Dan Sahlin (dan@sics.se) and
+ commentary by Jim Blandy (jimb@ai.mit.edu);
+ adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu),
+ and implemented by Roland McGrath (roland@ai.mit.edu).
+
+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>
+#endif
+
+#undef __ptr_t
+#if defined (__cplusplus) || (defined (__STDC__) && __STDC__)
+# define __ptr_t void *
+#else /* Not C++ or ANSI C. */
+# define __ptr_t char *
+#endif /* C++ or ANSI C. */
+
+#if defined (_LIBC)
+# include <string.h>
+#endif
+
+#if defined (HAVE_LIMITS_H) || defined (_LIBC)
+# include <limits.h>
+#endif
+
+#define LONG_MAX_32_BITS 2147483647
+
+#ifndef LONG_MAX
+#define LONG_MAX LONG_MAX_32_BITS
+#endif
+
+#include <sys/types.h>
+
+
+/* Search no more than N bytes of S for C. */
+
+__ptr_t
+memchr (s, c, n)
+ const __ptr_t s;
+ int c;
+ size_t n;
+{
+ const unsigned char *char_ptr;
+ const unsigned long int *longword_ptr;
+ unsigned long int longword, magic_bits, charmask;
+
+ c = (unsigned char) c;
+
+ /* Handle the first few characters by reading one character at a time.
+ Do this until CHAR_PTR is aligned on a longword boundary. */
+ for (char_ptr = (const unsigned char *) s;
+ n > 0 && ((unsigned long int) char_ptr
+ & (sizeof (longword) - 1)) != 0;
+ --n, ++char_ptr)
+ if (*char_ptr == c)
+ return (__ptr_t) char_ptr;
+
+ /* All these elucidatory comments refer to 4-byte longwords,
+ but the theory applies equally well to 8-byte longwords. */
+
+ longword_ptr = (unsigned long int *) char_ptr;
+
+ /* Bits 31, 24, 16, and 8 of this number are zero. Call these bits
+ the "holes." Note that there is a hole just to the left of
+ each byte, with an extra at the end:
+
+ bits: 01111110 11111110 11111110 11111111
+ bytes: AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD
+
+ The 1-bits make sure that carries propagate to the next 0-bit.
+ The 0-bits provide holes for carries to fall into. */
+
+ if (sizeof (longword) != 4 && sizeof (longword) != 8)
+ abort ();
+
+#if LONG_MAX <= LONG_MAX_32_BITS
+ magic_bits = 0x7efefeff;
+#else
+ magic_bits = ((unsigned long int) 0x7efefefe << 32) | 0xfefefeff;
+#endif
+
+ /* Set up a longword, each of whose bytes is C. */
+ charmask = c | (c << 8);
+ charmask |= charmask << 16;
+#if LONG_MAX > LONG_MAX_32_BITS
+ charmask |= charmask << 32;
+#endif
+
+ /* Instead of the traditional loop which tests each character,
+ we will test a longword at a time. The tricky part is testing
+ if *any of the four* bytes in the longword in question are zero. */
+ while (n >= sizeof (longword))
+ {
+ /* We tentatively exit the loop if adding MAGIC_BITS to
+ LONGWORD fails to change any of the hole bits of LONGWORD.
+
+ 1) Is this safe? Will it catch all the zero bytes?
+ Suppose there is a byte with all zeros. Any carry bits
+ propagating from its left will fall into the hole at its
+ least significant bit and stop. Since there will be no
+ carry from its most significant bit, the LSB of the
+ byte to the left will be unchanged, and the zero will be
+ detected.
+
+ 2) Is this worthwhile? Will it ignore everything except
+ zero bytes? Suppose every byte of LONGWORD has a bit set
+ somewhere. There will be a carry into bit 8. If bit 8
+ is set, this will carry into bit 16. If bit 8 is clear,
+ one of bits 9-15 must be set, so there will be a carry
+ into bit 16. Similarly, there will be a carry into bit
+ 24. If one of bits 24-30 is set, there will be a carry
+ into bit 31, so all of the hole bits will be changed.
+
+ The one misfire occurs when bits 24-30 are clear and bit
+ 31 is set; in this case, the hole at bit 31 is not
+ changed. If we had access to the processor carry flag,
+ we could close this loophole by putting the fourth hole
+ at bit 32!
+
+ So it ignores everything except 128's, when they're aligned
+ properly.
+
+ 3) But wait! Aren't we looking for C, not zero?
+ Good point. So what we do is XOR LONGWORD with a longword,
+ each of whose bytes is C. This turns each byte that is C
+ into a zero. */
+
+ longword = *longword_ptr++ ^ charmask;
+
+ /* Add MAGIC_BITS to LONGWORD. */
+ if ((((longword + magic_bits)
+
+ /* Set those bits that were unchanged by the addition. */
+ ^ ~longword)
+
+ /* Look at only the hole bits. If any of the hole bits
+ are unchanged, most likely one of the bytes was a
+ zero. */
+ & ~magic_bits) != 0)
+ {
+ /* Which of the bytes was C? If none of them were, it was
+ a misfire; continue the search. */
+
+ const unsigned char *cp = (const unsigned char *) (longword_ptr - 1);
+
+ if (cp[0] == c)
+ return (__ptr_t) cp;
+ if (cp[1] == c)
+ return (__ptr_t) &cp[1];
+ if (cp[2] == c)
+ return (__ptr_t) &cp[2];
+ if (cp[3] == c)
+ return (__ptr_t) &cp[3];
+#if LONG_MAX > 2147483647
+ if (cp[4] == c)
+ return (__ptr_t) &cp[4];
+ if (cp[5] == c)
+ return (__ptr_t) &cp[5];
+ if (cp[6] == c)
+ return (__ptr_t) &cp[6];
+ if (cp[7] == c)
+ return (__ptr_t) &cp[7];
+#endif
+ }
+
+ n -= sizeof (longword);
+ }
+
+ char_ptr = (const unsigned char *) longword_ptr;
+
+ while (n-- > 0)
+ {
+ if (*char_ptr == c)
+ return (__ptr_t) char_ptr;
+ else
+ ++char_ptr;
+ }
+
+ return 0;
+}
diff --git a/contrib/patch/partime.c b/contrib/patch/partime.c
new file mode 100644
index 000000000000..ce8710989b30
--- /dev/null
+++ b/contrib/patch/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/contrib/patch/partime.h b/contrib/patch/partime.h
new file mode 100644
index 000000000000..bcc8165c2634
--- /dev/null
+++ b/contrib/patch/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/contrib/patch/patch.1 b/contrib/patch/patch.1
new file mode 100644
index 000000000000..13fa1b95680d
--- /dev/null
+++ b/contrib/patch/patch.1
@@ -0,0 +1,1063 @@
+.\" patch man page
+.de Id
+.ds Dt \\$4
+..
+.Id $Id: patch.man,v 1.20 1997/06/17 22:32:49 eggert Exp $
+.ds = \-\^\-
+.de Sp
+.if t .sp .3
+.if n .sp
+..
+.TH PATCH 1 \*(Dt GNU
+.ta 3n
+.SH NAME
+patch \- apply a diff file to an original
+.SH SYNOPSIS
+.B patch
+.RI [ options ]
+.RI [ originalfile
+.RI [ patchfile ]]
+.Sp
+but usually just
+.Sp
+.BI "patch \-p" "num"
+.BI < patchfile
+.SH DESCRIPTION
+.B patch
+takes a patch file
+.I patchfile
+containing a difference listing produced by the
+.B diff
+program and applies those differences to one or more original files,
+producing patched versions.
+Normally the patched versions are put in place of the originals.
+Backups can be made; see the
+.B \-V
+or
+.B \*=version\-control
+option.
+The names of the files to be patched are usually taken from the patch file,
+but if there's just one file to be patched it can specified on the
+command line as
+.IR originalfile .
+.PP
+Upon startup, patch attempts to determine the type of the diff listing,
+unless overruled by a
+\fB\-c\fP (\fB\*=context\fP),
+\fB\-e\fP (\fB\*=ed\fP),
+\fB\-n\fP (\fB\*=normal\fP),
+or
+\fB\-u\fP (\fB\*=unified\fP)
+option.
+Context diffs (old-style, new-style, and unified) and
+normal diffs are applied by the
+.B patch
+program itself, while
+.B ed
+diffs are simply fed to the
+.BR ed (1)
+editor via a pipe.
+.PP
+.B patch
+tries to skip any leading garbage, apply the diff,
+and then skip any trailing garbage.
+Thus you could feed an article or message containing a
+diff listing to
+.BR patch ,
+and it should work.
+If the entire diff is indented by a consistent amount,
+this is taken into account.
+.PP
+With context diffs, and to a lesser extent with normal diffs,
+.B patch
+can detect when the line numbers mentioned in the patch are incorrect,
+and attempts to find the correct place to apply each hunk of the patch.
+As a first guess, it takes the line number mentioned for the hunk, plus or
+minus any offset used in applying the previous hunk.
+If that is not the correct place,
+.B patch
+scans both forwards and backwards for a set of lines matching the context
+given in the hunk.
+First
+.B patch
+looks for a place where all lines of the context match.
+If no such place is found, and it's a context diff, and the maximum fuzz factor
+is set to 1 or more, then another scan takes place ignoring the first and last
+line of context.
+If that fails, and the maximum fuzz factor is set to 2 or more,
+the first two and last two lines of context are ignored,
+and another scan is made.
+(The default maximum fuzz factor is 2.)
+If
+.B patch
+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
+.B #
+if
+.B \&.rej
+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.)
+The line numbers on the hunks in the reject file may be different than
+in the patch file: they reflect the approximate location patch thinks the
+failed hunks belong in the new file rather than the old one.
+.PP
+As each hunk is completed, you are told if the hunk
+failed, and if so which line (in the new file)
+.B patch
+thought the hunk should go on.
+If the hunk is installed at a different line
+from the line number specified in the diff you
+are told the offset.
+A single large offset
+.I may
+indicate that a hunk was installed in the
+wrong place.
+You are also told if a fuzz factor was used to make the match, in which
+case you should also be slightly suspicious.
+If the
+.B \*=verbose
+option is given, you are also told about hunks that match exactly.
+.PP
+If no original file
+.I origfile
+is specified on the command line,
+.B patch
+tries to figure out from the leading garbage what the name of the file
+to edit is, using the following rules.
+.TP 3
+.B " \(bu"
+If the header is that of a context diff,
+.B patch
+takes the old and new file names in the header.
+Any
+.B /dev/null
+names are ignored.
+.TP
+.B " \(bu"
+If there is an
+.B Index:\&
+line in the leading garbage
+and if either the old and new names are both absent or the
+.B POSIXLY_CORRECT
+environment variable is set,
+.B patch
+takes the name in the
+.B Index:\&
+line.
+.TP
+.B " \(bu"
+For the purpose of the following rules,
+the names are considered to be in the order (old, new, index),
+regardless of the order that they appear in the header.
+.TP
+.B " \(bu"
+If some of the named files exist,
+.B patch
+uses the first name if the
+.B POSIXLY_CORRECT
+environment variable is set, and the best name otherwise.
+.TP
+.B " \(bu"
+If
+.B patch
+is not ignoring \s-1RCS\s0 and \s-1SCCS\s0 (see the
+.BI "\-g " num
+or
+.BI \*=get= num
+option), and no named files exist
+but an \s-1RCS\s0 or \s-1SCCS\s0 master is found,
+.B patch
+uses the first named file with an \s-1RCS\s0 or \s-1SCCS\s0 master.
+.TP
+.B " \(bu"
+If no named files exist, no \s-1RCS\s0 or \s-1SCCS\s0 master was found,
+some names are given,
+.B POSIXLY_CORRECT
+is not set, and the patch appears to create a file,
+.B patch
+uses the best name requiring the creation of the fewest directories.
+.TP
+.B " \(bu"
+If no file name results from the above heuristics, you are asked
+for the name of the file to patch.
+.LP
+To determine the
+.I best
+of a nonempty list of file names,
+.B patch
+first takes all the names with the fewest path name components;
+of those, it then takes all the names with the shortest basename;
+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:\&
+line,
+.B patch
+takes the first word from the prerequisites line (normally a version
+number) and checks the original file to see if that word can be found.
+If not,
+.B patch
+asks for confirmation before proceeding.
+.PP
+The upshot of all this is that you should be able to say, while in a news
+interface, something like the following:
+.Sp
+ \fB| patch \-d /usr/src/local/blurfl\fP
+.Sp
+and patch a file in the
+.B blurfl
+directory directly from the article containing
+the patch.
+.PP
+If the patch file contains more than one patch,
+.B patch
+tries to apply each of them as if they came from separate patch files.
+This means, among other things, that it is assumed that the name of the file
+to patch must be determined for each diff listing,
+and that the garbage before each diff listing
+contains interesting things such as file names and revision level, as
+mentioned previously.
+.SH OPTIONS
+.TP 3
+\fB\-b\fP or \fB\*=backup\fP
+Make backup files.
+That is, when patching a file,
+rename or copy the original instead of removing it.
+When backing up a file that does not exist,
+an empty, unreadable backup file is created
+as a placeholder to represent the nonexistent file.
+.Sp
+This option is equivalent to
+.BR \*=version\-control=simple ;
+see the
+.B \-V
+or
+.B \*=version\-control
+option.
+.TP
+.B \*=backup\-if\-mismatch
+Back up a file if the patch does not match the file exactly
+and if backups are not otherwise requested.
+The backup file name is calculated as usual,
+except that if the version control method is
+.BR none ,
+a simple backup name is used.
+This is the default unless the
+.B POSIXLY_CORRECT
+environment variable is set.
+.TP
+.B \*=no\-backup\-if\-mismatch
+Do not back up a file if the patch does not match the file exactly
+and if backups are not otherwise requested.
+This is the default if the
+.B POSIXLY_CORRECT
+environment variable is set.
+.TP
+\fB\-B\fP \fIpref\fP or \fB\*=prefix=\fP\fIpref\fP
+Prefix simple backup file names with
+.IR pref .
+For example, with
+.B "\-B /junk/"
+the simple backup file name for
+.B src/patch/util.c
+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
+\fB\-d\fP \fIdir\fP or \fB\*=directory=\fP\fIdir\fP
+Change to the directory
+.I dir
+immediately, before doing
+anything else.
+.TP
+\fB\-D\fP \fIdefine\fP or \fB\*=ifdef=\fP\fIdefine\fP
+Use the
+.BR #ifdef " .\|.\|. " #endif
+construct to mark changes, with
+.I define
+as the differentiating symbol.
+.TP
+.B "\*=dry\-run"
+Print the results of applying the patches without actually changing any files.
+.TP
+\fB\-e\fP or \fB\*=ed\fP
+Interpret the patch file as an
+.B ed
+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 time stamps on the header to determine whether a file
+should exist after patching.
+However, if the input is not a context diff or if the
+.B POSIXLY_CORRECT
+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:\&
+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
+.B \-s
+for that.
+.TP
+\fB\-F\fP \fInum\fP or \fB\*=fuzz=\fP\fInum\fP
+Set the maximum fuzz factor.
+This option only applies to diffs that have context, and causes
+.B patch
+to ignore up to that many lines in looking for places to install a hunk.
+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 \fInum\fP or \fB\*=get=\fP\fInum\fP
+This option controls
+.BR patch 's
+actions when a file is under \s-1RCS\s0 or \s-1SCCS\s0 control,
+and does not exist or is read-only and matches the default version.
+If
+.I num
+is positive,
+.B patch
+gets (or checks out) the file from the revision control system; if zero,
+.B patch
+ignores \s-1RCS\s0 and \s-1SCCS\s0 and does not get the file; and if negative,
+.B patch
+asks the user whether to get the file.
+The default value of this option is given by the value of the
+.B PATCH_GET
+environment variable if it is set; if not, the default value is zero if
+.B POSIXLY_CORRECT
+is set, negative otherwise.
+.TP
+.B "\*=help"
+Print a summary of options and exit.
+.TP
+\fB\-i\fP \fIpatchfile\fP or \fB\*=input=\fP\fIpatchfile\fP
+Read the patch from
+.IR patchfile .
+If
+.I patchfile
+is
+.BR \- ,
+read from standard input, the default.
+.TP
+\fB\-l\fP or \fB\*=ignore\-whitespace\fP
+Match patterns loosely, in case tabs or spaces
+have been munged in your files.
+Any sequence of one or more blanks in the patch file matches any sequence
+in the original file, and sequences of blanks at the ends of lines are ignored.
+Normal characters must still match exactly.
+Each line of the context must still match a line in the original file.
+.TP
+\fB\-n\fP or \fB\*=normal\fP
+Interpret the patch file as a normal diff.
+.TP
+\fB\-N\fP or \fB\*=forward\fP
+Ignore patches that seem to be reversed or already applied.
+See also
+.BR \-R .
+.TP
+\fB\-o\fP \fIoutfile\fP or \fB\*=output=\fP\fIoutfile\fP
+Send output to
+.I outfile
+instead of patching files in place.
+.TP
+\fB\-p\fP\fInum\fP or \fB\*=strip\fP\fB=\fP\fInum\fP
+Strip the smallest prefix containing
+.I num
+leading slashes from each file name found in the patch file.
+A sequence of one or more adjacent slashes is counted as a single slash.
+This controls how file names found in the patch file are treated, in case
+you keep your files in a different directory than the person who sent
+out the patch.
+For example, supposing the file name in the patch file was
+.Sp
+ \fB/u/howard/src/blurfl/blurfl.c\fP
+.Sp
+setting
+.B \-p0
+gives the entire file name unmodified,
+.B \-p1
+gives
+.Sp
+ \fBu/howard/src/blurfl/blurfl.c\fP
+.Sp
+without the leading slash,
+.B \-p4
+gives
+.Sp
+ \fBblurfl/blurfl.c\fP
+.Sp
+and not specifying
+.B \-p
+at all just gives you \fBblurfl.c\fP.
+Whatever you end up with is looked for either in the current directory,
+or the directory specified by the
+.B \-d
+option.
+.TP
+\fB\-r\fP \fIrejectfile\fP or \fB\*=reject\-file=\fP\fIrejectfile\fP
+Put rejects into
+.I rejectfile
+instead of the default
+.B \&.rej
+file.
+.TP
+\fB\-R\fP or \fB\*=reverse\fP
+Assume that this patch was created with the old and new files swapped.
+(Yes, I'm afraid that does happen occasionally, human nature being what it
+is.)
+.B patch
+attempts to swap each hunk around before applying it.
+Rejects come out in the swapped format.
+The
+.B \-R
+option does not work with
+.B ed
+diff scripts because there is too little
+information to reconstruct the reverse operation.
+.Sp
+If the first hunk of a patch fails,
+.B patch
+reverses the hunk to see if it can be applied that way.
+If it can, you are asked if you want to have the
+.B \-R
+option set.
+If it can't, the patch continues to be applied normally.
+(Note: this method cannot detect a reversed patch if it is a normal diff
+and if the first command is an append (i.e. it should have been a delete)
+since appends always succeed, due to the fact that a null context matches
+anywhere.
+Luckily, most patches add or change lines rather than delete them, so most
+reversed normal diffs begin with a delete, which fails, triggering
+the heuristic.)
+.TP
+\fB\-s\fP or \fB\*=silent\fP or \fB\*=quiet\fP
+Work silently, unless an error occurs.
+.TP
+\fB\-t\fP or \fB\*=batch\fP
+Suppress questions like
+.BR \-f ,
+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:\&
+line
+in the patch; and assume that patches are reversed if they look like
+they are.
+.TP
+\fB\-T\fP or \fB\*=set\-time\fP
+Set the modification and access times of patched files from time stamps
+given in context diff headers, assuming that the context diff headers
+use local time. This option is not recommended, because patches using
+local time cannot easily be used by people in other time zones, and
+because local time stamps are ambiguous when local clocks move backwards
+during daylight-saving time adjustments. Instead of using this option,
+generate patches with \s-1UTC\s0 and use the
+.B \-Z
+or
+.B \*=set\-utc
+option instead.
+.TP
+\fB\-u\fP or \fB\*=unified\fP
+Interpret the patch file as a unified context diff.
+.TP
+\fB\-v\fP or \fB\*=version\fP
+Print out
+.BR patch 's
+revision header and patch level, and exit.
+.TP
+\fB\-V\fP \fImethod\fP or \fB\*=version\-control=\fP\fImethod\fP
+Use
+.I method
+to determine
+backup file names. The method can also be given by the
+.B PATCH_VERSION_CONTROL
+(or, if that's not set, the
+.BR VERSION_CONTROL )
+environment variable, which is overridden by this option.
+.Sp
+The value of
+.I method
+is like the \s-1GNU\s0
+Emacs `version-control' variable;
+.B patch
+also recognizes synonyms that
+are more descriptive. The valid values for
+.I method
+are (unique abbreviations are
+accepted):
+.RS
+.TP 3
+\fBexisting\fP or \fBnil\fP
+Make numbered backups of files that already have them,
+otherwise simple backups.
+.TP
+\fBnone\fP
+Do not make backups, unless backup-if-mismatch is in effect
+and patches do not match files.
+This is the default.
+.TP
+\fBnumbered\fP or \fBt\fP
+Make numbered backups. The numbered backup file name for
+.I F
+is
+.IB F .~ N ~
+where
+.I N
+is the version number.
+.TP
+\fBsimple\fP or \fBnever\fP
+Make simple backups.
+The
+.B \-B
+or
+.BR \*=prefix ,
+.B \-y
+or
+.BR \*=basename\-prefix ,
+and
+.B \-z
+or
+.BR \*=suffix
+options specify the simple backup file name.
+If none of these options are given, then a simple backup suffix is used;
+it is the value of the
+.B SIMPLE_BACKUP_SUFFIX
+environment variable if set, and is
+.B \&.orig
+otherwise.
+.PP
+With numbered or simple backups,
+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\*=verbose\fP
+Output extra information about the work being done.
+.TP
+\fB\-x\fP \fInum\fP or \fB\*=debug=\fP\fInum\fP
+Set internal debugging flags of interest only to
+.B patch
+patchers.
+.TP
+\fB\-y\fP \fIpref\fP or \fB\*=basename\-prefix=\fP\fIpref\fP
+Prefix the basename of the simple backup file name with
+.IR pref .
+For example, with
+.B "\-y .del/"
+the backup file name for
+.B src/patch/util.c
+is
+.BR src/patch/.del/util.c .
+.TP
+\fB\-z\fP \fIsuffix\fP or \fB\*=suffix=\fP\fIsuffix\fP
+Use
+.I suffix
+as the simple backup suffix.
+The backup extension may also be specified by the
+.B SIMPLE_BACKUP_SUFFIX
+environment variable, which is overridden by this option.
+.TP
+\fB\-Z\fP or \fB\*=set\-utc\fP
+Set the modification and access times of patched files from time stamps
+given in context diff headers, assuming that the context diff headers
+use Coordinated Universal Time (\s-1UTC\s0, often known as \s-1GMT\s0).
+Also see the
+.B \-T
+or
+.B \*=set\-time
+option.
+.Sp
+The
+.B \-Z
+or
+.B \*=set\-utc
+and
+.B \-T
+or
+.B \*=set\-time
+options normally refrain from setting a file's time if the file's original time
+does not match the time given in the patch header, or if its
+contents do not match the patch exactly. However, if the
+.B \-f
+or
+.B \*=force
+option is given, the file time is set regardless.
+.Sp
+Due to the limitations of
+.B diff
+output format, these options cannot update the times of files whose
+contents have not changed. Also, if you use these options, you should remove
+(e.g. with
+.BR "make\ clean" )
+all files that depend on the patched files, so that later invocations of
+.B make
+do not get confused by the patched files' times.
+.SH ENVIRONMENT
+.TP 3
+\fBPATCH_GET\fP
+This specifies whether
+.B patch
+gets missing or read-only files from \s-1RCS\s0 or \s-1SCCS\s0
+by default; see the
+.B \-g
+or
+.B \*=get
+option.
+.TP
+.B POSIXLY_CORRECT
+If set,
+.B patch
+conforms more strictly to the \s-1POSIX\s0 standard:
+it takes the first existing file from the list (old, new, index)
+when intuiting file names from diff headers,
+it does not remove files that are empty after patching,
+it does not ask whether to get files from \s-1RCS\s0 or \s-1SCCS\s0,
+it requires that all options precede the
+files in the command line,
+and by default it does not make backup files.
+.TP
+.B SIMPLE_BACKUP_SUFFIX
+Extension to use for simple backup file names instead of
+.BR \&.orig .
+.TP
+\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
+\fBVERSION_CONTROL\fP or \fBPATCH_VERSION_CONTROL\fP
+Selects version control style; see the
+.B \-v
+or
+.B \*=version\-control
+option.
+.SH FILES
+.TP 3
+.IB $TMPDIR "/p\(**"
+temporary files
+.TP
+.B /dev/tty
+controlling terminal; used to get answers to questions asked of the user
+.SH "SEE ALSO"
+.BR diff (1),
+.BR ed (1)
+.SH "NOTES FOR PATCH SENDERS"
+There are several things you should bear in mind if you are going to
+be sending out patches.
+.PP
+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.
+The
+.B diff
+command's headers should have dates
+and times in Universal Time using traditional Unix format,
+so that patch recipients can use the
+.B \-Z
+or
+.B \*=set\-utc
+option.
+Here is an example command, using Bourne shell syntax:
+.Sp
+ \fBLC_ALL=C TZ=UTC0 diff \-Naur gcc\-2.7 gcc\-2.8\fP
+.PP
+Tell your recipients how to apply the patch
+by telling them which directory to
+.B cd
+to, and which
+.B patch
+options to use. The option string
+.B "\-Np1"
+is recommended.
+Test your procedure by pretending to be a recipient and applying
+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:\&
+line in with the patch, it won't let them apply
+patches out of order without some warning.
+.PP
+You can create a file by sending out a diff that compares
+.B /dev/null
+or an empty file dated the Epoch (1970-01-01 00:00:00 \s-1UTC\s0)
+to the file you want to create.
+This only works if the file you want to create doesn't exist already in
+the target directory.
+Conversely, you can remove a file by sending out a context diff that compares
+the file to be deleted with an empty file dated the Epoch.
+The file will be removed unless the
+.B POSIXLY_CORRECT
+environment variable is set and the
+.B \-E
+or
+.B \*=remove\-empty\-files
+option is not given.
+An easy way to generate patches that create and remove files
+is to use \s-1GNU\s0
+.BR diff 's
+.B \-N
+or
+.B \*=new\-file
+option.
+.PP
+If the recipient is supposed to use the
+.BI \-p N
+option, do not send output that looks like this:
+.Sp
+.ft B
+.ne 3
+ diff \-Naur v2.0.29/prog/README prog/README
+.br
+ \-\^\-\^\- v2.0.29/prog/README Mon Mar 10 15:13:12 1997
+.br
+ +\^+\^+ prog/README Mon Mar 17 14:58:22 1997
+.ft
+.Sp
+because the two file names have different numbers of slashes,
+and different versions of
+.B patch
+interpret the file names differently.
+To avoid confusion, send output that looks like this instead:
+.Sp
+.ft B
+.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
+.br
+ +\^+\^+ 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,
+generate the diffs using \s-1UTC\s0,
+have the recipients apply the patch with the
+.B \-Z
+or
+.B \*=set\-utc
+option, and have them remove any unpatched files that depend on patched files
+(e.g. with
+.BR "make\ clean" ).
+.PP
+While you may be able to get away with putting 582 diff listings into
+one file, it may be wiser to group related patches into separate files in
+case something goes haywire.
+.SH DIAGNOSTICS
+Diagnostics generally indicate that
+.B patch
+couldn't parse your patch file.
+.PP
+If the
+.B \*=verbose
+option is given, the message
+.B Hmm.\|.\|.\&
+indicates that there is unprocessed text in
+the patch file and that
+.B patch
+is attempting to intuit whether there is a patch in that text and, if so,
+what kind of patch it is.
+.PP
+.BR patch 's
+exit status is
+0 if all hunks are applied successfully,
+1 if some hunks cannot be applied,
+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
+script, and can detect
+bad line numbers in a normal diff only when it finds a change or deletion.
+A context diff using fuzz factor 3 may have the same problem.
+Until a suitable interactive interface is added, you should probably do
+a context diff in these cases to see if the changes made sense.
+Of course, compiling without errors is a pretty good indication that the patch
+worked, but not always.
+.PP
+.B patch
+usually produces the correct results, even when it has to do a lot of
+guessing.
+However, the results are guaranteed to be correct only when the patch is
+applied to exactly the same version of the file that the patch was
+generated from.
+.SH "COMPATIBILITY ISSUES"
+The \s-1POSIX\s0 standard specifies behavior that differs from
+.BR patch 's
+traditional behavior.
+You should be aware of these differences if you must interoperate with
+.B patch
+versions 2.1 and earlier, which are not \s-1POSIX\s0-compliant.
+.TP 3
+.B " \(bu"
+In traditional
+.BR patch ,
+the
+.B \-p
+option's operand was optional, and a bare
+.B \-p
+was equivalent to
+.BR \-p0.
+The
+.B \-p
+option now requires an operand, and
+.B "\-p\ 0"
+is now equivalent to
+.BR \-p0 .
+For maximum compatibility, use options like
+.B \-p0
+and
+.BR \-p1 .
+.Sp
+Also,
+traditional
+.B patch
+simply counted slashes when stripping path prefixes;
+.B patch
+now counts pathname components.
+That is, a sequence of one or more adjacent slashes
+now counts as a single slash.
+For maximum portability, avoid sending patches containing
+.B //
+in file names.
+.TP
+.B " \(bu"
+In traditional
+.BR patch ,
+simple backups were enabled by default.
+This behavior is now enabled with the
+.B \-b
+or
+.B \*=backup
+option, or by setting the
+.B VERSION_CONTROL
+environment variable to
+.BR simple .
+.Sp
+Conversely, in \s-1POSIX\s0
+.BR patch ,
+backups are never made, even when there is a mismatch.
+In \s-1GNU\s0
+.BR patch ,
+this behavior is enabled with the
+.B \*=no\-backup\-if\-mismatch
+option or by setting the
+.B POSIXLY_CORRECT
+environment variable.
+.Sp
+The
+.BI \-b " suffix"
+option
+of traditional
+.B patch
+is equivalent to the
+.BI "\-b \-z" " suffix"
+options of \s-1GNU\s0
+.BR patch .
+.TP
+.B " \(bu"
+Traditional
+.B patch
+used a complicated (and incompletely documented) method
+to intuit the name of the file to be patched from the patch header.
+This method was not \s-1POSIX\s0-compliant, and had a few gotchas.
+Now
+.B patch
+uses a different, equally complicated (but better documented) method
+that is optionally \s-1POSIX\s0-compliant; we hope it has
+fewer gotchas. The two methods are compatible if the
+file names in the context diff header and the
+.B Index:\&
+line are all identical after prefix-stripping.
+Your patch is normally compatible if each header's file names
+all contain the same number of slashes.
+.TP
+.B " \(bu"
+When traditional
+.B patch
+asked the user a question, it sent the question to standard error
+and looked for an answer from
+the first file in the following list that was a terminal:
+standard error, standard output,
+.BR /dev/tty ,
+and standard input.
+Now
+.B patch
+sends questions to standard output and gets answers from
+.BR /dev/tty .
+Defaults for some answers have been changed so that
+.B patch
+never goes into an infinite loop when using default answers.
+.TP
+.B " \(bu"
+Traditional
+.B patch
+exited with a status value that counted the number of bad hunks,
+or with status 1 if there was real trouble.
+Now
+.B patch
+exits with status 1 if some hunks failed,
+or with 2 if there was real trouble.
+.TP
+.B " \(bu"
+Limit yourself to the following options when sending instructions
+meant to be executed by anyone running \s-1GNU\s0
+.BR patch ,
+traditional
+.BR patch ,
+or a \s-1POSIX\s0-compliant
+.BR patch .
+Spaces are significant in the following list, and operands are required.
+.Sp
+.nf
+.in +3
+.ne 11
+.B \-c
+.BI \-d " dir"
+.BI \-D " define"
+.B \-e
+.B \-l
+.B \-n
+.B \-N
+.BI \-o " outfile"
+.BI \-p num
+.B \-R
+.BI \-r " rejectfile"
+.in
+.fi
+.SH BUGS
+.B patch
+could be smarter about partial matches, excessively deviant offsets and
+swapped code, but that would take an extra pass.
+.PP
+If code has been duplicated (for instance with
+\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.
+.PP
+If you apply a patch you've already applied,
+.B patch
+thinks it is a reversed patch, and offers to un-apply the patch.
+This could be construed as a feature.
+.SH COPYING
+Copyright
+.if t \(co
+1984, 1985, 1986, 1988 Larry Wall.
+.br
+Copyright
+.if t \(co
+1997 Free Software Foundation, Inc.
+.PP
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+.PP
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+.PP
+Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be included in
+translations approved by the copyright holders instead of in
+the original English.
+.SH AUTHORS
+Larry Wall wrote the original version of
+.BR patch .
+Paul Eggert removed
+.BR patch 's
+arbitrary limits; added support for binary files,
+setting file times, and deleting files;
+and made it conform better to \s-1POSIX\s0.
+Other contributors include Wayne Davison, who added unidiff support,
+and David MacKenzie, who added configuration and backup support.
diff --git a/contrib/patch/patch.c b/contrib/patch/patch.c
new file mode 100644
index 000000000000..e976204e85b2
--- /dev/null
+++ b/contrib/patch/patch.c
@@ -0,0 +1,1293 @@
+/* patch - a program to apply diffs to original files */
+
+/* $Id: patch.c,v 1.22 1997/06/17 22:32:49 eggert Exp $ */
+
+/*
+Copyright 1984, 1985, 1986, 1987, 1988 Larry Wall
+Copyright 1989, 1990, 1991, 1992, 1993, 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.
+*/
+
+#define XTERN
+#include <common.h>
+#undef XTERN
+#define XTERN extern
+#include <argmatch.h>
+#include <backupfile.h>
+#include <getopt.h>
+#include <inp.h>
+#include <pch.h>
+#include <util.h>
+#include <version.h>
+
+#if HAVE_UTIME_H
+# include <utime.h>
+#endif
+/* Some nonstandard hosts don't declare this structure even in <utime.h>. */
+#if ! HAVE_STRUCT_UTIMBUF
+struct utimbuf
+{
+ time_t actime;
+ time_t modtime;
+};
+#endif
+
+/* Output stream state. */
+struct outstate
+{
+ FILE *ofp;
+ int after_newline;
+ int zero_output;
+};
+
+/* procedures */
+
+static FILE *create_output_file PARAMS ((char const *));
+static LINENUM locate_hunk PARAMS ((LINENUM));
+static bool apply_hunk PARAMS ((struct outstate *, LINENUM));
+static bool copy_till PARAMS ((struct outstate *, LINENUM));
+static bool patch_match PARAMS ((LINENUM, LINENUM, LINENUM, LINENUM));
+static bool similar PARAMS ((char const *, size_t, char const *, size_t));
+static bool spew_output PARAMS ((struct outstate *));
+static char const *make_temp PARAMS ((int));
+static int numeric_string PARAMS ((char const *, int, char const *));
+static void abort_hunk PARAMS ((void));
+static void cleanup PARAMS ((void));
+static void get_some_switches PARAMS ((void));
+static void init_output PARAMS ((char const *, struct outstate *));
+static void init_reject PARAMS ((char const *));
+static void reinitialize_almost_everything PARAMS ((void));
+static void usage PARAMS ((FILE *, int)) __attribute__((noreturn));
+
+static int backup_if_mismatch;
+static int remove_empty_files;
+
+/* TRUE if -R was specified on command line. */
+static int reverse_flag_specified;
+
+/* how many input lines have been irretractably output */
+static LINENUM last_frozen_line;
+
+static char const *do_defines; /* symbol to patch using ifdef, ifndef, etc. */
+static char const if_defined[] = "\n#ifdef %s\n";
+static char const not_defined[] = "#ifndef %s\n";
+static char const else_defined[] = "\n#else\n";
+static char const end_defined[] = "\n#endif /* %s */\n";
+
+static int Argc;
+static char * const *Argv;
+
+static FILE *rejfp; /* reject file pointer */
+
+static char const *patchname;
+static char *rejname;
+static char const * volatile TMPREJNAME;
+
+static LINENUM last_offset;
+static LINENUM maxfuzz = 2;
+
+static char serrbuf[BUFSIZ];
+
+char const program_name[] = "patch";
+
+/* Apply a set of diffs as appropriate. */
+
+int main PARAMS ((int, char **));
+
+int
+main(argc,argv)
+int argc;
+char **argv;
+{
+ char const *val;
+ bool somefailed = FALSE;
+ struct outstate outstate;
+
+ init_time ();
+
+ setbuf(stderr, serrbuf);
+
+ bufsize = 8 * 1024;
+ buf = xmalloc (bufsize);
+
+ strippath = INT_MAX;
+
+ posixly_correct = getenv ("POSIXLY_CORRECT") != 0;
+ backup_if_mismatch = ! posixly_correct;
+ patch_get = ((val = getenv ("PATCH_GET"))
+ ? numeric_string (val, 1, "PATCH_GET value")
+ : posixly_correct - 1);
+
+ {
+ char const *v;
+
+ v = getenv ("SIMPLE_BACKUP_SUFFIX");
+ if (v && *v)
+ simple_backup_suffix = v;
+
+ v = getenv ("PATCH_VERSION_CONTROL");
+ if (! v)
+ v = getenv ("VERSION_CONTROL");
+ if (v && *v)
+ backup_type = get_version (v);
+ }
+
+ /* 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();
+
+ init_output (outfile, &outstate);
+
+ /* Make sure we clean up in case of disaster. */
+ set_signals(0);
+
+ for (
+ open_patch_file (patchname);
+ there_is_another_patch();
+ reinitialize_almost_everything()
+ ) { /* for each patch in patch file */
+ int hunk = 0;
+ int failed = 0;
+ int mismatch = 0;
+ char *outname = outfile ? outfile : inname;
+
+ if (!skip_rest_of_patch)
+ get_input_file (inname, outname);
+
+ if (diff_type == ED_DIFF) {
+ outstate.zero_output = 0;
+ if (! dry_run)
+ {
+ do_ed_script (outstate.ofp);
+ if (! outfile)
+ {
+ struct stat statbuf;
+ if (stat (TMPOUTNAME, &statbuf) != 0)
+ pfatal ("%s", TMPOUTNAME);
+ outstate.zero_output = statbuf.st_size == 0;
+ }
+ }
+ } else {
+ int got_hunk;
+ int apply_anyway = 0;
+
+ /* initialize the patched file */
+ if (! skip_rest_of_patch && ! outfile)
+ init_output (TMPOUTNAME, &outstate);
+
+ /* initialize reject file */
+ init_reject(TMPREJNAME);
+
+ /* find out where all the lines are */
+ if (!skip_rest_of_patch)
+ scan_input (inname);
+
+ /* from here on, open no standard i/o files, because malloc */
+ /* might misfire and we can't catch it easily */
+
+ /* apply each hunk of patch */
+ while (0 < (got_hunk = another_hunk (diff_type, reverse))) {
+ LINENUM where = 0; /* Pacify `gcc -Wall'. */
+ LINENUM newwhere;
+ LINENUM fuzz = 0;
+ 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 (!skip_rest_of_patch) {
+ do {
+ where = locate_hunk(fuzz);
+ if (! where || fuzz || last_offset)
+ mismatch = 1;
+ if (hunk == 1 && ! where && ! (force | apply_anyway)
+ && reverse == reverse_flag_specified) {
+ /* dwim for reversed patch? */
+ if (!pch_swap()) {
+ say (
+"Not enough memory to try swapped hunk! Assuming unswapped.\n");
+ continue;
+ }
+ /* Try again. */
+ 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;
+ }
+ }
+ }
+ } while (!skip_rest_of_patch && !where
+ && ++fuzz <= mymaxfuzz);
+
+ if (skip_rest_of_patch) { /* just got decided */
+ if (outstate.ofp && ! outfile)
+ {
+ fclose (outstate.ofp);
+ outstate.ofp = 0;
+ }
+ }
+ }
+
+ newwhere = pch_newfirst() + last_offset;
+ if (skip_rest_of_patch) {
+ abort_hunk();
+ failed++;
+ if (verbosity == VERBOSE)
+ say ("Hunk #%d ignored at %ld.\n", hunk, newwhere);
+ }
+ else if (!where
+ || (where == 1 && pch_says_nonexistent (reverse)
+ && instat.st_size)) {
+ if (where)
+ say ("Patch attempted to create file `%s', which already exists.\n", inname);
+ abort_hunk();
+ failed++;
+ if (verbosity != SILENT)
+ say ("Hunk #%d FAILED at %ld.\n", hunk, newwhere);
+ }
+ else if (! apply_hunk (&outstate, where)) {
+ abort_hunk ();
+ failed++;
+ if (verbosity != SILENT)
+ say ("Hunk #%d FAILED at %ld.\n", hunk, newwhere);
+ } else {
+ if (verbosity == VERBOSE
+ || (verbosity != SILENT && (fuzz || last_offset))) {
+ say ("Hunk #%d succeeded at %ld", hunk, newwhere);
+ if (fuzz)
+ say (" with fuzz %ld", fuzz);
+ if (last_offset)
+ say (" (offset %ld line%s)",
+ last_offset, last_offset==1?"":"s");
+ say (".\n");
+ }
+ }
+ }
+
+ if (got_hunk < 0 && using_plan_a) {
+ if (outfile)
+ fatal ("out of memory using Plan A");
+ say ("\n\nRan out of memory using Plan A -- trying again...\n\n");
+ if (outstate.ofp)
+ {
+ fclose (outstate.ofp);
+ outstate.ofp = 0;
+ }
+ fclose (rejfp);
+ continue;
+ }
+
+ /* finish spewing out the new file */
+ if (!skip_rest_of_patch)
+ {
+ assert (hunk);
+ if (! spew_output (&outstate))
+ {
+ say ("Skipping patch.\n");
+ skip_rest_of_patch = TRUE;
+ }
+ }
+ }
+
+ /* and put the output where desired */
+ ignore_signals ();
+ if (! skip_rest_of_patch && ! outfile) {
+ if (outstate.zero_output
+ && (remove_empty_files
+ || (pch_says_nonexistent (reverse ^ 1) == 2
+ && ! posixly_correct)))
+ {
+ if (verbosity == VERBOSE)
+ say ("Removing file `%s'%s.\n", outname,
+ dry_run ? " and any empty ancestor directories" : "");
+ if (! dry_run)
+ {
+ move_file ((char *) 0, outname, (mode_t) 0,
+ (backup_type != none
+ || (backup_if_mismatch && (mismatch | failed))));
+ removedirs (outname);
+ }
+ }
+ else
+ {
+ if (! outstate.zero_output
+ && pch_says_nonexistent (reverse ^ 1))
+ {
+ mismatch = 1;
+ if (verbosity != SILENT)
+ say ("File `%s' is not empty after patch, as expected.\n",
+ outname);
+ }
+
+ if (! dry_run)
+ {
+ time_t t;
+
+ move_file (TMPOUTNAME, outname, instat.st_mode,
+ (backup_type != none
+ || (backup_if_mismatch && (mismatch | failed))));
+
+ if ((set_time | set_utc)
+ && (t = pch_timestamp (reverse ^ 1)) != (time_t) -1)
+ {
+ struct utimbuf utimbuf;
+ utimbuf.actime = utimbuf.modtime = t;
+
+ if (! force && ! inerrno
+ && ! pch_says_nonexistent (reverse)
+ && (t = pch_timestamp (reverse)) != (time_t) -1
+ && t != instat.st_mtime)
+ say ("not setting time of file `%s' (time mismatch)\n",
+ outname);
+ else if (! force && (mismatch | failed))
+ say ("not setting time of file `%s' (contents mismatch)\n",
+ outname);
+ else if (utime (outname, &utimbuf) != 0)
+ pfatal ("can't set timestamp on file `%s'", outname);
+ }
+
+ if (! inerrno && chmod (outname, instat.st_mode) != 0)
+ pfatal ("can't set permissions on file `%s'", outname);
+ }
+ }
+ }
+ if (diff_type != ED_DIFF) {
+ if (fclose (rejfp) != 0)
+ write_fatal ();
+ if (failed) {
+ somefailed = TRUE;
+ say ("%d out of %d hunk%s %s", failed, hunk, "s" + (hunk == 1),
+ skip_rest_of_patch ? "ignored" : "FAILED");
+ if (outname) {
+ char *rej = rejname;
+ if (!rejname) {
+ rej = xmalloc (strlen (outname) + 5);
+ strcpy (rej, outname);
+ addext (rej, ".rej", '#');
+ }
+ say (" -- saving rejects to %s", rej);
+ if (! dry_run)
+ {
+ 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);
+ }
+ say ("\n");
+ }
+ }
+ set_signals (1);
+ }
+ if (outstate.ofp && (ferror (outstate.ofp) || fclose (outstate.ofp) != 0))
+ write_fatal ();
+ cleanup ();
+ if (somefailed)
+ exit (1);
+ return 0;
+}
+
+/* Prepare to find the next patch to do in the patch file. */
+
+static void
+reinitialize_almost_everything()
+{
+ re_patch();
+ re_input();
+
+ input_lines = 0;
+ last_frozen_line = 0;
+
+ if (inname) {
+ free (inname);
+ inname = 0;
+ }
+
+ last_offset = 0;
+
+ diff_type = NO_DIFF;
+
+ if (revision) {
+ free(revision);
+ revision = 0;
+ }
+
+ reverse = reverse_flag_specified;
+ skip_rest_of_patch = FALSE;
+}
+
+static char const shortopts[] = "bB:cd:D:eEfF:g:i:lnNo:p:r:RstTuvV:x:Y:z:Z";
+static struct option const longopts[] =
+{
+ {"backup", no_argument, NULL, 'b'},
+ {"prefix", required_argument, NULL, 'B'},
+ {"context", no_argument, NULL, 'c'},
+ {"directory", required_argument, NULL, 'd'},
+ {"ifdef", required_argument, NULL, 'D'},
+ {"ed", no_argument, NULL, 'e'},
+ {"remove-empty-files", no_argument, NULL, 'E'},
+ {"force", no_argument, NULL, 'f'},
+ {"fuzz", required_argument, NULL, 'F'},
+ {"get", no_argument, NULL, 'g'},
+ {"input", required_argument, NULL, 'i'},
+ {"ignore-whitespace", no_argument, NULL, 'l'},
+ {"normal", no_argument, NULL, 'n'},
+ {"forward", no_argument, NULL, 'N'},
+ {"output", required_argument, NULL, 'o'},
+ {"strip", required_argument, NULL, 'p'},
+ {"reject-file", required_argument, NULL, 'r'},
+ {"reverse", no_argument, NULL, 'R'},
+ {"quiet", no_argument, NULL, 's'},
+ {"silent", no_argument, NULL, 's'},
+ {"batch", no_argument, NULL, 't'},
+ {"set-time", no_argument, NULL, 'T'},
+ {"unified", no_argument, NULL, 'u'},
+ {"version", no_argument, NULL, 'v'},
+ {"version-control", required_argument, NULL, 'V'},
+ {"debug", required_argument, NULL, 'x'},
+ {"basename-prefix", required_argument, NULL, 'Y'},
+ {"suffix", required_argument, NULL, 'z'},
+ {"set-utc", no_argument, NULL, 'Z'},
+ {"dry-run", no_argument, NULL, 129},
+ {"verbose", no_argument, NULL, 130},
+ {"binary", no_argument, NULL, 131},
+ {"help", no_argument, NULL, 132},
+ {"backup-if-mismatch", no_argument, NULL, 133},
+ {"no-backup-if-mismatch", no_argument, NULL, 134},
+ {NULL, no_argument, NULL, 0}
+};
+
+static char const *const option_help[] =
+{
+"Input options:",
+"",
+" -p NUM --strip=NUM Strip NUM leading components from file names.",
+" -F LINES --fuzz LINES Set the fuzz factor to LINES for inexact matching.",
+" -l --ignore-whitespace Ignore white space changes between patch and input.",
+"",
+" -c --context Interpret the patch as a context difference.",
+" -e --ed Interpret the patch as an ed script.",
+" -n --normal Interpret the patch as a normal difference.",
+" -u --unified Interpret the patch as a unified difference.",
+"",
+" -N --forward Ignore patches that appear to be reversed or already applied.",
+" -R --reverse Assume patches were created with old and new files swapped.",
+"",
+" -i PATCHFILE --input=PATCHFILE Read patch from PATCHFILE instead of stdin.",
+"",
+"Output options:",
+"",
+" -o FILE --output=FILE Output patched files to FILE.",
+" -r FILE --reject-file=FILE Output rejects to FILE.",
+"",
+" -D NAME --ifdef=NAME Make merged if-then-else output using NAME.",
+" -E --remove-empty-files Remove output files that are empty after patching.",
+"",
+" -Z --set-utc Set times of patched files, assuming diff uses UTC (GMT).",
+" -T --set-time Likewise, assuming local time.",
+"",
+"Backup and version control options:",
+"",
+" -V STYLE --version-control=STYLE Use STYLE version control.",
+" STYLE is either 'simple', 'numbered', or 'existing'.",
+"",
+" -b --backup Back up the original contents of each file.",
+" --backup-if-mismatch Back up if the patch does not match exactly.",
+" --no-backup-if-mismatch Back up mismatches only if otherwise requested.",
+" -B PREFIX --prefix=PREFIX Prepend PREFIX to backup file names.",
+" -Y PREFIX --basename-prefix=PREFIX Prepend PREFIX to backup file basenames.",
+" -z SUFFIX --suffix=SUFFIX Append SUFFIX to backup file names.",
+"",
+" -g NUM --get=NUM Get files from RCS or SCCS if positive; ask if negative.",
+"",
+"Miscellaneous options:",
+"",
+" -t --batch Ask no questions; skip bad-Prereq patches; assume reversed.",
+" -f --force Like -t, but ignore bad-Prereq patches, and assume unreversed.",
+" -s --quiet --silent Work silently unless an error occurs.",
+" --verbose Output extra information about the work being done.",
+" --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
+};
+
+static void
+usage (stream, status)
+ FILE *stream;
+ int status;
+{
+ char const * const *p;
+
+ if (status != 0)
+ {
+ fprintf (stream, "%s: Try `%s --help' for more information.\n",
+ program_name, Argv[0]);
+ }
+ else
+ {
+ fprintf (stream, "Usage: %s [OPTION]... [ORIGFILE [PATCHFILE]]\n\n",
+ Argv[0]);
+ for (p = option_help; *p; p++)
+ fprintf (stream, "%s\n", *p);
+ }
+
+ exit (status);
+}
+
+/* Process switches and filenames. */
+
+static void
+get_some_switches()
+{
+ register int optc;
+
+ if (rejname)
+ free (rejname);
+ rejname = 0;
+ if (optind == Argc)
+ return;
+ while ((optc = getopt_long (Argc, Argv, shortopts, longopts, (int *) 0))
+ != -1) {
+ switch (optc) {
+ case 'b':
+ /* Special hack for backward compatibility with CVS 1.9.
+ If the last 4 args are `-b SUFFIX ORIGFILE PATCHFILE',
+ treat `-b' as if it were `-z'. */
+ if (Argc - optind == 3
+ && strcmp (Argv[optind - 1], "-b") == 0
+ && ! (Argv[optind + 0][0] == '-' && Argv[optind + 0][1])
+ && ! (Argv[optind + 1][0] == '-' && Argv[optind + 1][1])
+ && ! (Argv[optind + 2][0] == '-' && Argv[optind + 2][1]))
+ {
+ optarg = Argv[optind++];
+ if (verbosity != SILENT)
+ say ("warning: the `-b %s' option is obsolete; use `-z %s' instead\n",
+ optarg, optarg);
+ goto case_z;
+ }
+ backup_type = simple;
+ break;
+ case 'B':
+ if (!*optarg)
+ fatal ("backup prefix is empty");
+ origprae = savestr (optarg);
+ break;
+ case 'c':
+ diff_type = CONTEXT_DIFF;
+ break;
+ case 'd':
+ if (chdir(optarg) < 0)
+ pfatal ("can't change directory to `%s'", optarg);
+ break;
+ case 'D':
+ do_defines = savestr (optarg);
+ break;
+ case 'e':
+ diff_type = ED_DIFF;
+ break;
+ case 'E':
+ remove_empty_files = TRUE;
+ break;
+ case 'f':
+ force = TRUE;
+ break;
+ case 'F':
+ maxfuzz = numeric_string (optarg, 0, "fuzz factor");
+ break;
+ case 'g':
+ patch_get = numeric_string (optarg, 1, "get option value");
+ break;
+ case 'i':
+ patchname = savestr (optarg);
+ break;
+ case 'l':
+ canonicalize = TRUE;
+ break;
+ case 'n':
+ diff_type = NORMAL_DIFF;
+ break;
+ case 'N':
+ noreverse = TRUE;
+ break;
+ case 'o':
+ if (strcmp (optarg, "-") == 0)
+ fatal ("can't output patches to standard output");
+ outfile = savestr (optarg);
+ break;
+ case 'p':
+ strippath = numeric_string (optarg, 0, "strip count");
+ break;
+ case 'r':
+ rejname = savestr (optarg);
+ break;
+ case 'R':
+ reverse = 1;
+ reverse_flag_specified = 1;
+ break;
+ case 's':
+ verbosity = SILENT;
+ break;
+ case 't':
+ batch = TRUE;
+ break;
+ case 'T':
+ set_time = 1;
+ break;
+ case 'u':
+ diff_type = UNI_DIFF;
+ break;
+ case 'v':
+ version();
+ exit (0);
+ break;
+ case 'V':
+ backup_type = get_version (optarg);
+ break;
+#if DEBUGGING
+ case 'x':
+ debug = numeric_string (optarg, 1, "debugging option");
+ break;
+#endif
+ case 'Y':
+ if (!*optarg)
+ fatal ("backup basename prefix is empty");
+ origbase = savestr (optarg);
+ break;
+ case 'z':
+ case_z:
+ if (!*optarg)
+ fatal ("backup suffix is empty");
+ simple_backup_suffix = savestr (optarg);
+ break;
+ case 'Z':
+ set_utc = 1;
+ break;
+ case 129:
+ dry_run = TRUE;
+ break;
+ case 130:
+ verbosity = VERBOSE;
+ break;
+ case 131:
+#if HAVE_SETMODE
+ binary_transput = O_BINARY;
+#endif
+ break;
+ case 132:
+ usage (stdout, 0);
+ case 133:
+ backup_if_mismatch = 1;
+ break;
+ case 134:
+ backup_if_mismatch = 0;
+ break;
+ default:
+ usage (stderr, 2);
+ }
+ }
+
+ /* Process any filename args. */
+ if (optind < Argc)
+ {
+ inname = savestr (Argv[optind++]);
+ invc = -1;
+ if (optind < Argc)
+ {
+ patchname = savestr (Argv[optind++]);
+ if (optind < Argc)
+ {
+ fprintf (stderr, "%s: extra operand `%s'\n",
+ program_name, Argv[optind]);
+ usage (stderr, 2);
+ }
+ }
+ }
+}
+
+/* Handle STRING (possibly negative if NEGATIVE_ALLOWED is nonzero)
+ of type ARGTYPE_MSGID by converting it to an integer,
+ returning the result. */
+static int
+numeric_string (string, negative_allowed, argtype_msgid)
+ char const *string;
+ int negative_allowed;
+ char const *argtype_msgid;
+{
+ int value = 0;
+ char const *p = string;
+ int sign = *p == '-' ? -1 : 1;
+
+ p += *p == '-' || *p == '+';
+
+ do
+ {
+ int v10 = value * 10;
+ int digit = *p - '0';
+ int signed_digit = sign * digit;
+ int next_value = v10 + signed_digit;
+
+ if (9 < (unsigned) digit)
+ fatal ("%s `%s' is not a number", argtype_msgid, string);
+
+ if (v10 / 10 != value || (next_value < v10) != (signed_digit < 0))
+ fatal ("%s `%s' is too large", argtype_msgid, string);
+
+ value = next_value;
+ }
+ while (*++p);
+
+ if (value < 0 && ! negative_allowed)
+ fatal ("%s `%s' is negative", argtype_msgid, string);
+
+ return value;
+}
+
+/* Attempt to find the right place to apply this hunk of patch. */
+
+static LINENUM
+locate_hunk(fuzz)
+LINENUM fuzz;
+{
+ register LINENUM first_guess = pch_first () + last_offset;
+ register LINENUM offset;
+ LINENUM pat_lines = pch_ptrn_lines();
+ 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;
+
+ /* Do not try lines <= 0. */
+ if (first_guess <= max_neg_offset)
+ max_neg_offset = first_guess - 1;
+
+ 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;
+ }
+ 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;
+ }
+ }
+ return 0;
+}
+
+/* We did not find the pattern, dump out the hunk so they can handle it. */
+
+static void
+abort_hunk()
+{
+ register LINENUM i;
+ register LINENUM pat_end = pch_end ();
+ /* add in last_offset to guess the same as the previous successful hunk */
+ LINENUM oldfirst = pch_first() + last_offset;
+ LINENUM newfirst = pch_newfirst() + last_offset;
+ LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1;
+ LINENUM newlast = newfirst + pch_repl_lines() - 1;
+ char const *stars =
+ (int) NEW_CONTEXT_DIFF <= (int) diff_type ? " ****" : "";
+ char const *minuses =
+ (int) NEW_CONTEXT_DIFF <= (int) diff_type ? " ----" : " -----";
+
+ fprintf(rejfp, "***************\n");
+ for (i=0; i<=pat_end; i++) {
+ switch (pch_char(i)) {
+ case '*':
+ if (oldlast < oldfirst)
+ fprintf(rejfp, "*** 0%s\n", stars);
+ else if (oldlast == oldfirst)
+ fprintf(rejfp, "*** %ld%s\n", oldfirst, stars);
+ else
+ fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, oldlast, stars);
+ break;
+ case '=':
+ if (newlast < newfirst)
+ fprintf(rejfp, "--- 0%s\n", minuses);
+ else if (newlast == newfirst)
+ fprintf(rejfp, "--- %ld%s\n", newfirst, minuses);
+ else
+ fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, newlast, minuses);
+ break;
+ case ' ': case '-': case '+': case '!':
+ fprintf (rejfp, "%c ", pch_char (i));
+ /* fall into */
+ case '\n':
+ pch_write_line (i, rejfp);
+ break;
+ default:
+ fatal ("fatal internal error in abort_hunk");
+ }
+ if (ferror (rejfp))
+ write_fatal ();
+ }
+}
+
+/* We found where to apply it (we hope), so do it. */
+
+static bool
+apply_hunk (outstate, where)
+ struct outstate *outstate;
+ LINENUM where;
+{
+ register LINENUM old = 1;
+ register LINENUM lastline = pch_ptrn_lines ();
+ register LINENUM new = lastline+1;
+ register enum {OUTSIDE, IN_IFNDEF, IN_IFDEF, IN_ELSE} def_state = OUTSIDE;
+ register char const *R_do_defines = do_defines;
+ register LINENUM pat_end = pch_end ();
+ register FILE *fp = outstate->ofp;
+
+ where--;
+ while (pch_char(new) == '=' || pch_char(new) == '\n')
+ new++;
+
+ while (old <= lastline) {
+ if (pch_char(old) == '-') {
+ assert (outstate->after_newline);
+ if (! copy_till (outstate, where + old - 1))
+ return FALSE;
+ if (R_do_defines) {
+ if (def_state == OUTSIDE) {
+ fprintf (fp, outstate->after_newline + if_defined,
+ R_do_defines);
+ def_state = IN_IFNDEF;
+ }
+ else if (def_state == IN_IFDEF) {
+ fprintf (fp, outstate->after_newline + else_defined);
+ def_state = IN_ELSE;
+ }
+ if (ferror (fp))
+ write_fatal ();
+ outstate->after_newline = pch_write_line (old, fp);
+ outstate->zero_output = 0;
+ }
+ last_frozen_line++;
+ old++;
+ }
+ else if (new > pat_end) {
+ break;
+ }
+ else if (pch_char(new) == '+') {
+ if (! copy_till (outstate, where + old - 1))
+ return FALSE;
+ if (R_do_defines) {
+ if (def_state == IN_IFNDEF) {
+ fprintf (fp, outstate->after_newline + else_defined);
+ def_state = IN_ELSE;
+ }
+ else if (def_state == OUTSIDE) {
+ fprintf (fp, outstate->after_newline + if_defined,
+ R_do_defines);
+ def_state = IN_IFDEF;
+ }
+ if (ferror (fp))
+ write_fatal ();
+ }
+ outstate->after_newline = pch_write_line (new, fp);
+ outstate->zero_output = 0;
+ new++;
+ }
+ else if (pch_char(new) != pch_char(old)) {
+ 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?",
+ pch_hunk_beg() + old,
+ pch_hunk_beg() + new);
+ }
+ else if (pch_char(new) == '!') {
+ assert (outstate->after_newline);
+ if (! copy_till (outstate, where + old - 1))
+ return FALSE;
+ assert (outstate->after_newline);
+ if (R_do_defines) {
+ fprintf (fp, not_defined, R_do_defines);
+ if (ferror (fp))
+ write_fatal ();
+ def_state = IN_IFNDEF;
+ }
+
+ do
+ {
+ if (R_do_defines) {
+ outstate->after_newline = pch_write_line (old, fp);
+ }
+ last_frozen_line++;
+ old++;
+ }
+ while (pch_char (old) == '!');
+
+ if (R_do_defines) {
+ fprintf (fp, outstate->after_newline + else_defined);
+ if (ferror (fp))
+ write_fatal ();
+ def_state = IN_ELSE;
+ }
+
+ do
+ {
+ outstate->after_newline = pch_write_line (new, fp);
+ new++;
+ }
+ while (pch_char (new) == '!');
+ outstate->zero_output = 0;
+ }
+ else {
+ assert(pch_char(new) == ' ');
+ old++;
+ new++;
+ if (R_do_defines && def_state != OUTSIDE) {
+ fprintf (fp, outstate->after_newline + end_defined,
+ R_do_defines);
+ if (ferror (fp))
+ write_fatal ();
+ outstate->after_newline = 1;
+ def_state = OUTSIDE;
+ }
+ }
+ }
+ if (new <= pat_end && pch_char(new) == '+') {
+ if (! copy_till (outstate, where + old - 1))
+ return FALSE;
+ if (R_do_defines) {
+ if (def_state == OUTSIDE) {
+ fprintf (fp, outstate->after_newline + if_defined,
+ R_do_defines);
+ def_state = IN_IFDEF;
+ }
+ else if (def_state == IN_IFNDEF) {
+ fprintf (fp, outstate->after_newline + else_defined);
+ def_state = IN_ELSE;
+ }
+ if (ferror (fp))
+ write_fatal ();
+ outstate->zero_output = 0;
+ }
+
+ do
+ {
+ if (! outstate->after_newline && putc ('\n', fp) == EOF)
+ write_fatal ();
+ outstate->after_newline = pch_write_line (new, fp);
+ outstate->zero_output = 0;
+ new++;
+ }
+ while (new <= pat_end && pch_char (new) == '+');
+ }
+ if (R_do_defines && def_state != OUTSIDE) {
+ fprintf (fp, outstate->after_newline + end_defined, R_do_defines);
+ if (ferror (fp))
+ write_fatal ();
+ outstate->after_newline = 1;
+ }
+ 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, outstate)
+ char const *name;
+ struct outstate *outstate;
+{
+ outstate->ofp = name ? create_output_file (name) : (FILE *) 0;
+ outstate->after_newline = 1;
+ outstate->zero_output = 1;
+}
+
+/* Open a file to put hunks we can't locate. */
+
+static void
+init_reject(name)
+ char const *name;
+{
+ rejfp = create_output_file (name);
+}
+
+/* Copy input file to output, up to wherever hunk is to be applied. */
+
+static bool
+copy_till (outstate, lastline)
+ register struct outstate *outstate;
+ register LINENUM lastline;
+{
+ register LINENUM R_last_frozen_line = last_frozen_line;
+ register FILE *fp = outstate->ofp;
+ register char const *s;
+ size_t size;
+
+ if (R_last_frozen_line > lastline)
+ {
+ say ("misordered hunks! output would be garbled\n");
+ return FALSE;
+ }
+ while (R_last_frozen_line < lastline)
+ {
+ s = ifetch (++R_last_frozen_line, 0, &size);
+ if (size)
+ {
+ if ((! outstate->after_newline && putc ('\n', fp) == EOF)
+ || ! fwrite (s, sizeof *s, size, fp))
+ write_fatal ();
+ outstate->after_newline = s[size - 1] == '\n';
+ outstate->zero_output = 0;
+ }
+ }
+ last_frozen_line = R_last_frozen_line;
+ return TRUE;
+}
+
+/* Finish copying the input file to the output file. */
+
+static bool
+spew_output (outstate)
+ struct outstate *outstate;
+{
+ if (debug & 256)
+ say ("il=%ld lfl=%ld\n", input_lines, last_frozen_line);
+
+ if (last_frozen_line < input_lines)
+ if (! copy_till (outstate, input_lines))
+ return FALSE;
+
+ if (outstate->ofp && ! outfile)
+ {
+ if (fclose (outstate->ofp) != 0)
+ write_fatal ();
+ outstate->ofp = 0;
+ }
+
+ return TRUE;
+}
+
+/* Does the patch pattern match at line base+offset? */
+
+static bool
+patch_match (base, offset, prefix_fuzz, suffix_fuzz)
+LINENUM base;
+LINENUM offset;
+LINENUM prefix_fuzz;
+LINENUM suffix_fuzz;
+{
+ register LINENUM pline = 1 + prefix_fuzz;
+ register LINENUM iline;
+ register LINENUM pat_lines = pch_ptrn_lines () - suffix_fuzz;
+ size_t size;
+ register char const *p;
+
+ for (iline=base+offset+prefix_fuzz; pline <= pat_lines; pline++,iline++) {
+ p = ifetch (iline, offset >= 0, &size);
+ if (canonicalize) {
+ if (!similar(p, size,
+ pfetch(pline),
+ pch_line_len(pline) ))
+ return FALSE;
+ }
+ else if (size != pch_line_len (pline)
+ || memcmp (p, pfetch (pline), size) != 0)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* Do two lines match with canonicalized white space? */
+
+static bool
+similar (a, alen, b, blen)
+ register char const *a;
+ register size_t alen;
+ register char const *b;
+ register size_t blen;
+{
+ /* Ignore presence or absence of trailing newlines. */
+ alen -= alen && a[alen - 1] == '\n';
+ blen -= blen && b[blen - 1] == '\n';
+
+ for (;;)
+ {
+ if (!blen || (*b == ' ' || *b == '\t'))
+ {
+ while (blen && (*b == ' ' || *b == '\t'))
+ b++, blen--;
+ if (alen)
+ {
+ if (!(*a == ' ' || *a == '\t'))
+ return FALSE;
+ do a++, alen--;
+ while (alen && (*a == ' ' || *a == '\t'));
+ }
+ if (!alen || !blen)
+ return alen == blen;
+ }
+ else if (!alen || *a++ != *b++)
+ return FALSE;
+ else
+ alen--, blen--;
+ }
+}
+
+/* Make a temporary file. */
+
+#if HAVE_MKTEMP
+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"); /* 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");
+#else
+ r = xmalloc (L_tmpnam);
+ if (! (tmpnam (r) == r && *r))
+ pfatal ("tmpnam");
+#endif
+ return r;
+}
+
+/* Fatal exit with cleanup. */
+
+void
+fatal_exit (sig)
+ int sig;
+{
+ cleanup ();
+
+ if (sig)
+ exit_with_signal (sig);
+
+ exit (2);
+}
+
+static void
+cleanup ()
+{
+ unlink (TMPINNAME);
+ unlink (TMPOUTNAME);
+ unlink (TMPPATNAME);
+ unlink (TMPREJNAME);
+}
diff --git a/contrib/patch/pch.c b/contrib/patch/pch.c
new file mode 100644
index 000000000000..64a627a7f0fb
--- /dev/null
+++ b/contrib/patch/pch.c
@@ -0,0 +1,1823 @@
+/* reading patches */
+
+/* $Id: pch.c,v 1.23 1997/06/17 06:52:12 eggert Exp $ */
+
+/*
+Copyright 1986, 1987, 1988 Larry Wall
+Copyright 1990, 1991, 1992, 1993, 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.
+*/
+
+#define XTERN extern
+#include <common.h>
+#include <backupfile.h>
+#include <inp.h>
+#include <util.h>
+#undef XTERN
+#define XTERN
+#include <pch.h>
+
+#define INITHUNKMAX 125 /* initial dynamic allocation size */
+
+/* Patch (diff listing) abstract type. */
+
+static FILE *pfp; /* patch file pointer */
+static int p_says_nonexistent[2]; /* [0] for old file, [1] for new;
+ value is 0 for nonempty, 1 for empty, 2 for nonexistent */
+static time_t p_timestamp[2]; /* timestamps in patch headers */
+static off_t p_filesize; /* size of the patch file */
+static LINENUM p_first; /* 1st line number */
+static LINENUM p_newfirst; /* 1st line number of replacement */
+static LINENUM p_ptrn_lines; /* # lines in pattern */
+static LINENUM p_repl_lines; /* # lines in replacement text */
+static LINENUM p_end = -1; /* last line in hunk */
+static LINENUM p_max; /* max allowed value of p_end */
+static LINENUM p_prefix_context; /* # of prefix context lines */
+static LINENUM p_suffix_context; /* # of suffix context lines */
+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 LINENUM hunkmax = INITHUNKMAX; /* size of above arrays */
+static int p_indent; /* indent to patch */
+static file_offset p_base; /* where to intuit this time */
+static LINENUM p_bline; /* line # of p_base */
+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 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. */
+
+void
+re_patch()
+{
+ p_first = 0;
+ p_newfirst = 0;
+ p_ptrn_lines = 0;
+ p_repl_lines = 0;
+ p_end = -1;
+ p_max = 0;
+ p_indent = 0;
+}
+
+/* Open the patch file at the beginning of time. */
+
+void
+open_patch_file(filename)
+ char const *filename;
+{
+ file_offset file_pos = 0;
+ struct stat st;
+ if (!filename || !*filename || strEQ (filename, "-"))
+ {
+ file_offset stdin_pos;
+#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) && (stdin_pos = file_tell (stdin)) != -1)
+ {
+ pfp = stdin;
+ file_pos = stdin_pos;
+ }
+ else
+ {
+ size_t charsread;
+ pfp = fopen (TMPPATNAME, "w+b");
+ if (!pfp)
+ pfatal ("can't create `%s'", TMPPATNAME);
+ for (st.st_size = 0;
+ (charsread = fread (buf, 1, bufsize, stdin)) != 0;
+ st.st_size += charsread)
+ if (fwrite (buf, 1, charsread, pfp) != charsread)
+ write_fatal ();
+ if (ferror (stdin) || fclose (stdin) != 0)
+ read_fatal ();
+ if (fflush (pfp) != 0
+ || file_seek (pfp, (file_offset) 0, SEEK_SET) != 0)
+ write_fatal ();
+ }
+ }
+ else
+ {
+ pfp = fopen (filename, binary_transput ? "rb" : "r");
+ if (!pfp)
+ 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();
+}
+
+/* Make sure our dynamically realloced tables are malloced to begin with. */
+
+void
+set_hunkmax()
+{
+ if (!p_line)
+ p_line = (char **) malloc (hunkmax * sizeof *p_line);
+ if (!p_len)
+ p_len = (size_t *) malloc (hunkmax * sizeof *p_len);
+ if (!p_Char)
+ p_Char = malloc (hunkmax * sizeof *p_Char);
+}
+
+/* Enlarge the arrays containing the current hunk of patch. */
+
+static bool
+grow_hunkmax()
+{
+ hunkmax *= 2;
+ assert (p_line && p_len && p_Char);
+ if ((p_line = (char **) realloc (p_line, hunkmax * sizeof (*p_line)))
+ && (p_len = (size_t *) realloc (p_len, hunkmax * sizeof (*p_len)))
+ && (p_Char = realloc (p_Char, hunkmax * sizeof (*p_Char))))
+ return TRUE;
+ if (!using_plan_a)
+ memory_fatal ();
+ /* Don't free previous values of p_line etc.,
+ since some broken implementations free them for us.
+ Whatever is null will be allocated again from within plan_a (),
+ of all places. */
+ return FALSE;
+}
+
+/* True if the remainder of the patch file contains a diff of some sort. */
+
+bool
+there_is_another_patch()
+{
+ if (p_base != 0 && p_base >= p_filesize) {
+ if (verbosity == VERBOSE)
+ say ("done\n");
+ return FALSE;
+ }
+ if (verbosity == VERBOSE)
+ say ("Hmm...");
+ diff_type = intuit_diff_type();
+ if (diff_type == NO_DIFF) {
+ if (verbosity == VERBOSE)
+ say (p_base
+ ? " Ignoring the trailing garbage.\ndone\n"
+ : " I can't seem to find a patch in there anywhere.\n");
+ return FALSE;
+ }
+ if (skip_rest_of_patch)
+ {
+ Fseek (pfp, p_start, SEEK_SET);
+ p_input_line = p_sline - 1;
+ return TRUE;
+ }
+ if (verbosity == VERBOSE)
+ say (" %sooks like %s to me...\n",
+ (p_base == 0 ? "L" : "The next patch l"),
+ diff_type == UNI_DIFF ? "a unified diff" :
+ diff_type == CONTEXT_DIFF ? "a context diff" :
+ diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" :
+ diff_type == NORMAL_DIFF ? "a normal diff" :
+ "an ed script" );
+
+ if (verbosity != SILENT)
+ {
+ if (p_indent)
+ say ("(Patch is indented %d space%s.)\n", p_indent, p_indent==1?"":"s");
+ if (! inname)
+ say ("can't find file to patch at input line %ld\n",
+ p_sline);
+ }
+
+ skip_to(p_start,p_sline);
+ while (!inname) {
+ if (force || batch) {
+ say ("No file to patch. Skipping patch.\n");
+ skip_rest_of_patch = TRUE;
+ return TRUE;
+ }
+ ask ("File to patch: ");
+ inname = fetchname (buf, 0, (time_t *) 0);
+ if (inname)
+ {
+ if (stat (inname, &instat) == 0)
+ {
+ inerrno = 0;
+ invc = -1;
+ }
+ else
+ {
+ perror (inname);
+ free (inname);
+ inname = 0;
+ }
+ }
+ if (!inname) {
+ ask ("Skip this patch? [y] ");
+ if (*buf != 'n') {
+ if (verbosity != SILENT)
+ say ("Skipping patch.\n");
+ skip_rest_of_patch = TRUE;
+ return TRUE;
+ }
+ }
+ }
+ return TRUE;
+}
+
+/* Determine what kind of diff is in the remaining part of the patch file. */
+
+static enum diff
+intuit_diff_type()
+{
+ register char *s;
+ register char *t;
+ register int indent;
+ 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 i;
+ char *name[3];
+ struct stat st[3];
+ int stat_errno[3];
+ int version_controlled[3];
+ register enum diff retval;
+
+ name[OLD] = name[NEW] = name[INDEX] = 0;
+ version_controlled[OLD] = -1;
+ version_controlled[NEW] = -1;
+ version_controlled[INDEX] = -1;
+ p_timestamp[OLD] = p_timestamp[NEW] = (time_t) -1;
+ p_says_nonexistent[OLD] = p_says_nonexistent[NEW] = 0;
+ Fseek (pfp, p_base, SEEK_SET);
+ p_input_line = p_bline - 1;
+ for (;;) {
+ previous_line = this_line;
+ last_line_was_command = this_is_a_command;
+ stars_last_line = stars_this_line;
+ this_line = file_tell (pfp);
+ indent = 0;
+ if (! pget_line (0)) {
+ if (first_command_line >= 0) {
+ /* nothing but deletes!? */
+ p_start = first_command_line;
+ p_sline = fcl_line;
+ retval = ED_DIFF;
+ goto scan_exit;
+ }
+ else {
+ p_start = this_line;
+ p_sline = p_input_line;
+ retval = NO_DIFF;
+ goto scan_exit;
+ }
+ }
+ for (s = buf; *s == ' ' || *s == '\t' || *s == 'X'; s++) {
+ if (*s == '\t')
+ indent = (indent + 8) & ~7;
+ else
+ indent++;
+ }
+ for (t = s; ISDIGIT (*t) || *t == ','; t++)
+ continue;
+ this_is_a_command = (ISDIGIT (*s) &&
+ (*t == 'd' || *t == 'c' || *t == 'a') );
+ if (first_command_line < 0 && this_is_a_command) {
+ first_command_line = this_line;
+ fcl_line = p_input_line;
+ p_indent = indent; /* assume this for now */
+ }
+ if (!stars_last_line && strnEQ(s, "*** ", 4))
+ name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]);
+ else if (strnEQ(s, "--- ", 4))
+ name[NEW] = fetchname (s+4, strippath, &p_timestamp[NEW]);
+ else if (strnEQ(s, "+++ ", 4))
+ /* Swap with NEW below. */
+ name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]);
+ else if (strnEQ(s, "Index:", 6))
+ name[INDEX] = fetchname (s+6, strippath, (time_t *) 0);
+ else if (strnEQ(s, "Prereq:", 7)) {
+ for (t = s + 7; ISSPACE ((unsigned char) *t); t++)
+ continue;
+ revision = t;
+ for (t = revision; *t && !ISSPACE ((unsigned char) *t); t++)
+ continue;
+ if (t == revision)
+ revision = 0;
+ else {
+ char oldc = *t;
+ *t = '\0';
+ revision = savestr (revision);
+ *t = oldc;
+ }
+ }
+ if ((diff_type == NO_DIFF || diff_type == ED_DIFF) &&
+ first_command_line >= 0 &&
+ strEQ(s, ".\n") ) {
+ p_indent = indent;
+ p_start = first_command_line;
+ p_sline = fcl_line;
+ retval = ED_DIFF;
+ goto scan_exit;
+ }
+ if ((diff_type == NO_DIFF || diff_type == UNI_DIFF)
+ && strnEQ(s, "@@ -", 4)) {
+
+ /* `name' and `p_timestamp' are backwards; swap them. */
+ time_t ti = p_timestamp[OLD];
+ p_timestamp[OLD] = p_timestamp[NEW];
+ p_timestamp[NEW] = ti;
+ t = name[OLD];
+ name[OLD] = name[NEW];
+ name[NEW] = t;
+
+ s += 4;
+ if (! atol (s))
+ p_says_nonexistent[OLD] = 1 + ! p_timestamp[OLD];
+ while (*s != ' ' && *s != '\n')
+ s++;
+ while (*s == ' ')
+ s++;
+ if (! atol (s))
+ p_says_nonexistent[NEW] = 1 + ! p_timestamp[NEW];
+ p_indent = indent;
+ p_start = this_line;
+ p_sline = p_input_line;
+ retval = UNI_DIFF;
+ if (! ((name[OLD] || ! p_timestamp[OLD])
+ && (name[NEW] || ! p_timestamp[NEW])))
+ say ("missing header for unified diff at line %ld of patch\n",
+ p_sline);
+ goto scan_exit;
+ }
+ stars_this_line = strnEQ(s, "********", 8);
+ if ((diff_type == NO_DIFF
+ || diff_type == CONTEXT_DIFF
+ || diff_type == NEW_CONTEXT_DIFF)
+ && stars_last_line && strnEQ (s, "*** ", 4)) {
+ s += 4;
+ if (! atol (s))
+ p_says_nonexistent[OLD] = 1 + ! p_timestamp[OLD];
+ /* if this is a new context diff the character just before */
+ /* the newline is a '*'. */
+ while (*s != '\n')
+ s++;
+ p_indent = indent;
+ p_start = previous_line;
+ p_sline = p_input_line - 1;
+ retval = (*(s-1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);
+
+ {
+ /* Scan the first hunk to see whether the file contents
+ appear to have been deleted. */
+ file_offset saved_p_base = p_base;
+ LINENUM saved_p_bline = p_bline;
+ Fseek (pfp, previous_line, SEEK_SET);
+ p_input_line -= 2;
+ if (another_hunk (retval, 0)
+ && ! p_repl_lines && p_newfirst == 1)
+ p_says_nonexistent[NEW] = 1 + ! p_timestamp[NEW];
+ next_intuit_at (saved_p_base, saved_p_bline);
+ }
+
+ if (! ((name[OLD] || ! p_timestamp[OLD])
+ && (name[NEW] || ! p_timestamp[NEW])))
+ say ("missing header for context diff at line %ld of patch\n",
+ p_sline);
+ goto scan_exit;
+ }
+ if ((diff_type == NO_DIFF || diff_type == NORMAL_DIFF) &&
+ last_line_was_command &&
+ (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2)) ) {
+ p_start = previous_line;
+ p_sline = p_input_line - 1;
+ p_indent = indent;
+ retval = NORMAL_DIFF;
+ goto scan_exit;
+ }
+ }
+
+ scan_exit:
+
+ /* 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):
+
+ - Take the old and new names from the context header if present,
+ and take the index name from the `Index:' line if present and
+ if either the old and new names are both absent
+ or posixly_correct is nonzero.
+ Consider the file names to be in the order (old, new, index).
+ - If some named files exist, use the first one if posixly_correct
+ is nonzero, the best one otherwise.
+ - If patch_get is nonzero, and no named files exist,
+ but an RCS or SCCS master file exists,
+ use the first named file with an RCS or SCCS master.
+ - If no named files exist, no RCS or SCCS master was found,
+ some names are given, posixly_correct is zero,
+ and the patch appears to create a file, then use the best name
+ requiring the creation of the fewest directories.
+ - Otherwise, report failure by setting `inname' to 0;
+ this causes our invoker to ask the user for a file name. */
+
+ i = NONE;
+
+ if (!inname)
+ {
+ enum nametype i0 = NONE;
+
+ if (! posixly_correct && (name[OLD] || name[NEW]) && name[INDEX])
+ {
+ free (name[INDEX]);
+ name[INDEX] = 0;
+ }
+
+ for (i = OLD; i <= INDEX; i++)
+ if (name[i])
+ {
+ 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;
+ }
+
+ if (! posixly_correct)
+ {
+ i = best_name (name, stat_errno);
+
+ if (i == NONE && patch_get)
+ {
+ enum nametype nope = NONE;
+
+ for (i = OLD; i <= INDEX; i++)
+ if (name[i])
+ {
+ char const *cs;
+ char *getbuf;
+ char *diffbuf;
+ int readonly = outfile && strcmp (outfile, name[i]) != 0;
+
+ if (nope == NONE || strcmp (name[nope], name[i]) != 0)
+ {
+ cs = (version_controller
+ (name[i], readonly, (struct stat *) 0,
+ &getbuf, &diffbuf));
+ version_controlled[i] = !! cs;
+ if (cs)
+ {
+ if (version_get (name[i], cs, 0, readonly,
+ getbuf, &st[i]))
+ stat_errno[i] = 0;
+ else
+ version_controlled[i] = 0;
+
+ free (getbuf);
+ free (diffbuf);
+
+ if (! stat_errno[i])
+ break;
+ }
+ }
+
+ nope = i;
+ }
+ }
+
+ if (p_says_nonexistent[reverse ^ (i == NONE || st[i].st_size == 0)])
+ {
+ assert (i0 != NONE);
+ if (ok_to_reverse
+ ("The next patch%s would %s the file `%s',\nwhich %s!",
+ reverse ? ", when reversed," : "",
+ (i == NONE ? "delete"
+ : st[i].st_size == 0 ? "empty out"
+ : "create"),
+ name[i == NONE || st[i].st_size == 0 ? i0 : i],
+ (i == NONE ? "does not exist"
+ : st[i].st_size == 0 ? "is already empty"
+ : "already exists")))
+ reverse ^= 1;
+ }
+
+ 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)
+ inerrno = -1;
+ else
+ {
+ inname = name[i];
+ name[i] = 0;
+ inerrno = stat_errno[i];
+ invc = version_controlled[i];
+ instat = st[i];
+ }
+
+ for (i = OLD; i <= INDEX; i++)
+ if (name[i])
+ free (name[i]);
+
+ 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)
+file_offset file_pos;
+LINENUM file_line;
+{
+ p_base = file_pos;
+ p_bline = file_line;
+}
+
+/* Basically a verbose fseek() to the actual diff listing. */
+
+static void
+skip_to(file_pos,file_line)
+file_offset file_pos;
+LINENUM file_line;
+{
+ register FILE *i = pfp;
+ register FILE *o = stdout;
+ register int c;
+
+ assert(p_base <= file_pos);
+ if ((verbosity == VERBOSE || !inname) && p_base < file_pos) {
+ Fseek (i, p_base, SEEK_SET);
+ say ("The text leading up to this was:\n--------------------------\n");
+
+ while (file_tell (i) < file_pos)
+ {
+ putc ('|', o);
+ do
+ {
+ if ((c = getc (i)) == EOF)
+ read_fatal ();
+ putc (c, o);
+ }
+ while (c != '\n');
+ }
+
+ say ("--------------------------\n");
+ }
+ else
+ Fseek (i, file_pos, SEEK_SET);
+ p_input_line = file_line - 1;
+}
+
+/* Make this a function for better debugging. */
+static void
+malformed ()
+{
+ fatal ("malformed patch at line %ld: %s", p_input_line, buf);
+ /* about as informative as "Syntax error" in C */
+}
+
+/* 1 if there is more of the current diff listing to process;
+ 0 if not; -1 if ran out of memory. */
+
+int
+another_hunk (difftype, rev)
+ enum diff difftype;
+ int rev;
+{
+ register char *s;
+ register LINENUM context = 0;
+ register size_t chars_read;
+
+ while (p_end >= 0) {
+ if (p_end == p_efake)
+ p_end = p_bfake; /* don't free twice */
+ else
+ free(p_line[p_end]);
+ p_end--;
+ }
+ assert(p_end == -1);
+ p_efake = -1;
+
+ p_max = hunkmax; /* gets reduced when --- found */
+ if (difftype == CONTEXT_DIFF || difftype == NEW_CONTEXT_DIFF) {
+ 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 */
+ register LINENUM fillsrc; /* index of first line to copy */
+ register LINENUM filldst; /* index of first missing line */
+ bool ptrn_spaces_eaten = FALSE; /* ptrn was slightly misformed */
+ bool some_context = FALSE; /* (perhaps internal) context seen */
+ register bool repl_could_be_missing = TRUE;
+ bool repl_missing = FALSE; /* we are now backtracking */
+ 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 */
+
+ /* Pacify `gcc -Wall'. */
+ fillsrc = filldst = repl_patch_line = repl_context = 0;
+
+ chars_read = get_line ();
+ if (chars_read == (size_t) -1
+ || chars_read <= 8
+ || strncmp (buf, "********", 8) != 0) {
+ next_intuit_at(line_beginning,p_input_line);
+ return chars_read == (size_t) -1 ? -1 : 0;
+ }
+ p_hunk_beg = p_input_line + 1;
+ while (p_end < p_max) {
+ chars_read = get_line ();
+ if (chars_read == (size_t) -1)
+ return -1;
+ if (!chars_read) {
+ if (repl_beginning && repl_could_be_missing) {
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ if (p_max - p_end < 4) {
+ strcpy (buf, " \n"); /* assume blank lines got chopped */
+ chars_read = 3;
+ } else {
+ fatal ("unexpected end of file in patch");
+ }
+ }
+ p_end++;
+ if (p_end == hunkmax)
+ fatal ("unterminated hunk starting at line %ld; giving up at line %ld: %s",
+ pch_hunk_beg (), p_input_line, buf);
+ assert(p_end < hunkmax);
+ p_Char[p_end] = *buf;
+ p_len[p_end] = 0;
+ p_line[p_end] = 0;
+ switch (*buf) {
+ case '*':
+ if (strnEQ(buf, "********", 8)) {
+ if (repl_beginning && repl_could_be_missing) {
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ else
+ fatal ("unexpected end of hunk at line %ld",
+ p_input_line);
+ }
+ if (p_end != 0) {
+ if (repl_beginning && repl_could_be_missing) {
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ fatal ("unexpected `***' at line %ld: %s",
+ p_input_line, buf);
+ }
+ context = 0;
+ p_len[p_end] = strlen (buf);
+ if (! (p_line[p_end] = savestr (buf))) {
+ p_end--;
+ return -1;
+ }
+ for (s = buf; *s && !ISDIGIT (*s); s++)
+ continue;
+ if (!*s)
+ malformed ();
+ if (strnEQ(s,"0,0",3))
+ remove_prefix (s, 2);
+ p_first = (LINENUM) atol(s);
+ while (ISDIGIT (*s))
+ s++;
+ if (*s == ',') {
+ while (*s && !ISDIGIT (*s))
+ s++;
+ if (!*s)
+ malformed ();
+ p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1;
+ }
+ else if (p_first)
+ p_ptrn_lines = 1;
+ else {
+ p_ptrn_lines = 0;
+ p_first = 1;
+ }
+ p_max = p_ptrn_lines + 6; /* we need this much at least */
+ while (p_max >= hunkmax)
+ if (! grow_hunkmax ())
+ return -1;
+ p_max = hunkmax;
+ break;
+ case '-':
+ 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:
+ s = buf + 1;
+ chars_read--;
+ if (*s == '\n' && canonicalize) {
+ strcpy (s, " \n");
+ chars_read = 2;
+ }
+ if (*s == ' ' || *s == '\t') {
+ s++;
+ chars_read--;
+ } else if (repl_beginning && repl_could_be_missing) {
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ 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)
+ && incomplete_line ());
+ p_len[p_end] = chars_read;
+ if (! (p_line[p_end] = savebuf (s, chars_read))) {
+ p_end--;
+ return -1;
+ }
+ context = 0;
+ break;
+ case '\t': case '\n': /* assume spaces got eaten */
+ s = buf;
+ if (*buf == '\t') {
+ s++;
+ chars_read--;
+ }
+ if (repl_beginning && repl_could_be_missing &&
+ (!ptrn_spaces_eaten || difftype == NEW_CONTEXT_DIFF) ) {
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ chars_read -=
+ (1 < chars_read
+ && p_end == (repl_beginning ? p_max : p_ptrn_lines)
+ && incomplete_line ());
+ p_len[p_end] = chars_read;
+ if (! (p_line[p_end] = savebuf (buf, chars_read))) {
+ p_end--;
+ return -1;
+ }
+ if (p_end != p_ptrn_lines + 1) {
+ ptrn_spaces_eaten |= (repl_beginning != 0);
+ some_context = TRUE;
+ context++;
+ if (!repl_beginning)
+ ptrn_copiable++;
+ p_Char[p_end] = ' ';
+ }
+ break;
+ case ' ':
+ s = buf + 1;
+ chars_read--;
+ if (*s == '\n' && canonicalize) {
+ strcpy (s, "\n");
+ chars_read = 2;
+ }
+ if (*s == ' ' || *s == '\t') {
+ s++;
+ chars_read--;
+ } else if (repl_beginning && repl_could_be_missing) {
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ some_context = TRUE;
+ context++;
+ if (!repl_beginning)
+ ptrn_copiable++;
+ chars_read -=
+ (1 < chars_read
+ && p_end == (repl_beginning ? p_max : p_ptrn_lines)
+ && incomplete_line ());
+ p_len[p_end] = chars_read;
+ if (! (p_line[p_end] = savebuf (buf + 2, chars_read))) {
+ p_end--;
+ return -1;
+ }
+ break;
+ default:
+ if (repl_beginning && repl_could_be_missing) {
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ malformed ();
+ }
+ }
+
+ hunk_done:
+ if (p_end >=0 && !repl_beginning)
+ fatal ("no `---' found in patch at line %ld", pch_hunk_beg ());
+
+ if (repl_missing) {
+
+ /* reset state back to just after --- */
+ p_input_line = repl_patch_line;
+ context = repl_context;
+ for (p_end--; p_end > repl_beginning; p_end--)
+ free(p_line[p_end]);
+ Fseek (pfp, repl_backtrack_position, SEEK_SET);
+
+ /* redundant 'new' context lines were omitted - set */
+ /* up to fill them in from the old file context */
+ fillsrc = 1;
+ filldst = repl_beginning+1;
+ fillcnt = p_repl_lines;
+ p_end = p_max;
+ }
+ else if (!some_context && fillcnt == 1) {
+ /* the first hunk was a null hunk with no context */
+ /* and we were expecting one line -- fix it up. */
+ while (filldst < p_end) {
+ p_line[filldst] = p_line[filldst+1];
+ p_Char[filldst] = p_Char[filldst+1];
+ p_len[filldst] = p_len[filldst+1];
+ filldst++;
+ }
+#if 0
+ repl_beginning--; /* this doesn't need to be fixed */
+#endif
+ p_end--;
+ p_first++; /* do append rather than insert */
+ fillcnt = 0;
+ p_ptrn_lines = 0;
+ }
+
+ 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
+ || (p_first > 1
+ && 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",
+"the telltale extra asterisks on the *** line that usually indicate",
+"the new style...)");
+ diff_type = difftype = NEW_CONTEXT_DIFF;
+ }
+
+ /* if there were omitted context lines, fill them in now */
+ if (fillcnt) {
+ p_bfake = filldst; /* remember where not to free() */
+ p_efake = filldst + fillcnt - 1;
+ while (fillcnt-- > 0) {
+ while (fillsrc <= p_end && fillsrc != repl_beginning
+ && p_Char[fillsrc] != ' ')
+ fillsrc++;
+ if (p_end < fillsrc || fillsrc == repl_beginning)
+ fatal ("replacement text or line numbers mangled in hunk at line %ld",
+ p_hunk_beg);
+ p_line[filldst] = p_line[fillsrc];
+ p_Char[filldst] = p_Char[fillsrc];
+ p_len[filldst] = p_len[fillsrc];
+ fillsrc++; filldst++;
+ }
+ while (fillsrc <= p_end && fillsrc != repl_beginning)
+ {
+ if (p_Char[fillsrc] == ' ')
+ fatal ("replacement text or line numbers mangled in hunk at line %ld",
+ p_hunk_beg);
+ fillsrc++;
+ }
+ if (debug & 64)
+ printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n",
+ fillsrc,filldst,repl_beginning,p_end+1);
+ assert(fillsrc==p_end+1 || fillsrc==repl_beginning);
+ assert(filldst==p_end+1 || filldst==repl_beginning);
+ }
+ }
+ else if (difftype == UNI_DIFF) {
+ 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 */
+ char ch = '\0';
+
+ chars_read = get_line ();
+ if (chars_read == (size_t) -1
+ || chars_read <= 4
+ || strncmp (buf, "@@ -", 4) != 0) {
+ next_intuit_at(line_beginning,p_input_line);
+ return chars_read == (size_t) -1 ? -1 : 0;
+ }
+ s = buf+4;
+ if (!*s)
+ malformed ();
+ p_first = (LINENUM) atol(s);
+ while (ISDIGIT (*s))
+ s++;
+ if (*s == ',') {
+ p_ptrn_lines = (LINENUM) atol(++s);
+ while (ISDIGIT (*s))
+ s++;
+ } else
+ p_ptrn_lines = 1;
+ if (*s == ' ') s++;
+ if (*s != '+' || !*++s)
+ malformed ();
+ p_newfirst = (LINENUM) atol(s);
+ while (ISDIGIT (*s))
+ s++;
+ if (*s == ',') {
+ p_repl_lines = (LINENUM) atol(++s);
+ while (ISDIGIT (*s))
+ s++;
+ } else
+ p_repl_lines = 1;
+ if (*s == ' ') s++;
+ if (*s != '@')
+ malformed ();
+ if (!p_ptrn_lines)
+ p_first++; /* do append rather than insert */
+ if (!p_repl_lines)
+ p_newfirst++;
+ p_max = p_ptrn_lines + p_repl_lines + 1;
+ while (p_max >= hunkmax)
+ if (! grow_hunkmax ())
+ return -1;
+ fillsrc = 1;
+ filldst = fillsrc + p_ptrn_lines;
+ p_end = filldst + p_repl_lines;
+ sprintf (buf,"*** %ld,%ld ****\n",p_first,p_first + p_ptrn_lines - 1);
+ p_len[0] = strlen (buf);
+ if (! (p_line[0] = savestr (buf))) {
+ p_end = -1;
+ return -1;
+ }
+ p_Char[0] = '*';
+ sprintf (buf,"--- %ld,%ld ----\n",p_newfirst,p_newfirst+p_repl_lines-1);
+ p_len[filldst] = strlen (buf);
+ if (! (p_line[filldst] = savestr (buf))) {
+ p_end = 0;
+ return -1;
+ }
+ p_Char[filldst++] = '=';
+ p_prefix_context = -1;
+ p_hunk_beg = p_input_line + 1;
+ while (fillsrc <= p_ptrn_lines || filldst <= p_end) {
+ chars_read = get_line ();
+ if (!chars_read) {
+ if (p_max - filldst < 3) {
+ strcpy (buf, " \n"); /* assume blank lines got chopped */
+ chars_read = 2;
+ } else {
+ fatal ("unexpected end of file in patch");
+ }
+ }
+ if (chars_read == (size_t) -1)
+ s = 0;
+ else if (*buf == '\t' || *buf == '\n') {
+ ch = ' '; /* assume the space got eaten */
+ s = savebuf (buf, chars_read);
+ }
+ else {
+ ch = *buf;
+ s = savebuf (buf+1, --chars_read);
+ }
+ if (!s) {
+ while (--filldst > p_ptrn_lines)
+ free(p_line[filldst]);
+ p_end = fillsrc-1;
+ return -1;
+ }
+ switch (ch) {
+ case '-':
+ if (fillsrc > p_ptrn_lines) {
+ free(s);
+ p_end = filldst-1;
+ malformed ();
+ }
+ chars_read -= fillsrc == p_ptrn_lines && incomplete_line ();
+ p_Char[fillsrc] = ch;
+ p_line[fillsrc] = s;
+ p_len[fillsrc++] = chars_read;
+ break;
+ case '=':
+ ch = ' ';
+ /* FALL THROUGH */
+ case ' ':
+ if (fillsrc > p_ptrn_lines) {
+ free(s);
+ while (--filldst > p_ptrn_lines)
+ free(p_line[filldst]);
+ p_end = fillsrc-1;
+ malformed ();
+ }
+ context++;
+ chars_read -= fillsrc == p_ptrn_lines && incomplete_line ();
+ p_Char[fillsrc] = ch;
+ p_line[fillsrc] = s;
+ p_len[fillsrc++] = chars_read;
+ s = savebuf (s, chars_read);
+ if (!s) {
+ while (--filldst > p_ptrn_lines)
+ free(p_line[filldst]);
+ p_end = fillsrc-1;
+ return -1;
+ }
+ /* FALL THROUGH */
+ case '+':
+ if (filldst > p_end) {
+ free(s);
+ while (--filldst > p_ptrn_lines)
+ free(p_line[filldst]);
+ p_end = fillsrc-1;
+ malformed ();
+ }
+ chars_read -= filldst == p_end && incomplete_line ();
+ p_Char[filldst] = ch;
+ p_line[filldst] = s;
+ p_len[filldst++] = chars_read;
+ break;
+ default:
+ p_end = filldst;
+ malformed ();
+ }
+ if (ch != ' ') {
+ if (p_prefix_context == -1)
+ p_prefix_context = context;
+ 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;
+ file_offset line_beginning = file_tell (pfp);
+
+ p_prefix_context = p_suffix_context = 0;
+ chars_read = get_line ();
+ if (chars_read == (size_t) -1 || !chars_read || !ISDIGIT (*buf)) {
+ next_intuit_at(line_beginning,p_input_line);
+ return chars_read == (size_t) -1 ? -1 : 0;
+ }
+ p_first = (LINENUM)atol(buf);
+ for (s = buf; ISDIGIT (*s); s++)
+ continue;
+ if (*s == ',') {
+ p_ptrn_lines = (LINENUM)atol(++s) - p_first + 1;
+ while (ISDIGIT (*s))
+ s++;
+ }
+ else
+ p_ptrn_lines = (*s != 'a');
+ hunk_type = *s;
+ if (hunk_type == 'a')
+ p_first++; /* do append rather than insert */
+ min = (LINENUM)atol(++s);
+ while (ISDIGIT (*s))
+ s++;
+ if (*s == ',')
+ max = (LINENUM)atol(++s);
+ else
+ max = min;
+ if (hunk_type == 'd')
+ min++;
+ p_end = p_ptrn_lines + 1 + max - min + 1;
+ while (p_end >= hunkmax)
+ if (! grow_hunkmax ())
+ {
+ p_end = -1;
+ return -1;
+ }
+ p_newfirst = min;
+ p_repl_lines = max - min + 1;
+ sprintf (buf, "*** %ld,%ld\n", p_first, p_first + p_ptrn_lines - 1);
+ p_len[0] = strlen (buf);
+ if (! (p_line[0] = savestr (buf))) {
+ p_end = -1;
+ return -1;
+ }
+ p_Char[0] = '*';
+ for (i=1; i<=p_ptrn_lines; i++) {
+ chars_read = get_line ();
+ if (chars_read == (size_t) -1)
+ {
+ p_end = i - 1;
+ return -1;
+ }
+ if (!chars_read)
+ fatal ("unexpected end of file in patch at line %ld",
+ p_input_line);
+ if (buf[0] != '<' || (buf[1] != ' ' && buf[1] != '\t'))
+ fatal ("`<' expected at line %ld of patch", p_input_line);
+ chars_read -= 2 + (i == p_ptrn_lines && incomplete_line ());
+ p_len[i] = chars_read;
+ if (! (p_line[i] = savebuf (buf + 2, chars_read))) {
+ p_end = i-1;
+ return -1;
+ }
+ p_Char[i] = '-';
+ }
+ if (hunk_type == 'c') {
+ chars_read = get_line ();
+ if (chars_read == (size_t) -1)
+ {
+ p_end = i - 1;
+ return -1;
+ }
+ if (! chars_read)
+ fatal ("unexpected end of file in patch at line %ld",
+ p_input_line);
+ if (*buf != '-')
+ fatal ("`---' expected at line %ld of patch", p_input_line);
+ }
+ sprintf (buf, "--- %ld,%ld\n", min, max);
+ p_len[i] = strlen (buf);
+ if (! (p_line[i] = savestr (buf))) {
+ p_end = i-1;
+ return -1;
+ }
+ p_Char[i] = '=';
+ for (i++; i<=p_end; i++) {
+ chars_read = get_line ();
+ if (chars_read == (size_t) -1)
+ {
+ p_end = i - 1;
+ return -1;
+ }
+ if (!chars_read)
+ fatal ("unexpected end of file in patch at line %ld",
+ p_input_line);
+ if (buf[0] != '>' || (buf[1] != ' ' && buf[1] != '\t'))
+ fatal ("`>' expected at line %ld of patch", p_input_line);
+ chars_read -= 2 + (i == p_end && incomplete_line ());
+ p_len[i] = chars_read;
+ if (! (p_line[i] = savebuf (buf + 2, chars_read))) {
+ p_end = i-1;
+ return -1;
+ }
+ p_Char[i] = '+';
+ }
+ }
+ if (rev) /* backwards patch? */
+ if (!pch_swap())
+ say ("Not enough memory to swap next hunk!\n");
+ if (debug & 2) {
+ LINENUM i;
+ char special;
+
+ for (i=0; i <= p_end; i++) {
+ if (i == p_ptrn_lines)
+ special = '^';
+ else
+ special = ' ';
+ fprintf (stderr, "%3ld %c %c ", i, p_Char[i], special);
+ pch_write_line (i, stderr);
+ fflush (stderr);
+ }
+ }
+ if (p_end+1 < hunkmax) /* paranoia reigns supreme... */
+ p_Char[p_end+1] = '^'; /* add a stopper for apply_hunk */
+ return 1;
+}
+
+static size_t
+get_line ()
+{
+ return pget_line (p_indent);
+}
+
+/* Input a line from the patch file, worrying about indentation.
+ Strip up to INDENT characters' worth of leading indentation.
+ Ignore any partial lines at end of input, but warn about them.
+ Succeed if a line was read; it is terminated by "\n\0" for convenience.
+ Return the number of characters read, including '\n' but not '\0'.
+ Return -1 if we ran out of memory. */
+
+static size_t
+pget_line (indent)
+ int indent;
+{
+ register FILE *fp = pfp;
+ register int c;
+ register int i = 0;
+ register char *b;
+ register size_t s;
+
+ for (;;)
+ {
+ c = getc (fp);
+ if (c == EOF)
+ {
+ if (ferror (fp))
+ read_fatal ();
+ return 0;
+ }
+ if (indent <= i)
+ break;
+ if (c == ' ' || c == 'X')
+ i++;
+ else if (c == '\t')
+ i = (i + 8) & ~7;
+ else
+ break;
+ }
+
+ i = 0;
+ b = buf;
+ s = bufsize;
+
+ for (;;)
+ {
+ if (i == s - 1)
+ {
+ s *= 2;
+ b = realloc (b, s);
+ if (!b)
+ {
+ if (!using_plan_a)
+ memory_fatal ();
+ return (size_t) -1;
+ }
+ buf = b;
+ bufsize = s;
+ }
+ b[i++] = c;
+ if (c == '\n')
+ break;
+ c = getc (fp);
+ if (c == EOF)
+ {
+ if (ferror (fp))
+ read_fatal ();
+ say ("patch unexpectedly ends in middle of line\n");
+ return 0;
+ }
+ }
+
+ b[i] = '\0';
+ p_input_line++;
+ return i;
+}
+
+static bool
+incomplete_line ()
+{
+ register FILE *fp = pfp;
+ register int c;
+ register file_offset line_beginning = file_tell (fp);
+
+ if (getc (fp) == '\\')
+ {
+ while ((c = getc (fp)) != '\n' && c != EOF)
+ continue;
+ return TRUE;
+ }
+ else
+ {
+ /* We don't trust ungetc. */
+ Fseek (pfp, line_beginning, SEEK_SET);
+ return FALSE;
+ }
+}
+
+/* Reverse the old and new portions of the current hunk. */
+
+bool
+pch_swap()
+{
+ char **tp_line; /* the text of the hunk */
+ size_t *tp_len; /* length of each line */
+ char *tp_char; /* +, -, and ! */
+ register LINENUM i;
+ register LINENUM n;
+ bool blankline = FALSE;
+ register char *s;
+
+ i = p_first;
+ p_first = p_newfirst;
+ p_newfirst = i;
+
+ /* make a scratch copy */
+
+ tp_line = p_line;
+ tp_len = p_len;
+ tp_char = p_Char;
+ p_line = 0; /* force set_hunkmax to allocate again */
+ p_len = 0;
+ p_Char = 0;
+ set_hunkmax();
+ if (!p_line || !p_len || !p_Char) {
+ if (p_line)
+ free (p_line);
+ p_line = tp_line;
+ if (p_len)
+ free (p_len);
+ p_len = tp_len;
+ if (p_Char)
+ free (p_Char);
+ p_Char = tp_char;
+ return FALSE; /* not enough memory to swap hunk! */
+ }
+
+ /* now turn the new into the old */
+
+ i = p_ptrn_lines + 1;
+ if (tp_char[i] == '\n') { /* account for possible blank line */
+ blankline = TRUE;
+ i++;
+ }
+ if (p_efake >= 0) { /* fix non-freeable ptr range */
+ if (p_efake <= i)
+ n = p_end - i + 1;
+ else
+ n = -i;
+ p_efake += n;
+ p_bfake += n;
+ }
+ for (n=0; i <= p_end; i++,n++) {
+ p_line[n] = tp_line[i];
+ p_Char[n] = tp_char[i];
+ if (p_Char[n] == '+')
+ p_Char[n] = '-';
+ p_len[n] = tp_len[i];
+ }
+ if (blankline) {
+ i = p_ptrn_lines + 1;
+ p_line[n] = tp_line[i];
+ p_Char[n] = tp_char[i];
+ p_len[n] = tp_len[i];
+ n++;
+ }
+ assert(p_Char[0] == '=');
+ p_Char[0] = '*';
+ for (s=p_line[0]; *s; s++)
+ if (*s == '-')
+ *s = '*';
+
+ /* now turn the old into the new */
+
+ assert(tp_char[0] == '*');
+ tp_char[0] = '=';
+ for (s=tp_line[0]; *s; s++)
+ if (*s == '*')
+ *s = '-';
+ for (i=0; n <= p_end; i++,n++) {
+ p_line[n] = tp_line[i];
+ p_Char[n] = tp_char[i];
+ if (p_Char[n] == '-')
+ p_Char[n] = '+';
+ p_len[n] = tp_len[i];
+ }
+ assert(i == p_ptrn_lines + 1);
+ i = p_ptrn_lines;
+ p_ptrn_lines = p_repl_lines;
+ p_repl_lines = i;
+ if (tp_line)
+ free (tp_line);
+ if (tp_len)
+ free (tp_len);
+ if (tp_char)
+ free (tp_char);
+ return TRUE;
+}
+
+/* Return whether file WHICH (0 = old, 1 = new) appears to nonexistent.
+ Return 1 for empty, 2 for nonexistent. */
+
+bool
+pch_says_nonexistent (which)
+ int which;
+{
+ return p_says_nonexistent[which];
+}
+
+/* Return timestamp of patch header for file WHICH (0 = old, 1 = new),
+ or -1 if there was no timestamp or an error in the timestamp. */
+
+time_t
+pch_timestamp (which)
+ int which;
+{
+ return p_timestamp[which];
+}
+
+/* Return the specified line position in the old file of the old context. */
+
+LINENUM
+pch_first()
+{
+ return p_first;
+}
+
+/* Return the number of lines of old context. */
+
+LINENUM
+pch_ptrn_lines()
+{
+ return p_ptrn_lines;
+}
+
+/* Return the probable line position in the new file of the first line. */
+
+LINENUM
+pch_newfirst()
+{
+ return p_newfirst;
+}
+
+/* Return the number of lines in the replacement text including context. */
+
+LINENUM
+pch_repl_lines()
+{
+ return p_repl_lines;
+}
+
+/* Return the number of lines in the whole hunk. */
+
+LINENUM
+pch_end()
+{
+ return p_end;
+}
+
+/* Return the number of context lines before the first changed line. */
+
+LINENUM
+pch_prefix_context ()
+{
+ return p_prefix_context;
+}
+
+/* Return the number of context lines after the last changed line. */
+
+LINENUM
+pch_suffix_context ()
+{
+ return p_suffix_context;
+}
+
+/* Return the length of a particular patch line. */
+
+size_t
+pch_line_len(line)
+LINENUM line;
+{
+ return p_len[line];
+}
+
+/* Return the control character (+, -, *, !, etc) for a patch line. */
+
+char
+pch_char(line)
+LINENUM line;
+{
+ return p_Char[line];
+}
+
+/* Return a pointer to a particular patch line. */
+
+char *
+pfetch(line)
+LINENUM line;
+{
+ return p_line[line];
+}
+
+/* Output a patch line. */
+
+bool
+pch_write_line (line, file)
+ LINENUM line;
+ FILE *file;
+{
+ bool after_newline = p_line[line][p_len[line] - 1] == '\n';
+ if (! fwrite (p_line[line], sizeof (*p_line[line]), p_len[line], file))
+ write_fatal ();
+ return after_newline;
+}
+
+/* Return where in the patch file this hunk began, for error messages. */
+
+LINENUM
+pch_hunk_beg()
+{
+ return p_hunk_beg;
+}
+
+/* Apply an ed script by feeding ed itself. */
+
+void
+do_ed_script (ofp)
+ FILE *ofp;
+{
+ static char const ed_program[] = ed_PROGRAM;
+
+ register char *t;
+ 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) {
+ assert (! inerrno);
+ copy_file (inname, TMPOUTNAME, instat.st_mode);
+ sprintf (buf, "%s %s%s", ed_program, verbosity == VERBOSE ? "" : "- ",
+ TMPOUTNAME);
+ fflush (stdout);
+ pipefp = popen(buf, binary_transput ? "wb" : "w");
+ if (!pipefp)
+ pfatal ("can't open pipe to `%s'", buf);
+ }
+ for (;;) {
+ beginning_of_this_line = file_tell (pfp);
+ chars_read = get_line ();
+ if (! chars_read) {
+ next_intuit_at(beginning_of_this_line,p_input_line);
+ break;
+ }
+ for (t = buf; ISDIGIT (*t) || *t == ','; t++)
+ continue;
+ this_line_is_command = (ISDIGIT (*buf) &&
+ (*t == 'd' || *t == 'c' || *t == 'a' || *t == 'i' || *t == 's') );
+ if (this_line_is_command) {
+ if (pipefp)
+ if (! fwrite (buf, sizeof *buf, chars_read, pipefp))
+ write_fatal ();
+ if (*t != 'd' && *t != 's') {
+ while ((chars_read = get_line ()) != 0) {
+ if (pipefp)
+ if (! fwrite (buf, sizeof *buf, chars_read, pipefp))
+ write_fatal ();
+ if (chars_read == 2 && strEQ (buf, ".\n"))
+ break;
+ }
+ }
+ }
+ else {
+ next_intuit_at(beginning_of_this_line,p_input_line);
+ break;
+ }
+ }
+ if (!pipefp)
+ return;
+ if (fwrite ("w\nq\n", sizeof (char), (size_t) 4, pipefp) == 0
+ || fflush (pipefp) != 0)
+ write_fatal ();
+ if (pclose (pipefp) != 0)
+ fatal ("%s FAILED", ed_program);
+
+ if (ofp)
+ {
+ FILE *ifp = fopen (TMPOUTNAME, binary_transput ? "rb" : "r");
+ int c;
+ if (!ifp)
+ pfatal ("can't open `%s'", TMPOUTNAME);
+ while ((c = getc (ifp)) != EOF)
+ if (putc (c, ofp) == EOF)
+ write_fatal ();
+ if (ferror (ifp) || fclose (ifp) != 0)
+ read_fatal ();
+ }
+}
diff --git a/contrib/patch/pch.h b/contrib/patch/pch.h
new file mode 100644
index 000000000000..2a4c3c00d40d
--- /dev/null
+++ b/contrib/patch/pch.h
@@ -0,0 +1,25 @@
+/* reading patches */
+
+/* $Id: pch.h,v 1.8 1997/06/13 06:28:37 eggert Exp $ */
+
+LINENUM pch_end PARAMS ((void));
+LINENUM pch_first PARAMS ((void));
+LINENUM pch_hunk_beg PARAMS ((void));
+LINENUM pch_newfirst PARAMS ((void));
+LINENUM pch_prefix_context PARAMS ((void));
+LINENUM pch_ptrn_lines PARAMS ((void));
+LINENUM pch_repl_lines PARAMS ((void));
+LINENUM pch_suffix_context PARAMS ((void));
+bool pch_swap PARAMS ((void));
+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));
+int pch_says_nonexistent PARAMS ((int));
+size_t pch_line_len PARAMS ((LINENUM));
+time_t pch_timestamp PARAMS ((int));
+void do_ed_script PARAMS ((FILE *));
+void open_patch_file PARAMS ((char const *));
+void re_patch PARAMS ((void));
+void set_hunkmax PARAMS ((void));
diff --git a/contrib/patch/quotearg.c b/contrib/patch/quotearg.c
new file mode 100644
index 000000000000..e4926e404f80
--- /dev/null
+++ b/contrib/patch/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/contrib/patch/quotearg.h b/contrib/patch/quotearg.h
new file mode 100644
index 000000000000..f32f9199dd26
--- /dev/null
+++ b/contrib/patch/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/contrib/patch/rename.c b/contrib/patch/rename.c
new file mode 100644
index 000000000000..d04a8bc0c8ec
--- /dev/null
+++ b/contrib/patch/rename.c
@@ -0,0 +1,112 @@
+/* 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
+ 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. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#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. */
+
+int
+rename (from, to)
+ char *from;
+ char *to;
+{
+ struct stat from_stats, to_stats;
+ int pid, status;
+
+ if (stat (from, &from_stats))
+ 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 (unlink (to) && errno != ENOENT)
+ return -1;
+ }
+
+#ifdef MVDIR
+
+/* 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))
+ {
+ /* 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/contrib/patch/util.c b/contrib/patch/util.c
new file mode 100644
index 000000000000..935b3250a168
--- /dev/null
+++ b/contrib/patch/util.c
@@ -0,0 +1,1070 @@
+/* utility functions for `patch' */
+
+/* $Id: util.c,v 1.22 1997/06/13 06:28:37 eggert Exp $ */
+
+/*
+Copyright 1986 Larry Wall
+Copyright 1992, 1993, 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.
+*/
+
+#define XTERN extern
+#include <common.h>
+#include <backupfile.h>
+#include <quotearg.h>
+#include <version.h>
+#undef XTERN
+#define XTERN
+#include <util.h>
+
+#include <maketime.h>
+#include <partime.h>
+
+#include <signal.h>
+#if !defined SIGCHLD && defined SIGCLD
+#define SIGCHLD SIGCLD
+#endif
+#if ! HAVE_RAISE
+# define raise(sig) kill (getpid (), sig)
+#endif
+
+#ifdef __STDC__
+# include <stdarg.h>
+# define vararg_start va_start
+#else
+# define vararg_start(ap,p) va_start (ap)
+# if HAVE_VARARGS_H
+# include <varargs.h>
+# else
+ typedef char *va_list;
+# define va_dcl int va_alist;
+# define va_start(ap) ((ap) = (va_list) &va_alist)
+# define va_arg(ap, t) (((t *) ((ap) += sizeof (t))) [-1])
+# define va_end(ap)
+# endif
+#endif
+
+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, mode, backup)
+ char const *from;
+ char *to;
+ mode_t mode;
+ int backup;
+#endif
+{
+ struct stat to_st;
+ int to_errno = ! backup ? -1 : stat (to, &to_st) == 0 ? 0 : errno;
+
+ if (backup)
+ {
+ int try_makedirs_errno = 0;
+ char *bakname;
+
+ if (origprae || origbase)
+ {
+ char const *p = origprae ? origprae : "";
+ char const *b = origbase ? origbase : "";
+ char const *o = base_name (to);
+ size_t plen = strlen (p);
+ size_t tlen = o - to;
+ size_t blen = strlen (b);
+ size_t osize = strlen (o) + 1;
+ bakname = xmalloc (plen + tlen + blen + osize);
+ memcpy (bakname, p, plen);
+ 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
+ {
+ bakname = find_backup_file_name (to);
+ if (!bakname)
+ memory_fatal ();
+ }
+
+ if (to_errno)
+ {
+ int fd;
+ if (debug & 4)
+ say ("creating empty unreadable file `%s'\n", bakname);
+ try_makedirs_errno = ENOENT;
+ unlink (bakname);
+ while ((fd = creat (bakname, 0)) < 0)
+ {
+ if (errno != try_makedirs_errno)
+ pfatal ("can't create file `%s'", bakname);
+ makedirs (bakname);
+ try_makedirs_errno = 0;
+ }
+ if (close (fd) != 0)
+ pfatal ("can't close `%s'", bakname);
+ }
+ else
+ {
+ if (debug & 4)
+ say ("renaming `%s' to `%s'\n", to, bakname);
+ while (rename (to, bakname) != 0)
+ {
+ if (errno != try_makedirs_errno)
+ pfatal ("can't rename `%s' to `%s'", to, bakname);
+ makedirs (bakname);
+ try_makedirs_errno = 0;
+ }
+ }
+
+ free (bakname);
+ }
+
+ if (from)
+ {
+ if (debug & 4)
+ say ("renaming `%s' to `%s'\n", from, to);
+
+ if (rename (from, to) != 0)
+ {
+ 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);
+ }
+ }
+ 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 (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;
+ 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 ();
+}
+
+static char const DEV_NULL[] = NULL_DEVICE;
+
+static char const SCCSPREFIX[] = "s.";
+static char const GET[] = "get ";
+static char const GET_LOCKED[] = "get -e ";
+static char const SCCSDIFF1[] = "get -p ";
+static char const SCCSDIFF2[] = "|diff - %s";
+
+static char const RCSSUFFIX[] = ",v";
+static char const CHECKOUT[] = "co %s";
+static char const CHECKOUT_LOCKED[] = "co -l %s";
+static char const RCSDIFF1[] = "rcsdiff %s";
+
+/* Return "RCS" if FILENAME is controlled by RCS,
+ "SCCS" if it is controlled by SCCS, and 0 otherwise.
+ READONLY is nonzero if we desire only readonly access to FILENAME.
+ FILESTAT describes FILENAME's status or is 0 if FILENAME does not exist.
+ If successful and if GETBUF is nonzero, set *GETBUF to a command
+ that gets the file; similarly for DIFFBUF and a command to diff the file.
+ *GETBUF and *DIFFBUF must be freed by the caller. */
+char const *
+version_controller (filename, readonly, filestat, getbuf, diffbuf)
+ char const *filename;
+ int readonly;
+ struct stat const *filestat;
+ char **getbuf;
+ char **diffbuf;
+{
+ struct stat cstat;
+ char const *filebase = base_name (filename);
+ char const *dotslash = *filename == '-' ? "./" : "";
+ size_t dir_len = filebase - filename;
+ size_t filenamelen = strlen (filename);
+ size_t maxfixlen = sizeof "SCCS/" - 1 + sizeof SCCSPREFIX - 1;
+ size_t maxtrysize = filenamelen + maxfixlen + 1;
+ size_t quotelen = quote_system_arg (0, filename);
+ size_t maxgetsize = sizeof GET_LOCKED + quotelen + maxfixlen;
+ size_t maxdiffsize =
+ (sizeof SCCSDIFF1 + sizeof SCCSDIFF2 + sizeof DEV_NULL - 1
+ + 2 * quotelen + maxfixlen);
+ char *trybuf = xmalloc (maxtrysize);
+ char const *r = 0;
+
+ strcpy (trybuf, filename);
+
+#define try1(f,a1) (sprintf (trybuf + dir_len, f, a1), stat (trybuf, &cstat) == 0)
+#define try2(f,a1,a2) (sprintf (trybuf + dir_len, f, a1,a2), stat (trybuf, &cstat) == 0)
+
+ /* Check that RCS file is not working file.
+ Some hosts don't report file name length errors. */
+
+ if ((try2 ("RCS/%s%s", filebase, RCSSUFFIX)
+ || try1 ("RCS/%s", filebase)
+ || try2 ("%s%s", filebase, RCSSUFFIX))
+ && ! (filestat
+ && filestat->st_dev == cstat.st_dev
+ && filestat->st_ino == cstat.st_ino))
+ {
+ if (getbuf)
+ {
+ char *p = *getbuf = xmalloc (maxgetsize);
+ sprintf (p, readonly ? CHECKOUT : CHECKOUT_LOCKED, dotslash);
+ p += strlen (p);
+ p += quote_system_arg (p, filename);
+ *p = '\0';
+ }
+
+ if (diffbuf)
+ {
+ char *p = *diffbuf = xmalloc (maxdiffsize);
+ sprintf (p, RCSDIFF1, dotslash);
+ p += strlen (p);
+ p += quote_system_arg (p, filename);
+ *p++ = '>';
+ strcpy (p, DEV_NULL);
+ }
+
+ r = "RCS";
+ }
+ else if (try2 ("SCCS/%s%s", SCCSPREFIX, filebase)
+ || try2 ("%s%s", SCCSPREFIX, filebase))
+ {
+ if (getbuf)
+ {
+ char *p = *getbuf = xmalloc (maxgetsize);
+ sprintf (p, readonly ? GET : GET_LOCKED);
+ p += strlen (p);
+ p += quote_system_arg (p, trybuf);
+ *p = '\0';
+ }
+
+ if (diffbuf)
+ {
+ char *p = *diffbuf = xmalloc (maxdiffsize);
+ strcpy (p, SCCSDIFF1);
+ p += sizeof SCCSDIFF1 - 1;
+ p += quote_system_arg (p, trybuf);
+ sprintf (p, SCCSDIFF2, dotslash);
+ p += strlen (p);
+ p += quote_system_arg (p, filename);
+ *p++ = '>';
+ strcpy (p, DEV_NULL);
+ }
+
+ r = "SCCS";
+ }
+
+ free (trybuf);
+ return r;
+}
+
+/* Get FILENAME from version control system CS. The file already exists if
+ EXISTS is nonzero. Only readonly access is needed if READONLY is nonzero.
+ Use the command GETBUF to actually get the named file.
+ Store the resulting file status into *FILESTAT.
+ Return nonzero if successful. */
+int
+version_get (filename, cs, exists, readonly, getbuf, filestat)
+ char const *filename;
+ char const *cs;
+ int exists;
+ int readonly;
+ char const *getbuf;
+ struct stat *filestat;
+{
+ if (patch_get < 0)
+ {
+ ask ("Get file `%s' from %s%s? [y] ", filename,
+ cs, readonly ? "" : " with lock");
+ if (*buf == 'n')
+ return 0;
+ }
+
+ if (dry_run)
+ {
+ if (! exists)
+ fatal ("can't do dry run on nonexistent version-controlled file `%s'; invoke `%s' and try again",
+ filename, getbuf);
+ }
+ else
+ {
+ if (verbosity == VERBOSE)
+ say ("Getting file `%s' from %s%s...\n", filename,
+ cs, readonly ? "" : " with lock");
+ if (systemic (getbuf) != 0)
+ fatal ("can't get file `%s' from %s", filename, cs);
+ if (stat (filename, filestat) != 0)
+ pfatal ("%s", filename);
+ }
+
+ return 1;
+}
+
+/* Allocate a unique area for a string. */
+
+char *
+savebuf (s, size)
+ register char const *s;
+ register size_t size;
+{
+ register char *rv;
+
+ assert (s && size);
+ rv = malloc (size);
+
+ if (! rv)
+ {
+ if (! using_plan_a)
+ memory_fatal ();
+ }
+ else
+ memcpy (rv, s, size);
+
+ return rv;
+}
+
+char *
+savestr(s)
+ char const *s;
+{
+ return savebuf (s, strlen (s) + 1);
+}
+
+void
+remove_prefix (p, prefixlen)
+ char *p;
+ size_t prefixlen;
+{
+ char const *s = p + prefixlen;
+ while ((*p++ = *s++))
+ continue;
+}
+
+#if !HAVE_VPRINTF
+#define vfprintf my_vfprintf
+static int vfprintf PARAMS ((FILE *, char const *, va_list));
+static int
+vfprintf (stream, format, args)
+ FILE *stream;
+ char const *format;
+ va_list args;
+{
+#if !HAVE_DOPRNT && HAVE__DOPRINTF
+# define _doprnt _doprintf
+#endif
+#if HAVE_DOPRNT || HAVE__DOPRINTF
+ _doprnt (format, args, stream);
+ return ferror (stream) ? -1 : 0;
+#else
+ int *a = (int *) args;
+ return fprintf (stream, format,
+ a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]);
+#endif
+}
+#endif /* !HAVE_VPRINTF */
+
+/* Terminal output, pun intended. */
+
+#ifdef __STDC__
+void
+fatal (char const *format, ...)
+#else
+/*VARARGS1*/ void
+fatal (format, va_alist)
+ char const *format;
+ va_dcl
+#endif
+{
+ va_list args;
+ fprintf (stderr, "%s: **** ", program_name);
+ vararg_start (args, format);
+ vfprintf (stderr, format, args);
+ va_end (args);
+ putc ('\n', stderr);
+ fflush (stderr);
+ fatal_exit (0);
+}
+
+void
+memory_fatal ()
+{
+ fatal ("out of memory");
+}
+
+void
+read_fatal ()
+{
+ pfatal ("read error");
+}
+
+void
+write_fatal ()
+{
+ pfatal ("write error");
+}
+
+/* Say something from patch, something from the system, then silence . . . */
+
+#ifdef __STDC__
+void
+pfatal (char const *format, ...)
+#else
+/*VARARGS1*/ void
+pfatal (format, va_alist)
+ char const *format;
+ va_dcl
+#endif
+{
+ int errnum = errno;
+ va_list args;
+ fprintf (stderr, "%s: **** ", program_name);
+ vararg_start (args, format);
+ vfprintf (stderr, format, args);
+ va_end (args);
+ fflush (stderr); /* perror bypasses stdio on some hosts. */
+ errno = errnum;
+ perror (" ");
+ fflush (stderr);
+ fatal_exit (0);
+}
+
+/* Tell the user something. */
+
+#ifdef __STDC__
+void
+say (char const *format, ...)
+#else
+/*VARARGS1*/ void
+say (format, va_alist)
+ char const *format;
+ va_dcl
+#endif
+{
+ va_list args;
+ vararg_start (args, format);
+ vfprintf (stdout, format, args);
+ va_end (args);
+ fflush (stdout);
+}
+
+/* Get a response from the user, somehow or other. */
+
+#ifdef __STDC__
+void
+ask (char const *format, ...)
+#else
+/*VARARGS1*/ void
+ask (format, va_alist)
+ char const *format;
+ va_dcl
+#endif
+{
+ static int ttyfd = -2;
+ int r;
+ va_list args;
+
+ vararg_start (args, format);
+ vfprintf (stdout, format, args);
+ va_end (args);
+ fflush (stdout);
+
+ if (ttyfd == -2)
+ {
+ /* If standard output is not a tty, don't bother opening /dev/tty,
+ since it's unlikely that stdout will be seen by the tty user.
+ The isatty test also works around a bug in GNU Emacs 19.34 under Linux
+ which makes a call-process `patch' hang when it reads from /dev/tty.
+ POSIX.2 requires that we read /dev/tty, though. */
+ ttyfd = (posixly_correct || isatty (STDOUT_FILENO)
+ ? open (TTY_DEVICE, O_RDONLY)
+ : -1);
+ }
+
+ if (ttyfd < 0)
+ {
+ /* No terminal at all -- default it. */
+ printf ("\n");
+ buf[0] = '\n';
+ buf[1] = '\0';
+ }
+ else
+ {
+ 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)
+ {
+ perror ("tty read");
+ fflush (stderr);
+ close (ttyfd);
+ ttyfd = -1;
+ r = 0;
+ }
+ buf[s + 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 || ! (force && verbosity == SILENT))
+ {
+ va_list args;
+ vararg_start (args, format);
+ vfprintf (stdout, format, args);
+ va_end (args);
+ }
+
+ if (noreverse)
+ {
+ printf (" Skipping patch.\n");
+ skip_rest_of_patch = TRUE;
+ r = 0;
+ }
+ else if (force)
+ {
+ if (verbosity != SILENT)
+ printf (" Applying it anyway.\n");
+ r = 0;
+ }
+ else if (batch)
+ {
+ say (reverse ? " Ignoring -R.\n" : " Assuming -R.\n");
+ r = 1;
+ }
+ else
+ {
+ ask (reverse ? " Ignore -R? [y] " : " Assume -R? [y] ");
+ r = *buf != 'n';
+ if (! r)
+ {
+ ask ("Apply anyway? [n] ");
+ if (*buf != 'y')
+ {
+ if (verbosity != SILENT)
+ say ("Skipping patch.\n");
+ 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))
+static int const sigs[] = {
+#ifdef SIGHUP
+ SIGHUP,
+#endif
+#ifdef SIGPIPE
+ SIGPIPE,
+#endif
+#ifdef SIGTERM
+ SIGTERM,
+#endif
+#ifdef SIGXCPU
+ SIGXCPU,
+#endif
+#ifdef SIGXFSZ
+ SIGXFSZ,
+#endif
+ SIGINT
+};
+
+#if !HAVE_SIGPROCMASK
+#define sigset_t int
+#define sigemptyset(s) (*(s) = 0)
+#ifndef sigmask
+#define sigmask(sig) (1 << ((sig) - 1))
+#endif
+#define sigaddset(s, sig) (*(s) |= sigmask (sig))
+#define sigismember(s, sig) ((*(s) & sigmask (sig)) != 0)
+#ifndef SIG_BLOCK
+#define SIG_BLOCK 0
+#endif
+#ifndef SIG_UNBLOCK
+#define SIG_UNBLOCK (SIG_BLOCK + 1)
+#endif
+#ifndef SIG_SETMASK
+#define SIG_SETMASK (SIG_BLOCK + 2)
+#endif
+#define sigprocmask(how, n, o) \
+ ((how) == SIG_BLOCK \
+ ? ((o) ? *(o) = sigblock (*(n)) : sigblock (*(n))) \
+ : (how) == SIG_UNBLOCK \
+ ? sigsetmask (((o) ? *(o) = sigblock (0) : sigblock (0)) & ~*(n)) \
+ : (o ? *(o) = sigsetmask (*(n)) : sigsetmask (*(n))))
+#if !HAVE_SIGSETMASK
+#define sigblock(mask) 0
+#define sigsetmask(mask) 0
+#endif
+#endif
+
+static sigset_t initial_signal_mask;
+static sigset_t signals_to_block;
+
+#if ! HAVE_SIGACTION
+static RETSIGTYPE fatal_exit_handler PARAMS ((int)) __attribute__ ((noreturn));
+static RETSIGTYPE
+fatal_exit_handler (sig)
+ int sig;
+{
+ signal (sig, SIG_IGN);
+ fatal_exit (sig);
+}
+#endif
+
+void
+set_signals(reset)
+int reset;
+{
+ int i;
+#if HAVE_SIGACTION
+ struct sigaction initial_act, fatal_act;
+ fatal_act.sa_handler = fatal_exit;
+ sigemptyset (&fatal_act.sa_mask);
+ fatal_act.sa_flags = 0;
+#define setup_handler(sig) sigaction (sig, &fatal_act, (struct sigaction *) 0)
+#else
+#define setup_handler(sig) signal (sig, fatal_exit_handler)
+#endif
+
+ if (!reset)
+ {
+#ifdef SIGCHLD
+ /* System V fork+wait does not work if SIGCHLD is ignored. */
+ signal (SIGCHLD, SIG_DFL);
+#endif
+ sigemptyset (&signals_to_block);
+ for (i = 0; i < NUM_SIGS; i++)
+ {
+ int ignoring_signal;
+#if HAVE_SIGACTION
+ if (sigaction (sigs[i], (struct sigaction *) 0, &initial_act) != 0)
+ continue;
+ ignoring_signal = initial_act.sa_handler == SIG_IGN;
+#else
+ ignoring_signal = signal (sigs[i], SIG_IGN) == SIG_IGN;
+#endif
+ if (! ignoring_signal)
+ {
+ sigaddset (&signals_to_block, sigs[i]);
+ setup_handler (sigs[i]);
+ }
+ }
+ }
+ else
+ {
+ /* Undo the effect of ignore_signals. */
+#if HAVE_SIGPROCMASK || HAVE_SIGSETMASK
+ sigprocmask (SIG_SETMASK, &initial_signal_mask, (sigset_t *) 0);
+#else
+ for (i = 0; i < NUM_SIGS; i++)
+ if (sigismember (&signals_to_block, sigs[i]))
+ setup_handler (sigs[i]);
+#endif
+ }
+}
+
+/* How to handle certain events when in a critical region. */
+
+void
+ignore_signals()
+{
+#if HAVE_SIGPROCMASK || HAVE_SIGSETMASK
+ sigprocmask (SIG_BLOCK, &signals_to_block, &initial_signal_mask);
+#else
+ int i;
+ for (i = 0; i < NUM_SIGS; i++)
+ if (sigismember (&signals_to_block, sigs[i]))
+ signal (sigs[i], SIG_IGN);
+#endif
+}
+
+void
+exit_with_signal (sig)
+ int sig;
+{
+ sigset_t s;
+ signal (sig, SIG_DFL);
+ sigemptyset (&s);
+ sigaddset (&s, sig);
+ sigprocmask (SIG_UNBLOCK, &s, (sigset_t *) 0);
+ raise (sig);
+ exit (2);
+}
+
+int
+systemic (command)
+ char const *command;
+{
+ if (debug & 8)
+ say ("+ %s\n", command);
+ fflush (stdout);
+ return system (command);
+}
+
+#if !HAVE_MKDIR
+/* These mkdir and rmdir substitutes are good enough for `patch';
+ they are not general emulators. */
+
+static int doprogram PARAMS ((char const *, char const *));
+static int mkdir PARAMS ((char const *, mode_t));
+static int rmdir PARAMS ((char const *));
+
+static int
+doprogram (program, arg)
+ char const *program;
+ char const *arg;
+{
+ int result;
+ static char const DISCARD_OUTPUT[] = " 2>/dev/null";
+ size_t program_len = strlen (program);
+ char *cmd = xmalloc (program_len + 1 + quote_system_arg (0, arg)
+ + sizeof DISCARD_OUTPUT);
+ char *p = cmd;
+ strcpy (p, program);
+ p += program_len;
+ *p++ = ' ';
+ p += quote_system_arg (p, arg);
+ strcpy (p, DISCARD_OUTPUT);
+ result = systemic (cmd);
+ free (cmd);
+ return result;
+}
+
+#ifdef __STDC__
+/* If mode_t doesn't promote to itself, we can't use old-style definition. */
+static int
+mkdir (char const *path, mode_t mode)
+#else
+static int
+mkdir (path, mode)
+ char const *path;
+ mode_t mode; /* ignored */
+#endif
+{
+ return doprogram ("mkdir", path);
+}
+
+static int
+rmdir (path)
+ char const *path;
+{
+ int result = doprogram ("rmdir", path);
+ errno = EEXIST;
+ return result;
+}
+#endif
+
+/* Replace '/' with '\0' in FILENAME if it marks a place that
+ needs testing for the existence of directory. Return the address
+ of the last location replaced, or 0 if none were replaced. */
+static char *replace_slashes PARAMS ((char *));
+static char *
+replace_slashes (filename)
+ char *filename;
+{
+ char *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 (ISSLASH (*f))
+ {
+ char *slash = f;
+
+ /* Treat multiple slashes as if they were one slash. */
+ while (ISSLASH (f[1]))
+ f++;
+
+ /* Ignore slashes at the end of the path. */
+ if (! f[1])
+ break;
+
+ /* "." and ".." need not be tested. */
+ if (! (slash - component_start <= 2
+ && component_start[0] == '.' && slash[-1] == '.'))
+ {
+ *slash = '\0';
+ last_location_replaced = slash;
+ }
+
+ component_start = f + 1;
+ }
+
+ return last_location_replaced;
+}
+
+/* Make sure we'll have the directories to create a file.
+ Ignore the last element of `filename'. */
+
+static void
+makedirs (filename)
+ register char *filename;
+{
+ register char *f;
+ register char *flim = replace_slashes (filename);
+
+ 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)
+ {
+ mkdir (filename,
+ S_IRUSR|S_IWUSR|S_IXUSR
+ |S_IRGRP|S_IWGRP|S_IXGRP
+ |S_IROTH|S_IWOTH|S_IXOTH);
+ *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] = '/';
+ }
+}
+
+static time_t initial_time;
+
+void
+init_time ()
+{
+ time (&initial_time);
+}
+
+/* Make filenames more reasonable. */
+
+char *
+fetchname (at, strip_leading, pstamp)
+char *at;
+int strip_leading;
+time_t *pstamp;
+{
+ char *name;
+ register char *t;
+ int sleading = strip_leading;
+ time_t stamp = (time_t) -1;
+
+ while (ISSPACE ((unsigned char) *at))
+ at++;
+ if (debug & 128)
+ say ("fetchname %s %d\n", at, strip_leading);
+
+ name = at;
+ /* Strip off up to `sleading' leading slashes and null terminate. */
+ for (t = at; *t; t++)
+ {
+ if (ISSLASH (*t))
+ {
+ while (ISSLASH (t[1]))
+ t++;
+ if (--sleading >= 0)
+ name = t+1;
+ }
+ else if (ISSPACE ((unsigned char) *t))
+ {
+ if (set_time | set_utc)
+ stamp = str2time (t, initial_time, set_utc ? 0L : TM_LOCAL_ZONE);
+ else
+ {
+ /* The head says the file is nonexistent if the timestamp
+ is the epoch; but the listed time is local time, not UTC,
+ and POSIX.1 allows local time to be 24 hours away from UTC.
+ So match any time within 24 hours of the epoch.
+ Use a default time zone 24 hours behind UTC so that any
+ non-zoned time within 24 hours of the epoch is valid. */
+ stamp = str2time (t, initial_time, -24L * 60 * 60);
+ if (0 <= stamp && stamp <= 2 * 24L * 60 * 60)
+ stamp = 0;
+ }
+
+ *t = '\0';
+ break;
+ }
+ }
+
+ if (!*name)
+ return 0;
+
+ /* Allow files to be created by diffing against /dev/null. */
+ if (strcmp (at, "/dev/null") == 0)
+ {
+ if (pstamp)
+ *pstamp = 0;
+ return 0;
+ }
+
+ if (pstamp)
+ *pstamp = stamp;
+
+ return savestr (name);
+}
+
+GENERIC_OBJECT *
+xmalloc (size)
+ size_t size;
+{
+ register GENERIC_OBJECT *p = malloc (size);
+ if (!p)
+ memory_fatal ();
+ return p;
+}
+
+void
+Fseek (stream, offset, ptrname)
+ FILE *stream;
+ file_offset offset;
+ int ptrname;
+{
+ if (file_seek (stream, offset, ptrname) != 0)
+ pfatal ("fseek");
+}
diff --git a/contrib/patch/util.h b/contrib/patch/util.h
new file mode 100644
index 000000000000..f7fda0af815b
--- /dev/null
+++ b/contrib/patch/util.h
@@ -0,0 +1,32 @@
+/* utility functions for `patch' */
+
+/* $Id: util.h,v 1.14 1997/06/13 06:28:37 eggert Exp $ */
+
+int ok_to_reverse PARAMS ((char const *, ...)) __attribute__ ((format (printf, 1, 2)));
+void ask PARAMS ((char const *, ...)) __attribute__ ((format (printf, 1, 2)));
+void say PARAMS ((char const *, ...)) __attribute__ ((format (printf, 1, 2)));
+
+void fatal PARAMS ((char const *, ...))
+ __attribute__ ((noreturn, format (printf, 1, 2)));
+void pfatal PARAMS ((char const *, ...))
+ __attribute__ ((noreturn, format (printf, 1, 2)));
+
+char *fetchname PARAMS ((char *, int, time_t *));
+char *savebuf PARAMS ((char const *, size_t));
+char *savestr PARAMS ((char const *));
+char const *version_controller PARAMS ((char const *, int, struct stat const *, char **, char **));
+int version_get PARAMS ((char const *, char const *, int, int, char const *, struct stat *));
+int create_file PARAMS ((char const *, int, mode_t));
+int systemic PARAMS ((char const *));
+void Fseek PARAMS ((FILE *, file_offset, int));
+void copy_file PARAMS ((char const *, char const *, mode_t));
+void exit_with_signal PARAMS ((int)) __attribute__ ((noreturn));
+void ignore_signals PARAMS ((void));
+void init_time PARAMS ((void));
+void memory_fatal PARAMS ((void));
+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/contrib/patch/version.c b/contrib/patch/version.c
new file mode 100644
index 000000000000..ea08437b0852
--- /dev/null
+++ b/contrib/patch/version.c
@@ -0,0 +1,30 @@
+/* Print the version number. */
+
+/* $Id: version.c,v 1.5 1997/05/21 18:29:20 eggert Exp $ */
+
+#define XTERN extern
+#include <common.h>
+#undef XTERN
+#define XTERN
+#include <patchlevel.h>
+#include <version.h>
+
+static char const copyright_string[] = "\
+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\
+You may redistribute copies of this program\n\
+under the terms of the GNU General Public License.\n\
+For more information about these matters, see the file named COPYING.";
+
+static char const authorship_msgid[] = "\
+written by Larry Wall with lots o' patches by Paul Eggert";
+
+void
+version()
+{
+ printf ("%s %s\n%s\n\n%s\n\n%s\n", program_name, PATCH_VERSION,
+ copyright_string, free_software_msgid, authorship_msgid);
+}
diff --git a/contrib/patch/version.h b/contrib/patch/version.h
new file mode 100644
index 000000000000..b061c94f0bb5
--- /dev/null
+++ b/contrib/patch/version.h
@@ -0,0 +1,5 @@
+/* Print the version number. */
+
+/* $Id: version.h,v 1.3 1997/04/07 01:07:00 eggert Exp $ */
+
+void version PARAMS ((void));