mirror of
https://https.git.savannah.gnu.org/git/patch.git
synced 2026-01-27 01:44:34 +00:00
Import of patch-2.1.tar.gz
This commit is contained in:
commit
068f401ee3
339
COPYING
Normal file
339
COPYING
Normal 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
360
ChangeLog
Normal 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
21
EXTERN.h
Normal 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
118
INSTALL
Normal 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
19
INTERN.h
Normal 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
88
Makefile.in
Normal 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
18
NEWS
Normal 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
45
README
Normal 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
475
alloca.c
Normal 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
402
backupfile.c
Normal 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
46
backupfile.h
Normal 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
190
common.h
Normal 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
80
config.h.in
Normal 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
|
||||
24
configure.in
Normal file
24
configure.in
Normal 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
731
getopt.c
Normal 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
129
getopt.h
Normal 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
176
getopt1.c
Normal 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
369
inp.c
Normal 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
18
inp.h
Normal 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
945
patch.c
Normal 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
570
patch.man
Normal 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
1
patchlevel.h
Normal file
@ -0,0 +1 @@
|
||||
#define PATCH_VERSION "2.1"
|
||||
36
pch.h
Normal file
36
pch.h
Normal 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
51
rename.c
Normal 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
433
util.c
Normal 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
88
util.h
Normal 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
25
version.c
Normal 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);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user