Import of patch-2.1.tar.gz

This commit is contained in:
Andreas Gruenbacher 2009-03-12 15:09:25 +01:00
commit 068f401ee3
30 changed files with 8236 additions and 0 deletions

339
COPYING Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, 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
Appendix: 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., 675 Mass Ave, Cambridge, MA 02139, 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.

360
ChangeLog Normal file
View File

@ -0,0 +1,360 @@
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).
* Apply unidiff patches from davison@dri.com (Wayne Davison).
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.
Local Variables:
mode: indented-text
left-margin: 8
version-control: never
end:

21
EXTERN.h Normal file
View File

@ -0,0 +1,21 @@
/* $Header: EXTERN.h,v 2.0 86/09/17 15:35:37 lwall Exp $
*
* $Log: EXTERN.h,v $
* Revision 2.0 86/09/17 15:35:37 lwall
* Baseline for netwide release.
*
*/
#ifdef EXT
#undef EXT
#endif
#define EXT extern
#ifdef INIT
#undef INIT
#endif
#define INIT(x)
#ifdef DOINIT
#undef DOINIT
#endif

118
INSTALL Normal file
View File

@ -0,0 +1,118 @@
This is a generic INSTALL file for utilities distributions.
If this package does not come with, e.g., installable documentation or
data files, please ignore the references to them below.
To compile this package:
1. Configure the package for your system. In the directory that this
file is in, type `./configure'. If you're using `csh' on an old
version of System V, you might need to type `sh configure' instead to
prevent `csh' from trying to execute `configure' itself.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation, and
creates the Makefile(s) (one in each subdirectory of the source
directory). In some packages it creates a C header file containing
system-dependent definitions. It also creates a file `config.status'
that you can run in the future to recreate the current configuration.
Running `configure' takes a minute or two. While it is running, it
prints some messages that tell what it is doing. If you don't want to
see the messages, run `configure' with its standard output redirected
to `/dev/null'; for example, `./configure >/dev/null'.
To compile the package in a different directory from the one
containing the source code, you must use a version of `make' that
supports the VPATH variable, such as GNU `make'. `cd' to the directory
where you want the object files and executables to go and run
`configure'. `configure' automatically checks for the source code in
the directory that `configure' is in and in `..'. If for some reason
`configure' is not in the source code directory that you are
configuring, then it will report that it can't find the source code.
In that case, run `configure' with the option `--srcdir=DIR', where
DIR is the directory that contains the source code.
By default, `make install' will install the package's files in
/usr/local/bin, /usr/local/lib, /usr/local/man, etc. You can specify an
installation prefix other than /usr/local by giving `configure' the option
`--prefix=PATH'. Alternately, you can do so by consistently giving a value
for the `prefix' variable when you run `make', e.g.,
make prefix=/usr/gnu
make prefix=/usr/gnu install
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If
you give `configure' the option `--exec-prefix=PATH' or set the
`make' variable `exec_prefix' to PATH, the package will use PATH as
the prefix for installing programs and libraries. Data files and
documentation will still use the regular prefix. Normally, all files
are installed using the regular prefix.
Another `configure' option is useful mainly in `Makefile' rules for
updating `config.status' and `Makefile'. The `--no-create' option
figures out the configuration for your system and records it in
`config.status', without actually configuring the package (creating
`Makefile's and perhaps a configuration header file). Later, you can
run `./config.status' to actually configure the package. You can also
give `config.status' the `--recheck' option, which makes it re-run
`configure' with the same arguments you used before. This option is
useful if you change `configure'.
Some packages pay attention to `--with-PACKAGE' options to `configure',
where PACKAGE is something like `gnu-libc' or `x' (for the X Window System).
The README should mention any --with- options that the package recognizes.
`configure' ignores any other arguments that you give it.
If your system requires unusual options for compilation or linking
that `configure' doesn't know about, you can give `configure' initial
values for some variables by setting them in the environment. In
Bourne-compatible shells, you can do that on the command line like
this:
CC='gcc -traditional' DEFS=-D_POSIX_SOURCE ./configure
The `make' variables that you might want to override with environment
variables when running `configure' are:
(For these variables, any value given in the environment overrides the
value that `configure' would choose:)
CC C compiler program.
Default is `cc', or `gcc' if `gcc' is in your PATH.
INSTALL Program to use to install files.
Default is `install' if you have it, `cp' otherwise.
(For these variables, any value given in the environment is added to
the value that `configure' chooses:)
DEFS Configuration options, in the form `-Dfoo -Dbar ...'
Do not use this variable in packages that create a
configuration header file.
LIBS Libraries to link with, in the form `-lfoo -lbar ...'
If you need to do unusual things to compile the package, we encourage
you to figure out how `configure' could check whether to do them, and
mail diffs or instructions to the address given in the README so we
can include them in the next release.
2. Type `make' to compile the package. If you want, you can override
the `make' variables CFLAGS and LDFLAGS like this:
make CFLAGS=-O2 LDFLAGS=-s
3. If the package comes with self-tests and you want to run them,
type `make check'. If you're not sure whether there are any, try it;
if `make' responds with something like
make: *** No way to make target `check'. Stop.
then the package does not come with self-tests.
4. Type `make install' to install programs, data files, and
documentation.
5. You can remove the program binaries and object files from the
source directory by typing `make clean'. To also remove the
Makefile(s), the header file containing system-dependent definitions
(if the package uses one), and `config.status' (all the files that
`configure' created), type `make distclean'.
The file `configure.in' is used as a template to create `configure' by
a program called `autoconf'. You will only need it if you want to
regenerate `configure' using a newer version of `autoconf'.

19
INTERN.h Normal file
View File

@ -0,0 +1,19 @@
/* $Header: INTERN.h,v 2.0 86/09/17 15:35:58 lwall Exp $
*
* $Log: INTERN.h,v $
* Revision 2.0 86/09/17 15:35:58 lwall
* Baseline for netwide release.
*
*/
#ifdef EXT
#undef EXT
#endif
#define EXT
#ifdef INIT
#undef INIT
#endif
#define INIT(x) = x
#define DOINIT

88
Makefile.in Normal file
View File

@ -0,0 +1,88 @@
# Makefile for GNU patch.
#### Start of system configuration section. ####
srcdir = @srcdir@
VPATH = @srcdir@
CC = @CC@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
LIBS = @LIBS@
CFLAGS = -g
LDFLAGS = -g
prefix = /usr/local
exec_prefix = $(prefix)
bindir = $(exec_prefix)/bin
# Where to put the manual pages.
mandir = $(prefix)/man/man1
# Extension (not including `.') for the manual page filenames.
manext = 1
#### End of system configuration section. ####
SHELL = /bin/sh
SRCS = backupfile.c getopt.c getopt1.c inp.c patch.c pch.c util.c \
version.c rename.c alloca.c
OBJS = backupfile.o getopt.o getopt1.o inp.o patch.o pch.o util.o \
version.o @LIBOBJS@ @ALLOCA@
HDRS = EXTERN.h INTERN.h backupfile.h common.h getopt.h \
inp.h patchlevel.h pch.h util.h version.h
MISC = COPYING ChangeLog INSTALL Makefile.in README NEWS \
configure configure.in config.h.in patch.man
DISTFILES = $(MISC) $(SRCS) $(HDRS)
all: patch
.c.o:
$(CC) -c -DHAVE_CONFIG_H -I. $(CPPFLAGS) $(CFLAGS) $<
patch: $(OBJS)
$(CC) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
install: all
$(INSTALL_PROGRAM) patch $(bindir)/patch
-$(INSTALL_DATA) $(srcdir)/patch.man $(mandir)/patch.$(manext)
uninstall:
rm -f $(bindir)/patch $(mandir)/patch.$(manext)
TAGS: $(SRCS)
etags $(SRCS)
clean:
rm -f patch *.o core
mostlyclean: clean
distclean: clean
rm -f Makefile config.status config.h
realclean: distclean
rm -f TAGS
dist: $(DISTFILES)
echo patch-`sed -e '/PATCH_VERSION/!d' -e 's/[^0-9]*\([0-9a-z.]*\).*/\1/' -e q patchlevel.h` > .fname
rm -rf `cat .fname`
mkdir `cat .fname`
ln $(DISTFILES) `cat .fname`
tar -chf - `cat .fname` | gzip >`cat .fname`.tar.gz
rm -rf `cat .fname` .fname
backupfile.o: config.h backupfile.h
getopt.o getopt1.o: config.h getopt.h
inp.o: config.h common.h inp.h util.h EXTERN.h INTERN.h pch.h
patch.o: config.h common.h inp.h pch.h util.h version.h backupfile.h \
INTERN.h EXTERN.h getopt.h
pch.o: config.h common.h pch.h util.h EXTERN.h INTERN.h
util.o: config.h common.h util.h backupfile.h EXTERN.h INTERN.h
version.o: config.h common.h version.h patchlevel.h util.h \
EXTERN.h INTERN.h

18
NEWS Normal file
View File

@ -0,0 +1,18 @@
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.

45
README Normal file
View File

@ -0,0 +1,45 @@
This version of patch contains modifications made by the Free Software
Foundation, summarized in the file ChangeLog. Primarily they are to
support the unified context diff format that GNU diff can produce, to
support making GNU Emacs-style backup files, and to support the GNU
conventions for option parsing and configuring and compilation. They
also include fixes for some bugs.
The FSF 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. I have heard that he has been too busy working on
other things, like Perl.
Here is a wish list of some projects to improve patch:
1. Correctly handle files and patchfiles that contain NUL characters.
This is hard to do straightforwardly; it would be less work to
adopt a kind of escape encoding internally.
Let ESC be a "control prefix". ESC @ stands for NUL. ESC [ stands for ESC.
You need to crunch this when reading input (replace fgets),
and when writing the output file (replace fputs),
but otherwise everything can go along as it does now.
Be careful to handle reject files correctly;
I think they are currently created using `write', not `fputs'.
2. Correctly handle patches produced by GNU diff for files that do
not end with a newline.
Please send bug reports for this version of patch to
bug-gnu-utils@prep.ai.mit.edu as well as to Larry Wall (lwall@netlabs.com).
--djm@gnu.ai.mit.edu (David MacKenzie)
Patch Kit, Version 2.0
Copyright (c) 1988, Larry Wall
You may copy the patch kit in whole or in part as long as you don't try to
make money off it, or pretend that you wrote it.
--------------------------------------------------------------------------
See the file INSTALL for compilation and installation instructions for Unix.
For non-Unix systems, copy config.h.in 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 appropriate for your system.

475
alloca.c Normal file
View File

@ -0,0 +1,475 @@
/* alloca.c -- allocate automatically reclaimed memory
(Mostly) portable public-domain implementation -- D A Gwyn
This implementation of the PWB library alloca function,
which is used to allocate space off the run-time stack so
that it is automatically reclaimed upon procedure exit,
was inspired by discussions with J. Q. Johnson of Cornell.
J.Otto Tennant <jot@cray.com> contributed the Cray support.
There are some preprocessor constants that can
be defined when compiling for your specific system, for
improved efficiency; however, the defaults should be okay.
The general concept of this implementation is to keep
track of all alloca-allocated blocks, and reclaim any
that are found to be deeper in the stack than the current
invocation. This heuristic does not reclaim storage as
soon as it becomes invalid, but it will do so eventually.
As a special case, alloca(0) reclaims storage without
allocating any. It is a good idea to use alloca(0) in
your main control loop, etc. to force garbage collection. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* If compiling with GCC, this file's not needed. */
#ifndef alloca
#ifdef emacs
#ifdef static
/* actually, only want this if static is defined as ""
-- this is for usg, in which emacs must undefine static
in order to make unexec workable
*/
#ifndef STACK_DIRECTION
you
lose
-- must know STACK_DIRECTION at compile-time
#endif /* STACK_DIRECTION undefined */
#endif /* static */
#endif /* emacs */
/* If your stack is a linked list of frames, you have to
provide an "address metric" ADDRESS_FUNCTION macro. */
#ifdef CRAY
long i00afunc ();
#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
#else
#define ADDRESS_FUNCTION(arg) &(arg)
#endif
#if __STDC__
typedef void *pointer;
#else
typedef char *pointer;
#endif
#define NULL 0
/* Different portions of Emacs need to call different versions of
malloc. The Emacs executable needs alloca to call xmalloc, because
ordinary malloc isn't protected from input signals. On the other
hand, the utilities in lib-src need alloca to call malloc; some of
them are very simple, and don't have an xmalloc routine.
Non-Emacs programs expect this to call use xmalloc.
Callers below should use malloc. */
#ifndef emacs
#define malloc xmalloc
extern pointer xmalloc ();
#endif
/* Define STACK_DIRECTION if you know the direction of stack
growth for your system; otherwise it will be automatically
deduced at run-time.
STACK_DIRECTION > 0 => grows toward higher addresses
STACK_DIRECTION < 0 => grows toward lower addresses
STACK_DIRECTION = 0 => direction of growth unknown */
#ifndef STACK_DIRECTION
#define STACK_DIRECTION 0 /* Direction unknown. */
#endif
#if STACK_DIRECTION != 0
#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
#else /* STACK_DIRECTION == 0; need run-time code. */
static int stack_dir; /* 1 or -1 once known. */
#define STACK_DIR stack_dir
static void
find_stack_direction ()
{
static char *addr = NULL; /* Address of first `dummy', once known. */
auto char dummy; /* To get stack address. */
if (addr == NULL)
{ /* Initial entry. */
addr = ADDRESS_FUNCTION (dummy);
find_stack_direction (); /* Recurse once. */
}
else
{
/* Second entry. */
if (ADDRESS_FUNCTION (dummy) > addr)
stack_dir = 1; /* Stack grew upward. */
else
stack_dir = -1; /* Stack grew downward. */
}
}
#endif /* STACK_DIRECTION == 0 */
/* An "alloca header" is used to:
(a) chain together all alloca'ed blocks;
(b) keep track of stack depth.
It is very important that sizeof(header) agree with malloc
alignment chunk size. The following default should work okay. */
#ifndef ALIGN_SIZE
#define ALIGN_SIZE sizeof(double)
#endif
typedef union hdr
{
char align[ALIGN_SIZE]; /* To force sizeof(header). */
struct
{
union hdr *next; /* For chaining headers. */
char *deep; /* For stack depth measure. */
} h;
} header;
static header *last_alloca_header = NULL; /* -> last alloca header. */
/* Return a pointer to at least SIZE bytes of storage,
which will be automatically reclaimed upon exit from
the procedure that called alloca. Originally, this space
was supposed to be taken from the current stack frame of the
caller, but that method cannot be made to work for some
implementations of C, for example under Gould's UTX/32. */
pointer
alloca (size)
unsigned size;
{
auto char probe; /* Probes stack depth: */
register char *depth = ADDRESS_FUNCTION (probe);
#if STACK_DIRECTION == 0
if (STACK_DIR == 0) /* Unknown growth direction. */
find_stack_direction ();
#endif
/* Reclaim garbage, defined as all alloca'd storage that
was allocated from deeper in the stack than currently. */
{
register header *hp; /* Traverses linked list. */
for (hp = last_alloca_header; hp != NULL;)
if ((STACK_DIR > 0 && hp->h.deep > depth)
|| (STACK_DIR < 0 && hp->h.deep < depth))
{
register header *np = hp->h.next;
free ((pointer) hp); /* Collect garbage. */
hp = np; /* -> next header. */
}
else
break; /* Rest are not deeper. */
last_alloca_header = hp; /* -> last valid storage. */
}
if (size == 0)
return NULL; /* No allocation required. */
/* Allocate combined header + user data storage. */
{
register pointer new = malloc (sizeof (header) + size);
/* Address of header. */
((header *) new)->h.next = last_alloca_header;
((header *) new)->h.deep = depth;
last_alloca_header = (header *) new;
/* User storage begins just after header. */
return (pointer) ((char *) new + sizeof (header));
}
}
#ifdef CRAY
#ifdef DEBUG_I00AFUNC
#include <stdio.h>
#endif
#ifndef CRAY_STACK
#define CRAY_STACK
#ifndef CRAY2
/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
struct stack_control_header
{
long shgrow:32; /* Number of times stack has grown. */
long shaseg:32; /* Size of increments to stack. */
long shhwm:32; /* High water mark of stack. */
long shsize:32; /* Current size of stack (all segments). */
};
/* The stack segment linkage control information occurs at
the high-address end of a stack segment. (The stack
grows from low addresses to high addresses.) The initial
part of the stack segment linkage control information is
0200 (octal) words. This provides for register storage
for the routine which overflows the stack. */
struct stack_segment_linkage
{
long ss[0200]; /* 0200 overflow words. */
long sssize:32; /* Number of words in this segment. */
long ssbase:32; /* Offset to stack base. */
long:32;
long sspseg:32; /* Offset to linkage control of previous
segment of stack. */
long:32;
long sstcpt:32; /* Pointer to task common address block. */
long sscsnm; /* Private control structure number for
microtasking. */
long ssusr1; /* Reserved for user. */
long ssusr2; /* Reserved for user. */
long sstpid; /* Process ID for pid based multi-tasking. */
long ssgvup; /* Pointer to multitasking thread giveup. */
long sscray[7]; /* Reserved for Cray Research. */
long ssa0;
long ssa1;
long ssa2;
long ssa3;
long ssa4;
long ssa5;
long ssa6;
long ssa7;
long sss0;
long sss1;
long sss2;
long sss3;
long sss4;
long sss5;
long sss6;
long sss7;
};
#else /* CRAY2 */
/* The following structure defines the vector of words
returned by the STKSTAT library routine. */
struct stk_stat
{
long now; /* Current total stack size. */
long maxc; /* Amount of contiguous space which would
be required to satisfy the maximum
stack demand to date. */
long high_water; /* Stack high-water mark. */
long overflows; /* Number of stack overflow ($STKOFEN) calls. */
long hits; /* Number of internal buffer hits. */
long extends; /* Number of block extensions. */
long stko_mallocs; /* Block allocations by $STKOFEN. */
long underflows; /* Number of stack underflow calls ($STKRETN). */
long stko_free; /* Number of deallocations by $STKRETN. */
long stkm_free; /* Number of deallocations by $STKMRET. */
long segments; /* Current number of stack segments. */
long maxs; /* Maximum number of stack segments so far. */
long pad_size; /* Stack pad size. */
long current_address; /* Current stack segment address. */
long current_size; /* Current stack segment size. This
number is actually corrupted by STKSTAT to
include the fifteen word trailer area. */
long initial_address; /* Address of initial segment. */
long initial_size; /* Size of initial segment. */
};
/* The following structure describes the data structure which trails
any stack segment. I think that the description in 'asdef' is
out of date. I only describe the parts that I am sure about. */
struct stk_trailer
{
long this_address; /* Address of this block. */
long this_size; /* Size of this block (does not include
this trailer). */
long unknown2;
long unknown3;
long link; /* Address of trailer block of previous
segment. */
long unknown5;
long unknown6;
long unknown7;
long unknown8;
long unknown9;
long unknown10;
long unknown11;
long unknown12;
long unknown13;
long unknown14;
};
#endif /* CRAY2 */
#endif /* not CRAY_STACK */
#ifdef CRAY2
/* Determine a "stack measure" for an arbitrary ADDRESS.
I doubt that "lint" will like this much. */
static long
i00afunc (long *address)
{
struct stk_stat status;
struct stk_trailer *trailer;
long *block, size;
long result = 0;
/* We want to iterate through all of the segments. The first
step is to get the stack status structure. We could do this
more quickly and more directly, perhaps, by referencing the
$LM00 common block, but I know that this works. */
STKSTAT (&status);
/* Set up the iteration. */
trailer = (struct stk_trailer *) (status.current_address
+ status.current_size
- 15);
/* There must be at least one stack segment. Therefore it is
a fatal error if "trailer" is null. */
if (trailer == 0)
abort ();
/* Discard segments that do not contain our argument address. */
while (trailer != 0)
{
block = (long *) trailer->this_address;
size = trailer->this_size;
if (block == 0 || size == 0)
abort ();
trailer = (struct stk_trailer *) trailer->link;
if ((block <= address) && (address < (block + size)))
break;
}
/* Set the result to the offset in this segment and add the sizes
of all predecessor segments. */
result = address - block;
if (trailer == 0)
{
return result;
}
do
{
if (trailer->this_size <= 0)
abort ();
result += trailer->this_size;
trailer = (struct stk_trailer *) trailer->link;
}
while (trailer != 0);
/* We are done. Note that if you present a bogus address (one
not in any segment), you will get a different number back, formed
from subtracting the address of the first block. This is probably
not what you want. */
return (result);
}
#else /* not CRAY2 */
/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
Determine the number of the cell within the stack,
given the address of the cell. The purpose of this
routine is to linearize, in some sense, stack addresses
for alloca. */
static long
i00afunc (long address)
{
long stkl = 0;
long size, pseg, this_segment, stack;
long result = 0;
struct stack_segment_linkage *ssptr;
/* Register B67 contains the address of the end of the
current stack segment. If you (as a subprogram) store
your registers on the stack and find that you are past
the contents of B67, you have overflowed the segment.
B67 also points to the stack segment linkage control
area, which is what we are really interested in. */
stkl = CRAY_STACKSEG_END ();
ssptr = (struct stack_segment_linkage *) stkl;
/* If one subtracts 'size' from the end of the segment,
one has the address of the first word of the segment.
If this is not the first segment, 'pseg' will be
nonzero. */
pseg = ssptr->sspseg;
size = ssptr->sssize;
this_segment = stkl - size;
/* It is possible that calling this routine itself caused
a stack overflow. Discard stack segments which do not
contain the target address. */
while (!(this_segment <= address && address <= stkl))
{
#ifdef DEBUG_I00AFUNC
fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
#endif
if (pseg == 0)
break;
stkl = stkl - pseg;
ssptr = (struct stack_segment_linkage *) stkl;
size = ssptr->sssize;
pseg = ssptr->sspseg;
this_segment = stkl - size;
}
result = address - this_segment;
/* If you subtract pseg from the current end of the stack,
you get the address of the previous stack segment's end.
This seems a little convoluted to me, but I'll bet you save
a cycle somewhere. */
while (pseg != 0)
{
#ifdef DEBUG_I00AFUNC
fprintf (stderr, "%011o %011o\n", pseg, size);
#endif
stkl = stkl - pseg;
ssptr = (struct stack_segment_linkage *) stkl;
size = ssptr->sssize;
pseg = ssptr->sspseg;
result += size;
}
return (result);
}
#endif /* not CRAY2 */
#endif /* CRAY */
#endif /* no alloca */

402
backupfile.c Normal file
View File

@ -0,0 +1,402 @@
/* backupfile.c -- make Emacs style backup file names
Copyright (C) 1990, 1991, 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by David MacKenzie <djm@gnu.ai.mit.edu>.
Some algorithms adapted from GNU Emacs. */
#include "config.h"
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include "backupfile.h"
#ifdef STDC_HEADERS
#include <string.h>
#include <stdlib.h>
#else
char *malloc ();
#endif
#if defined (HAVE_UNISTD_H)
#include <unistd.h>
#endif
#if defined(DIRENT) || defined(_POSIX_VERSION)
#include <dirent.h>
#define NLENGTH(direct) (strlen((direct)->d_name))
#else /* not (DIRENT or _POSIX_VERSION) */
#define dirent direct
#define NLENGTH(direct) ((direct)->d_namlen)
#ifdef SYSNDIR
#include <sys/ndir.h>
#endif /* SYSNDIR */
#ifdef SYSDIR
#include <sys/dir.h>
#endif /* SYSDIR */
#ifdef NDIR
#include <ndir.h>
#endif /* NDIR */
#endif /* DIRENT or _POSIX_VERSION */
#ifndef isascii
#define ISDIGIT(c) (isdigit ((unsigned char) (c)))
#else
#define ISDIGIT(c) (isascii (c) && isdigit (c))
#endif
#if defined (_POSIX_VERSION)
/* POSIX does not require that the d_ino field be present, and some
systems do not provide it. */
#define REAL_DIR_ENTRY(dp) 1
#else
#define REAL_DIR_ENTRY(dp) ((dp)->d_ino != 0)
#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. */
char *simple_backup_suffix = "~";
char *basename ();
char *dirname ();
static char *concat ();
char *find_backup_file_name ();
static char *make_version_name ();
static int max_backup_version ();
static int version_number ();
/* Return NAME with any leading path stripped off. */
char *
basename (name)
char *name;
{
char *r = name, *p = name;
while (*p)
if (*p++ == '/')
r = p;
return r;
}
#ifndef NODIR
/* Return the name of the new backup file for file FILE,
allocated with malloc. Return 0 if out of memory.
FILE must not end with a '/' unless it is the root directory.
Do not call this function if backup_type == none. */
char *
find_backup_file_name (file)
char *file;
{
char *dir;
char *base_versions;
int highest_backup;
if (backup_type == simple)
{
char *s = malloc (strlen (file) + strlen (simple_backup_suffix) + 1);
strcpy (s, file);
addext (s, simple_backup_suffix, '~');
return s;
}
base_versions = concat (basename (file), ".~");
if (base_versions == 0)
return 0;
dir = dirname (file);
if (dir == 0)
{
free (base_versions);
return 0;
}
highest_backup = max_backup_version (base_versions, dir);
free (base_versions);
free (dir);
if (backup_type == numbered_existing && highest_backup == 0)
return concat (file, simple_backup_suffix);
return make_version_name (file, highest_backup + 1);
}
/* 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.
FILE should already have ".~" appended to it. */
static int
max_backup_version (file, dir)
char *file, *dir;
{
DIR *dirp;
struct dirent *dp;
int highest_version;
int this_version;
int 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)
continue;
this_version = version_number (file, dp->d_name, file_name_length);
if (this_version > highest_version)
highest_version = this_version;
}
closedir (dirp);
return highest_version;
}
/* Return a string, allocated with malloc, containing
"FILE.~VERSION~". Return 0 if out of memory. */
static char *
make_version_name (file, version)
char *file;
int version;
{
char *backup_name;
backup_name = malloc (strlen (file) + 16);
if (backup_name == 0)
return 0;
sprintf (backup_name, "%s.~%d~", file, version);
return backup_name;
}
/* If BACKUP is a numbered backup of BASE, return its version number;
otherwise return 0. BASE_LENGTH is the length of BASE.
BASE should already have ".~" appended to it. */
static int
version_number (base, backup, base_length)
char *base;
char *backup;
int base_length;
{
int version;
char *p;
version = 0;
if (!strncmp (base, backup, base_length) && ISDIGIT (backup[base_length]))
{
for (p = &backup[base_length]; ISDIGIT (*p); ++p)
version = version * 10 + *p - '0';
if (p[0] != '~' || p[1])
version = 0;
}
return version;
}
/* Return the newly-allocated concatenation of STR1 and STR2.
If out of memory, return 0. */
static char *
concat (str1, str2)
char *str1, *str2;
{
char *newstr;
char str1_length = strlen (str1);
newstr = malloc (str1_length + strlen (str2) + 1);
if (newstr == 0)
return 0;
strcpy (newstr, str1);
strcpy (newstr + str1_length, str2);
return newstr;
}
/* Return the leading directories part of PATH,
allocated with malloc. If out of memory, return 0.
Assumes that trailing slashes have already been
removed. */
char *
dirname (path)
char *path;
{
char *newpath;
char *slash;
int length; /* Length of result, not including NUL. */
slash = basename (path);
if (slash == path)
{
/* File is in the current directory. */
path = ".";
length = 1;
}
else
{
/* Remove any trailing slashes from result. */
while (*--slash == '/' && slash > path)
;
length = slash - path + 1;
}
newpath = malloc (length + 1);
if (newpath == 0)
return 0;
strncpy (newpath, path, length);
newpath[length] = 0;
return newpath;
}
/* 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)
char *arg;
char **optlist;
{
int i; /* Temporary index in OPTLIST. */
int 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)
char *kind;
char *value;
int problem;
{
fprintf (stderr, "patch: ");
if (problem == -1)
fprintf (stderr, "invalid");
else /* Assume -2. */
fprintf (stderr, "ambiguous");
fprintf (stderr, " %s `%s'\n", kind, value);
}
static char *backup_args[] =
{
"never", "simple", "nil", "existing", "t", "numbered", 0
};
static 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)
char *version;
{
int i;
if (version == 0 || *version == 0)
return numbered_existing;
i = argmatch (version, backup_args);
if (i >= 0)
return backup_types[i];
invalid_arg ("version control type", version, i);
exit (1);
}
#endif /* NODIR */
/* 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, *ext;
int e;
{
char *s = basename (filename);
int slen = strlen (s), extlen = strlen (ext);
long slen_max = -1;
#if HAVE_PATHCONF && defined (_PC_NAME_MAX)
#ifndef _POSIX_NAME_MAX
#define _POSIX_NAME_MAX 14
#endif
if (slen + extlen <= _POSIX_NAME_MAX)
/* 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 == -1) {
#if HAVE_LONG_FILE_NAMES
slen_max = 255;
#else
slen_max = 14;
#endif
}
if (slen + extlen <= slen_max)
strcpy (s + slen, ext);
else
{
if (slen_max <= slen) {
/* Try to preserve difference between .h .c etc. */
if (slen == slen_max && s[slen - 2] == '.')
s[slen - 2] = s[slen - 1];
slen = slen_max - 1;
}
s[slen] = e;
s[slen + 1] = 0;
}
}

46
backupfile.h Normal file
View File

@ -0,0 +1,46 @@
/* backupfile.h -- declarations for making Emacs style backup file names
Copyright (C) 1990, 1991, 1992 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., 675 Mass Ave, Cambridge, MA 02139, 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 *simple_backup_suffix;
#ifdef __STDC__
char *find_backup_file_name (char *file);
enum backup_type get_version (char *version);
void addext (char *, char *, int);
#else
char *find_backup_file_name ();
enum backup_type get_version ();
void addext ();
#endif

190
common.h Normal file
View File

@ -0,0 +1,190 @@
/* $Header: common.h,v 2.0.1.2 88/06/22 20:44:53 lwall Locked $
*
* $Log: common.h,v $
* Revision 2.0.1.2 88/06/22 20:44:53 lwall
* patch12: sprintf was declared wrong
*
* Revision 2.0.1.1 88/06/03 15:01:56 lwall
* patch10: support for shorter extensions.
*
* Revision 2.0 86/09/17 15:36:39 lwall
* Baseline for netwide release.
*
*/
#define DEBUGGING
#define VOIDUSED 7
#include "config.h"
/* shut lint up about the following when return value ignored */
#define Signal (void)signal
#define Unlink (void)unlink
#define Lseek (void)lseek
#define Fseek (void)fseek
#define Fstat (void)fstat
#define Pclose (void)pclose
#define Close (void)close
#define Fclose (void)fclose
#define Fflush (void)fflush
#define Sprintf (void)sprintf
#define Mktemp (void)mktemp
#define Strcpy (void)strcpy
#define Strcat (void)strcat
/* NeXT declares malloc and realloc incompatibly from us in some of
these files. Temporarily redefine them to prevent errors. */
#define malloc system_malloc
#define realloc system_realloc
#include <stdio.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <signal.h>
#undef malloc
#undef realloc
/* constants */
/* AIX predefines these. */
#ifdef TRUE
#undef TRUE
#endif
#ifdef FALSE
#undef FALSE
#endif
#define TRUE (1)
#define FALSE (0)
#define MAXHUNKSIZE 100000 /* is this enough lines? */
#define INITHUNKMAX 125 /* initial dynamic allocation size */
#define MAXLINELEN 1024
#define BUFFERSIZE 1024
#define SCCSPREFIX "s."
#define GET "get %s"
#define GET_LOCKED "get -e %s"
#define SCCSDIFF "get -p %s | diff - %s >/dev/null"
#define RCSSUFFIX ",v"
#define CHECKOUT "co %s"
#define CHECKOUT_LOCKED "co -l %s"
#define RCSDIFF "rcsdiff %s > /dev/null"
/* handy definitions */
#define Null(t) ((t)0)
#define Nullch Null(char *)
#define Nullfp Null(FILE *)
#define Nulline Null(LINENUM)
#define Ctl(ch) ((ch) & 037)
#define strNE(s1,s2) (strcmp(s1, s2))
#define strEQ(s1,s2) (!strcmp(s1, s2))
#define strnNE(s1,s2,l) (strncmp(s1, s2, l))
#define strnEQ(s1,s2,l) (!strncmp(s1, s2, l))
/* typedefs */
typedef char bool;
typedef long LINENUM; /* must be signed */
typedef unsigned MEM; /* what to feed malloc */
/* globals */
EXT int Argc; /* guess */
EXT char **Argv;
EXT int optind_last; /* for restarting plan_b */
EXT struct stat filestat; /* file statistics area */
EXT int filemode INIT(0644);
EXT char buf[MAXLINELEN]; /* general purpose buffer */
EXT FILE *ofp INIT(Nullfp); /* output file pointer */
EXT FILE *rejfp INIT(Nullfp); /* reject file pointer */
EXT int myuid; /* cache getuid return value */
EXT bool using_plan_a INIT(TRUE); /* try to keep everything in memory */
EXT bool out_of_mem INIT(FALSE); /* ran out of memory in plan a */
#define MAXFILEC 2
EXT int filec INIT(0); /* how many file arguments? */
EXT char *filearg[MAXFILEC];
EXT bool ok_to_create_file INIT(FALSE);
EXT char *bestguess INIT(Nullch); /* guess at correct filename */
EXT char *outname INIT(Nullch);
EXT char rejname[128];
EXT char *origprae INIT(Nullch);
EXT char *TMPOUTNAME;
EXT char *TMPINNAME;
EXT char *TMPREJNAME;
EXT char *TMPPATNAME;
EXT bool toutkeep INIT(FALSE);
EXT bool trejkeep INIT(FALSE);
EXT LINENUM last_offset INIT(0);
#ifdef DEBUGGING
EXT int debug INIT(0);
#endif
EXT LINENUM maxfuzz INIT(2);
EXT bool force INIT(FALSE);
EXT bool batch INIT(FALSE);
EXT bool verbose INIT(TRUE);
EXT bool reverse INIT(FALSE);
EXT bool noreverse INIT(FALSE);
EXT bool skip_rest_of_patch INIT(FALSE);
EXT int strippath INIT(957);
EXT bool canonicalize INIT(FALSE);
#define CONTEXT_DIFF 1
#define NORMAL_DIFF 2
#define ED_DIFF 3
#define NEW_CONTEXT_DIFF 4
#define UNI_DIFF 5
EXT int diff_type INIT(0);
EXT bool do_defines INIT(FALSE); /* patch using ifdef, ifndef, etc. */
EXT char if_defined[128]; /* #ifdef xyzzy */
EXT char not_defined[128]; /* #ifndef xyzzy */
EXT char else_defined[] INIT("#else\n");/* #else */
EXT char end_defined[128]; /* #endif xyzzy */
EXT char *revision INIT(Nullch); /* prerequisite revision, if any */
#include <errno.h>
#ifdef STDC_HEADERS
#include <stdlib.h>
#include <string.h>
#else
extern int errno;
FILE *popen();
char *malloc();
char *realloc();
long atol();
char *getenv();
char *strcpy();
char *strcat();
#endif
char *mktemp();
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#else
long lseek();
#endif
#if defined(_POSIX_VERSION) || defined(HAVE_FCNTL_H)
#include <fcntl.h>
#endif
#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

80
config.h.in Normal file
View File

@ -0,0 +1,80 @@
/* Portability variables. -*- C -*- */
/* Define if the system does not support the `const' keyword. */
#undef const
/* Define if the system supports file names longer than 14 characters. */
#undef HAVE_LONG_FILE_NAMES
/* Define if the system has pathconf(). */
#undef HAVE_PATHCONF
/* Define if the system has strerror(). */
#undef HAVE_STRERROR
/* Define if the system has ANSI C header files and library functions. */
#undef STDC_HEADERS
/* Define if the system uses strchr instead of index
and strrchr instead of rindex. */
#undef HAVE_STRING_H
#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
#define index strchr
#define rindex strrchr
#endif
/* Define if the system has unistd.h. */
#undef HAVE_UNISTD_H
/* Define if the system has fcntl.h. */
#undef HAVE_FCNTL_H
/* Define as either int or void -- the type that signal handlers return. */
#undef RETSIGTYPE
#ifndef RETSIGTYPE
#define RETSIGTYPE void
#endif
/* Which directory library header to use. */
#undef DIRENT /* dirent.h */
#undef SYSNDIR /* sys/ndir.h */
#undef SYSDIR /* sys/dir.h */
#undef NDIR /* ndir.h */
#undef NODIR /* none -- don't make numbered backup files */
/* Define if the system lets you pass fewer arguments to a function
than the function actually accepts (in the absence of a prototype).
Defining it makes I/O calls slightly more efficient.
You need not bother defining it unless your C preprocessor chokes on
multi-line arguments to macros. */
#undef CANVARARG
/* Define Reg* as either `register' or nothing, depending on whether
the C compiler pays attention to this many register declarations.
The intent is that you don't have to order your register declarations
in the order of importance, so you can freely declare register variables
in sub-blocks of code and as function parameters.
Do not use Reg<n> more than once per routine.
These don't really matter a lot, since most modern C compilers ignore
register declarations and often do a better job of allocating
registers than people do. */
#define Reg1 register
#define Reg2 register
#define Reg3 register
#define Reg4 register
#define Reg5 register
#define Reg6 register
#define Reg7
#define Reg8
#define Reg9
#define Reg10
#define Reg11
#define Reg12
#define Reg13
#define Reg14
#define Reg15
#define Reg16

1125
configure vendored Executable file

File diff suppressed because it is too large Load Diff

24
configure.in Normal file
View File

@ -0,0 +1,24 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT(patch.c)
AC_CONFIG_HEADER(config.h)
AC_PROG_CC
AC_PROG_CPP
AC_AIX
AC_MINIX
AC_ISC_POSIX
AC_CONST
AC_PROG_INSTALL
AC_DIR_HEADER
if test -z "$dirheader"; then
AC_DEFINE(NODIR)
fi
AC_RETSIGTYPE
AC_STDC_HEADERS
AC_UNISTD_H
AC_HAVE_HEADERS(string.h fcntl.h)
AC_REPLACE_FUNCS(rename)
AC_HAVE_FUNCS(pathconf strerror)
AC_ALLOCA
AC_LONG_FILE_NAMES
AC_XENIX_DIR
AC_OUTPUT(Makefile)

731
getopt.c Normal file
View File

@ -0,0 +1,731 @@
/* 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, 1993
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, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* NOTE!!! AIX requires this to be the first thing in the file.
Do not put ANYTHING before it! */
#if !defined (__GNUC__) && defined (_AIX)
#pragma alloca
#endif
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef __GNUC__
#define alloca __builtin_alloca
#else /* not __GNUC__ */
#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
#include <alloca.h>
#else
#ifndef _AIX
char *alloca ();
#endif
#endif /* alloca.h */
#endif /* not __GNUC__ */
#if !__STDC__ && !defined(const) && IN_GCC
#define const
#endif
/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */
#ifndef _NO_PROTO
#define _NO_PROTO
#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. */
#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
#undef alloca
/* Don't include stdlib.h for non-GNU C libraries because some of them
contain conflicting prototypes for getopt. */
#include <stdlib.h>
#else /* Not GNU C library. */
#define __alloca alloca
#endif /* GNU C library. */
/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
long-named option. Because this is not POSIX.2 compliant, it is
being phased out. */
/* #define GETOPT_COMPAT */
/* 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 = 0;
/* 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 EOF, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
/* XXX 1003.2 says this must be 1 before any call. */
int optind = 0;
/* 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 EOF with `optind' != ARGC. */
static enum
{
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
} ordering;
#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
#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n))
#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;
}
static void
my_bcopy (from, to, size)
const char *from;
char *to;
int size;
{
int i;
for (i = 0; i < size; i++)
to[i] = from[i];
}
#endif /* GNU C 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;
/* 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. */
static void
exchange (argv)
char **argv;
{
int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
char **temp = (char **) __alloca (nonopts_size);
/* Interchange the two blocks of data in ARGV. */
my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size);
my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt],
(optind - last_nonopt) * sizeof (char *));
my_bcopy ((char *) temp,
(char *) &argv[first_nonopt + optind - last_nonopt],
nonopts_size);
/* Update records for the slots the non-options now occupy. */
first_nonopt += (optind - last_nonopt);
last_nonopt = optind;
}
/* 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 `EOF'.
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;
{
int option_index;
optarg = 0;
/* Initialize the internal data when the first call is made.
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. */
if (optind == 0)
{
first_nonopt = last_nonopt = optind = 1;
nextchar = NULL;
/* 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 (getenv ("POSIXLY_CORRECT") != NULL)
ordering = REQUIRE_ORDER;
else
ordering = PERMUTE;
}
if (nextchar == NULL || *nextchar == '\0')
{
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;
/* Now skip any additional non-options
and extend the range of non-options previously skipped. */
while (optind < argc
&& (argv[optind][0] != '-' || argv[optind][1] == '\0')
#ifdef GETOPT_COMPAT
&& (longopts == NULL
|| argv[optind][0] != '+' || argv[optind][1] == '\0')
#endif /* GETOPT_COMPAT */
)
optind++;
last_nonopt = optind;
}
/* 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 EOF;
}
/* 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 ((argv[optind][0] != '-' || argv[optind][1] == '\0')
#ifdef GETOPT_COMPAT
&& (longopts == NULL
|| argv[optind][0] != '+' || argv[optind][1] == '\0')
#endif /* GETOPT_COMPAT */
)
{
if (ordering == REQUIRE_ORDER)
return EOF;
optarg = argv[optind++];
return 1;
}
/* We have found another option-ARGV-element.
Start decoding its characters. */
nextchar = (argv[optind] + 1
+ (longopts != NULL && argv[optind][1] == '-'));
}
if (longopts != NULL
&& ((argv[optind][0] == '-'
&& (argv[optind][1] == '-' || long_only))
#ifdef GETOPT_COMPAT
|| argv[optind][0] == '+'
#endif /* GETOPT_COMPAT */
))
{
const struct option *p;
char *s = nextchar;
int exact = 0;
int ambig = 0;
const struct option *pfound = NULL;
int indfound;
while (*s && *s != '=')
s++;
/* Test all options for either exact match or abbreviated matches. */
for (p = longopts, option_index = 0; p->name;
p++, option_index++)
if (!strncmp (p->name, nextchar, s - nextchar))
{
if (s - 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 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++;
return '?';
}
if (pfound != NULL)
{
option_index = indfound;
optind++;
if (*s)
{
/* Don't test has_arg with >, because some C compilers don't
allow it to be used on enums. */
if (pfound->has_arg)
optarg = s + 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);
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;
}
/* 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] == '-'
#ifdef GETOPT_COMPAT
|| argv[optind][0] == '+'
#endif /* GETOPT_COMPAT */
|| 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++;
return '?';
}
}
/* Look at and handle the next 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 0
if (c < 040 || c >= 0177)
fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
argv[0], c);
else
fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
#else
/* 1003.2 specifies the format of this message. */
fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
#endif
}
optopt = c;
return '?';
}
if (temp[1] == ':')
{
if (temp[2] == ':')
{
/* This is an option that accepts an argument optionally. */
if (*nextchar != '\0')
{
optarg = nextchar;
optind++;
}
else
optarg = 0;
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)
{
#if 0
fprintf (stderr, "%s: option `-%c' requires an argument\n",
argv[0], c);
#else
/* 1003.2 specifies the format of this message. */
fprintf (stderr, "%s: option requires an argument -- %c\n",
argv[0], c);
#endif
}
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 /* _LIBC or not __GNU_LIBRARY__. */
#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 == EOF)
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 */

129
getopt.h Normal file
View File

@ -0,0 +1,129 @@
/* Declarations for getopt.
Copyright (C) 1989, 1990, 1991, 1992, 1993 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, 675 Mass Ave, Cambridge, MA 02139, 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 EOF, 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 __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 __STDC__
#if defined(__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 /* not __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 /* not __STDC__ */
#ifdef __cplusplus
}
#endif
#endif /* _GETOPT_H */

176
getopt1.c Normal file
View File

@ -0,0 +1,176 @@
/* getopt_long and getopt_long_only entry points for GNU getopt.
Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
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, 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "getopt.h"
#if !__STDC__ && !defined(const) && IN_GCC
#define const
#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. */
#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
#include <stdlib.h>
#else
char *getenv ();
#endif
#ifndef NULL
#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 /* _LIBC or not __GNU_LIBRARY__. */
#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 == EOF)
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 */

369
inp.c Normal file
View File

@ -0,0 +1,369 @@
/* $Header: inp.c,v 2.0.1.1 88/06/03 15:06:13 lwall Locked $
*
* $Log: inp.c,v $
* Revision 2.0.1.1 88/06/03 15:06:13 lwall
* patch10: made a little smarter about sccs files
*
* Revision 2.0 86/09/17 15:37:02 lwall
* Baseline for netwide release.
*
*/
#include "EXTERN.h"
#include "common.h"
#include "util.h"
#include "pch.h"
#include "INTERN.h"
#include "inp.h"
/* Input-file-with-indexable-lines abstract type */
static long i_size; /* size of the input file */
static char *i_womp; /* plan a buffer for entire file */
static char **i_ptr; /* pointers to lines in i_womp */
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 int tireclen; /* length of records in tmp file */
/* New patch--prepare to edit another file. */
void
re_input()
{
if (using_plan_a) {
i_size = 0;
#ifndef lint
if (i_ptr != Null(char**))
free((char *)i_ptr);
#endif
if (i_womp != Nullch)
free(i_womp);
i_womp = Nullch;
i_ptr = Null(char **);
}
else {
using_plan_a = TRUE; /* maybe the next one is smaller */
Close(tifd);
tifd = -1;
free(tibuf[0]);
free(tibuf[1]);
tibuf[0] = tibuf[1] = Nullch;
tiline[0] = tiline[1] = -1;
tireclen = 0;
}
}
/* Constuct the line index, somehow or other. */
void
scan_input(filename)
char *filename;
{
if (!plan_a(filename))
plan_b(filename);
if (verbose) {
say3("Patching file %s using Plan %s...\n", filename,
(using_plan_a ? "A" : "B") );
}
}
/* Try keeping everything in memory. */
bool
plan_a(filename)
char *filename;
{
int ifd, statfailed;
Reg1 char *s;
Reg2 LINENUM iline;
char lbuf[MAXLINELEN];
int output_elsewhere = strcmp(filename, outname);
statfailed = stat(filename, &filestat);
if (statfailed && ok_to_create_file) {
if (verbose)
say2("(Creating file %s...)\n",filename);
makedirs(filename, TRUE);
close(creat(filename, 0666));
statfailed = stat(filename, &filestat);
}
/* For nonexistent or read-only files, look for RCS or SCCS versions. */
if (statfailed
|| (! output_elsewhere
&& (/* No one can write to it. */
(filestat.st_mode & 0222) == 0
/* I can't write to it. */
|| ((filestat.st_mode & 0022) == 0
&& filestat.st_uid != myuid)))) {
struct stat cstat;
char *cs = Nullch;
char *filebase;
int pathlen;
filebase = basename(filename);
pathlen = filebase - filename;
/* Put any leading path into `s'.
Leave room in lbuf for the diff command. */
s = lbuf + 20;
strncpy(s, filename, pathlen);
#define try(f,a1,a2) (Sprintf(s + pathlen, f, a1, a2), stat(s, &cstat) == 0)
if (( try("RCS/%s%s", filebase, RCSSUFFIX)
|| try("RCS/%s" , filebase, 0)
|| try( "%s%s", filebase, RCSSUFFIX))
&&
/* Check that RCS file is not working file.
Some hosts don't report file name length errors. */
(statfailed
|| ( (filestat.st_dev ^ cstat.st_dev)
| (filestat.st_ino ^ cstat.st_ino)))) {
Sprintf(buf, output_elsewhere?CHECKOUT:CHECKOUT_LOCKED, filename);
Sprintf(lbuf, RCSDIFF, filename);
cs = "RCS";
} else if ( try("SCCS/%s%s", SCCSPREFIX, filebase)
|| try( "%s%s", SCCSPREFIX, filebase)) {
Sprintf(buf, output_elsewhere?GET:GET_LOCKED, s);
Sprintf(lbuf, SCCSDIFF, s, filename);
cs = "SCCS";
} else if (statfailed)
fatal2("can't find %s\n", filename);
/* else we can't write to it but it's not under a version
control system, so just proceed. */
if (cs) {
if (!statfailed) {
if ((filestat.st_mode & 0222) != 0)
/* The owner can write to it. */
fatal3("file %s seems to be locked by somebody else under %s\n",
filename, cs);
/* It might be checked out unlocked. See if it's safe to
check out the default version locked. */
if (verbose)
say3("Comparing file %s to default %s version...\n",
filename, cs);
if (system(lbuf))
fatal3("can't check out file %s: differs from default %s version\n",
filename, cs);
}
if (verbose)
say3("Checking out file %s from %s...\n", filename, cs);
if (system(buf) || stat(filename, &filestat))
fatal3("can't check out file %s from %s\n", filename, cs);
}
}
filemode = filestat.st_mode;
if (!S_ISREG(filemode))
fatal2("%s is not a normal file--can't patch\n", filename);
i_size = filestat.st_size;
if (out_of_mem) {
set_hunkmax(); /* make sure dynamic arrays are allocated */
out_of_mem = FALSE;
return FALSE; /* force plan b because plan a bombed */
}
#ifdef lint
i_womp = Nullch;
#else
i_womp = malloc((MEM)(i_size+2)); /* lint says this may alloc less than */
/* i_size, but that's okay, I think. */
#endif
if (i_womp == Nullch)
return FALSE;
if ((ifd = open(filename, 0)) < 0)
pfatal2("can't open file %s", filename);
#ifndef lint
if (read(ifd, i_womp, (int)i_size) != i_size) {
Close(ifd); /* probably means i_size > 15 or 16 bits worth */
free(i_womp); /* at this point it doesn't matter if i_womp was */
return FALSE; /* undersized. */
}
#endif
Close(ifd);
if (i_size && i_womp[i_size-1] != '\n')
i_womp[i_size++] = '\n';
i_womp[i_size] = '\0';
/* count the lines in the buffer so we know how many pointers we need */
iline = 0;
for (s=i_womp; *s; s++) {
if (*s == '\n')
iline++;
}
#ifdef lint
i_ptr = Null(char**);
#else
i_ptr = (char **)malloc((MEM)((iline + 2) * sizeof(char *)));
#endif
if (i_ptr == Null(char **)) { /* shucks, it was a near thing */
free((char *)i_womp);
return FALSE;
}
/* now scan the buffer and build pointer array */
iline = 1;
i_ptr[iline] = i_womp;
for (s=i_womp; *s; s++) {
if (*s == '\n')
i_ptr[++iline] = s+1; /* these are NOT null terminated */
}
input_lines = iline - 1;
/* now check for revision, if any */
if (revision != Nullch) {
if (!rev_in_string(i_womp)) {
if (force) {
if (verbose)
say2(
"Warning: this file doesn't appear to be the %s version--patching anyway.\n",
revision);
}
else if (batch) {
fatal2(
"this file doesn't appear to be the %s version--aborting.\n", revision);
}
else {
ask2(
"This file doesn't appear to be the %s version--patch anyway? [n] ",
revision);
if (*buf != 'y')
fatal1("aborted\n");
}
}
else if (verbose)
say2("Good. This file appears to be the %s version.\n",
revision);
}
return TRUE; /* plan a will work */
}
/* Keep (virtually) nothing in memory. */
void
plan_b(filename)
char *filename;
{
Reg3 FILE *ifp;
Reg1 int i = 0;
Reg2 int maxlen = 1;
Reg4 bool found_revision = (revision == Nullch);
using_plan_a = FALSE;
if ((ifp = fopen(filename, "r")) == Nullfp)
pfatal2("can't open file %s", filename);
if ((tifd = creat(TMPINNAME, 0666)) < 0)
pfatal2("can't open file %s", TMPINNAME);
while (fgets(buf, sizeof buf, ifp) != Nullch) {
if (revision != Nullch && !found_revision && rev_in_string(buf))
found_revision = TRUE;
if ((i = strlen(buf)) > maxlen)
maxlen = i; /* find longest line */
}
if (revision != Nullch) {
if (!found_revision) {
if (force) {
if (verbose)
say2(
"Warning: this file doesn't appear to be the %s version--patching anyway.\n",
revision);
}
else if (batch) {
fatal2(
"this file doesn't appear to be the %s version--aborting.\n", revision);
}
else {
ask2(
"This file doesn't appear to be the %s version--patch anyway? [n] ",
revision);
if (*buf != 'y')
fatal1("aborted\n");
}
}
else if (verbose)
say2("Good. This file appears to be the %s version.\n",
revision);
}
Fseek(ifp, 0L, 0); /* rewind file */
lines_per_buf = BUFFERSIZE / maxlen;
tireclen = maxlen;
tibuf[0] = malloc((MEM)(BUFFERSIZE + 1));
tibuf[1] = malloc((MEM)(BUFFERSIZE + 1));
if (tibuf[1] == Nullch)
fatal1("out of memory\n");
for (i=1; ; i++) {
if (! (i % lines_per_buf)) /* new block */
if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
pfatal1("can't write temp file");
if (fgets(tibuf[0] + maxlen * (i%lines_per_buf), maxlen + 1, ifp)
== Nullch) {
input_lines = i - 1;
if (i % lines_per_buf)
if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
pfatal1("can't write temp file");
break;
}
}
Fclose(ifp);
Close(tifd);
if ((tifd = open(TMPINNAME, 0)) < 0) {
pfatal2("can't reopen file %s", TMPINNAME);
}
}
/* Fetch a line from the input file, \n terminated, not necessarily \0. */
char *
ifetch(line,whichbuf)
Reg1 LINENUM line;
int whichbuf; /* ignored when file in memory */
{
if (line < 1 || line > input_lines)
return "";
if (using_plan_a)
return i_ptr[line];
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;
#ifndef lint /* complains of long accuracy */
Lseek(tifd, (long)baseline / lines_per_buf * BUFFERSIZE, 0);
#endif
if (read(tifd, tibuf[whichbuf], BUFFERSIZE) < 0)
pfatal2("error reading tmp file %s", TMPINNAME);
}
return tibuf[whichbuf] + (tireclen*offline);
}
}
/* True if the string argument contains the revision number we want. */
bool
rev_in_string(string)
char *string;
{
Reg1 char *s;
Reg2 int patlen;
if (revision == Nullch)
return TRUE;
patlen = strlen(revision);
if (strnEQ(string,revision,patlen) && isspace(string[patlen]))
return TRUE;
for (s = string; *s; s++) {
if (isspace(*s) && strnEQ(s+1, revision, patlen) &&
isspace(s[patlen+1] )) {
return TRUE;
}
}
return FALSE;
}

18
inp.h Normal file
View File

@ -0,0 +1,18 @@
/* $Header: inp.h,v 2.0 86/09/17 15:37:25 lwall Exp $
*
* $Log: inp.h,v $
* Revision 2.0 86/09/17 15:37:25 lwall
* Baseline for netwide release.
*
*/
EXT LINENUM input_lines INIT(0); /* how long is input file in lines */
EXT LINENUM last_frozen_line INIT(0); /* how many input lines have been */
/* irretractibly output */
bool rev_in_string();
void scan_input();
bool plan_a(); /* returns false if insufficient memory */
void plan_b();
char *ifetch();

945
patch.c Normal file
View File

@ -0,0 +1,945 @@
char rcsid[] =
"$Header: patch.c,v 2.0.2.0 90/05/01 22:17:50 davison Locked $";
/* patch - a program to apply diffs to original files
*
* Copyright 1986, Larry Wall
*
* This program may be copied as long as you don't try to make any
* money off of it, or pretend that you wrote it.
*
* $Log: patch.c,v $
* Revision 2.0.2.0 90/05/01 22:17:50 davison
* patch12u: unidiff support added
*
* Revision 2.0.1.6 88/06/22 20:46:39 lwall
* patch12: rindex() wasn't declared
*
* Revision 2.0.1.5 88/06/03 15:09:37 lwall
* patch10: exit code improved.
* patch10: better support for non-flexfilenames.
*
* Revision 2.0.1.4 87/02/16 14:00:04 lwall
* Short replacement caused spurious "Out of sync" message.
*
* Revision 2.0.1.3 87/01/30 22:45:50 lwall
* Improved diagnostic on sync error.
* Moved do_ed_script() to pch.c.
*
* Revision 2.0.1.2 86/11/21 09:39:15 lwall
* Fuzz factor caused offset of installed lines.
*
* Revision 2.0.1.1 86/10/29 13:10:22 lwall
* Backwards search could terminate prematurely.
*
* Revision 2.0 86/09/17 15:37:32 lwall
* Baseline for netwide release.
*
* Revision 1.5 86/08/01 20:53:24 lwall
* Changed some %d's to %ld's.
* Linted.
*
* Revision 1.4 86/08/01 19:17:29 lwall
* Fixes for machines that can't vararg.
* Added fuzz factor.
* Generalized -p.
* General cleanup.
*
* 85/08/15 van%ucbmonet@berkeley
* Changes for 4.3bsd diff -c.
*
* Revision 1.3 85/03/26 15:07:43 lwall
* Frozen.
*
* Revision 1.2.1.9 85/03/12 17:03:35 lwall
* Changed pfp->_file to fileno(pfp).
*
* Revision 1.2.1.8 85/03/12 16:30:43 lwall
* Check i_ptr and i_womp to make sure they aren't null before freeing.
* Also allow ed output to be suppressed.
*
* Revision 1.2.1.7 85/03/12 15:56:13 lwall
* Added -p option from jromine@uci-750a.
*
* Revision 1.2.1.6 85/03/12 12:12:51 lwall
* Now checks for normalness of file to patch.
*
* Revision 1.2.1.5 85/03/12 11:52:12 lwall
* Added -D (#ifdef) option from joe@fluke.
*
* Revision 1.2.1.4 84/12/06 11:14:15 lwall
* Made smarter about SCCS subdirectories.
*
* Revision 1.2.1.3 84/12/05 11:18:43 lwall
* Added -l switch to do loose string comparison.
*
* Revision 1.2.1.2 84/12/04 09:47:13 lwall
* Failed hunk count not reset on multiple patch file.
*
* Revision 1.2.1.1 84/12/04 09:42:37 lwall
* Branch for sdcrdcf changes.
*
* Revision 1.2 84/11/29 13:29:51 lwall
* Linted. Identifiers uniqified. 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.
*
* Revision 1.1 84/11/09 17:03:58 lwall
* Initial revision
*
*/
#include "INTERN.h"
#include "common.h"
#include "EXTERN.h"
#include "version.h"
#include "util.h"
#include "pch.h"
#include "inp.h"
#include "backupfile.h"
#include "getopt.h"
/* procedures */
void reinitialize_almost_everything();
void get_some_switches();
LINENUM locate_hunk();
void abort_hunk();
void apply_hunk();
void init_output();
void init_reject();
void copy_till();
void spew_output();
void dump_line();
bool patch_match();
bool similar();
void re_input();
void my_exit();
/* TRUE if -E was specified on command line. */
static int remove_empty_files = FALSE;
/* TRUE if -R was specified on command line. */
static int reverse_flag_specified = FALSE;
/* Apply a set of diffs as appropriate. */
int
main(argc,argv)
int argc;
char **argv;
{
LINENUM where;
LINENUM newwhere;
LINENUM fuzz;
LINENUM mymaxfuzz;
int hunk = 0;
int failed = 0;
int failtotal = 0;
bool rev_okayed = 0;
int i;
setbuf(stderr, serrbuf);
for (i = 0; i<MAXFILEC; i++)
filearg[i] = Nullch;
myuid = getuid();
/* Cons up the names of the temporary files. */
{
/* Directory for temporary files. */
char *tmpdir;
int tmpname_len;
tmpdir = getenv ("TMPDIR");
if (tmpdir == NULL) {
tmpdir = "/tmp";
}
tmpname_len = strlen (tmpdir) + 20;
TMPOUTNAME = (char *) malloc (tmpname_len);
strcpy (TMPOUTNAME, tmpdir);
strcat (TMPOUTNAME, "/patchoXXXXXX");
Mktemp(TMPOUTNAME);
TMPINNAME = (char *) malloc (tmpname_len);
strcpy (TMPINNAME, tmpdir);
strcat (TMPINNAME, "/patchiXXXXXX");
Mktemp(TMPINNAME);
TMPREJNAME = (char *) malloc (tmpname_len);
strcpy (TMPREJNAME, tmpdir);
strcat (TMPREJNAME, "/patchrXXXXXX");
Mktemp(TMPREJNAME);
TMPPATNAME = (char *) malloc (tmpname_len);
strcpy (TMPPATNAME, tmpdir);
strcat (TMPPATNAME, "/patchpXXXXXX");
Mktemp(TMPPATNAME);
}
{
char *v;
v = getenv ("SIMPLE_BACKUP_SUFFIX");
if (v)
simple_backup_suffix = v;
else
simple_backup_suffix = ".orig";
#ifndef NODIR
v = getenv ("VERSION_CONTROL");
backup_type = get_version (v); /* OK to pass NULL. */
#endif
}
/* parse switches */
Argc = argc;
Argv = argv;
get_some_switches();
/* make sure we clean up /tmp in case of disaster */
set_signals(0);
for (
open_patch_file(filearg[1]);
there_is_another_patch();
reinitialize_almost_everything()
) { /* for each patch in patch file */
if (outname == Nullch)
outname = savestr(filearg[0]);
/* for ed script just up and do it and exit */
if (diff_type == ED_DIFF) {
do_ed_script();
continue;
}
/* initialize the patched file */
if (!skip_rest_of_patch)
init_output(TMPOUTNAME);
/* initialize reject file */
init_reject(TMPREJNAME);
/* find out where all the lines are */
if (!skip_rest_of_patch)
scan_input(filearg[0]);
/* 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 */
hunk = 0;
failed = 0;
rev_okayed = FALSE;
out_of_mem = FALSE;
while (another_hunk()) {
hunk++;
fuzz = Nulline;
mymaxfuzz = pch_context();
if (maxfuzz < mymaxfuzz)
mymaxfuzz = maxfuzz;
if (!skip_rest_of_patch) {
do {
where = locate_hunk(fuzz);
if (hunk == 1 && where == Nulline && !(force|rev_okayed)) {
/* dwim for reversed patch? */
if (!pch_swap()) {
if (fuzz == Nulline)
say1(
"Not enough memory to try swapped hunk! Assuming unswapped.\n");
continue;
}
reverse = !reverse;
where = locate_hunk(fuzz); /* try again */
if (where == Nulline) { /* didn't find it swapped */
if (!pch_swap()) /* put it back to normal */
fatal1("lost hunk on alloc error!\n");
reverse = !reverse;
}
else if (noreverse) {
if (!pch_swap()) /* put it back to normal */
fatal1("lost hunk on alloc error!\n");
reverse = !reverse;
say1(
"Ignoring previously applied (or reversed) patch.\n");
skip_rest_of_patch = TRUE;
}
else if (batch) {
if (verbose)
say3(
"%seversed (or previously applied) patch detected! %s -R.",
reverse ? "R" : "Unr",
reverse ? "Assuming" : "Ignoring");
}
else {
ask3(
"%seversed (or previously applied) patch detected! %s -R? [y] ",
reverse ? "R" : "Unr",
reverse ? "Assume" : "Ignore");
if (*buf == 'n') {
ask1("Apply anyway? [n] ");
if (*buf == 'y')
rev_okayed = TRUE;
else
skip_rest_of_patch = TRUE;
where = Nulline;
reverse = !reverse;
if (!pch_swap()) /* put it back to normal */
fatal1("lost hunk on alloc error!\n");
}
}
}
} while (!skip_rest_of_patch && where == Nulline &&
++fuzz <= mymaxfuzz);
if (skip_rest_of_patch) { /* just got decided */
Fclose(ofp);
ofp = Nullfp;
}
}
newwhere = pch_newfirst() + last_offset;
if (skip_rest_of_patch) {
abort_hunk();
failed++;
if (verbose)
say3("Hunk #%d ignored at %ld.\n", hunk, newwhere);
}
else if (where == Nulline) {
abort_hunk();
failed++;
if (verbose)
say3("Hunk #%d failed at %ld.\n", hunk, newwhere);
}
else {
apply_hunk(where);
if (verbose) {
say3("Hunk #%d succeeded at %ld", hunk, newwhere);
if (fuzz)
say2(" with fuzz %ld", fuzz);
if (last_offset)
say3(" (offset %ld line%s)",
last_offset, last_offset==1L?"":"s");
say1(".\n");
}
}
}
if (out_of_mem && using_plan_a) {
optind = optind_last;
say1("\n\nRan out of memory using Plan A--trying again...\n\n");
if (ofp)
Fclose(ofp);
ofp = Nullfp;
if (rejfp)
Fclose(rejfp);
rejfp = Nullfp;
continue;
}
assert(hunk);
/* finish spewing out the new file */
if (!skip_rest_of_patch)
spew_output();
/* and put the output where desired */
ignore_signals();
if (!skip_rest_of_patch) {
struct stat statbuf;
char *realout = outname;
if (move_file(TMPOUTNAME, outname) < 0) {
toutkeep = TRUE;
realout = TMPOUTNAME;
chmod(TMPOUTNAME, filemode);
}
else
chmod(outname, filemode);
if (remove_empty_files && stat(realout, &statbuf) == 0
&& statbuf.st_size == 0) {
if (verbose)
say2("Removing %s (empty after patching).\n", realout);
while (unlink(realout) >= 0) ; /* while is for Eunice. */
}
}
Fclose(rejfp);
rejfp = Nullfp;
if (failed) {
failtotal += failed;
if (!*rejname) {
Strcpy(rejname, outname);
addext(rejname, ".rej", '#');
}
if (skip_rest_of_patch) {
say4("%d out of %d hunks ignored--saving rejects to %s\n",
failed, hunk, rejname);
}
else {
say4("%d out of %d hunks failed--saving rejects to %s\n",
failed, hunk, rejname);
}
if (move_file(TMPREJNAME, rejname) < 0)
trejkeep = TRUE;
}
set_signals(1);
}
my_exit(failtotal);
}
/* Prepare to find the next patch to do in the patch file. */
void
reinitialize_almost_everything()
{
re_patch();
re_input();
input_lines = 0;
last_frozen_line = 0;
filec = 0;
if (filearg[0] != Nullch && !out_of_mem) {
free(filearg[0]);
filearg[0] = Nullch;
}
if (outname != Nullch) {
free(outname);
outname = Nullch;
}
last_offset = 0;
diff_type = 0;
if (revision != Nullch) {
free(revision);
revision = Nullch;
}
reverse = reverse_flag_specified;
skip_rest_of_patch = FALSE;
get_some_switches();
if (filec >= 2)
fatal1("you may not change to a different patch file\n");
}
static char *shortopts = "-b:B:cd:D:eEfF:lnNo:p::r:RsStuvV:x:";
static struct option longopts[] =
{
{"suffix", 1, NULL, 'b'},
{"prefix", 1, NULL, 'B'},
{"context", 0, NULL, 'c'},
{"directory", 1, NULL, 'd'},
{"ifdef", 1, NULL, 'D'},
{"ed", 0, NULL, 'e'},
{"remove-empty-files", 0, NULL, 'E'},
{"force", 0, NULL, 'f'},
{"fuzz", 1, NULL, 'F'},
{"ignore-whitespace", 0, NULL, 'l'},
{"normal", 0, NULL, 'n'},
{"forward", 0, NULL, 'N'},
{"output", 1, NULL, 'o'},
{"strip", 2, NULL, 'p'},
{"reject-file", 1, NULL, 'r'},
{"reverse", 0, NULL, 'R'},
{"quiet", 0, NULL, 's'},
{"silent", 0, NULL, 's'},
{"skip", 0, NULL, 'S'},
{"batch", 0, NULL, 't'},
{"unified", 0, NULL, 'u'},
{"version", 0, NULL, 'v'},
{"version-control", 1, NULL, 'V'},
{"debug", 1, NULL, 'x'},
{0, 0, 0, 0}
};
/* Process switches and filenames up to next '+' or end of list. */
void
get_some_switches()
{
Reg1 int optc;
rejname[0] = '\0';
optind_last = optind;
if (optind == Argc)
return;
while ((optc = getopt_long (Argc, Argv, shortopts, longopts, (int *) 0))
!= -1) {
if (optc == 1) {
if (strEQ(optarg, "+"))
return;
if (filec == MAXFILEC)
fatal1("too many file arguments\n");
filearg[filec++] = savestr(optarg);
}
else {
switch (optc) {
case 'b':
simple_backup_suffix = savestr(optarg);
break;
case 'B':
origprae = savestr(optarg);
break;
case 'c':
diff_type = CONTEXT_DIFF;
break;
case 'd':
if (chdir(optarg) < 0)
pfatal2("can't cd to %s", optarg);
break;
case 'D':
do_defines = TRUE;
if (!isalpha(*optarg) && '_' != *optarg)
fatal1("argument to -D is not an identifier\n");
Sprintf(if_defined, "#ifdef %s\n", optarg);
Sprintf(not_defined, "#ifndef %s\n", optarg);
Sprintf(end_defined, "#endif /* %s */\n", optarg);
break;
case 'e':
diff_type = ED_DIFF;
break;
case 'E':
remove_empty_files = TRUE;
break;
case 'f':
force = TRUE;
break;
case 'F':
maxfuzz = atoi(optarg);
break;
case 'l':
canonicalize = TRUE;
break;
case 'n':
diff_type = NORMAL_DIFF;
break;
case 'N':
noreverse = TRUE;
break;
case 'o':
outname = savestr(optarg);
break;
case 'p':
if (optarg)
strippath = atoi(optarg);
else
strippath = 0;
break;
case 'r':
Strcpy(rejname, optarg);
break;
case 'R':
reverse = TRUE;
reverse_flag_specified = TRUE;
break;
case 's':
verbose = FALSE;
break;
case 'S':
skip_rest_of_patch = TRUE;
break;
case 't':
batch = TRUE;
break;
case 'u':
diff_type = UNI_DIFF;
break;
case 'v':
version();
break;
case 'V':
#ifndef NODIR
backup_type = get_version (optarg);
#endif
break;
#ifdef DEBUGGING
case 'x':
debug = atoi(optarg);
break;
#endif
default:
fprintf(stderr, "\
Usage: %s [options] [origfile [patchfile]] [+ [options] [origfile]]...\n",
Argv[0]);
fprintf(stderr, "\
Options:\n\
[-ceEflnNRsStuv] [-b backup-ext] [-B backup-prefix] [-d directory]\n\
[-D symbol] [-F max-fuzz] [-o out-file] [-p[strip-count]]\n\
[-r rej-name] [-V {numbered,existing,simple}] [--context]\n\
[--prefix=backup-prefix] [--suffix=backup-ext] [--ifdef=symbol]\n\
[--directory=directory] [--ed] [--fuzz=max-fuzz] [--force] [--batch]\n\
[--ignore-whitespace] [--forward] [--reverse] [--output=out-file]\n");
fprintf(stderr, "\
[--strip[=strip-count]] [--normal] [--reject-file=rej-name] [--skip]\n\
[--remove-empty-files] [--quiet] [--silent] [--unified] [--version]\n\
[--version-control={numbered,existing,simple}]\n");
my_exit(1);
}
}
}
/* Process any filename args given after "--". */
for (; optind < Argc; ++optind) {
if (filec == MAXFILEC)
fatal1("too many file arguments\n");
filearg[filec++] = savestr(Argv[optind]);
}
}
/* Attempt to find the right place to apply this hunk of patch. */
LINENUM
locate_hunk(fuzz)
LINENUM fuzz;
{
Reg1 LINENUM first_guess = pch_first() + last_offset;
Reg2 LINENUM offset;
LINENUM pat_lines = pch_ptrn_lines();
Reg3 LINENUM max_pos_offset = input_lines - first_guess
- pat_lines + 1;
Reg4 LINENUM max_neg_offset = first_guess - last_frozen_line - 1
+ pch_context();
if (!pat_lines) /* null range matches always */
return first_guess;
if (max_neg_offset >= first_guess) /* do not try lines < 0 */
max_neg_offset = first_guess - 1;
if (first_guess <= input_lines && patch_match(first_guess, Nulline, fuzz))
return first_guess;
for (offset = 1; ; offset++) {
Reg5 bool check_after = (offset <= max_pos_offset);
Reg6 bool check_before = (offset <= max_neg_offset);
if (check_after && patch_match(first_guess, offset, fuzz)) {
#ifdef DEBUGGING
if (debug & 1)
say3("Offset changing from %ld to %ld\n", last_offset, offset);
#endif
last_offset = offset;
return first_guess+offset;
}
else if (check_before && patch_match(first_guess, -offset, fuzz)) {
#ifdef DEBUGGING
if (debug & 1)
say3("Offset changing from %ld to %ld\n", last_offset, -offset);
#endif
last_offset = -offset;
return first_guess-offset;
}
else if (!check_before && !check_after)
return Nulline;
}
}
/* We did not find the pattern, dump out the hunk so they can handle it. */
void
abort_hunk()
{
Reg1 LINENUM i;
Reg2 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 *stars = (diff_type >= NEW_CONTEXT_DIFF ? " ****" : "");
char *minuses = (diff_type >= NEW_CONTEXT_DIFF ? " ----" : " -----");
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 '\n':
fprintf(rejfp, "%s", pfetch(i));
break;
case ' ': case '-': case '+': case '!':
fprintf(rejfp, "%c %s", pch_char(i), pfetch(i));
break;
default:
fatal1("fatal internal error in abort_hunk\n");
}
}
}
/* We found where to apply it (we hope), so do it. */
void
apply_hunk(where)
LINENUM where;
{
Reg1 LINENUM old = 1;
Reg2 LINENUM lastline = pch_ptrn_lines();
Reg3 LINENUM new = lastline+1;
#define OUTSIDE 0
#define IN_IFNDEF 1
#define IN_IFDEF 2
#define IN_ELSE 3
Reg4 int def_state = OUTSIDE;
Reg5 bool R_do_defines = do_defines;
Reg6 LINENUM pat_end = pch_end();
where--;
while (pch_char(new) == '=' || pch_char(new) == '\n')
new++;
while (old <= lastline) {
if (pch_char(old) == '-') {
copy_till(where + old - 1);
if (R_do_defines) {
if (def_state == OUTSIDE) {
fputs(not_defined, ofp);
def_state = IN_IFNDEF;
}
else if (def_state == IN_IFDEF) {
fputs(else_defined, ofp);
def_state = IN_ELSE;
}
fputs(pfetch(old), ofp);
}
last_frozen_line++;
old++;
}
else if (new > pat_end) {
break;
}
else if (pch_char(new) == '+') {
copy_till(where + old - 1);
if (R_do_defines) {
if (def_state == IN_IFNDEF) {
fputs(else_defined, ofp);
def_state = IN_ELSE;
}
else if (def_state == OUTSIDE) {
fputs(if_defined, ofp);
def_state = IN_IFDEF;
}
}
fputs(pfetch(new), ofp);
new++;
}
else if (pch_char(new) != pch_char(old)) {
say3("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n",
pch_hunk_beg() + old,
pch_hunk_beg() + new);
#ifdef DEBUGGING
say3("oldchar = '%c', newchar = '%c'\n",
pch_char(old), pch_char(new));
#endif
my_exit(1);
}
else if (pch_char(new) == '!') {
copy_till(where + old - 1);
if (R_do_defines) {
fputs(not_defined, ofp);
def_state = IN_IFNDEF;
}
while (pch_char(old) == '!') {
if (R_do_defines) {
fputs(pfetch(old), ofp);
}
last_frozen_line++;
old++;
}
if (R_do_defines) {
fputs(else_defined, ofp);
def_state = IN_ELSE;
}
while (pch_char(new) == '!') {
fputs(pfetch(new), ofp);
new++;
}
}
else {
assert(pch_char(new) == ' ');
old++;
new++;
if (R_do_defines && def_state != OUTSIDE) {
fputs(end_defined, ofp);
def_state = OUTSIDE;
}
}
}
if (new <= pat_end && pch_char(new) == '+') {
copy_till(where + old - 1);
if (R_do_defines) {
if (def_state == OUTSIDE) {
fputs(if_defined, ofp);
def_state = IN_IFDEF;
}
else if (def_state == IN_IFNDEF) {
fputs(else_defined, ofp);
def_state = IN_ELSE;
}
}
while (new <= pat_end && pch_char(new) == '+') {
fputs(pfetch(new), ofp);
new++;
}
}
if (R_do_defines && def_state != OUTSIDE) {
fputs(end_defined, ofp);
}
}
/* Open the new file. */
void
init_output(name)
char *name;
{
ofp = fopen(name, "w");
if (ofp == Nullfp)
pfatal2("can't create %s", name);
}
/* Open a file to put hunks we can't locate. */
void
init_reject(name)
char *name;
{
rejfp = fopen(name, "w");
if (rejfp == Nullfp)
pfatal2("can't create %s", name);
}
/* Copy input file to output, up to wherever hunk is to be applied. */
void
copy_till(lastline)
Reg1 LINENUM lastline;
{
Reg2 LINENUM R_last_frozen_line = last_frozen_line;
if (R_last_frozen_line > lastline)
fatal1("misordered hunks! output would be garbled\n");
while (R_last_frozen_line < lastline) {
dump_line(++R_last_frozen_line);
}
last_frozen_line = R_last_frozen_line;
}
/* Finish copying the input file to the output file. */
void
spew_output()
{
#ifdef DEBUGGING
if (debug & 256)
say3("il=%ld lfl=%ld\n",input_lines,last_frozen_line);
#endif
if (input_lines)
copy_till(input_lines); /* dump remainder of file */
Fclose(ofp);
ofp = Nullfp;
}
/* Copy one line from input to output. */
void
dump_line(line)
LINENUM line;
{
Reg1 char *s;
Reg2 char R_newline = '\n';
/* Note: string is not null terminated. */
for (s=ifetch(line, 0); putc(*s, ofp) != R_newline; s++) ;
}
/* Does the patch pattern match at line base+offset? */
bool
patch_match(base, offset, fuzz)
LINENUM base;
LINENUM offset;
LINENUM fuzz;
{
Reg1 LINENUM pline = 1 + fuzz;
Reg2 LINENUM iline;
Reg3 LINENUM pat_lines = pch_ptrn_lines() - fuzz;
for (iline=base+offset+fuzz; pline <= pat_lines; pline++,iline++) {
if (canonicalize) {
if (!similar(ifetch(iline, (offset >= 0)),
pfetch(pline),
pch_line_len(pline) ))
return FALSE;
}
else if (strnNE(ifetch(iline, (offset >= 0)),
pfetch(pline),
pch_line_len(pline) ))
return FALSE;
}
return TRUE;
}
/* Do two lines match with canonicalized white space? */
bool
similar(a,b,len)
Reg1 char *a;
Reg2 char *b;
Reg3 int len;
{
while (len) {
if (isspace(*b)) { /* whitespace (or \n) to match? */
if (!isspace(*a)) /* no corresponding whitespace? */
return FALSE;
while (len && isspace(*b) && *b != '\n')
b++,len--; /* skip pattern whitespace */
while (isspace(*a) && *a != '\n')
a++; /* skip target whitespace */
if (*a == '\n' || *b == '\n')
return (*a == *b); /* should end in sync */
}
else if (*a++ != *b++) /* match non-whitespace chars */
return FALSE;
else
len--; /* probably not necessary */
}
return TRUE; /* actually, this is not reached */
/* since there is always a \n */
}
/* Exit with cleanup. */
void
my_exit(status)
int status;
{
Unlink(TMPINNAME);
if (!toutkeep) {
Unlink(TMPOUTNAME);
}
if (!trejkeep) {
Unlink(TMPREJNAME);
}
Unlink(TMPPATNAME);
exit(status);
}

570
patch.man Normal file
View File

@ -0,0 +1,570 @@
.\" -*- nroff -*-
.rn '' }`
'\" $Header: patch.man,v 2.0.1.2 88/06/22 20:47:18 lwall Locked $
'\"
'\" $Log: patch.man,v $
'\" Revision 2.0.1.2 88/06/22 20:47:18 lwall
'\" patch12: now avoids Bell System Logo
'\"
'\" Revision 2.0.1.1 88/06/03 15:12:51 lwall
'\" patch10: -B switch was contributed.
'\"
'\" Revision 2.0 86/09/17 15:39:09 lwall
'\" Baseline for netwide release.
'\"
'\" Revision 1.4 86/08/01 19:23:22 lwall
'\" Documented -v, -p, -F.
'\" Added notes to patch senders.
'\"
'\" Revision 1.3 85/03/26 15:11:06 lwall
'\" Frozen.
'\"
'\" Revision 1.2.1.4 85/03/12 16:14:27 lwall
'\" Documented -p.
'\"
'\" Revision 1.2.1.3 85/03/12 16:09:41 lwall
'\" Documented -D.
'\"
'\" Revision 1.2.1.2 84/12/05 11:06:55 lwall
'\" Added -l switch, and noted bistability bug.
'\"
'\" Revision 1.2.1.1 84/12/04 17:23:39 lwall
'\" Branch for sdcrdcf changes.
'\"
'\" Revision 1.2 84/12/04 17:22:02 lwall
'\" Baseline version.
'\"
.de Sh
.br
.ne 5
.PP
\fB\\$1\fR
.PP
..
.de Sp
.if t .sp .5v
.if n .sp
..
'\"
'\" Set up \*(-- to give an unbreakable dash;
'\" string Tr holds user defined translation string.
'\" Bell System Logo is used as a dummy character.
'\"
.ie n \{\
.tr \(*W-\*(Tr
.ds -- \(*W-
.if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
.if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
.ds L" ""
.ds R" ""
.ds L' '
.ds R' '
'br \}
.el \{\
.ds -- \(em\|
.tr \*(Tr
.ds L" ``
.ds R" ''
.ds L' `
.ds R' '
'br\}
.TH PATCH 1 LOCAL
.SH NAME
patch - apply a diff file to an original
.SH SYNOPSIS
.B patch
[options] [origfile [patchfile]] [+ [options] [origfile]]...
.sp
but usually just
.sp
.B patch
<patchfile
.SH DESCRIPTION
.I Patch
will take a patch file containing any of the four forms of difference
listing produced by the
.I diff
program and apply those differences to an original file, producing a patched
version.
By default, the patched version is put in place of the original, with
the original file backed up to the same name with the
extension \*(L".orig\*(R" (\*(L"~\*(R" on systems that do not
support long file names), or as specified by the
\fB\-b\fP (\fB\-\-suffix\fP),
\fB\-B\fP (\fB\-\-prefix\fP),
or
\fB\-V\fP (\fB\-\-version\-control\fP)
options.
The extension used for making backup files may also be specified in the
.B SIMPLE_BACKUP_SUFFIX
environment variable, which is overridden by the above options.
.PP
If the backup file already exists,
.B patch
creates a new backup file name by changing the first lowercase letter
in the last component of the file's name into uppercase. If there are
no more lowercase letters in the name, it removes the first character
from the name. It repeats this process until it comes up with a
backup file that does not already exist.
.PP
You may also specify where you want the output to go with a
\fB\-o\fP (\fB\-\-output\fP)
option; if that file already exists, it is backed up first.
.PP
If
.I patchfile
is omitted, or is a hyphen, the patch will be read from standard input.
.PP
Upon startup, patch will attempt to determine the type of the diff listing,
unless over-ruled 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
.I patch
program itself, while
.I ed
diffs are simply fed to the
.I ed
editor via a pipe.
.PP
.I Patch
will try 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
.IR patch ,
and it should work.
If the entire diff is indented by a consistent amount,
this will be taken into account.
.PP
With context diffs, and to a lesser extent with normal diffs,
.I patch
can detect when the line numbers mentioned in the patch are incorrect,
and will attempt 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,
.I patch
will scan both forwards and backwards for a set of lines matching the context
given in the hunk.
First
.I 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
.I patch
cannot find a place to install that hunk of the patch, it will put the
hunk out to a reject file, which normally is the name of the output file
plus \*(L".rej\*(R" (\*(L"#\*(R" on systems that do not support
long file names).
(Note that the rejected hunk will come out in context diff form whether the
input patch was a context diff or a normal diff.
If the input was a normal diff, many of the contexts will simply be 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 will be told whether the hunk succeeded or
failed, and which line (in the new file)
.I patch
thought the hunk should go on.
If this is different from the line number specified in the diff you will
be told the offset.
A single large offset MAY be an indication that a hunk was installed in the
wrong place.
You will also be told if a fuzz factor was used to make the match, in which
case you should also be slightly suspicious.
.PP
If no original file is specified on the command line,
.I patch
will try to figure out from the leading garbage what the name of the file
to edit is.
In the header of a context diff, the file name is found from lines beginning
with \*(L"***\*(R" or \*(L"---\*(R", with the shortest name of an existing
file winning.
Only context diffs have lines like that, but if there is an \*(L"Index:\*(R"
line in the leading garbage,
.I patch
will try to use the file name from that line.
The context diff header takes precedence over an Index line.
If no file name can be intuited from the leading garbage, you will be asked
for the name of the file to patch.
.PP
If the original file cannot be found or is read-only, but a suitable
SCCS or RCS file is handy,
.I patch
will attempt to get or check out the file.
.PP
Additionally, if the leading garbage contains a \*(L"Prereq: \*(R" line,
.I patch
will take the first word from the prerequisites line (normally a version
number) and check the input file to see if that word can be found.
If not,
.I patch
will ask for confirmation before proceeding.
.PP
The upshot of all this is that you should be able to say, while in a news
interface, the following:
.Sp
| patch -d /usr/src/local/blurfl
.Sp
and patch a file in the blurfl directory directly from the article containing
the patch.
.PP
If the patch file contains more than one patch,
.I patch
will try 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 will
be examined for interesting things such as file names and revision level, as
mentioned previously.
You can give options (and another original file name) for the second and
subsequent patches by separating the corresponding argument lists
by a \*(L'+\*(R'.
(The argument list for a second or subsequent patch may not specify a new
patch file, however.)
.PP
.I Patch
recognizes the following options:
.TP 5
.B "\-b suff, \-\-suffix=suff"
causes
.B suff
to be interpreted as the backup extension, to be
used in place of \*(L".orig\*(R" or \*(L"~\*(R".
.TP 5
.B "\-B pref, \-\-prefix=pref"
causes
.B pref
to be interpreted as a prefix to the backup file
name. If this argument is specified, any argument from
.B \-b
will be ignored.
.TP 5
.B "\-c, \-\-context"
forces
.I patch
to interpret the patch file as a context diff.
.TP 5
.B "\-d dir, \-\-directory=dir"
causes
.I patch
to interpret
.B dir
as a directory, and cd to it before doing
anything else.
.TP 5
.B "\-D sym, \-\-ifdef=sym"
causes
.I patch
to use the "#ifdef...#endif" construct to mark changes.
.B sym
will be used as the differentiating symbol.
.TP 5
.B "\-e, \-\-ed"
forces
.I patch
to interpret the patch file as an
.I ed
script.
.TP 5
.B "\-E, \-\-remove\-empty\-files"
causes
.I patch
to remove output files that are empty after the patches have been applied.
.TP 5
.B "\-f, \-\-force"
forces
.I patch
to assume that the user knows exactly what he or she is doing, and to not
ask any questions. It assumes the following: skip patches for which a
file to patch can't be found; patch files even though they have the
wrong version for the ``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 5
.B "\-t, \-\-batch"
similar to
.BR \-f ,
in that it suppresses questions, but makes some different assumptions:
skip patches for which a file to patch can't be found (the same as \fB\-f\fP);
skip patches for which the file has the wrong version for the ``Prereq:'' line
in the patch; and assume that patches are reversed if they look like
they are.
.TP 5
.B "\-F number, \-\-fuzz=number"
sets the maximum fuzz factor.
This option only applies to context diffs, and causes
.I 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 5
.B "\-l, \-\-ignore\-whitespace"
causes the pattern matching to be done loosely, in case the tabs and
spaces have been munged in your input file.
Any sequence of whitespace in the pattern line will match any sequence
in the input file.
Normal characters must still match exactly.
Each line of the context must still match a line in the input file.
.TP 5
.B "\-n, \-\-normal"
forces
.I patch
to interpret the patch file as a normal diff.
.TP 5
.B "\-N, \-\-forward"
causes
.I patch
to ignore patches that it thinks are reversed or already applied.
See also
.B \-R .
.TP 5
.B "\-o file, \-\-output=file"
causes
.B file
to be interpreted as the output file name.
.TP 5
.B "\-p[number], \-\-strip[=number]"
sets the pathname strip count,
which controls how pathnames found in the patch file are treated, in case
the you keep your files in a different directory than the person who sent
out the patch.
The strip count specifies how many slashes are to be stripped from
the front of the pathname.
(Any intervening directory names also go away.)
For example, supposing the file name in the patch file was
.sp
/u/howard/src/blurfl/blurfl.c
.sp
setting
.B \-p
or
.B \-p0
gives the entire pathname unmodified,
.B \-p1
gives
.sp
u/howard/src/blurfl/blurfl.c
.sp
without the leading slash,
.B \-p4
gives
.sp
blurfl/blurfl.c
.sp
and not specifying
.B \-p
at all just gives you "blurfl.c", unless all of the directories in the
leading path (u/howard/src/blurfl) exist and that path is relative,
in which case you get the entire pathname unmodified.
Whatever you end up with is looked for either in the current directory,
or the directory specified by the
.B \-d
option.
.TP 5
.B "\-r file, \-\-reject\-file=file"
causes
.B file
to be interpreted as the reject file name.
.TP 5
.B "\-R, \-\-reverse"
tells
.I patch
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.)
.I Patch
will attempt to swap each hunk around before applying it.
Rejects will come out in the swapped format.
The
.B \-R
option will not work with
.I ed
diff scripts because there is too little
information to reconstruct the reverse operation.
.Sp
If the first hunk of a patch fails,
.I patch
will reverse the hunk to see if it can be applied that way.
If it can, you will be asked if you want to have the
.B \-R
option set.
If it can't, the patch will continue 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 will match
anywhere.
Luckily, most patches add or change lines rather than delete them, so most
reversed normal diffs will begin with a delete, which will fail, triggering
the heuristic.)
.TP 5
.B "\-s, \-\-silent, \-\-quiet"
makes
.I patch
do its work silently, unless an error occurs.
.TP 5
.B "\-S, \-\-skip"
causes
.I patch
to ignore this patch from the patch file, but continue on looking
for the next patch in the file.
Thus
.sp
patch -S + -S + <patchfile
.sp
will ignore the first and second of three patches.
.TP 5
.B "\-u, \-\-unified"
forces
.I patch
to interpret the patch file as a unified context diff (a unidiff).
.TP 5
.B "\-v, \-\-version"
causes
.I patch
to print out its revision header and patch level.
.TP 5
.B "\-V method, \-\-version\-\-control=method"
causes
.B method
to be interpreted as a method for creating
backup file names. The type of backups made can also be given in the
.B VERSION_CONTROL
environment variable, which is overridden by this option.
The
.B -B
option overrides this option, causing the prefix to always be used for
making backup file names.
The value of the
.B VERSION_CONTROL
environment variable and the argument to the
.B -V
option are like the GNU
Emacs `version-control' variable; they also recognize synonyms that
are more descriptive. The valid values are (unique abbreviations are
accepted):
.RS
.TP
`t' or `numbered'
Always make numbered backups.
.TP
`nil' or `existing'
Make numbered backups of files that already
have them, simple backups of the others.
This is the default.
.TP
`never' or `simple'
Always make simple backups.
.RE
.TP 5
.B "\-x number, \-\-debug=number"
sets internal debugging flags, and is of interest only to
.I patch
patchers.
.SH AUTHOR
Larry Wall <lwall@netlabs.com>
.br
with many other contributors.
.SH ENVIRONMENT
.TP
.B TMPDIR
Directory to put temporary files in; default is /tmp.
.TP
.B SIMPLE_BACKUP_SUFFIX
Extension to use for backup file names instead of \*(L".orig\*(R" or
\*(L"~\*(R".
.TP
.B VERSION_CONTROL
Selects when numbered backup files are made.
.SH FILES
$TMPDIR/patch*
.SH SEE ALSO
diff(1)
.SH NOTES FOR PATCH SENDERS
There are several things you should bear in mind if you are going to
be sending out patches.
First, you can save people a lot of grief by keeping a 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 Prereq: line in with the patch, it won't let them apply
patches out of order without some warning.
Second, make sure you've specified the file names right, either in a
context diff header, or with an Index: line.
If you are patching something in a subdirectory, be sure to tell the patch
user to specify a
.B \-p
option as needed.
Third, you can create a file by sending out a diff that compares a
null file to the file you want to create.
This will only work if the file you want to create doesn't exist already in
the target directory.
Fourth, take care not to send out reversed patches, since it makes people wonder
whether they already applied the patch.
Fifth, while you may be able to get away with putting 582 diff listings into
one file, it is probably wiser to group related patches into separate files in
case something goes haywire.
.SH DIAGNOSTICS
Too many to list here, but generally indicative that
.I patch
couldn't parse your patch file.
.PP
The message \*(L"Hmm...\*(R" indicates that there is unprocessed text in
the patch file and that
.I patch
is attempting to intuit whether there is a patch in that text and, if so,
what kind of patch it is.
.PP
.I Patch
will exit with a non-zero status if any reject files were created.
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
.I Patch
cannot tell if the line numbers are off in an
.I ed
script, and can only detect
bad line numbers in a normal diff when it finds a \*(L"change\*(R" or
a \*(L"delete\*(R" command.
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
.I 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 BUGS
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 #ifdef OLDCODE ... #else ...
#endif),
.I 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,
.I patch
will think it is a reversed patch, and offer to un-apply the patch.
This could be construed as a feature.
.rn }` ''

1
patchlevel.h Normal file
View File

@ -0,0 +1 @@
#define PATCH_VERSION "2.1"

1305
pch.c Normal file

File diff suppressed because it is too large Load Diff

36
pch.h Normal file
View File

@ -0,0 +1,36 @@
/* $Header: pch.h,v 2.0.1.1 87/01/30 22:47:16 lwall Exp $
*
* $Log: pch.h,v $
* Revision 2.0.1.1 87/01/30 22:47:16 lwall
* Added do_ed_script().
*
* Revision 2.0 86/09/17 15:39:57 lwall
* Baseline for netwide release.
*
*/
EXT FILE *pfp INIT(Nullfp); /* patch file pointer */
void re_patch();
void open_patch_file();
void set_hunkmax();
void grow_hunkmax();
bool there_is_another_patch();
int intuit_diff_type();
void next_intuit_at();
void skip_to();
bool another_hunk();
bool pch_swap();
char *pfetch();
short pch_line_len();
LINENUM pch_first();
LINENUM pch_ptrn_lines();
LINENUM pch_newfirst();
LINENUM pch_repl_lines();
LINENUM pch_end();
LINENUM pch_context();
LINENUM pch_hunk_beg();
char pch_char();
char *pfetch();
char *pgets();
void do_ed_script();

51
rename.c Normal file
View File

@ -0,0 +1,51 @@
/* rename.c -- BSD compatible directory function for System V
Copyright (C) 1988, 1990, 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#ifndef STDC_HEADERS
extern int errno;
#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;
if (stat (from, &from_stats))
return -1;
if (unlink (to) && errno != ENOENT)
return -1;
if (link (from, to))
return -1;
if (unlink (from) && errno != ENOENT)
{
unlink (to);
return -1;
}
return 0;
}

433
util.c Normal file
View File

@ -0,0 +1,433 @@
#include "EXTERN.h"
#include "common.h"
#include "INTERN.h"
#include "util.h"
#include "backupfile.h"
void my_exit();
#ifndef HAVE_STRERROR
static char *
private_strerror (errnum)
int errnum;
{
extern char *sys_errlist[];
extern int sys_nerr;
if (errnum > 0 && errnum <= sys_nerr)
return sys_errlist[errnum];
return "Unknown system error";
}
#define strerror private_strerror
#endif /* !HAVE_STRERROR */
/* Rename a file, copying it if necessary. */
int
move_file(from,to)
char *from, *to;
{
char bakname[512];
Reg1 char *s;
Reg2 int i;
Reg3 int fromfd;
/* to stdout? */
if (strEQ(to, "-")) {
#ifdef DEBUGGING
if (debug & 4)
say2("Moving %s to stdout.\n", from);
#endif
fromfd = open(from, 0);
if (fromfd < 0)
pfatal2("internal error, can't reopen %s", from);
while ((i=read(fromfd, buf, sizeof buf)) > 0)
if (write(1, buf, i) != 1)
pfatal1("write failed");
Close(fromfd);
return 0;
}
if (origprae) {
Strcpy(bakname, origprae);
Strcat(bakname, to);
} else {
#ifndef NODIR
char *backupname = find_backup_file_name(to);
if (backupname == (char *) 0)
fatal1("out of memory\n");
Strcpy(bakname, backupname);
free(backupname);
#else /* NODIR */
Strcpy(bakname, to);
Strcat(bakname, simple_backup_suffix);
#endif /* NODIR */
}
if (stat(to, &filestat) == 0) { /* output file exists */
dev_t to_device = filestat.st_dev;
ino_t to_inode = filestat.st_ino;
char *simplename = bakname;
for (s=bakname; *s; s++) {
if (*s == '/')
simplename = s+1;
}
/* Find a backup name that is not the same file.
Change the first lowercase char into uppercase;
if that isn't sufficient, chop off the first char and try again. */
while (stat(bakname, &filestat) == 0 &&
to_device == filestat.st_dev && to_inode == filestat.st_ino) {
/* Skip initial non-lowercase chars. */
for (s=simplename; *s && !islower(*s); s++) ;
if (*s)
*s = toupper(*s);
else
Strcpy(simplename, simplename+1);
}
while (unlink(bakname) >= 0) ; /* while() is for benefit of Eunice */
#ifdef DEBUGGING
if (debug & 4)
say3("Moving %s to %s.\n", to, bakname);
#endif
if (rename(to, bakname) < 0) {
say4("Can't backup %s, output is in %s: %s\n", to, from,
strerror(errno));
return -1;
}
while (unlink(to) >= 0) ;
}
#ifdef DEBUGGING
if (debug & 4)
say3("Moving %s to %s.\n", from, to);
#endif
if (rename(from, to) < 0) { /* different file system? */
Reg4 int tofd;
tofd = creat(to, 0666);
if (tofd < 0) {
say4("Can't create %s, output is in %s: %s\n",
to, from, strerror(errno));
return -1;
}
fromfd = open(from, 0);
if (fromfd < 0)
pfatal2("internal error, can't reopen %s", from);
while ((i=read(fromfd, buf, sizeof buf)) > 0)
if (write(tofd, buf, i) != i)
pfatal1("write failed");
Close(fromfd);
Close(tofd);
}
Unlink(from);
return 0;
}
/* Copy a file. */
void
copy_file(from,to)
char *from, *to;
{
Reg3 int tofd;
Reg2 int fromfd;
Reg1 int i;
tofd = creat(to, 0666);
if (tofd < 0)
pfatal2("can't create %s", to);
fromfd = open(from, 0);
if (fromfd < 0)
pfatal2("internal error, can't reopen %s", from);
while ((i=read(fromfd, buf, sizeof buf)) > 0)
if (write(tofd, buf, i) != i)
pfatal2("write to %s failed", to);
Close(fromfd);
Close(tofd);
}
/* Allocate a unique area for a string. */
char *
savestr(s)
Reg1 char *s;
{
Reg3 char *rv;
Reg2 char *t;
if (!s)
s = "Oops";
t = s;
while (*t++);
rv = malloc((MEM) (t - s));
if (rv == Nullch) {
if (using_plan_a)
out_of_mem = TRUE;
else
fatal1("out of memory\n");
}
else {
t = rv;
while (*t++ = *s++);
}
return rv;
}
#if defined(lint) && defined(CANVARARG)
/*VARARGS ARGSUSED*/
say(pat) char *pat; { ; }
/*VARARGS ARGSUSED*/
fatal(pat) char *pat; { ; }
/*VARARGS ARGSUSED*/
pfatal(pat) char *pat; { ; }
/*VARARGS ARGSUSED*/
ask(pat) char *pat; { ; }
#else
/* Vanilla terminal output (buffered). */
void
say(pat,arg1,arg2,arg3)
char *pat;
long arg1,arg2,arg3;
{
fprintf(stderr, pat, arg1, arg2, arg3);
Fflush(stderr);
}
/* Terminal output, pun intended. */
void /* very void */
fatal(pat,arg1,arg2,arg3)
char *pat;
long arg1,arg2,arg3;
{
fprintf(stderr, "patch: **** ");
fprintf(stderr, pat, arg1, arg2, arg3);
my_exit(1);
}
/* Say something from patch, something from the system, then silence . . . */
void /* very void */
pfatal(pat,arg1,arg2,arg3)
char *pat;
long arg1,arg2,arg3;
{
int errnum = errno;
fprintf(stderr, "patch: **** ");
fprintf(stderr, pat, arg1, arg2, arg3);
fprintf(stderr, ": %s\n", strerror(errnum));
my_exit(1);
}
/* Get a response from the user, somehow or other. */
void
ask(pat,arg1,arg2,arg3)
char *pat;
long arg1,arg2,arg3;
{
int ttyfd;
int r;
bool tty2 = isatty(2);
Sprintf(buf, pat, arg1, arg2, arg3);
Fflush(stderr);
write(2, buf, strlen(buf));
if (tty2) { /* might be redirected to a file */
r = read(2, buf, sizeof buf);
}
else if (isatty(1)) { /* this may be new file output */
Fflush(stdout);
write(1, buf, strlen(buf));
r = read(1, buf, sizeof buf);
}
else if ((ttyfd = open("/dev/tty", 2)) >= 0 && isatty(ttyfd)) {
/* might be deleted or unwriteable */
write(ttyfd, buf, strlen(buf));
r = read(ttyfd, buf, sizeof buf);
Close(ttyfd);
}
else if (isatty(0)) { /* this is probably patch input */
Fflush(stdin);
write(0, buf, strlen(buf));
r = read(0, buf, sizeof buf);
}
else { /* no terminal at all--default it */
buf[0] = '\n';
r = 1;
}
if (r <= 0)
buf[0] = 0;
else
buf[r] = '\0';
if (!tty2)
say1(buf);
}
#endif /* lint */
/* How to handle certain events when not in a critical region. */
void
set_signals(reset)
int reset;
{
#ifndef lint
static RETSIGTYPE (*hupval)(),(*intval)();
if (!reset) {
hupval = signal(SIGHUP, SIG_IGN);
if (hupval != SIG_IGN)
hupval = (RETSIGTYPE(*)())my_exit;
intval = signal(SIGINT, SIG_IGN);
if (intval != SIG_IGN)
intval = (RETSIGTYPE(*)())my_exit;
}
Signal(SIGHUP, hupval);
Signal(SIGINT, intval);
#endif
}
/* How to handle certain events when in a critical region. */
void
ignore_signals()
{
#ifndef lint
Signal(SIGHUP, SIG_IGN);
Signal(SIGINT, SIG_IGN);
#endif
}
/* Make sure we'll have the directories to create a file.
If `striplast' is TRUE, ignore the last element of `filename'. */
void
makedirs(filename,striplast)
Reg1 char *filename;
bool striplast;
{
char tmpbuf[256];
Reg2 char *s = tmpbuf;
char *dirv[20]; /* Point to the NULs between elements. */
Reg3 int i;
Reg4 int dirvp = 0; /* Number of finished entries in dirv. */
/* Copy `filename' into `tmpbuf' with a NUL instead of a slash
between the directories. */
while (*filename) {
if (*filename == '/') {
filename++;
dirv[dirvp++] = s;
*s++ = '\0';
}
else {
*s++ = *filename++;
}
}
*s = '\0';
dirv[dirvp] = s;
if (striplast)
dirvp--;
if (dirvp < 0)
return;
strcpy(buf, "mkdir");
s = buf;
for (i=0; i<=dirvp; i++) {
struct stat sbuf;
if (stat(tmpbuf, &sbuf) && errno == ENOENT) {
while (*s) s++;
*s++ = ' ';
strcpy(s, tmpbuf);
}
*dirv[i] = '/';
}
if (s != buf)
system(buf);
}
/* Make filenames more reasonable. */
char *
fetchname(at,strip_leading,assume_exists)
char *at;
int strip_leading;
int assume_exists;
{
char *fullname;
char *name;
Reg1 char *t;
char tmpbuf[200];
int sleading = strip_leading;
if (!at)
return Nullch;
while (isspace(*at))
at++;
#ifdef DEBUGGING
if (debug & 128)
say4("fetchname %s %d %d\n",at,strip_leading,assume_exists);
#endif
if (strnEQ(at, "/dev/null", 9)) /* so files can be created by diffing */
return Nullch; /* against /dev/null. */
name = fullname = t = savestr(at);
/* Strip off up to `sleading' leading slashes and null terminate. */
for (; *t && !isspace(*t); t++)
if (*t == '/')
if (--sleading >= 0)
name = t+1;
*t = '\0';
/* If no -p option was given (957 is the default value!),
we were given a relative pathname,
and the leading directories that we just stripped off all exist,
put them back on. */
if (strip_leading == 957 && name != fullname && *fullname != '/') {
name[-1] = '\0';
if (stat(fullname, &filestat) == 0 && S_ISDIR (filestat.st_mode)) {
name[-1] = '/';
name=fullname;
}
}
name = savestr(name);
free(fullname);
if (stat(name, &filestat) && !assume_exists) {
char *filebase = basename(name);
int pathlen = filebase - name;
/* Put any leading path into `tmpbuf'. */
strncpy(tmpbuf, name, pathlen);
#define try(f, a1, a2) (Sprintf(tmpbuf + pathlen, f, a1, a2), stat(tmpbuf, &filestat) == 0)
if ( try("RCS/%s%s", filebase, RCSSUFFIX)
|| try("RCS/%s" , filebase, 0)
|| try( "%s%s", filebase, RCSSUFFIX)
|| try("SCCS/%s%s", SCCSPREFIX, filebase)
|| try( "%s%s", SCCSPREFIX, filebase))
return name;
free(name);
name = Nullch;
}
return name;
}
char *
xmalloc (size)
unsigned size;
{
register char *p = (char *) malloc (size);
if (!p)
fatal("out of memory");
return p;
}

88
util.h Normal file
View File

@ -0,0 +1,88 @@
/* $Header: util.h,v 2.0 86/09/17 15:40:06 lwall Exp $
*
* $Log: util.h,v $
* Revision 2.0 86/09/17 15:40:06 lwall
* Baseline for netwide release.
*
*/
/* and for those machine that can't handle a variable argument list */
#ifdef CANVARARG
#define say1 say
#define say2 say
#define say3 say
#define say4 say
#define ask1 ask
#define ask2 ask
#define ask3 ask
#define ask4 ask
#define fatal1 fatal
#define fatal2 fatal
#define fatal3 fatal
#define fatal4 fatal
#define pfatal1 pfatal
#define pfatal2 pfatal
#define pfatal3 pfatal
#define pfatal4 pfatal
#else /* hope they allow multi-line macro actual arguments */
#ifdef lint
#define say1(a) say(a, 0, 0, 0)
#define say2(a,b) say(a, (b)==(b), 0, 0)
#define say3(a,b,c) say(a, (b)==(b), (c)==(c), 0)
#define say4(a,b,c,d) say(a, (b)==(b), (c)==(c), (d)==(d))
#define ask1(a) ask(a, 0, 0, 0)
#define ask2(a,b) ask(a, (b)==(b), 0, 0)
#define ask3(a,b,c) ask(a, (b)==(b), (c)==(c), 0)
#define ask4(a,b,c,d) ask(a, (b)==(b), (c)==(c), (d)==(d))
#define fatal1(a) fatal(a, 0, 0, 0)
#define fatal2(a,b) fatal(a, (b)==(b), 0, 0)
#define fatal3(a,b,c) fatal(a, (b)==(b), (c)==(c), 0)
#define fatal4(a,b,c,d) fatal(a, (b)==(b), (c)==(c), (d)==(d))
#define pfatal1(a) pfatal(a, 0, 0, 0)
#define pfatal2(a,b) pfatal(a, (b)==(b), 0, 0)
#define pfatal3(a,b,c) pfatal(a, (b)==(b), (c)==(c), 0)
#define pfatal4(a,b,c,d) pfatal(a, (b)==(b), (c)==(c), (d)==(d))
#else /* lint */
/* if this doesn't work, try defining CANVARARG above */
#define say1(a) say(a, Nullch, Nullch, Nullch)
#define say2(a,b) say(a, b, Nullch, Nullch)
#define say3(a,b,c) say(a, b, c, Nullch)
#define say4 say
#define ask1(a) ask(a, Nullch, Nullch, Nullch)
#define ask2(a,b) ask(a, b, Nullch, Nullch)
#define ask3(a,b,c) ask(a, b, c, Nullch)
#define ask4 ask
#define fatal1(a) fatal(a, Nullch, Nullch, Nullch)
#define fatal2(a,b) fatal(a, b, Nullch, Nullch)
#define fatal3(a,b,c) fatal(a, b, c, Nullch)
#define fatal4 fatal
#define pfatal1(a) pfatal(a, Nullch, Nullch, Nullch)
#define pfatal2(a,b) pfatal(a, b, Nullch, Nullch)
#define pfatal3(a,b,c) pfatal(a, b, c, Nullch)
#define pfatal4 pfatal
#endif /* lint */
/* if neither of the above work, join all multi-line macro calls. */
#endif
EXT char serrbuf[BUFSIZ]; /* buffer for stderr */
char *fetchname();
int move_file();
void copy_file();
void say();
void fatal();
void pfatal();
void ask();
char *savestr();
void set_signals();
void ignore_signals();
void makedirs();
char *basename();

25
version.c Normal file
View File

@ -0,0 +1,25 @@
/* $Header: version.c,v 2.0 86/09/17 15:40:11 lwall Exp $
*
* $Log: version.c,v $
* Revision 2.0 86/09/17 15:40:11 lwall
* Baseline for netwide release.
*
*/
#include "EXTERN.h"
#include "common.h"
#include "util.h"
#include "INTERN.h"
#include "patchlevel.h"
#include "version.h"
void my_exit();
/* Print out the version number and die. */
void
version()
{
fprintf(stderr, "Patch version %s\n", PATCH_VERSION);
my_exit(0);
}

9
version.h Normal file
View File

@ -0,0 +1,9 @@
/* $Header: version.h,v 2.0 86/09/17 15:40:14 lwall Exp $
*
* $Log: version.h,v $
* Revision 2.0 86/09/17 15:40:14 lwall
* Baseline for netwide release.
*
*/
void version();