Import of GNU patch version 2.4.
This commit is contained in:
commit
511633a2fe
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/patch/dist/; revision=27044 svn path=/vendor/patch/2.4/; revision=27046; tag=vendor/misc-GNU/patch/2.4
340
contrib/patch/COPYING
Normal file
340
contrib/patch/COPYING
Normal file
@ -0,0 +1,340 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
1627
contrib/patch/ChangeLog
Normal file
1627
contrib/patch/ChangeLog
Normal file
File diff suppressed because it is too large
Load Diff
158
contrib/patch/NEWS
Normal file
158
contrib/patch/NEWS
Normal file
@ -0,0 +1,158 @@
|
||||
Known problems:
|
||||
|
||||
* The diffutils 2.7 documentation for `patch' is obsolete; this should be
|
||||
fixed in diffutils 2.8. Until then, see `patch --help' or `man patch'.
|
||||
|
||||
Change in version 2.4:
|
||||
|
||||
* New options:
|
||||
-Z or --set-utc sets times of patched files, assuming diff uses UTC (GMT).
|
||||
-T or --set-time is similar, assuming local time (not recommended).
|
||||
--backup-if-mismatch makes a backup if the patch does not match exactly
|
||||
--no-backup-if-mismatch makes a backup only if otherwise requested
|
||||
|
||||
* The default is now --backup-if-mismatch unless POSIXLY_CORRECT is set.
|
||||
|
||||
* The -B or --prefix, -Y or --basename-prefix, and -z or --suffix options
|
||||
no longer affect whether backups are made (as they did in patch 2.2 and 2.3);
|
||||
they now merely specify the file names used when simple backups are made.
|
||||
|
||||
* When patching a nonexistent file and making backups, an empty backup file
|
||||
is now made (just as with traditional patch); but the backup file is
|
||||
unreadable, as a way of indicating that it represents a nonexistent file.
|
||||
|
||||
* `patch' now matches against empty and nonexistent files more generously.
|
||||
A patch against an empty file applies to a nonexistent file, and vice versa.
|
||||
|
||||
* -g or --get and PATCH_GET now have a numeric value that specifies
|
||||
whether `patch' is getting files.
|
||||
If the value is positive, working files are gotten from RCS or SCCS files;
|
||||
if zero, `patch' ignores RCS and SCCS and working files are not gotten;
|
||||
and if negative, `patch' asks the user whether to get each file.
|
||||
The default is normally negative, but it is zero if POSIXLY_CORRECT is set.
|
||||
|
||||
* The -G or --no-get option introduced in GNU patch 2.3 has been removed;
|
||||
use -g0 instead.
|
||||
|
||||
* The method used to intuit names of files to be patched is changed again:
|
||||
`Index:' lines are normally ignored for context diffs,
|
||||
and RCS and SCCS files are normally looked for when files do not exist.
|
||||
The complete new method is described in the man page.
|
||||
|
||||
* By default, `patch' is now more verbose when patches do not match exactly.
|
||||
|
||||
* The manual page has a new COMPATIBILITY ISSUES section.
|
||||
|
||||
Changes in version 2.3:
|
||||
|
||||
* Unless the POSIXLY_CORRECT environment variable is set:
|
||||
|
||||
- `patch' now distinguishes more accurately between empty and
|
||||
nonexistent files if the input is a context diff.
|
||||
A file is assumed to not exist if its context diff header
|
||||
suggests that it is empty, and if the header timestamp
|
||||
looks like it might be equivalent to 1970-01-01 00:00:00 UTC.
|
||||
- Files that ``become nonexistent'' after patching are now removed.
|
||||
When a file is removed, any empty ancestor directories are also removed.
|
||||
|
||||
* Files are now automatically gotten from RCS and SCCS
|
||||
if the -g or --get option is specified.
|
||||
(The -G or --no-get option, also introduced in 2.3, was withdrawn in 2.4.)
|
||||
|
||||
* If the PATCH_VERSION_CONTROL environment variable is set,
|
||||
it overrides the VERSION_CONTROL environment variable.
|
||||
|
||||
* The method used to intuit names of files to be patched is changed.
|
||||
(It was further revised in 2.4; see above.)
|
||||
|
||||
* The new --binary option makes `patch' read and write files in binary mode.
|
||||
This option has no effect on POSIX-compliant hosts;
|
||||
it is useful only in on operating systems like DOS
|
||||
that distinguish between text and binary I/O.
|
||||
|
||||
* The environment variables TMP and TEMP are consulted for the name of
|
||||
the temporary directory if TMPDIR is not set.
|
||||
|
||||
* A port to MS-DOS and MS-Windows is available; see the `pc' directory.
|
||||
|
||||
* Backup file names are no longer ever computed by uppercasing characters,
|
||||
since this isn't portable to systems with case-insensitive file names.
|
||||
|
||||
Changes in version 2.2:
|
||||
|
||||
* Arbitrary limits removed (e.g. line length, file name length).
|
||||
|
||||
* On POSIX.1-compliant hosts, you can now patch binary files using the output
|
||||
of GNU `diff -a'.
|
||||
|
||||
* New options:
|
||||
--dry-run
|
||||
--help
|
||||
--verbose
|
||||
-i FILE or --input=FILE
|
||||
-y PREF or --basename-prefix=PREF
|
||||
|
||||
* patch is now quieter by default; use --verbose for the old chatty behavior.
|
||||
|
||||
* Patch now complies better with POSIX.2 if your host complies with POSIX.1.
|
||||
|
||||
Therefore:
|
||||
- By default, no backups are made.
|
||||
(But this was changed again in patch 2.4; see above.)
|
||||
- The simple backup file name for F defaults to F.orig
|
||||
regardless of whether the file system supports long file names,
|
||||
and F~ is used only if F.orig is too long for that particular file.
|
||||
- Similarly for the reject file names F.rej and F#.
|
||||
|
||||
Also:
|
||||
- The pseudo-option `+' has been withdrawn.
|
||||
- -b is equivalent to --version-control=simple;
|
||||
`-z SUFF' has the meaning that `-b SUFF' used to.
|
||||
- Names of files to be patched are taken first from *** line and then from
|
||||
--- line of context diffs; then from Index: line; /dev/tty is
|
||||
consulted if none of the above files exist. However, if the patch
|
||||
appears to create a file, the file does not have to exist: instead,
|
||||
the first name with the longest existing directory prefix is taken.
|
||||
(These rules were changed again in patch 2.3 and 2.4; see above.)
|
||||
- Exit status 0 means success, 1 means hunks were rejected, 2 means trouble.
|
||||
- `-l' ignores changes only in spaces and tabs, not in other white space.
|
||||
- If no `-p' option is given, `-pINFINITY' is assumed, instead of trying
|
||||
to guess the proper value.
|
||||
- `-p' now requires an operand; use `-p 0' to get the effect of the old plain
|
||||
`-p' option.
|
||||
- `-p' treats two or more adjacent slashes as if it were one slash.
|
||||
- The TERM signal is caught.
|
||||
- New option `-i F' reads patch from F instead of stdin.
|
||||
|
||||
* The `patch' options and build procedure conform to current GNU standards.
|
||||
For example, the `--version' option now outputs copyright information.
|
||||
|
||||
* When the patch is creating a file, but a nonempty file of that name already
|
||||
exists, `patch' now asks for confirmation before patching.
|
||||
|
||||
* RCS is used only if the version control method is `existing'
|
||||
and there is already an RCS file. Similarly for SCCS.
|
||||
(But this was changed again in patch 2.3 and 2.4; see above.)
|
||||
|
||||
* Copyright notices have been clarified. Every file in this version of `patch'
|
||||
can be distributed under the GNU General Public License. See README for
|
||||
details.
|
||||
|
||||
Changes in version 2.1:
|
||||
|
||||
* A few more portability bugs have been fixed. The version number has
|
||||
been changed from 2.0.12g11 to 2.1, because the name
|
||||
`patch-2.0.12g10' was too long for traditional Unix file systems.
|
||||
|
||||
Versions 2.0.12g9 through 2.0.12g11 fix various portability bugs.
|
||||
|
||||
Changes in version 2.0.12g8:
|
||||
|
||||
* Start of the 12g series, with a GNU-style configure script and
|
||||
long-named options.
|
||||
* Added the -t --batch option, similar to -f.
|
||||
* Improved detection of files that are locked under RCS or SCCS.
|
||||
* Reinstate the -E option to remove output files that are empty after
|
||||
being patched.
|
||||
* Print the system error message when system calls fail.
|
||||
* Fixed various bugs and portability problems.
|
52
contrib/patch/README
Normal file
52
contrib/patch/README
Normal file
@ -0,0 +1,52 @@
|
||||
This version of `patch' has many changes made by the Free Software Foundation.
|
||||
They add support for:
|
||||
* handling arbitrary binary data and large files
|
||||
* the unified context diff format that GNU diff can produce
|
||||
* making GNU Emacs-style backup files
|
||||
* improved interaction with RCS and SCCS
|
||||
* the GNU conventions for option parsing and configuring and compilation.
|
||||
* better POSIX.2 compliance
|
||||
They also fix some bugs. See the NEWS and ChangeLog files for details.
|
||||
|
||||
Tutorial-style documentation for patch is included in the GNU
|
||||
diffutils package. Unfortunately, the diffutils 2.7 documentation
|
||||
for `patch' is obsolete; this should be fixed in diffutils 2.8.
|
||||
In the mean time, see `patch --help', or consult the man page
|
||||
in this distribution.
|
||||
|
||||
For GNU and Unix build and installation instructions, see the file INSTALL.
|
||||
For MS-DOS using DJGPP tools, see the file pc/djgpp/README.
|
||||
For other systems, copy config.hin to config.h and change
|
||||
#undef statements in it to #define as appropriate for your system,
|
||||
and copy Makefile.in to Makefile and set the variables that are
|
||||
enclosed in @ signs as appropriate for your system.
|
||||
|
||||
Please send bug reports for this version of patch to
|
||||
bug-gnu-utils@prep.ai.mit.edu.
|
||||
|
||||
The Free Software Foundation is distributing this version of patch
|
||||
independently because as of this writing, Larry Wall has not released a
|
||||
new version of patch since mid-1988. We have heard that he has been
|
||||
too busy working on other things, like Perl. He has graciously agreed
|
||||
to let GNU `patch' be distributed under the terms of the GNU General
|
||||
Public License.
|
||||
|
||||
------
|
||||
|
||||
Copyright 1984, 1985, 1986, 1987, 1988 Larry Wall
|
||||
Copyright 1989, 1990, 1991, 1992, 1993, 1997 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this file; see the file COPYING.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
14
contrib/patch/acconfig.h
Normal file
14
contrib/patch/acconfig.h
Normal file
@ -0,0 +1,14 @@
|
||||
/* Local acconfig.h for autoheader.
|
||||
Descriptive text for the C preprocessor macros that
|
||||
the patch configure.in can define.
|
||||
autoheader copies the comments into config.hin. */
|
||||
|
||||
/* Define if there is a member named d_ino in the struct describing
|
||||
directory headers. */
|
||||
#undef D_INO_IN_DIRENT
|
||||
|
||||
/* Define if memchr works. */
|
||||
#undef HAVE_MEMCHR
|
||||
|
||||
/* Define if `struct utimbuf' is declared -- usually in <utime.h>. */
|
||||
#undef HAVE_STRUCT_UTIMBUF
|
106
contrib/patch/addext.c
Normal file
106
contrib/patch/addext.c
Normal file
@ -0,0 +1,106 @@
|
||||
/* addext.c -- add an extension to a file name
|
||||
Copyright (C) 1990, 1997 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* Written by David MacKenzie <djm@gnu.ai.mit.edu> and Paul Eggert */
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_DOS_FILE_NAMES
|
||||
#define HAVE_DOS_FILE_NAMES 0
|
||||
#endif
|
||||
#ifndef HAVE_LONG_FILE_NAMES
|
||||
#define HAVE_LONG_FILE_NAMES 0
|
||||
#endif
|
||||
|
||||
#include <backupfile.h>
|
||||
|
||||
#if HAVE_LIMITS_H
|
||||
# include <limits.h>
|
||||
#endif
|
||||
#ifndef _POSIX_NAME_MAX
|
||||
#define _POSIX_NAME_MAX 14
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#if HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# include <strings.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
/* Append to FILENAME the extension EXT, unless the result would be too long,
|
||||
in which case just append the character E. */
|
||||
|
||||
void
|
||||
addext (filename, ext, e)
|
||||
char *filename;
|
||||
char const *ext;
|
||||
int e;
|
||||
{
|
||||
char *s = base_name (filename);
|
||||
size_t slen = strlen (s), extlen = strlen (ext);
|
||||
long slen_max = -1;
|
||||
|
||||
#if HAVE_PATHCONF && defined _PC_NAME_MAX
|
||||
if (slen + extlen <= _POSIX_NAME_MAX && ! HAVE_DOS_FILE_NAMES)
|
||||
/* The file name is so short there's no need to call pathconf. */
|
||||
slen_max = _POSIX_NAME_MAX;
|
||||
else if (s == filename)
|
||||
slen_max = pathconf (".", _PC_NAME_MAX);
|
||||
else
|
||||
{
|
||||
char c = *s;
|
||||
*s = 0;
|
||||
slen_max = pathconf (filename, _PC_NAME_MAX);
|
||||
*s = c;
|
||||
}
|
||||
#endif
|
||||
if (slen_max < 0)
|
||||
slen_max = HAVE_LONG_FILE_NAMES ? 255 : 14;
|
||||
|
||||
if (HAVE_DOS_FILE_NAMES && slen_max <= 12)
|
||||
{
|
||||
/* Live within DOS's 8.3 limit. */
|
||||
char *dot = strchr (s, '.');
|
||||
if (dot)
|
||||
{
|
||||
slen -= dot + 1 - s;
|
||||
s = dot + 1;
|
||||
slen_max = 3;
|
||||
}
|
||||
else
|
||||
slen_max = 8;
|
||||
extlen = 9; /* Don't use EXT. */
|
||||
}
|
||||
|
||||
if (slen + extlen <= slen_max)
|
||||
strcpy (s + slen, ext);
|
||||
else
|
||||
{
|
||||
if (slen_max <= slen)
|
||||
slen = slen_max - 1;
|
||||
s[slen] = e;
|
||||
s[slen + 1] = 0;
|
||||
}
|
||||
}
|
92
contrib/patch/argmatch.c
Normal file
92
contrib/patch/argmatch.c
Normal file
@ -0,0 +1,92 @@
|
||||
/* argmatch.c -- find a match for a string in an array
|
||||
Copyright (C) 1990, 1997 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* Written by David MacKenzie <djm@gnu.ai.mit.edu> */
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <argmatch.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#if HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# include <strings.h>
|
||||
#endif
|
||||
|
||||
/* If ARG is an unambiguous match for an element of the
|
||||
null-terminated array OPTLIST, return the index in OPTLIST
|
||||
of the matched element, else -1 if it does not match any element
|
||||
or -2 if it is ambiguous (is a prefix of more than one element). */
|
||||
|
||||
int
|
||||
argmatch (arg, optlist)
|
||||
const char *arg;
|
||||
const char *const *optlist;
|
||||
{
|
||||
int i; /* Temporary index in OPTLIST. */
|
||||
size_t arglen; /* Length of ARG. */
|
||||
int matchind = -1; /* Index of first nonexact match. */
|
||||
int ambiguous = 0; /* If nonzero, multiple nonexact match(es). */
|
||||
|
||||
arglen = strlen (arg);
|
||||
|
||||
/* Test all elements for either exact match or abbreviated matches. */
|
||||
for (i = 0; optlist[i]; i++)
|
||||
{
|
||||
if (!strncmp (optlist[i], arg, arglen))
|
||||
{
|
||||
if (strlen (optlist[i]) == arglen)
|
||||
/* Exact match found. */
|
||||
return i;
|
||||
else if (matchind == -1)
|
||||
/* First nonexact match found. */
|
||||
matchind = i;
|
||||
else
|
||||
/* Second nonexact match found. */
|
||||
ambiguous = 1;
|
||||
}
|
||||
}
|
||||
if (ambiguous)
|
||||
return -2;
|
||||
else
|
||||
return matchind;
|
||||
}
|
||||
|
||||
/* Error reporting for argmatch.
|
||||
KIND is a description of the type of entity that was being matched.
|
||||
VALUE is the invalid value that was given.
|
||||
PROBLEM is the return value from argmatch. */
|
||||
|
||||
void
|
||||
invalid_arg (kind, value, problem)
|
||||
const char *kind;
|
||||
const char *value;
|
||||
int problem;
|
||||
{
|
||||
fprintf (stderr, "%s: ", program_name);
|
||||
if (problem == -1)
|
||||
fprintf (stderr, "invalid");
|
||||
else /* Assume -2. */
|
||||
fprintf (stderr, "ambiguous");
|
||||
fprintf (stderr, " %s `%s'\n", kind, value);
|
||||
}
|
12
contrib/patch/argmatch.h
Normal file
12
contrib/patch/argmatch.h
Normal file
@ -0,0 +1,12 @@
|
||||
/* argmatch.h -- declarations for matching arguments against option lists */
|
||||
|
||||
#if defined __STDC__ || __GNUC__
|
||||
# define __ARGMATCH_P(args) args
|
||||
#else
|
||||
# define __ARGMATCH_P(args) ()
|
||||
#endif
|
||||
|
||||
int argmatch __ARGMATCH_P ((const char *, const char * const *));
|
||||
void invalid_arg __ARGMATCH_P ((const char *, const char *, int));
|
||||
|
||||
extern char const program_name[];
|
251
contrib/patch/backupfile.c
Normal file
251
contrib/patch/backupfile.c
Normal file
@ -0,0 +1,251 @@
|
||||
/* backupfile.c -- make Emacs style backup file names
|
||||
Copyright (C) 1990,1991,1992,1993,1995,1997 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* Written by David MacKenzie <djm@gnu.ai.mit.edu>.
|
||||
Some algorithms adapted from GNU Emacs. */
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <argmatch.h>
|
||||
#include <backupfile.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#if HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# include <strings.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_DIRENT_H
|
||||
# include <dirent.h>
|
||||
# define NLENGTH(direct) strlen ((direct)->d_name)
|
||||
#else
|
||||
# define dirent direct
|
||||
# define NLENGTH(direct) ((size_t) (direct)->d_namlen)
|
||||
# if HAVE_SYS_NDIR_H
|
||||
# include <sys/ndir.h>
|
||||
# endif
|
||||
# if HAVE_SYS_DIR_H
|
||||
# include <sys/dir.h>
|
||||
# endif
|
||||
# if HAVE_NDIR_H
|
||||
# include <ndir.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if CLOSEDIR_VOID
|
||||
/* Fake a return value. */
|
||||
# define CLOSEDIR(d) (closedir (d), 0)
|
||||
#else
|
||||
# define CLOSEDIR(d) closedir (d)
|
||||
#endif
|
||||
|
||||
#if STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
char *malloc ();
|
||||
#endif
|
||||
|
||||
#if HAVE_DIRENT_H || HAVE_NDIR_H || HAVE_SYS_DIR_H || HAVE_SYS_NDIR_H
|
||||
# define HAVE_DIR 1
|
||||
#else
|
||||
# define HAVE_DIR 0
|
||||
#endif
|
||||
|
||||
#if HAVE_LIMITS_H
|
||||
# include <limits.h>
|
||||
#endif
|
||||
#ifndef CHAR_BIT
|
||||
#define CHAR_BIT 8
|
||||
#endif
|
||||
/* Upper bound on the string length of an integer converted to string.
|
||||
302 / 1000 is ceil (log10 (2.0)). Subtract 1 for the sign bit;
|
||||
add 1 for integer division truncation; add 1 more for a minus sign. */
|
||||
#define INT_STRLEN_BOUND(t) ((sizeof (t) * CHAR_BIT - 1) * 302 / 1000 + 2)
|
||||
|
||||
/* ISDIGIT differs from isdigit, as follows:
|
||||
- Its arg may be any int or unsigned int; it need not be an unsigned char.
|
||||
- It's guaranteed to evaluate its argument exactly once.
|
||||
- It's typically faster.
|
||||
Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
|
||||
only '0' through '9' are digits. Prefer ISDIGIT to isdigit unless
|
||||
it's important to use the locale's definition of `digit' even when the
|
||||
host does not conform to Posix. */
|
||||
#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
|
||||
|
||||
#if D_INO_IN_DIRENT
|
||||
# define REAL_DIR_ENTRY(dp) ((dp)->d_ino != 0)
|
||||
#else
|
||||
# define REAL_DIR_ENTRY(dp) 1
|
||||
#endif
|
||||
|
||||
/* Which type of backup file names are generated. */
|
||||
enum backup_type backup_type = none;
|
||||
|
||||
/* The extension added to file names to produce a simple (as opposed
|
||||
to numbered) backup file name. */
|
||||
const char *simple_backup_suffix = ".orig";
|
||||
|
||||
static int max_backup_version __BACKUPFILE_P ((const char *, const char *));
|
||||
static int version_number __BACKUPFILE_P ((const char *, const char *, size_t));
|
||||
|
||||
/* Return the name of the new backup file for file FILE,
|
||||
allocated with malloc. Return 0 if out of memory.
|
||||
FILE must not end with a '/' unless it is the root directory. */
|
||||
|
||||
char *
|
||||
find_backup_file_name (file)
|
||||
const char *file;
|
||||
{
|
||||
size_t backup_suffix_size_max;
|
||||
size_t file_len = strlen (file);
|
||||
size_t numbered_suffix_size_max = INT_STRLEN_BOUND (int) + 4;
|
||||
char *s;
|
||||
const char *suffix = simple_backup_suffix;
|
||||
|
||||
/* Allow room for simple or `.~N~' backups. */
|
||||
backup_suffix_size_max = strlen (simple_backup_suffix) + 1;
|
||||
if (HAVE_DIR && backup_suffix_size_max < numbered_suffix_size_max)
|
||||
backup_suffix_size_max = numbered_suffix_size_max;
|
||||
|
||||
s = malloc (file_len + backup_suffix_size_max + numbered_suffix_size_max);
|
||||
if (s)
|
||||
{
|
||||
strcpy (s, file);
|
||||
|
||||
#if HAVE_DIR
|
||||
if (backup_type != simple && backup_type != none)
|
||||
{
|
||||
int highest_backup;
|
||||
size_t dir_len = base_name (s) - s;
|
||||
|
||||
strcpy (s + dir_len, ".");
|
||||
highest_backup = max_backup_version (file + dir_len, s);
|
||||
if (! (backup_type == numbered_existing && highest_backup == 0))
|
||||
{
|
||||
char *numbered_suffix = s + (file_len + backup_suffix_size_max);
|
||||
sprintf (numbered_suffix, ".~%d~", highest_backup + 1);
|
||||
suffix = numbered_suffix;
|
||||
}
|
||||
strcpy (s, file);
|
||||
}
|
||||
#endif /* HAVE_DIR */
|
||||
|
||||
addext (s, suffix, '~');
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
#if HAVE_DIR
|
||||
|
||||
/* Return the number of the highest-numbered backup file for file
|
||||
FILE in directory DIR. If there are no numbered backups
|
||||
of FILE in DIR, or an error occurs reading DIR, return 0.
|
||||
*/
|
||||
|
||||
static int
|
||||
max_backup_version (file, dir)
|
||||
const char *file;
|
||||
const char *dir;
|
||||
{
|
||||
DIR *dirp;
|
||||
struct dirent *dp;
|
||||
int highest_version;
|
||||
int this_version;
|
||||
size_t file_name_length;
|
||||
|
||||
dirp = opendir (dir);
|
||||
if (!dirp)
|
||||
return 0;
|
||||
|
||||
highest_version = 0;
|
||||
file_name_length = strlen (file);
|
||||
|
||||
while ((dp = readdir (dirp)) != 0)
|
||||
{
|
||||
if (!REAL_DIR_ENTRY (dp) || NLENGTH (dp) < file_name_length + 4)
|
||||
continue;
|
||||
|
||||
this_version = version_number (file, dp->d_name, file_name_length);
|
||||
if (this_version > highest_version)
|
||||
highest_version = this_version;
|
||||
}
|
||||
if (CLOSEDIR (dirp))
|
||||
return 0;
|
||||
return highest_version;
|
||||
}
|
||||
|
||||
/* If BACKUP is a numbered backup of BASE, return its version number;
|
||||
otherwise return 0. BASE_LENGTH is the length of BASE.
|
||||
*/
|
||||
|
||||
static int
|
||||
version_number (base, backup, base_length)
|
||||
const char *base;
|
||||
const char *backup;
|
||||
size_t base_length;
|
||||
{
|
||||
int version;
|
||||
const char *p;
|
||||
|
||||
version = 0;
|
||||
if (strncmp (base, backup, base_length) == 0
|
||||
&& backup[base_length] == '.'
|
||||
&& backup[base_length + 1] == '~')
|
||||
{
|
||||
for (p = &backup[base_length + 2]; ISDIGIT (*p); ++p)
|
||||
version = version * 10 + *p - '0';
|
||||
if (p[0] != '~' || p[1])
|
||||
version = 0;
|
||||
}
|
||||
return version;
|
||||
}
|
||||
#endif /* HAVE_DIR */
|
||||
|
||||
static const char * const backup_args[] =
|
||||
{
|
||||
"never", "simple", "nil", "existing", "t", "numbered", 0
|
||||
};
|
||||
|
||||
static const enum backup_type backup_types[] =
|
||||
{
|
||||
simple, simple, numbered_existing, numbered_existing, numbered, numbered
|
||||
};
|
||||
|
||||
/* Return the type of backup indicated by VERSION.
|
||||
Unique abbreviations are accepted. */
|
||||
|
||||
enum backup_type
|
||||
get_version (version)
|
||||
const char *version;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (version == 0 || *version == 0)
|
||||
return numbered_existing;
|
||||
i = argmatch (version, backup_args);
|
||||
if (i < 0)
|
||||
{
|
||||
invalid_arg ("version control type", version, i);
|
||||
exit (2);
|
||||
}
|
||||
return backup_types[i];
|
||||
}
|
50
contrib/patch/backupfile.h
Normal file
50
contrib/patch/backupfile.h
Normal file
@ -0,0 +1,50 @@
|
||||
/* backupfile.h -- declarations for making Emacs style backup file names
|
||||
Copyright (C) 1990, 1991, 1992, 1997 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* When to make backup files. */
|
||||
enum backup_type
|
||||
{
|
||||
/* Never make backups. */
|
||||
none,
|
||||
|
||||
/* Make simple backups of every file. */
|
||||
simple,
|
||||
|
||||
/* Make numbered backups of files that already have numbered backups,
|
||||
and simple backups of the others. */
|
||||
numbered_existing,
|
||||
|
||||
/* Make numbered backups of every file. */
|
||||
numbered
|
||||
};
|
||||
|
||||
extern enum backup_type backup_type;
|
||||
extern char const *simple_backup_suffix;
|
||||
|
||||
#ifndef __BACKUPFILE_P
|
||||
# if defined __STDC__ || __GNUC__
|
||||
# define __BACKUPFILE_P(args) args
|
||||
# else
|
||||
# define __BACKUPFILE_P(args) ()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
char *base_name __BACKUPFILE_P ((char const *));
|
||||
char *find_backup_file_name __BACKUPFILE_P ((char const *));
|
||||
enum backup_type get_version __BACKUPFILE_P ((char const *));
|
||||
void addext __BACKUPFILE_P ((char *, char const *, int));
|
32
contrib/patch/basename.c
Normal file
32
contrib/patch/basename.c
Normal file
@ -0,0 +1,32 @@
|
||||
/* basename.c -- return the last element in a path */
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <backupfile.h>
|
||||
|
||||
#ifndef FILESYSTEM_PREFIX_LEN
|
||||
#define FILESYSTEM_PREFIX_LEN(f) 0
|
||||
#endif
|
||||
|
||||
#ifndef ISSLASH
|
||||
#define ISSLASH(c) ((c) == '/')
|
||||
#endif
|
||||
|
||||
/* In general, we can't use the builtin `basename' function if available,
|
||||
since it has different meanings in different environments.
|
||||
In some environments the builtin `basename' modifies its argument. */
|
||||
|
||||
char *
|
||||
base_name (name)
|
||||
char const *name;
|
||||
{
|
||||
char const *base = name += FILESYSTEM_PREFIX_LEN (name);
|
||||
|
||||
for (; *name; name++)
|
||||
if (ISSLASH (*name))
|
||||
base = name + 1;
|
||||
|
||||
return (char *) base;
|
||||
}
|
307
contrib/patch/common.h
Normal file
307
contrib/patch/common.h
Normal file
@ -0,0 +1,307 @@
|
||||
/* common definitions for `patch' */
|
||||
|
||||
/* $Id: common.h,v 1.18 1997/06/13 06:28:37 eggert Exp $ */
|
||||
|
||||
/*
|
||||
Copyright 1986, 1988 Larry Wall
|
||||
Copyright 1990, 1991, 1992, 1993, 1997 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef DEBUGGING
|
||||
#define DEBUGGING 1
|
||||
#endif
|
||||
|
||||
/* We must define `volatile' and `const' first (the latter inside config.h),
|
||||
so that they're used consistently in all system includes. */
|
||||
#ifndef __STDC__
|
||||
# ifndef volatile
|
||||
# define volatile
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Enable support for fseeko and ftello on hosts
|
||||
where it is available but is turned off by default.
|
||||
This must be defined before any system file is included. */
|
||||
#define _LARGEFILE_SOURCE 1
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#if ! defined S_ISDIR && defined S_IFDIR
|
||||
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
||||
#endif
|
||||
#if ! defined S_ISREG && defined S_IFREG
|
||||
# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
||||
#endif
|
||||
#ifndef S_IXOTH
|
||||
#define S_IXOTH 1
|
||||
#endif
|
||||
#ifndef S_IWOTH
|
||||
#define S_IWOTH 2
|
||||
#endif
|
||||
#ifndef S_IROTH
|
||||
#define S_IROTH 4
|
||||
#endif
|
||||
#ifndef S_IXGRP
|
||||
#define S_IXGRP (S_IXOTH << 3)
|
||||
#endif
|
||||
#ifndef S_IWGRP
|
||||
#define S_IWGRP (S_IWOTH << 3)
|
||||
#endif
|
||||
#ifndef S_IRGRP
|
||||
#define S_IRGRP (S_IROTH << 3)
|
||||
#endif
|
||||
#ifndef S_IXUSR
|
||||
#define S_IXUSR (S_IXOTH << 6)
|
||||
#endif
|
||||
#ifndef S_IWUSR
|
||||
#define S_IWUSR (S_IWOTH << 6)
|
||||
#endif
|
||||
#ifndef S_IRUSR
|
||||
#define S_IRUSR (S_IROTH << 6)
|
||||
#endif
|
||||
|
||||
#if HAVE_LIMITS_H
|
||||
# include <limits.h>
|
||||
#endif
|
||||
#ifndef INT_MAX
|
||||
#define INT_MAX 2147483647
|
||||
#endif
|
||||
#ifndef LONG_MIN
|
||||
#define LONG_MIN (-1-2147483647L)
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
/* CTYPE_DOMAIN (C) is nonzero if the unsigned char C can safely be given
|
||||
as an argument to <ctype.h> macros like `isspace'. */
|
||||
#if STDC_HEADERS
|
||||
#define CTYPE_DOMAIN(c) 1
|
||||
#else
|
||||
#define CTYPE_DOMAIN(c) ((unsigned) (c) <= 0177)
|
||||
#endif
|
||||
#ifndef ISSPACE
|
||||
#define ISSPACE(c) (CTYPE_DOMAIN (c) && isspace (c))
|
||||
#endif
|
||||
|
||||
#ifndef ISDIGIT
|
||||
#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef FILESYSTEM_PREFIX_LEN
|
||||
#define FILESYSTEM_PREFIX_LEN(f) 0
|
||||
#endif
|
||||
|
||||
#ifndef ISSLASH
|
||||
#define ISSLASH(c) ((c) == '/')
|
||||
#endif
|
||||
|
||||
|
||||
/* constants */
|
||||
|
||||
/* AIX predefines these. */
|
||||
#ifdef TRUE
|
||||
#undef TRUE
|
||||
#endif
|
||||
#ifdef FALSE
|
||||
#undef FALSE
|
||||
#endif
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
/* handy definitions */
|
||||
|
||||
#define strEQ(s1,s2) (!strcmp(s1, s2))
|
||||
#define strnEQ(s1,s2,l) (!strncmp(s1, s2, l))
|
||||
|
||||
/* typedefs */
|
||||
|
||||
typedef int bool; /* must promote to itself */
|
||||
typedef long LINENUM; /* must be signed */
|
||||
|
||||
/* globals */
|
||||
|
||||
extern char const program_name[];
|
||||
|
||||
XTERN char *buf; /* general purpose buffer */
|
||||
XTERN size_t bufsize; /* allocated size of buf */
|
||||
|
||||
XTERN bool using_plan_a; /* try to keep everything in memory */
|
||||
|
||||
XTERN char *inname;
|
||||
XTERN char *outfile;
|
||||
XTERN int inerrno;
|
||||
XTERN int invc;
|
||||
XTERN struct stat instat;
|
||||
XTERN bool dry_run;
|
||||
XTERN bool posixly_correct;
|
||||
|
||||
XTERN char const *origprae;
|
||||
XTERN char const *origbase;
|
||||
|
||||
XTERN char const * volatile TMPOUTNAME;
|
||||
XTERN char const * volatile TMPINNAME;
|
||||
XTERN char const * volatile TMPPATNAME;
|
||||
|
||||
#ifdef DEBUGGING
|
||||
XTERN int debug;
|
||||
#else
|
||||
# define debug 0
|
||||
#endif
|
||||
XTERN bool force;
|
||||
XTERN bool batch;
|
||||
XTERN bool noreverse;
|
||||
XTERN int reverse;
|
||||
XTERN enum { DEFAULT_VERBOSITY, SILENT, VERBOSE } verbosity;
|
||||
XTERN bool skip_rest_of_patch;
|
||||
XTERN int strippath;
|
||||
XTERN bool canonicalize;
|
||||
XTERN int patch_get;
|
||||
XTERN int set_time;
|
||||
XTERN int set_utc;
|
||||
|
||||
enum diff
|
||||
{
|
||||
NO_DIFF,
|
||||
CONTEXT_DIFF,
|
||||
NORMAL_DIFF,
|
||||
ED_DIFF,
|
||||
NEW_CONTEXT_DIFF,
|
||||
UNI_DIFF
|
||||
};
|
||||
|
||||
XTERN enum diff diff_type;
|
||||
|
||||
XTERN char *revision; /* prerequisite revision, if any */
|
||||
|
||||
#ifdef __STDC__
|
||||
# define GENERIC_OBJECT void
|
||||
#else
|
||||
# define GENERIC_OBJECT char
|
||||
#endif
|
||||
|
||||
#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 6) || __STRICT_ANSI__
|
||||
# define __attribute__(x)
|
||||
#endif
|
||||
|
||||
#ifndef PARAMS
|
||||
# ifdef __STDC__
|
||||
# define PARAMS(args) args
|
||||
# else
|
||||
# define PARAMS(args) ()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
GENERIC_OBJECT *xmalloc PARAMS ((size_t));
|
||||
void fatal_exit PARAMS ((int)) __attribute__ ((noreturn));
|
||||
|
||||
#include <errno.h>
|
||||
#if !STDC_HEADERS && !defined errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#if STDC_HEADERS || HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# if !HAVE_MEMCHR
|
||||
# define memcmp(s1, s2, n) bcmp (s1, s2, n)
|
||||
# define memcpy(d, s, n) bcopy (s, d, n)
|
||||
GENERIC_OBJECT *memchr ();
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
long atol ();
|
||||
char *getenv ();
|
||||
GENERIC_OBJECT *malloc ();
|
||||
GENERIC_OBJECT *realloc ();
|
||||
#endif
|
||||
|
||||
#if HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#ifndef lseek
|
||||
off_t lseek ();
|
||||
#endif
|
||||
#ifndef SEEK_SET
|
||||
#define SEEK_SET 0
|
||||
#endif
|
||||
#ifndef STDIN_FILENO
|
||||
#define STDIN_FILENO 0
|
||||
#endif
|
||||
#ifndef STDOUT_FILENO
|
||||
#define STDOUT_FILENO 1
|
||||
#endif
|
||||
#ifndef STDERR_FILENO
|
||||
#define STDERR_FILENO 2
|
||||
#endif
|
||||
#if _LFS_LARGEFILE
|
||||
typedef off_t file_offset;
|
||||
# define file_seek fseeko
|
||||
# define file_tell ftello
|
||||
#else
|
||||
typedef long file_offset;
|
||||
# define file_seek fseek
|
||||
# define file_tell ftell
|
||||
#endif
|
||||
|
||||
#if HAVE_FCNTL_H
|
||||
# include <fcntl.h>
|
||||
#endif
|
||||
#ifndef O_RDONLY
|
||||
#define O_RDONLY 0
|
||||
#endif
|
||||
#ifndef O_WRONLY
|
||||
#define O_WRONLY 1
|
||||
#endif
|
||||
#ifndef O_RDWR
|
||||
#define O_RDWR 2
|
||||
#endif
|
||||
#ifndef _O_BINARY
|
||||
#define _O_BINARY 0
|
||||
#endif
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY _O_BINARY
|
||||
#endif
|
||||
#ifndef O_CREAT
|
||||
#define O_CREAT 0
|
||||
#endif
|
||||
#ifndef O_TRUNC
|
||||
#define O_TRUNC 0
|
||||
#endif
|
||||
|
||||
#if HAVE_SETMODE
|
||||
XTERN int binary_transput; /* O_BINARY if binary i/o is desired */
|
||||
#else
|
||||
# define binary_transput 0
|
||||
#endif
|
||||
|
||||
#ifndef NULL_DEVICE
|
||||
#define NULL_DEVICE "/dev/null"
|
||||
#endif
|
||||
|
||||
#ifndef TTY_DEVICE
|
||||
#define TTY_DEVICE "/dev/tty"
|
||||
#endif
|
1053
contrib/patch/getopt.c
Normal file
1053
contrib/patch/getopt.c
Normal file
File diff suppressed because it is too large
Load Diff
133
contrib/patch/getopt.h
Normal file
133
contrib/patch/getopt.h
Normal file
@ -0,0 +1,133 @@
|
||||
/* Declarations for getopt.
|
||||
Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc.
|
||||
|
||||
NOTE: The canonical source of this file is maintained with the GNU C Library.
|
||||
Bugs can be reported to bug-glibc@prep.ai.mit.edu.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
USA. */
|
||||
|
||||
#ifndef _GETOPT_H
|
||||
#define _GETOPT_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* For communication from `getopt' to the caller.
|
||||
When `getopt' finds an option that takes an argument,
|
||||
the argument value is returned here.
|
||||
Also, when `ordering' is RETURN_IN_ORDER,
|
||||
each non-option ARGV-element is returned here. */
|
||||
|
||||
extern char *optarg;
|
||||
|
||||
/* Index in ARGV of the next element to be scanned.
|
||||
This is used for communication to and from the caller
|
||||
and for communication between successive calls to `getopt'.
|
||||
|
||||
On entry to `getopt', zero means this is the first call; initialize.
|
||||
|
||||
When `getopt' returns -1, this is the index of the first of the
|
||||
non-option elements that the caller should itself scan.
|
||||
|
||||
Otherwise, `optind' communicates from one call to the next
|
||||
how much of ARGV has been scanned so far. */
|
||||
|
||||
extern int optind;
|
||||
|
||||
/* Callers store zero here to inhibit the error message `getopt' prints
|
||||
for unrecognized options. */
|
||||
|
||||
extern int opterr;
|
||||
|
||||
/* Set to an option character which was unrecognized. */
|
||||
|
||||
extern int optopt;
|
||||
|
||||
/* Describe the long-named options requested by the application.
|
||||
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
|
||||
of `struct option' terminated by an element containing a name which is
|
||||
zero.
|
||||
|
||||
The field `has_arg' is:
|
||||
no_argument (or 0) if the option does not take an argument,
|
||||
required_argument (or 1) if the option requires an argument,
|
||||
optional_argument (or 2) if the option takes an optional argument.
|
||||
|
||||
If the field `flag' is not NULL, it points to a variable that is set
|
||||
to the value given in the field `val' when the option is found, but
|
||||
left unchanged if the option is not found.
|
||||
|
||||
To have a long-named option do something other than set an `int' to
|
||||
a compiled-in constant, such as set a value from `optarg', set the
|
||||
option's `flag' field to zero and its `val' field to a nonzero
|
||||
value (the equivalent single-letter option character, if there is
|
||||
one). For long options that have a zero `flag' field, `getopt'
|
||||
returns the contents of the `val' field. */
|
||||
|
||||
struct option
|
||||
{
|
||||
#if defined (__STDC__) && __STDC__
|
||||
const char *name;
|
||||
#else
|
||||
char *name;
|
||||
#endif
|
||||
/* has_arg can't be an enum because some compilers complain about
|
||||
type mismatches in all the code that assumes it is an int. */
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
|
||||
/* Names for the values of the `has_arg' field of `struct option'. */
|
||||
|
||||
#define no_argument 0
|
||||
#define required_argument 1
|
||||
#define optional_argument 2
|
||||
|
||||
#if defined (__STDC__) && __STDC__
|
||||
#ifdef __GNU_LIBRARY__
|
||||
/* Many other libraries have conflicting prototypes for getopt, with
|
||||
differences in the consts, in stdlib.h. To avoid compilation
|
||||
errors, only prototype getopt for the GNU C library. */
|
||||
extern int getopt (int argc, char *const *argv, const char *shortopts);
|
||||
#else /* not __GNU_LIBRARY__ */
|
||||
extern int getopt ();
|
||||
#endif /* __GNU_LIBRARY__ */
|
||||
extern int getopt_long (int argc, char *const *argv, const char *shortopts,
|
||||
const struct option *longopts, int *longind);
|
||||
extern int getopt_long_only (int argc, char *const *argv,
|
||||
const char *shortopts,
|
||||
const struct option *longopts, int *longind);
|
||||
|
||||
/* Internal only. Users should not call this directly. */
|
||||
extern int _getopt_internal (int argc, char *const *argv,
|
||||
const char *shortopts,
|
||||
const struct option *longopts, int *longind,
|
||||
int long_only);
|
||||
#else /* not __STDC__ */
|
||||
extern int getopt ();
|
||||
extern int getopt_long ();
|
||||
extern int getopt_long_only ();
|
||||
|
||||
extern int _getopt_internal ();
|
||||
#endif /* __STDC__ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _GETOPT_H */
|
189
contrib/patch/getopt1.c
Normal file
189
contrib/patch/getopt1.c
Normal file
@ -0,0 +1,189 @@
|
||||
/* getopt_long and getopt_long_only entry points for GNU getopt.
|
||||
Copyright (C) 1987,88,89,90,91,92,93,94,96,97 Free Software Foundation, Inc.
|
||||
|
||||
NOTE: The canonical source of this file is maintained with the GNU C Library.
|
||||
Bugs can be reported to bug-glibc@prep.ai.mit.edu.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
USA. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "getopt.h"
|
||||
|
||||
#if !defined (__STDC__) || !__STDC__
|
||||
/* This is a separate conditional since some stdc systems
|
||||
reject `defined (const)'. */
|
||||
#ifndef const
|
||||
#define const
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* Comment out all this code if we are using the GNU C Library, and are not
|
||||
actually compiling the library itself. This code is part of the GNU C
|
||||
Library, but also included in many other GNU distributions. Compiling
|
||||
and linking in this code is a waste when using the GNU C library
|
||||
(especially if it is a shared library). Rather than having every GNU
|
||||
program understand `configure --with-gnu-libc' and omit the object files,
|
||||
it is simpler to just do this in the source for each such file. */
|
||||
|
||||
#define GETOPT_INTERFACE_VERSION 2
|
||||
#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
|
||||
#include <gnu-versions.h>
|
||||
#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
|
||||
#define ELIDE_CODE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ELIDE_CODE
|
||||
|
||||
|
||||
/* This needs to come after some library #include
|
||||
to get __GNU_LIBRARY__ defined. */
|
||||
#ifdef __GNU_LIBRARY__
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
int
|
||||
getopt_long (argc, argv, options, long_options, opt_index)
|
||||
int argc;
|
||||
char *const *argv;
|
||||
const char *options;
|
||||
const struct option *long_options;
|
||||
int *opt_index;
|
||||
{
|
||||
return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
|
||||
}
|
||||
|
||||
/* Like getopt_long, but '-' as well as '--' can indicate a long option.
|
||||
If an option that starts with '-' (not '--') doesn't match a long option,
|
||||
but does match a short option, it is parsed as a short option
|
||||
instead. */
|
||||
|
||||
int
|
||||
getopt_long_only (argc, argv, options, long_options, opt_index)
|
||||
int argc;
|
||||
char *const *argv;
|
||||
const char *options;
|
||||
const struct option *long_options;
|
||||
int *opt_index;
|
||||
{
|
||||
return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
|
||||
}
|
||||
|
||||
|
||||
#endif /* Not ELIDE_CODE. */
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int c;
|
||||
int digit_optind = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int this_option_optind = optind ? optind : 1;
|
||||
int option_index = 0;
|
||||
static struct option long_options[] =
|
||||
{
|
||||
{"add", 1, 0, 0},
|
||||
{"append", 0, 0, 0},
|
||||
{"delete", 1, 0, 0},
|
||||
{"verbose", 0, 0, 0},
|
||||
{"create", 0, 0, 0},
|
||||
{"file", 1, 0, 0},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
c = getopt_long (argc, argv, "abc:d:0123456789",
|
||||
long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 0:
|
||||
printf ("option %s", long_options[option_index].name);
|
||||
if (optarg)
|
||||
printf (" with arg %s", optarg);
|
||||
printf ("\n");
|
||||
break;
|
||||
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
if (digit_optind != 0 && digit_optind != this_option_optind)
|
||||
printf ("digits occur in two different argv-elements.\n");
|
||||
digit_optind = this_option_optind;
|
||||
printf ("option %c\n", c);
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
printf ("option a\n");
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
printf ("option b\n");
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
printf ("option c with value `%s'\n", optarg);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
printf ("option d with value `%s'\n", optarg);
|
||||
break;
|
||||
|
||||
case '?':
|
||||
break;
|
||||
|
||||
default:
|
||||
printf ("?? getopt returned character code 0%o ??\n", c);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
{
|
||||
printf ("non-option ARGV-elements: ");
|
||||
while (optind < argc)
|
||||
printf ("%s ", argv[optind++]);
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
#endif /* TEST */
|
442
contrib/patch/inp.c
Normal file
442
contrib/patch/inp.c
Normal file
@ -0,0 +1,442 @@
|
||||
/* inputting files to be patched */
|
||||
|
||||
/* $Id: inp.c,v 1.16 1997/06/13 06:28:37 eggert Exp $ */
|
||||
|
||||
/*
|
||||
Copyright 1986, 1988 Larry Wall
|
||||
Copyright 1991, 1992, 1993, 1997 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#define XTERN extern
|
||||
#include <common.h>
|
||||
#include <backupfile.h>
|
||||
#include <pch.h>
|
||||
#include <util.h>
|
||||
#undef XTERN
|
||||
#define XTERN
|
||||
#include <inp.h>
|
||||
|
||||
/* Input-file-with-indexable-lines abstract type */
|
||||
|
||||
static char const **i_ptr; /* pointers to lines in plan A buffer */
|
||||
|
||||
static size_t tibufsize; /* size of plan b buffers */
|
||||
#ifndef TIBUFSIZE_MINIMUM
|
||||
#define TIBUFSIZE_MINIMUM (8 * 1024) /* minimum value for tibufsize */
|
||||
#endif
|
||||
static int tifd = -1; /* plan b virtual string array */
|
||||
static char *tibuf[2]; /* plan b buffers */
|
||||
static LINENUM tiline[2] = {-1, -1}; /* 1st line in each buffer */
|
||||
static LINENUM lines_per_buf; /* how many lines per buffer */
|
||||
static size_t tireclen; /* length of records in tmp file */
|
||||
static size_t last_line_size; /* size of last input line */
|
||||
|
||||
static bool plan_a PARAMS ((char const *));/* yield FALSE if memory runs out */
|
||||
static void plan_b PARAMS ((char const *));
|
||||
static void report_revision PARAMS ((int));
|
||||
|
||||
/* New patch--prepare to edit another file. */
|
||||
|
||||
void
|
||||
re_input()
|
||||
{
|
||||
if (using_plan_a) {
|
||||
if (i_ptr) {
|
||||
free (i_ptr);
|
||||
i_ptr = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
close (tifd);
|
||||
tifd = -1;
|
||||
free(tibuf[0]);
|
||||
tibuf[0] = 0;
|
||||
tiline[0] = tiline[1] = -1;
|
||||
tireclen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Construct the line index, somehow or other. */
|
||||
|
||||
void
|
||||
scan_input(filename)
|
||||
char *filename;
|
||||
{
|
||||
using_plan_a = ! (debug & 16) && plan_a (filename);
|
||||
if (!using_plan_a)
|
||||
plan_b(filename);
|
||||
switch (verbosity)
|
||||
{
|
||||
case SILENT:
|
||||
break;
|
||||
|
||||
case VERBOSE:
|
||||
say ("Patching file `%s' using Plan %s...\n",
|
||||
filename, using_plan_a ? "A" : "B");
|
||||
break;
|
||||
|
||||
case DEFAULT_VERBOSITY:
|
||||
say ("patching file `%s'\n", filename);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Report whether a desired revision was found. */
|
||||
|
||||
static void
|
||||
report_revision (found_revision)
|
||||
int found_revision;
|
||||
{
|
||||
if (found_revision)
|
||||
{
|
||||
if (verbosity == VERBOSE)
|
||||
say ("Good. This file appears to be the %s version.\n", revision);
|
||||
}
|
||||
else if (force)
|
||||
{
|
||||
if (verbosity != SILENT)
|
||||
say ("Warning: this file doesn't appear to be the %s version -- patching anyway.\n",
|
||||
revision);
|
||||
}
|
||||
else if (batch)
|
||||
{
|
||||
fatal ("This file doesn't appear to be the %s version -- aborting.",
|
||||
revision);
|
||||
}
|
||||
else
|
||||
{
|
||||
ask ("This file doesn't appear to be the %s version -- patch anyway? [n] ",
|
||||
revision);
|
||||
if (*buf != 'y')
|
||||
fatal ("aborted");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
get_input_file (filename, outname)
|
||||
char const *filename;
|
||||
char const *outname;
|
||||
{
|
||||
int elsewhere = strcmp (filename, outname);
|
||||
char const *cs;
|
||||
char *diffbuf;
|
||||
char *getbuf;
|
||||
|
||||
if (inerrno == -1)
|
||||
inerrno = stat (inname, &instat) == 0 ? 0 : errno;
|
||||
|
||||
/* Perhaps look for RCS or SCCS versions. */
|
||||
if (patch_get
|
||||
&& invc != 0
|
||||
&& (inerrno
|
||||
|| (! elsewhere
|
||||
&& (/* No one can write to it. */
|
||||
(instat.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) == 0
|
||||
/* Only the owner (who's not me) can write to it. */
|
||||
|| ((instat.st_mode & (S_IWGRP|S_IWOTH)) == 0
|
||||
&& instat.st_uid != geteuid ()))))
|
||||
&& (invc = !! (cs = (version_controller
|
||||
(filename, elsewhere,
|
||||
inerrno ? (struct stat *) 0 : &instat,
|
||||
&getbuf, &diffbuf))))) {
|
||||
|
||||
if (!inerrno) {
|
||||
if (!elsewhere
|
||||
&& (instat.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) != 0)
|
||||
/* Somebody can write to it. */
|
||||
fatal ("file `%s' seems to be locked by somebody else under %s",
|
||||
filename, cs);
|
||||
/* It might be checked out unlocked. See if it's safe to
|
||||
check out the default version locked. */
|
||||
if (verbosity == VERBOSE)
|
||||
say ("Comparing file `%s' to default %s version...\n",
|
||||
filename, cs);
|
||||
if (systemic (diffbuf) != 0)
|
||||
{
|
||||
say ("warning: patching file `%s', which does not match default %s version\n",
|
||||
filename, cs);
|
||||
cs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (cs && version_get (filename, cs, ! inerrno, elsewhere, getbuf,
|
||||
&instat))
|
||||
inerrno = 0;
|
||||
|
||||
free (getbuf);
|
||||
free (diffbuf);
|
||||
|
||||
} else if (inerrno && !pch_says_nonexistent (reverse))
|
||||
{
|
||||
errno = inerrno;
|
||||
pfatal ("can't find file `%s'", filename);
|
||||
}
|
||||
|
||||
if (inerrno)
|
||||
{
|
||||
instat.st_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
|
||||
instat.st_size = 0;
|
||||
}
|
||||
else if (! S_ISREG (instat.st_mode))
|
||||
fatal ("`%s' is not a regular file -- can't patch", filename);
|
||||
}
|
||||
|
||||
|
||||
/* Try keeping everything in memory. */
|
||||
|
||||
static bool
|
||||
plan_a(filename)
|
||||
char const *filename;
|
||||
{
|
||||
register char const *s;
|
||||
register char const *lim;
|
||||
register char const **ptr;
|
||||
register char *buffer;
|
||||
register LINENUM iline;
|
||||
size_t size = instat.st_size;
|
||||
size_t allocated_bytes_per_input_byte = sizeof *i_ptr + sizeof (char);
|
||||
size_t allocated_bytes = (size + 2) * allocated_bytes_per_input_byte;
|
||||
|
||||
/* Fail if arithmetic overflow occurs during size calculations,
|
||||
or if storage isn't available. */
|
||||
if (size != instat.st_size
|
||||
|| size + 2 < 2
|
||||
|| allocated_bytes / allocated_bytes_per_input_byte != size + 2
|
||||
|| ! (ptr = (char const **) malloc (allocated_bytes)))
|
||||
return FALSE;
|
||||
|
||||
buffer = (char *) (ptr + (size + 2));
|
||||
|
||||
/* Read the input file, but don't bother reading it if it's empty.
|
||||
When creating files, the files do not actually exist. */
|
||||
if (size)
|
||||
{
|
||||
int ifd = open (filename, O_RDONLY|binary_transput);
|
||||
size_t buffered = 0, n;
|
||||
if (ifd < 0)
|
||||
pfatal ("can't open file `%s'", filename);
|
||||
while (size - buffered != 0
|
||||
&& (n = read (ifd, buffer + buffered, size - buffered)) != 0)
|
||||
{
|
||||
if (n == -1)
|
||||
{
|
||||
/* Perhaps size is too large for this host. */
|
||||
close (ifd);
|
||||
free (ptr);
|
||||
return FALSE;
|
||||
}
|
||||
buffered += n;
|
||||
}
|
||||
|
||||
/* Some non-POSIX hosts exaggerate st_size in text mode;
|
||||
or the file may have shrunk! */
|
||||
size = buffered;
|
||||
|
||||
if (close (ifd) != 0)
|
||||
read_fatal ();
|
||||
}
|
||||
|
||||
/* Scan the buffer and build array of pointers to lines. */
|
||||
iline = 0;
|
||||
lim = buffer + size;
|
||||
for (s = buffer; ; s++)
|
||||
{
|
||||
ptr[++iline] = s;
|
||||
if (! (s = (char *) memchr (s, '\n', lim - s)))
|
||||
break;
|
||||
}
|
||||
if (size && lim[-1] != '\n')
|
||||
ptr[++iline] = lim;
|
||||
input_lines = iline - 1;
|
||||
|
||||
if (revision)
|
||||
{
|
||||
char const *rev = revision;
|
||||
int rev0 = rev[0];
|
||||
int found_revision = 0;
|
||||
size_t revlen = strlen (rev);
|
||||
|
||||
if (revlen <= size)
|
||||
{
|
||||
char const *limrev = lim - revlen;
|
||||
|
||||
for (s = buffer; (s = (char *) memchr (s, rev0, limrev - s)); s++)
|
||||
if (memcmp (s, rev, revlen) == 0
|
||||
&& (s == buffer || ISSPACE ((unsigned char) s[-1]))
|
||||
&& (s + 1 == limrev || ISSPACE ((unsigned char) s[revlen])))
|
||||
{
|
||||
found_revision = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
report_revision (found_revision);
|
||||
}
|
||||
|
||||
/* Plan A will work. */
|
||||
i_ptr = ptr;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Keep (virtually) nothing in memory. */
|
||||
|
||||
static void
|
||||
plan_b(filename)
|
||||
char const *filename;
|
||||
{
|
||||
register FILE *ifp;
|
||||
register int c;
|
||||
register size_t len;
|
||||
register size_t maxlen;
|
||||
register int found_revision;
|
||||
register size_t i;
|
||||
register char const *rev;
|
||||
register size_t revlen;
|
||||
register LINENUM line;
|
||||
|
||||
if (instat.st_size == 0)
|
||||
filename = NULL_DEVICE;
|
||||
if (! (ifp = fopen (filename, binary_transput ? "rb" : "r")))
|
||||
pfatal ("can't open file `%s'", filename);
|
||||
tifd = create_file (TMPINNAME, O_RDWR | O_BINARY, (mode_t) 0);
|
||||
i = 0;
|
||||
len = 0;
|
||||
maxlen = 1;
|
||||
rev = revision;
|
||||
found_revision = !rev;
|
||||
revlen = rev ? strlen (rev) : 0;
|
||||
|
||||
while ((c = getc (ifp)) != EOF)
|
||||
{
|
||||
len++;
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
if (maxlen < len)
|
||||
maxlen = len;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
if (!found_revision)
|
||||
{
|
||||
if (i == revlen)
|
||||
{
|
||||
found_revision = ISSPACE ((unsigned char) c);
|
||||
i = (size_t) -1;
|
||||
}
|
||||
else if (i != (size_t) -1)
|
||||
i = rev[i]==c ? i + 1 : (size_t) -1;
|
||||
|
||||
if (i == (size_t) -1 && ISSPACE ((unsigned char) c))
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (revision)
|
||||
report_revision (found_revision);
|
||||
Fseek (ifp, (off_t) 0, SEEK_SET); /* rewind file */
|
||||
for (tibufsize = TIBUFSIZE_MINIMUM; tibufsize < maxlen; tibufsize <<= 1)
|
||||
continue;
|
||||
lines_per_buf = tibufsize / maxlen;
|
||||
tireclen = maxlen;
|
||||
tibuf[0] = xmalloc (2 * tibufsize);
|
||||
tibuf[1] = tibuf[0] + tibufsize;
|
||||
|
||||
for (line = 1; ; line++)
|
||||
{
|
||||
char *p = tibuf[0] + maxlen * (line % lines_per_buf);
|
||||
char const *p0 = p;
|
||||
if (! (line % lines_per_buf)) /* new block */
|
||||
if (write (tifd, tibuf[0], tibufsize) != tibufsize)
|
||||
write_fatal ();
|
||||
if ((c = getc (ifp)) == EOF)
|
||||
break;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
*p++ = c;
|
||||
if (c == '\n')
|
||||
{
|
||||
last_line_size = p - p0;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((c = getc (ifp)) == EOF)
|
||||
{
|
||||
last_line_size = p - p0;
|
||||
line++;
|
||||
goto EOF_reached;
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF_reached:
|
||||
if (ferror (ifp) || fclose (ifp) != 0)
|
||||
read_fatal ();
|
||||
|
||||
if (line % lines_per_buf != 0)
|
||||
if (write (tifd, tibuf[0], tibufsize) != tibufsize)
|
||||
write_fatal ();
|
||||
input_lines = line - 1;
|
||||
}
|
||||
|
||||
/* Fetch a line from the input file. */
|
||||
|
||||
char const *
|
||||
ifetch (line, whichbuf, psize)
|
||||
register LINENUM line;
|
||||
int whichbuf; /* ignored when file in memory */
|
||||
size_t *psize;
|
||||
{
|
||||
register char const *q;
|
||||
register char const *p;
|
||||
|
||||
if (line < 1 || line > input_lines) {
|
||||
*psize = 0;
|
||||
return "";
|
||||
}
|
||||
if (using_plan_a) {
|
||||
p = i_ptr[line];
|
||||
*psize = i_ptr[line + 1] - p;
|
||||
return p;
|
||||
} else {
|
||||
LINENUM offline = line % lines_per_buf;
|
||||
LINENUM baseline = line - offline;
|
||||
|
||||
if (tiline[0] == baseline)
|
||||
whichbuf = 0;
|
||||
else if (tiline[1] == baseline)
|
||||
whichbuf = 1;
|
||||
else {
|
||||
tiline[whichbuf] = baseline;
|
||||
if (lseek (tifd, (off_t) (baseline/lines_per_buf * tibufsize),
|
||||
SEEK_SET) == -1
|
||||
|| read (tifd, tibuf[whichbuf], tibufsize) < 0)
|
||||
read_fatal ();
|
||||
}
|
||||
p = tibuf[whichbuf] + (tireclen*offline);
|
||||
if (line == input_lines)
|
||||
*psize = last_line_size;
|
||||
else {
|
||||
for (q = p; *q++ != '\n'; )
|
||||
continue;
|
||||
*psize = q - p;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
}
|
10
contrib/patch/inp.h
Normal file
10
contrib/patch/inp.h
Normal file
@ -0,0 +1,10 @@
|
||||
/* inputting files to be patched */
|
||||
|
||||
/* $Id: inp.h,v 1.4 1997/04/07 01:07:00 eggert Exp $ */
|
||||
|
||||
XTERN LINENUM input_lines; /* how long is input file in lines */
|
||||
|
||||
char const *ifetch PARAMS ((LINENUM, int, size_t *));
|
||||
void get_input_file PARAMS ((char const *, char const *));
|
||||
void re_input PARAMS ((void));
|
||||
void scan_input PARAMS ((char *));
|
391
contrib/patch/maketime.c
Normal file
391
contrib/patch/maketime.c
Normal file
@ -0,0 +1,391 @@
|
||||
/* Convert struct partime into time_t. */
|
||||
|
||||
/* Copyright 1992, 1993, 1994, 1995, 1997 Paul Eggert
|
||||
Distributed under license by the Free Software Foundation, Inc.
|
||||
|
||||
This file is part of RCS.
|
||||
|
||||
RCS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
RCS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with RCS; see the file COPYING.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Report problems and direct all questions to:
|
||||
|
||||
rcs-bugs@cs.purdue.edu
|
||||
|
||||
*/
|
||||
|
||||
#if has_conf_h
|
||||
# include <conf.h>
|
||||
#else
|
||||
# if HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
# else
|
||||
# ifndef __STDC__
|
||||
# define const
|
||||
# endif
|
||||
# endif
|
||||
/* MIPS RISCOS4.52 defines time_t in <sys/types.h> not <time.h>. */
|
||||
# include <sys/types.h>
|
||||
# if HAVE_LIMITS_H
|
||||
# include <limits.h>
|
||||
# endif
|
||||
# ifndef LONG_MIN
|
||||
# define LONG_MIN (-1-2147483647L)
|
||||
# endif
|
||||
# if STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
# include <time.h>
|
||||
# ifdef __STDC__
|
||||
# define P(x) x
|
||||
# else
|
||||
# define P(x) ()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <partime.h>
|
||||
#include <maketime.h>
|
||||
|
||||
char const maketId[] =
|
||||
"$Id: maketime.c,v 5.15 1997/06/17 16:54:36 eggert Exp $";
|
||||
|
||||
static int isleap P ((int));
|
||||
static int month_days P ((struct tm const *));
|
||||
static time_t maketime P ((struct partime const *, time_t));
|
||||
|
||||
/* For maximum portability, use only localtime and gmtime.
|
||||
Make no assumptions about the time_t epoch or the range of time_t values.
|
||||
Avoid mktime because it's not universal and because there's no easy,
|
||||
portable way for mktime to yield the inverse of gmtime. */
|
||||
|
||||
#define TM_YEAR_ORIGIN 1900
|
||||
|
||||
static int
|
||||
isleap (y)
|
||||
int y;
|
||||
{
|
||||
return (y & 3) == 0 && (y % 100 != 0 || y % 400 == 0);
|
||||
}
|
||||
|
||||
/* days in year before start of months 0-12 */
|
||||
static int const month_yday[] =
|
||||
{
|
||||
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
|
||||
};
|
||||
|
||||
/* Yield the number of days in TM's month. */
|
||||
static int
|
||||
month_days (tm)
|
||||
struct tm const *tm;
|
||||
{
|
||||
int m = tm->tm_mon;
|
||||
return (month_yday[m + 1] - month_yday[m]
|
||||
+ (m == 1 && isleap (tm->tm_year + TM_YEAR_ORIGIN)));
|
||||
}
|
||||
|
||||
/* Convert UNIXTIME to struct tm form.
|
||||
Use gmtime if available and if !LOCALZONE, localtime otherwise. */
|
||||
struct tm *
|
||||
time2tm (unixtime, localzone)
|
||||
time_t unixtime;
|
||||
int localzone;
|
||||
{
|
||||
struct tm *tm;
|
||||
#ifdef TZ_is_unset
|
||||
static char const *TZ;
|
||||
if (!TZ && !(TZ = getenv ("TZ")))
|
||||
TZ_is_unset ("The TZ environment variable is not set; please set it to your timezone");
|
||||
#endif
|
||||
if (localzone || !(tm = gmtime (&unixtime)))
|
||||
tm = localtime (&unixtime);
|
||||
return tm;
|
||||
}
|
||||
|
||||
/* Yield A - B, measured in seconds. */
|
||||
time_t
|
||||
difftm (a, b)
|
||||
struct tm const *a;
|
||||
struct tm const *b;
|
||||
{
|
||||
int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
|
||||
int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
|
||||
int ac = ay / 100 - (ay % 100 < 0);
|
||||
int bc = by / 100 - (by % 100 < 0);
|
||||
int difference_in_day_of_year = a->tm_yday - b->tm_yday;
|
||||
int intervening_leap_days = (((ay >> 2) - (by >> 2))
|
||||
- (ac - bc)
|
||||
+ ((ac >> 2) - (bc >> 2)));
|
||||
time_t difference_in_years = ay - by;
|
||||
time_t difference_in_days
|
||||
= (difference_in_years * 365
|
||||
+ (intervening_leap_days + difference_in_day_of_year));
|
||||
return (((((difference_in_days * 24
|
||||
+ (a->tm_hour - b->tm_hour))
|
||||
* 60)
|
||||
+ (a->tm_min - b->tm_min))
|
||||
* 60)
|
||||
+ (a->tm_sec - b->tm_sec));
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust time T by adding SECONDS. SECONDS must be at most 24 hours' worth.
|
||||
* Adjust only T's year, mon, mday, hour, min and sec members;
|
||||
* plus adjust wday if it is defined.
|
||||
*/
|
||||
void
|
||||
adjzone (t, seconds)
|
||||
register struct tm *t;
|
||||
long seconds;
|
||||
{
|
||||
/*
|
||||
* This code can be off by a second if SECONDS is not a multiple of 60,
|
||||
* if T is local time, and if a leap second happens during this minute.
|
||||
* But this bug has never occurred, and most likely will not ever occur.
|
||||
* Liberia, the last country for which SECONDS % 60 was nonzero,
|
||||
* switched to UTC in May 1972; the first leap second was in June 1972.
|
||||
*/
|
||||
int leap_second = t->tm_sec == 60;
|
||||
long sec = seconds + (t->tm_sec - leap_second);
|
||||
if (sec < 0)
|
||||
{
|
||||
if ((t->tm_min -= (59 - sec) / 60) < 0)
|
||||
{
|
||||
if ((t->tm_hour -= (59 - t->tm_min) / 60) < 0)
|
||||
{
|
||||
t->tm_hour += 24;
|
||||
if (TM_DEFINED (t->tm_wday) && --t->tm_wday < 0)
|
||||
t->tm_wday = 6;
|
||||
if (--t->tm_mday <= 0)
|
||||
{
|
||||
if (--t->tm_mon < 0)
|
||||
{
|
||||
--t->tm_year;
|
||||
t->tm_mon = 11;
|
||||
}
|
||||
t->tm_mday = month_days (t);
|
||||
}
|
||||
}
|
||||
t->tm_min += 24 * 60;
|
||||
}
|
||||
sec += 24L * 60 * 60;
|
||||
}
|
||||
else if (60 <= (t->tm_min += sec / 60))
|
||||
if (24 <= (t->tm_hour += t->tm_min / 60))
|
||||
{
|
||||
t->tm_hour -= 24;
|
||||
if (TM_DEFINED (t->tm_wday) && ++t->tm_wday == 7)
|
||||
t->tm_wday = 0;
|
||||
if (month_days (t) < ++t->tm_mday)
|
||||
{
|
||||
if (11 < ++t->tm_mon)
|
||||
{
|
||||
++t->tm_year;
|
||||
t->tm_mon = 0;
|
||||
}
|
||||
t->tm_mday = 1;
|
||||
}
|
||||
}
|
||||
t->tm_min %= 60;
|
||||
t->tm_sec = (int) (sec % 60) + leap_second;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert TM to time_t, using localtime if LOCALZONE and gmtime otherwise.
|
||||
* Use only TM's year, mon, mday, hour, min, and sec members.
|
||||
* Ignore TM's old tm_yday and tm_wday, but fill in their correct values.
|
||||
* Yield -1 on failure (e.g. a member out of range).
|
||||
* Posix 1003.1-1990 doesn't allow leap seconds, but some implementations
|
||||
* have them anyway, so allow them if localtime/gmtime does.
|
||||
*/
|
||||
time_t
|
||||
tm2time (tm, localzone)
|
||||
struct tm *tm;
|
||||
int localzone;
|
||||
{
|
||||
/* Cache the most recent t,tm pairs; 1 for gmtime, 1 for localtime. */
|
||||
static time_t t_cache[2];
|
||||
static struct tm tm_cache[2];
|
||||
|
||||
time_t d, gt;
|
||||
struct tm const *gtm;
|
||||
/*
|
||||
* The maximum number of iterations should be enough to handle any
|
||||
* combinations of leap seconds, time zone rule changes, and solar time.
|
||||
* 4 is probably enough; we use a bigger number just to be safe.
|
||||
*/
|
||||
int remaining_tries = 8;
|
||||
|
||||
/* Avoid subscript errors. */
|
||||
if (12 <= (unsigned) tm->tm_mon)
|
||||
return -1;
|
||||
|
||||
tm->tm_yday = month_yday[tm->tm_mon] + tm->tm_mday
|
||||
- (tm->tm_mon < 2 || !isleap (tm->tm_year + TM_YEAR_ORIGIN));
|
||||
|
||||
/* Make a first guess. */
|
||||
gt = t_cache[localzone];
|
||||
gtm = gt ? &tm_cache[localzone] : time2tm (gt, localzone);
|
||||
|
||||
/* Repeatedly use the error from the guess to improve the guess. */
|
||||
while ((d = difftm (tm, gtm)) != 0)
|
||||
{
|
||||
if (--remaining_tries == 0)
|
||||
return -1;
|
||||
gt += d;
|
||||
gtm = time2tm (gt, localzone);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that the guess actually matches;
|
||||
* overflow can cause difftm to yield 0 even on differing times,
|
||||
* or tm may have members out of range (e.g. bad leap seconds).
|
||||
*/
|
||||
#define TM_DIFFER(a,b) \
|
||||
( \
|
||||
((a)->tm_year ^ (b)->tm_year) | \
|
||||
((a)->tm_mon ^ (b)->tm_mon) | \
|
||||
((a)->tm_mday ^ (b)->tm_mday) | \
|
||||
((a)->tm_hour ^ (b)->tm_hour) | \
|
||||
((a)->tm_min ^ (b)->tm_min) | \
|
||||
((a)->tm_sec ^ (b)->tm_sec) \
|
||||
)
|
||||
if (TM_DIFFER (tm, gtm))
|
||||
{
|
||||
/*
|
||||
* If gt is a leap second, try gt+1; if it is one greater than
|
||||
* a leap second, try gt-1; otherwise, it doesn't matter.
|
||||
* Leap seconds always fall at month end.
|
||||
*/
|
||||
int yd = tm->tm_year - gtm->tm_year;
|
||||
gt += yd + (yd ? 0 : tm->tm_mon - gtm->tm_mon);
|
||||
gtm = time2tm (gt, localzone);
|
||||
if (TM_DIFFER (tm, gtm))
|
||||
return -1;
|
||||
}
|
||||
t_cache[localzone] = gt;
|
||||
tm_cache[localzone] = *gtm;
|
||||
|
||||
tm->tm_wday = gtm->tm_wday;
|
||||
return gt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check *PT and convert it to time_t.
|
||||
* If it is incompletely specified, use DEFAULT_TIME to fill it out.
|
||||
* Use localtime if PT->zone is the special value TM_LOCAL_ZONE.
|
||||
* Yield -1 on failure.
|
||||
* ISO 8601 day-of-year and week numbers are not yet supported.
|
||||
*/
|
||||
static time_t
|
||||
maketime (pt, default_time)
|
||||
struct partime const *pt;
|
||||
time_t default_time;
|
||||
{
|
||||
int localzone, wday;
|
||||
struct tm tm;
|
||||
struct tm *tm0 = 0;
|
||||
time_t r;
|
||||
|
||||
tm0 = 0; /* Keep gcc -Wall happy. */
|
||||
localzone = pt->zone == TM_LOCAL_ZONE;
|
||||
|
||||
tm = pt->tm;
|
||||
|
||||
if (TM_DEFINED (pt->ymodulus) || !TM_DEFINED (tm.tm_year))
|
||||
{
|
||||
/* Get tm corresponding to default time. */
|
||||
tm0 = time2tm (default_time, localzone);
|
||||
if (!localzone)
|
||||
adjzone (tm0, pt->zone);
|
||||
}
|
||||
|
||||
if (TM_DEFINED (pt->ymodulus))
|
||||
tm.tm_year +=
|
||||
(tm0->tm_year + TM_YEAR_ORIGIN) / pt->ymodulus * pt->ymodulus;
|
||||
else if (!TM_DEFINED (tm.tm_year))
|
||||
{
|
||||
/* Set default year, month, day from current time. */
|
||||
tm.tm_year = tm0->tm_year + TM_YEAR_ORIGIN;
|
||||
if (!TM_DEFINED (tm.tm_mon))
|
||||
{
|
||||
tm.tm_mon = tm0->tm_mon;
|
||||
if (!TM_DEFINED (tm.tm_mday))
|
||||
tm.tm_mday = tm0->tm_mday;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert from partime year (Gregorian) to Posix year. */
|
||||
tm.tm_year -= TM_YEAR_ORIGIN;
|
||||
|
||||
/* Set remaining default fields to be their minimum values. */
|
||||
if (!TM_DEFINED (tm.tm_mon))
|
||||
tm.tm_mon = 0;
|
||||
if (!TM_DEFINED (tm.tm_mday))
|
||||
tm.tm_mday = 1;
|
||||
if (!TM_DEFINED (tm.tm_hour))
|
||||
tm.tm_hour = 0;
|
||||
if (!TM_DEFINED (tm.tm_min))
|
||||
tm.tm_min = 0;
|
||||
if (!TM_DEFINED (tm.tm_sec))
|
||||
tm.tm_sec = 0;
|
||||
|
||||
if (!localzone)
|
||||
adjzone (&tm, -pt->zone);
|
||||
wday = tm.tm_wday;
|
||||
|
||||
/* Convert and fill in the rest of the tm. */
|
||||
r = tm2time (&tm, localzone);
|
||||
|
||||
/* Check weekday. */
|
||||
if (r != -1 && TM_DEFINED (wday) && wday != tm.tm_wday)
|
||||
return -1;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Parse a free-format date in SOURCE, yielding a Unix format time. */
|
||||
time_t
|
||||
str2time (source, default_time, default_zone)
|
||||
char const *source;
|
||||
time_t default_time;
|
||||
long default_zone;
|
||||
{
|
||||
struct partime pt;
|
||||
|
||||
if (*partime (source, &pt))
|
||||
return -1;
|
||||
if (pt.zone == TM_UNDEFINED_ZONE)
|
||||
pt.zone = default_zone;
|
||||
return maketime (&pt, default_time);
|
||||
}
|
||||
|
||||
#if TEST
|
||||
#include <stdio.h>
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
time_t default_time = time ((time_t *) 0);
|
||||
long default_zone = argv[1] ? atol (argv[1]) : 0;
|
||||
char buf[1000];
|
||||
while (fgets (buf, sizeof (buf), stdin))
|
||||
{
|
||||
time_t t = str2time (buf, default_time, default_zone);
|
||||
printf ("%s", asctime (gmtime (&t)));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
39
contrib/patch/maketime.h
Normal file
39
contrib/patch/maketime.h
Normal file
@ -0,0 +1,39 @@
|
||||
/* Yield time_t from struct partime yielded by partime. */
|
||||
|
||||
/* Copyright 1993, 1994, 1995 Paul Eggert
|
||||
Distributed under license by the Free Software Foundation, Inc.
|
||||
|
||||
This file is part of RCS.
|
||||
|
||||
RCS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
RCS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with RCS; see the file COPYING.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Report problems and direct all questions to:
|
||||
|
||||
rcs-bugs@cs.purdue.edu
|
||||
|
||||
*/
|
||||
|
||||
#if defined __STDC__ || has_prototypes
|
||||
# define __MAKETIME_P(x) x
|
||||
#else
|
||||
# define __MAKETIME_P(x) ()
|
||||
#endif
|
||||
|
||||
struct tm *time2tm __MAKETIME_P ((time_t, int));
|
||||
time_t difftm __MAKETIME_P ((struct tm const *, struct tm const *));
|
||||
time_t str2time __MAKETIME_P ((char const *, time_t, long));
|
||||
time_t tm2time __MAKETIME_P ((struct tm *, int));
|
||||
void adjzone __MAKETIME_P ((struct tm *, long));
|
199
contrib/patch/memchr.c
Normal file
199
contrib/patch/memchr.c
Normal file
@ -0,0 +1,199 @@
|
||||
/* Copyright (C) 1991, 1993, 1996 Free Software Foundation, Inc.
|
||||
Based on strlen implementation by Torbjorn Granlund (tege@sics.se),
|
||||
with help from Dan Sahlin (dan@sics.se) and
|
||||
commentary by Jim Blandy (jimb@ai.mit.edu);
|
||||
adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu),
|
||||
and implemented by Roland McGrath (roland@ai.mit.edu).
|
||||
|
||||
NOTE: The canonical source of this file is maintained with the GNU C Library.
|
||||
Bugs can be reported to bug-glibc@prep.ai.mit.edu.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
USA. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#undef __ptr_t
|
||||
#if defined (__cplusplus) || (defined (__STDC__) && __STDC__)
|
||||
# define __ptr_t void *
|
||||
#else /* Not C++ or ANSI C. */
|
||||
# define __ptr_t char *
|
||||
#endif /* C++ or ANSI C. */
|
||||
|
||||
#if defined (_LIBC)
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_LIMITS_H) || defined (_LIBC)
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
#define LONG_MAX_32_BITS 2147483647
|
||||
|
||||
#ifndef LONG_MAX
|
||||
#define LONG_MAX LONG_MAX_32_BITS
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
/* Search no more than N bytes of S for C. */
|
||||
|
||||
__ptr_t
|
||||
memchr (s, c, n)
|
||||
const __ptr_t s;
|
||||
int c;
|
||||
size_t n;
|
||||
{
|
||||
const unsigned char *char_ptr;
|
||||
const unsigned long int *longword_ptr;
|
||||
unsigned long int longword, magic_bits, charmask;
|
||||
|
||||
c = (unsigned char) c;
|
||||
|
||||
/* Handle the first few characters by reading one character at a time.
|
||||
Do this until CHAR_PTR is aligned on a longword boundary. */
|
||||
for (char_ptr = (const unsigned char *) s;
|
||||
n > 0 && ((unsigned long int) char_ptr
|
||||
& (sizeof (longword) - 1)) != 0;
|
||||
--n, ++char_ptr)
|
||||
if (*char_ptr == c)
|
||||
return (__ptr_t) char_ptr;
|
||||
|
||||
/* All these elucidatory comments refer to 4-byte longwords,
|
||||
but the theory applies equally well to 8-byte longwords. */
|
||||
|
||||
longword_ptr = (unsigned long int *) char_ptr;
|
||||
|
||||
/* Bits 31, 24, 16, and 8 of this number are zero. Call these bits
|
||||
the "holes." Note that there is a hole just to the left of
|
||||
each byte, with an extra at the end:
|
||||
|
||||
bits: 01111110 11111110 11111110 11111111
|
||||
bytes: AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD
|
||||
|
||||
The 1-bits make sure that carries propagate to the next 0-bit.
|
||||
The 0-bits provide holes for carries to fall into. */
|
||||
|
||||
if (sizeof (longword) != 4 && sizeof (longword) != 8)
|
||||
abort ();
|
||||
|
||||
#if LONG_MAX <= LONG_MAX_32_BITS
|
||||
magic_bits = 0x7efefeff;
|
||||
#else
|
||||
magic_bits = ((unsigned long int) 0x7efefefe << 32) | 0xfefefeff;
|
||||
#endif
|
||||
|
||||
/* Set up a longword, each of whose bytes is C. */
|
||||
charmask = c | (c << 8);
|
||||
charmask |= charmask << 16;
|
||||
#if LONG_MAX > LONG_MAX_32_BITS
|
||||
charmask |= charmask << 32;
|
||||
#endif
|
||||
|
||||
/* Instead of the traditional loop which tests each character,
|
||||
we will test a longword at a time. The tricky part is testing
|
||||
if *any of the four* bytes in the longword in question are zero. */
|
||||
while (n >= sizeof (longword))
|
||||
{
|
||||
/* We tentatively exit the loop if adding MAGIC_BITS to
|
||||
LONGWORD fails to change any of the hole bits of LONGWORD.
|
||||
|
||||
1) Is this safe? Will it catch all the zero bytes?
|
||||
Suppose there is a byte with all zeros. Any carry bits
|
||||
propagating from its left will fall into the hole at its
|
||||
least significant bit and stop. Since there will be no
|
||||
carry from its most significant bit, the LSB of the
|
||||
byte to the left will be unchanged, and the zero will be
|
||||
detected.
|
||||
|
||||
2) Is this worthwhile? Will it ignore everything except
|
||||
zero bytes? Suppose every byte of LONGWORD has a bit set
|
||||
somewhere. There will be a carry into bit 8. If bit 8
|
||||
is set, this will carry into bit 16. If bit 8 is clear,
|
||||
one of bits 9-15 must be set, so there will be a carry
|
||||
into bit 16. Similarly, there will be a carry into bit
|
||||
24. If one of bits 24-30 is set, there will be a carry
|
||||
into bit 31, so all of the hole bits will be changed.
|
||||
|
||||
The one misfire occurs when bits 24-30 are clear and bit
|
||||
31 is set; in this case, the hole at bit 31 is not
|
||||
changed. If we had access to the processor carry flag,
|
||||
we could close this loophole by putting the fourth hole
|
||||
at bit 32!
|
||||
|
||||
So it ignores everything except 128's, when they're aligned
|
||||
properly.
|
||||
|
||||
3) But wait! Aren't we looking for C, not zero?
|
||||
Good point. So what we do is XOR LONGWORD with a longword,
|
||||
each of whose bytes is C. This turns each byte that is C
|
||||
into a zero. */
|
||||
|
||||
longword = *longword_ptr++ ^ charmask;
|
||||
|
||||
/* Add MAGIC_BITS to LONGWORD. */
|
||||
if ((((longword + magic_bits)
|
||||
|
||||
/* Set those bits that were unchanged by the addition. */
|
||||
^ ~longword)
|
||||
|
||||
/* Look at only the hole bits. If any of the hole bits
|
||||
are unchanged, most likely one of the bytes was a
|
||||
zero. */
|
||||
& ~magic_bits) != 0)
|
||||
{
|
||||
/* Which of the bytes was C? If none of them were, it was
|
||||
a misfire; continue the search. */
|
||||
|
||||
const unsigned char *cp = (const unsigned char *) (longword_ptr - 1);
|
||||
|
||||
if (cp[0] == c)
|
||||
return (__ptr_t) cp;
|
||||
if (cp[1] == c)
|
||||
return (__ptr_t) &cp[1];
|
||||
if (cp[2] == c)
|
||||
return (__ptr_t) &cp[2];
|
||||
if (cp[3] == c)
|
||||
return (__ptr_t) &cp[3];
|
||||
#if LONG_MAX > 2147483647
|
||||
if (cp[4] == c)
|
||||
return (__ptr_t) &cp[4];
|
||||
if (cp[5] == c)
|
||||
return (__ptr_t) &cp[5];
|
||||
if (cp[6] == c)
|
||||
return (__ptr_t) &cp[6];
|
||||
if (cp[7] == c)
|
||||
return (__ptr_t) &cp[7];
|
||||
#endif
|
||||
}
|
||||
|
||||
n -= sizeof (longword);
|
||||
}
|
||||
|
||||
char_ptr = (const unsigned char *) longword_ptr;
|
||||
|
||||
while (n-- > 0)
|
||||
{
|
||||
if (*char_ptr == c)
|
||||
return (__ptr_t) char_ptr;
|
||||
else
|
||||
++char_ptr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
742
contrib/patch/partime.c
Normal file
742
contrib/patch/partime.c
Normal file
@ -0,0 +1,742 @@
|
||||
/* Parse a string, yielding a struct partime that describes it. */
|
||||
|
||||
/* Copyright 1993, 1994, 1995, 1997 Paul Eggert
|
||||
Distributed under license by the Free Software Foundation, Inc.
|
||||
|
||||
This file is part of RCS.
|
||||
|
||||
RCS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
RCS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with RCS; see the file COPYING.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Report problems and direct all questions to:
|
||||
|
||||
rcs-bugs@cs.purdue.edu
|
||||
|
||||
*/
|
||||
|
||||
#if has_conf_h
|
||||
# include <conf.h>
|
||||
#else
|
||||
# if HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
# else
|
||||
# ifndef __STDC__
|
||||
# define const
|
||||
# endif
|
||||
# endif
|
||||
# if HAVE_LIMITS_H
|
||||
# include <limits.h>
|
||||
# endif
|
||||
# ifndef LONG_MIN
|
||||
# define LONG_MIN (-1-2147483647L)
|
||||
# endif
|
||||
# if STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
# include <time.h>
|
||||
# ifdef __STDC__
|
||||
# define P(x) x
|
||||
# else
|
||||
# define P(x) ()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#if STDC_HEADERS
|
||||
# define CTYPE_DOMAIN(c) 1
|
||||
#else
|
||||
# define CTYPE_DOMAIN(c) ((unsigned) (c) <= 0177)
|
||||
#endif
|
||||
#define ISALNUM(c) (CTYPE_DOMAIN (c) && isalnum (c))
|
||||
#define ISALPHA(c) (CTYPE_DOMAIN (c) && isalpha (c))
|
||||
#define ISSPACE(c) (CTYPE_DOMAIN (c) && isspace (c))
|
||||
#define ISUPPER(c) (CTYPE_DOMAIN (c) && isupper (c))
|
||||
#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
|
||||
|
||||
#include <partime.h>
|
||||
|
||||
char const partimeId[] =
|
||||
"$Id: partime.c,v 5.16 1997/05/19 06:33:53 eggert Exp $";
|
||||
|
||||
|
||||
/* Lookup tables for names of months, weekdays, time zones. */
|
||||
|
||||
#define NAME_LENGTH_MAXIMUM 4
|
||||
|
||||
struct name_val
|
||||
{
|
||||
char name[NAME_LENGTH_MAXIMUM];
|
||||
int val;
|
||||
};
|
||||
|
||||
|
||||
static char const *parse_decimal P ((char const *, int, int, int, int, int *, int *));
|
||||
static char const *parse_fixed P ((char const *, int, int *));
|
||||
static char const *parse_pattern_letter P ((char const *, int, struct partime *));
|
||||
static char const *parse_prefix P ((char const *, struct partime *, int *));
|
||||
static char const *parse_ranged P ((char const *, int, int, int, int *));
|
||||
static int lookup P ((char const *, struct name_val const[]));
|
||||
static int merge_partime P ((struct partime *, struct partime const *));
|
||||
static void undefine P ((struct partime *));
|
||||
|
||||
|
||||
static struct name_val const month_names[] =
|
||||
{
|
||||
{"jan", 0},
|
||||
{"feb", 1},
|
||||
{"mar", 2},
|
||||
{"apr", 3},
|
||||
{"may", 4},
|
||||
{"jun", 5},
|
||||
{"jul", 6},
|
||||
{"aug", 7},
|
||||
{"sep", 8},
|
||||
{"oct", 9},
|
||||
{"nov", 10},
|
||||
{"dec", 11},
|
||||
{"", TM_UNDEFINED}
|
||||
};
|
||||
|
||||
static struct name_val const weekday_names[] =
|
||||
{
|
||||
{"sun", 0},
|
||||
{"mon", 1},
|
||||
{"tue", 2},
|
||||
{"wed", 3},
|
||||
{"thu", 4},
|
||||
{"fri", 5},
|
||||
{"sat", 6},
|
||||
{"", TM_UNDEFINED}
|
||||
};
|
||||
|
||||
#define hr60nonnegative(t) ((t)/100 * 60 + (t)%100)
|
||||
#define hr60(t) ((t)<0 ? -hr60nonnegative(-(t)) : hr60nonnegative(t))
|
||||
#define zs(t,s) {s, hr60(t)}
|
||||
#define zd(t,s,d) zs(t, s), zs((t)+100, d)
|
||||
|
||||
static struct name_val const zone_names[] =
|
||||
{
|
||||
zs (-1000, "hst"), /* Hawaii */
|
||||
zd (-1000, "hast", "hadt"), /* Hawaii-Aleutian */
|
||||
zd (- 900, "akst", "akdt"), /* Alaska */
|
||||
zd (- 800, "pst" , "pdt" ), /* Pacific */
|
||||
zd (- 700, "mst" , "mdt" ), /* Mountain */
|
||||
zd (- 600, "cst" , "cdt" ), /* Central */
|
||||
zd (- 500, "est" , "edt" ), /* Eastern */
|
||||
zd (- 400, "ast" , "adt" ), /* Atlantic */
|
||||
zd (- 330, "nst" , "ndt" ), /* Newfoundland */
|
||||
zs ( 000, "utc" ), /* Coordinated Universal */
|
||||
zs ( 000, "uct" ), /* " */
|
||||
zs ( 000, "cut" ), /* " */
|
||||
zs ( 000, "ut"), /* Universal */
|
||||
zs ( 000, "z"), /* Zulu (required by ISO 8601) */
|
||||
zd ( 000, "gmt" , "bst" ), /* Greenwich Mean, British Summer */
|
||||
zd ( 000, "wet" , "west"), /* Western European */
|
||||
zd ( 100, "cet" , "cest"), /* Central European */
|
||||
zd ( 100, "met" , "mest"), /* Middle European (bug in old tz versions) */
|
||||
zd ( 100, "mez" , "mesz"), /* Mittel-Europaeische Zeit */
|
||||
zd ( 200, "eet" , "eest"), /* Eastern European */
|
||||
zs ( 530, "ist" ), /* India */
|
||||
zd ( 900, "jst" , "jdt" ), /* Japan */
|
||||
zd ( 900, "kst" , "kdt" ), /* Korea */
|
||||
zd ( 1200, "nzst", "nzdt"), /* New Zealand */
|
||||
{"lt", 1},
|
||||
#if 0
|
||||
/* The following names are duplicates or are not well attested.
|
||||
There are lots more where these came from. */
|
||||
zs (-1100, "sst" ), /* Samoan */
|
||||
zd (- 900, "yst" , "ydt" ), /* Yukon - name is no longer used */
|
||||
zd (- 500, "ast" , "adt" ), /* Acre */
|
||||
zd (- 400, "wst" , "wdt" ), /* Western Brazil */
|
||||
zd (- 400, "cst" , "cdt" ), /* Chile */
|
||||
zd (- 200, "fst" , "fdt" ), /* Fernando de Noronha */
|
||||
zs ( 000, "wat" ), /* West African */
|
||||
zs ( 100, "cat" ), /* Central African */
|
||||
zs ( 200, "sat" ), /* South African */
|
||||
zd ( 200, "ist" , "idt" ), /* Israel */
|
||||
zs ( 300, "eat" ), /* East African */
|
||||
zd ( 300, "msk" , "msd" ), /* Moscow */
|
||||
zd ( 330, "ist" , "idt" ), /* Iran */
|
||||
zs ( 800, "hkt" ), /* Hong Kong */
|
||||
zs ( 800, "sgt" ), /* Singapore */
|
||||
zd ( 800, "cst" , "cdt" ), /* China */
|
||||
zd ( 800, "wst" , "wst" ), /* Western Australia */
|
||||
zd ( 930, "cst" , "cst" ), /* Central Australia */
|
||||
zs ( 1000, "gst" ), /* Guam */
|
||||
zd ( 1000, "est" , "est" ), /* Eastern Australia */
|
||||
#endif
|
||||
{"", -1}
|
||||
};
|
||||
|
||||
/* Look for a prefix of S in TABLE, returning val for first matching entry. */
|
||||
static int
|
||||
lookup (s, table)
|
||||
char const *s;
|
||||
struct name_val const table[];
|
||||
{
|
||||
int j;
|
||||
char buf[NAME_LENGTH_MAXIMUM];
|
||||
|
||||
for (j = 0; j < NAME_LENGTH_MAXIMUM; j++)
|
||||
{
|
||||
unsigned char c = *s++;
|
||||
if (! ISALPHA (c))
|
||||
{
|
||||
buf[j] = '\0';
|
||||
break;
|
||||
}
|
||||
buf[j] = ISUPPER (c) ? tolower (c) : c;
|
||||
}
|
||||
|
||||
for (;; table++)
|
||||
for (j = 0; ; j++)
|
||||
if (j == NAME_LENGTH_MAXIMUM || ! table[0].name[j])
|
||||
return table[0].val;
|
||||
else if (buf[j] != table[0].name[j])
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Set *T to ``undefined'' values. */
|
||||
static void
|
||||
undefine (t)
|
||||
struct partime *t;
|
||||
{
|
||||
t->tm.tm_sec = t->tm.tm_min = t->tm.tm_hour = t->tm.tm_mday = t->tm.tm_mon
|
||||
= t->tm.tm_year = t->tm.tm_wday = t->tm.tm_yday
|
||||
= t->ymodulus = t->yweek
|
||||
= TM_UNDEFINED;
|
||||
t->zone = TM_UNDEFINED_ZONE;
|
||||
}
|
||||
|
||||
/* Array of patterns to look for in a date string.
|
||||
Order is important: we look for the first matching pattern
|
||||
whose values do not contradict values that we already know about.
|
||||
See `parse_pattern_letter' below for the meaning of the pattern codes. */
|
||||
static char const *const patterns[] =
|
||||
{
|
||||
/* These traditional patterns must come first,
|
||||
to prevent an ISO 8601 format from misinterpreting their prefixes. */
|
||||
"E_n_y", "x", /* RFC 822 */
|
||||
"E_n", "n_E", "n", "t:m:s_A", "t:m_A", "t_A", /* traditional */
|
||||
"y/N/D$", /* traditional RCS */
|
||||
|
||||
/* ISO 8601:1988 formats, generalized a bit. */
|
||||
"y-N-D$", "4ND$", "Y-N$",
|
||||
"RND$", "-R=N$", "-R$", "--N=D$", "N=DT",
|
||||
"--N$", "---D$", "DT",
|
||||
"Y-d$", "4d$", "R=d$", "-d$", "dT",
|
||||
"y-W-X", "yWX", "y=W",
|
||||
"-r-W-X", "r-W-XT", "-rWX", "rWXT", "-W=X", "W=XT", "-W",
|
||||
"-w-X", "w-XT", "---X$", "XT", "4$",
|
||||
"T",
|
||||
"h:m:s$", "hms$", "h:m$", "hm$", "h$", "-m:s$", "-ms$", "-m$", "--s$",
|
||||
"Y", "Z",
|
||||
|
||||
0
|
||||
};
|
||||
|
||||
/* Parse an initial prefix of STR, setting *T accordingly.
|
||||
Return the first character after the prefix, or 0 if it couldn't be parsed.
|
||||
Start with pattern *PI; if success, set *PI to the next pattern to try.
|
||||
Set *PI to -1 if we know there are no more patterns to try;
|
||||
if *PI is initially negative, give up immediately. */
|
||||
static char const *
|
||||
parse_prefix (str, t, pi)
|
||||
char const *str;
|
||||
struct partime *t;
|
||||
int *pi;
|
||||
{
|
||||
int i = *pi;
|
||||
char const *pat;
|
||||
unsigned char c;
|
||||
|
||||
if (i < 0)
|
||||
return 0;
|
||||
|
||||
/* Remove initial noise. */
|
||||
while (! ISALNUM (c = *str) && c != '-' && c != '+')
|
||||
{
|
||||
if (! c)
|
||||
{
|
||||
undefine (t);
|
||||
*pi = -1;
|
||||
return str;
|
||||
}
|
||||
str++;
|
||||
}
|
||||
|
||||
/* Try a pattern until one succeeds. */
|
||||
while ((pat = patterns[i++]) != 0)
|
||||
{
|
||||
char const *s = str;
|
||||
undefine (t);
|
||||
do
|
||||
{
|
||||
if (! (c = *pat++))
|
||||
{
|
||||
*pi = i;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
while ((s = parse_pattern_letter (s, c, t)) != 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Parse an initial prefix of S of length DIGITS; it must be a number.
|
||||
Store the parsed number into *RES.
|
||||
Return the first character after the prefix, or 0 if it wasn't parsed. */
|
||||
static char const *
|
||||
parse_fixed (s, digits, res)
|
||||
char const *s;
|
||||
int digits, *res;
|
||||
{
|
||||
int n = 0;
|
||||
char const *lim = s + digits;
|
||||
while (s < lim)
|
||||
{
|
||||
unsigned d = *s++ - '0';
|
||||
if (9 < d)
|
||||
return 0;
|
||||
n = 10 * n + d;
|
||||
}
|
||||
*res = n;
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Parse an initial prefix of S of length DIGITS;
|
||||
it must be a number in the range LO through HI.
|
||||
Store the parsed number into *RES.
|
||||
Return the first character after the prefix, or 0 if it wasn't parsed. */
|
||||
static char const *
|
||||
parse_ranged (s, digits, lo, hi, res)
|
||||
char const *s;
|
||||
int digits, lo, hi, *res;
|
||||
{
|
||||
s = parse_fixed (s, digits, res);
|
||||
return s && lo <= *res && *res <= hi ? s : 0;
|
||||
}
|
||||
|
||||
/* Parse an initial prefix of S of length DIGITS;
|
||||
it must be a number in the range LO through HI
|
||||
and it may be followed by a fraction to be computed using RESOLUTION.
|
||||
Store the parsed number into *RES; store the fraction times RESOLUTION,
|
||||
rounded to the nearest integer, into *FRES.
|
||||
Return the first character after the prefix, or 0 if it wasn't parsed. */
|
||||
static char const *
|
||||
parse_decimal (s, digits, lo, hi, resolution, res, fres)
|
||||
char const *s;
|
||||
int digits, lo, hi, resolution, *res, *fres;
|
||||
{
|
||||
s = parse_fixed (s, digits, res);
|
||||
if (s && lo <= *res && *res <= hi)
|
||||
{
|
||||
int f = 0;
|
||||
if ((s[0] == ',' || s[0] == '.') && ISDIGIT (s[1]))
|
||||
{
|
||||
char const *s1 = ++s;
|
||||
int num10 = 0, denom10 = 10, product;
|
||||
while (ISDIGIT (*++s))
|
||||
{
|
||||
int d = denom10 * 10;
|
||||
if (d / 10 != denom10)
|
||||
return 0; /* overflow */
|
||||
denom10 = d;
|
||||
}
|
||||
s = parse_fixed (s1, (int) (s - s1), &num10);
|
||||
product = num10 * resolution;
|
||||
f = (product + (denom10 >> 1)) / denom10;
|
||||
f -= f & (product % denom10 == denom10 >> 1); /* round to even */
|
||||
if (f < 0 || product/resolution != num10)
|
||||
return 0; /* overflow */
|
||||
}
|
||||
*fres = f;
|
||||
return s;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Parse an initial prefix of S; it must denote a time zone.
|
||||
Set *ZONE to the number of seconds east of GMT,
|
||||
or to TM_LOCAL_ZONE if it is the local time zone.
|
||||
Return the first character after the prefix, or 0 if it wasn't parsed. */
|
||||
char *
|
||||
parzone (s, zone)
|
||||
char const *s;
|
||||
long *zone;
|
||||
{
|
||||
char sign;
|
||||
int hh, mm, ss;
|
||||
int minutesEastOfUTC;
|
||||
long offset, z;
|
||||
|
||||
/* The formats are LT, n, n DST, nDST, no, o
|
||||
where n is a time zone name
|
||||
and o is a time zone offset of the form [-+]hh[:mm[:ss]]. */
|
||||
switch (*s)
|
||||
{
|
||||
case '-':
|
||||
case '+':
|
||||
z = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
minutesEastOfUTC = lookup (s, zone_names);
|
||||
if (minutesEastOfUTC == -1)
|
||||
return 0;
|
||||
|
||||
/* Don't bother to check rest of spelling. */
|
||||
while (ISALPHA ((unsigned char) *s))
|
||||
s++;
|
||||
|
||||
/* Don't modify LT. */
|
||||
if (minutesEastOfUTC == 1)
|
||||
{
|
||||
*zone = TM_LOCAL_ZONE;
|
||||
return (char *) s;
|
||||
}
|
||||
|
||||
z = minutesEastOfUTC * 60L;
|
||||
|
||||
/* Look for trailing " DST". */
|
||||
if ((s[-1] == 'T' || s[-1] == 't')
|
||||
&& (s[-2] == 'S' || s[-2] == 's')
|
||||
&& (s[-3] == 'D' || s[-3] == 'd'))
|
||||
goto trailing_dst;
|
||||
while (ISSPACE ((unsigned char) *s))
|
||||
s++;
|
||||
if ((s[0] == 'D' || s[0] == 'd')
|
||||
&& (s[1] == 'S' || s[1] == 's')
|
||||
&& (s[2] == 'T' || s[2] == 't'))
|
||||
{
|
||||
s += 3;
|
||||
trailing_dst:
|
||||
*zone = z + 60*60;
|
||||
return (char *) s;
|
||||
}
|
||||
|
||||
switch (*s)
|
||||
{
|
||||
case '-':
|
||||
case '+':
|
||||
break;
|
||||
|
||||
default:
|
||||
*zone = z;
|
||||
return (char *) s;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
sign = *s++;
|
||||
|
||||
if (! (s = parse_ranged (s, 2, 0, 23, &hh)))
|
||||
return 0;
|
||||
mm = ss = 0;
|
||||
if (*s == ':')
|
||||
s++;
|
||||
if (ISDIGIT (*s))
|
||||
{
|
||||
if (! (s = parse_ranged (s, 2, 0, 59, &mm)))
|
||||
return 0;
|
||||
if (*s == ':' && s[-3] == ':' && ISDIGIT (s[1])
|
||||
&& ! (s = parse_ranged (s + 1, 2, 0, 59, &ss)))
|
||||
return 0;
|
||||
}
|
||||
if (ISDIGIT (*s))
|
||||
return 0;
|
||||
offset = (hh * 60 + mm) * 60L + ss;
|
||||
*zone = z + (sign == '-' ? -offset : offset);
|
||||
/* ?? Are fractions allowed here? If so, they're not implemented. */
|
||||
return (char *) s;
|
||||
}
|
||||
|
||||
/* Parse an initial prefix of S, matching the pattern whose code is C.
|
||||
Set *T accordingly.
|
||||
Return the first character after the prefix, or 0 if it wasn't parsed. */
|
||||
static char const *
|
||||
parse_pattern_letter (s, c, t)
|
||||
char const *s;
|
||||
int c;
|
||||
struct partime *t;
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '$': /* The next character must be a non-digit. */
|
||||
if (ISDIGIT (*s))
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case '-':
|
||||
case '/':
|
||||
case ':':
|
||||
/* These characters stand for themselves. */
|
||||
if (*s++ != c)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case '4': /* 4-digit year */
|
||||
s = parse_fixed (s, 4, &t->tm.tm_year);
|
||||
break;
|
||||
|
||||
case '=': /* optional '-' */
|
||||
s += *s == '-';
|
||||
break;
|
||||
|
||||
case 'A': /* AM or PM */
|
||||
/* This matches the regular expression [AaPp][Mm]?.
|
||||
It must not be followed by a letter or digit;
|
||||
otherwise it would match prefixes of strings like "PST". */
|
||||
switch (*s++)
|
||||
{
|
||||
case 'A':
|
||||
case 'a':
|
||||
if (t->tm.tm_hour == 12)
|
||||
t->tm.tm_hour = 0;
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
case 'p':
|
||||
if (t->tm.tm_hour != 12)
|
||||
t->tm.tm_hour += 12;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
switch (*s)
|
||||
{
|
||||
case 'M':
|
||||
case 'm':
|
||||
s++;
|
||||
break;
|
||||
}
|
||||
if (ISALNUM ((unsigned char) *s))
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case 'D': /* day of month [01-31] */
|
||||
s = parse_ranged (s, 2, 1, 31, &t->tm.tm_mday);
|
||||
break;
|
||||
|
||||
case 'd': /* day of year [001-366] */
|
||||
s = parse_ranged (s, 3, 1, 366, &t->tm.tm_yday);
|
||||
t->tm.tm_yday--;
|
||||
break;
|
||||
|
||||
case 'E': /* extended day of month [1-9, 01-31] */
|
||||
s = parse_ranged (s, (ISDIGIT (s[0]) && ISDIGIT (s[1])) + 1, 1, 31,
|
||||
&t->tm.tm_mday);
|
||||
break;
|
||||
|
||||
case 'h': /* hour [00-23 followed by optional fraction] */
|
||||
{
|
||||
int frac;
|
||||
s = parse_decimal (s, 2, 0, 23, 60 * 60, &t->tm.tm_hour, &frac);
|
||||
t->tm.tm_min = frac / 60;
|
||||
t->tm.tm_sec = frac % 60;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'm': /* minute [00-59 followed by optional fraction] */
|
||||
s = parse_decimal (s, 2, 0, 59, 60, &t->tm.tm_min, &t->tm.tm_sec);
|
||||
break;
|
||||
|
||||
case 'n': /* month name [e.g. "Jan"] */
|
||||
if (! TM_DEFINED (t->tm.tm_mon = lookup (s, month_names)))
|
||||
return 0;
|
||||
/* Don't bother to check rest of spelling. */
|
||||
while (ISALPHA ((unsigned char) *s))
|
||||
s++;
|
||||
break;
|
||||
|
||||
case 'N': /* month [01-12] */
|
||||
s = parse_ranged (s, 2, 1, 12, &t->tm.tm_mon);
|
||||
t->tm.tm_mon--;
|
||||
break;
|
||||
|
||||
case 'r': /* year % 10 (remainder in origin-0 decade) [0-9] */
|
||||
s = parse_fixed (s, 1, &t->tm.tm_year);
|
||||
t->ymodulus = 10;
|
||||
break;
|
||||
|
||||
case_R:
|
||||
case 'R': /* year % 100 (remainder in origin-0 century) [00-99] */
|
||||
s = parse_fixed (s, 2, &t->tm.tm_year);
|
||||
t->ymodulus = 100;
|
||||
break;
|
||||
|
||||
case 's': /* second [00-60 followed by optional fraction] */
|
||||
{
|
||||
int frac;
|
||||
s = parse_decimal (s, 2, 0, 60, 1, &t->tm.tm_sec, &frac);
|
||||
t->tm.tm_sec += frac;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'T': /* 'T' or 't' */
|
||||
switch (*s++)
|
||||
{
|
||||
case 'T':
|
||||
case 't':
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 't': /* traditional hour [1-9 or 01-12] */
|
||||
s = parse_ranged (s, (ISDIGIT (s[0]) && ISDIGIT (s[1])) + 1, 1, 12,
|
||||
&t->tm.tm_hour);
|
||||
break;
|
||||
|
||||
case 'w': /* 'W' or 'w' only (stands for current week) */
|
||||
switch (*s++)
|
||||
{
|
||||
case 'W':
|
||||
case 'w':
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'W': /* 'W' or 'w', followed by a week of year [00-53] */
|
||||
switch (*s++)
|
||||
{
|
||||
case 'W':
|
||||
case 'w':
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
s = parse_ranged (s, 2, 0, 53, &t->yweek);
|
||||
break;
|
||||
|
||||
case 'X': /* weekday (1=Mon ... 7=Sun) [1-7] */
|
||||
s = parse_ranged (s, 1, 1, 7, &t->tm.tm_wday);
|
||||
t->tm.tm_wday--;
|
||||
break;
|
||||
|
||||
case 'x': /* weekday name [e.g. "Sun"] */
|
||||
if (! TM_DEFINED (t->tm.tm_wday = lookup (s, weekday_names)))
|
||||
return 0;
|
||||
/* Don't bother to check rest of spelling. */
|
||||
while (ISALPHA ((unsigned char) *s))
|
||||
s++;
|
||||
break;
|
||||
|
||||
case 'y': /* either R or Y */
|
||||
if (ISDIGIT (s[0]) && ISDIGIT (s[1]) && ! ISDIGIT (s[2]))
|
||||
goto case_R;
|
||||
/* fall into */
|
||||
case 'Y': /* year in full [4 or more digits] */
|
||||
{
|
||||
int len = 0;
|
||||
while (ISDIGIT (s[len]))
|
||||
len++;
|
||||
if (len < 4)
|
||||
return 0;
|
||||
s = parse_fixed (s, len, &t->tm.tm_year);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Z': /* time zone */
|
||||
s = parzone (s, &t->zone);
|
||||
break;
|
||||
|
||||
case '_': /* possibly empty sequence of non-alphanumerics */
|
||||
while (! ISALNUM ((unsigned char) *s) && *s)
|
||||
s++;
|
||||
break;
|
||||
|
||||
default: /* bad pattern */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/* If there is no conflict, merge into *T the additional information in *U
|
||||
and return 0. Otherwise do nothing and return -1. */
|
||||
static int
|
||||
merge_partime (t, u)
|
||||
struct partime *t;
|
||||
struct partime const *u;
|
||||
{
|
||||
# define conflict(a,b) ((a) != (b) && TM_DEFINED (a) && TM_DEFINED (b))
|
||||
if (conflict (t->tm.tm_sec, u->tm.tm_sec)
|
||||
|| conflict (t->tm.tm_min, u->tm.tm_min)
|
||||
|| conflict (t->tm.tm_hour, u->tm.tm_hour)
|
||||
|| conflict (t->tm.tm_mday, u->tm.tm_mday)
|
||||
|| conflict (t->tm.tm_mon, u->tm.tm_mon)
|
||||
|| conflict (t->tm.tm_year, u->tm.tm_year)
|
||||
|| conflict (t->tm.tm_wday, u->tm.tm_yday)
|
||||
|| conflict (t->ymodulus, u->ymodulus)
|
||||
|| conflict (t->yweek, u->yweek)
|
||||
|| (t->zone != u->zone
|
||||
&& t->zone != TM_UNDEFINED_ZONE
|
||||
&& u->zone != TM_UNDEFINED_ZONE))
|
||||
return -1;
|
||||
# undef conflict
|
||||
# define merge_(a,b) if (TM_DEFINED (b)) (a) = (b);
|
||||
merge_ (t->tm.tm_sec, u->tm.tm_sec)
|
||||
merge_ (t->tm.tm_min, u->tm.tm_min)
|
||||
merge_ (t->tm.tm_hour, u->tm.tm_hour)
|
||||
merge_ (t->tm.tm_mday, u->tm.tm_mday)
|
||||
merge_ (t->tm.tm_mon, u->tm.tm_mon)
|
||||
merge_ (t->tm.tm_year, u->tm.tm_year)
|
||||
merge_ (t->tm.tm_wday, u->tm.tm_yday)
|
||||
merge_ (t->ymodulus, u->ymodulus)
|
||||
merge_ (t->yweek, u->yweek)
|
||||
# undef merge_
|
||||
if (u->zone != TM_UNDEFINED_ZONE)
|
||||
t->zone = u->zone;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Parse a date/time prefix of S, putting the parsed result into *T.
|
||||
Return the first character after the prefix.
|
||||
The prefix may contain no useful information;
|
||||
in that case, *T will contain only undefined values. */
|
||||
char *
|
||||
partime (s, t)
|
||||
char const *s;
|
||||
struct partime *t;
|
||||
{
|
||||
struct partime p;
|
||||
|
||||
undefine (t);
|
||||
|
||||
while (*s)
|
||||
{
|
||||
int i = 0;
|
||||
char const *s1;
|
||||
|
||||
do
|
||||
{
|
||||
if (! (s1 = parse_prefix (s, &p, &i)))
|
||||
return (char *) s;
|
||||
}
|
||||
while (merge_partime (t, &p) != 0);
|
||||
|
||||
s = s1;
|
||||
}
|
||||
|
||||
return (char *) s;
|
||||
}
|
67
contrib/patch/partime.h
Normal file
67
contrib/patch/partime.h
Normal file
@ -0,0 +1,67 @@
|
||||
/* Parse a string, yielding a struct partime that describes it. */
|
||||
|
||||
/* Copyright 1993, 1994, 1995, 1997 Paul Eggert
|
||||
Distributed under license by the Free Software Foundation, Inc.
|
||||
|
||||
This file is part of RCS.
|
||||
|
||||
RCS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
RCS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with RCS; see the file COPYING.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Report problems and direct all questions to:
|
||||
|
||||
rcs-bugs@cs.purdue.edu
|
||||
|
||||
*/
|
||||
|
||||
#define TM_UNDEFINED (-1)
|
||||
#define TM_DEFINED(x) (0 <= (x))
|
||||
|
||||
/* #include <limits.h> if you want to use these symbols. */
|
||||
#define TM_LOCAL_ZONE LONG_MIN
|
||||
#define TM_UNDEFINED_ZONE (LONG_MIN + 1)
|
||||
|
||||
struct partime
|
||||
{
|
||||
/* This structure describes the parsed time.
|
||||
Only the following tm_* values in it are used:
|
||||
sec, min, hour, mday, mon, year, wday, yday.
|
||||
If TM_UNDEFINED (value), the parser never found the value.
|
||||
The tm_year field is the actual year, not the year - 1900;
|
||||
but see ymodulus below. */
|
||||
struct tm tm;
|
||||
|
||||
/* If !TM_UNDEFINED (ymodulus),
|
||||
then tm.tm_year is actually modulo ymodulus. */
|
||||
int ymodulus;
|
||||
|
||||
/* Week of year, ISO 8601 style.
|
||||
If TM_UNDEFINED (yweek), the parser never found yweek.
|
||||
Weeks start on Mondays.
|
||||
Week 1 includes Jan 4. */
|
||||
int yweek;
|
||||
|
||||
/* Seconds east of UTC; or TM_LOCAL_ZONE or TM_UNDEFINED_ZONE. */
|
||||
long zone;
|
||||
};
|
||||
|
||||
#if defined __STDC__ || has_prototypes
|
||||
# define __PARTIME_P(x) x
|
||||
#else
|
||||
# define __PARTIME_P(x) ()
|
||||
#endif
|
||||
|
||||
char *partime __PARTIME_P ((char const *, struct partime *));
|
||||
char *parzone __PARTIME_P ((char const *, long *));
|
1063
contrib/patch/patch.1
Normal file
1063
contrib/patch/patch.1
Normal file
File diff suppressed because it is too large
Load Diff
1293
contrib/patch/patch.c
Normal file
1293
contrib/patch/patch.c
Normal file
File diff suppressed because it is too large
Load Diff
1823
contrib/patch/pch.c
Normal file
1823
contrib/patch/pch.c
Normal file
File diff suppressed because it is too large
Load Diff
25
contrib/patch/pch.h
Normal file
25
contrib/patch/pch.h
Normal file
@ -0,0 +1,25 @@
|
||||
/* reading patches */
|
||||
|
||||
/* $Id: pch.h,v 1.8 1997/06/13 06:28:37 eggert Exp $ */
|
||||
|
||||
LINENUM pch_end PARAMS ((void));
|
||||
LINENUM pch_first PARAMS ((void));
|
||||
LINENUM pch_hunk_beg PARAMS ((void));
|
||||
LINENUM pch_newfirst PARAMS ((void));
|
||||
LINENUM pch_prefix_context PARAMS ((void));
|
||||
LINENUM pch_ptrn_lines PARAMS ((void));
|
||||
LINENUM pch_repl_lines PARAMS ((void));
|
||||
LINENUM pch_suffix_context PARAMS ((void));
|
||||
bool pch_swap PARAMS ((void));
|
||||
bool pch_write_line PARAMS ((LINENUM, FILE *));
|
||||
bool there_is_another_patch PARAMS ((void));
|
||||
char *pfetch PARAMS ((LINENUM));
|
||||
char pch_char PARAMS ((LINENUM));
|
||||
int another_hunk PARAMS ((enum diff, int));
|
||||
int pch_says_nonexistent PARAMS ((int));
|
||||
size_t pch_line_len PARAMS ((LINENUM));
|
||||
time_t pch_timestamp PARAMS ((int));
|
||||
void do_ed_script PARAMS ((FILE *));
|
||||
void open_patch_file PARAMS ((char const *));
|
||||
void re_patch PARAMS ((void));
|
||||
void set_hunkmax PARAMS ((void));
|
125
contrib/patch/quotearg.c
Normal file
125
contrib/patch/quotearg.c
Normal file
@ -0,0 +1,125 @@
|
||||
/* Shell command argument quoting.
|
||||
Copyright (C) 1994, 1995, 1997 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* Written by Paul Eggert <eggert@twinsun.com> */
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <quotearg.h>
|
||||
|
||||
/* Place into QUOTED a quoted version of ARG suitable for `system'.
|
||||
Return the length of the resulting string (which is not null-terminated).
|
||||
If QUOTED is null, return the length without any side effects. */
|
||||
|
||||
size_t
|
||||
quote_system_arg (quoted, arg)
|
||||
char *quoted;
|
||||
char const *arg;
|
||||
{
|
||||
char const *a;
|
||||
size_t len = 0;
|
||||
|
||||
/* Scan ARG, copying it to QUOTED if QUOTED is not null,
|
||||
looking for shell metacharacters. */
|
||||
|
||||
for (a = arg; ; a++)
|
||||
{
|
||||
char c = *a;
|
||||
switch (c)
|
||||
{
|
||||
case 0:
|
||||
/* ARG has no shell metacharacters. */
|
||||
return len;
|
||||
|
||||
case '=':
|
||||
if (*arg == '-')
|
||||
break;
|
||||
/* Fall through. */
|
||||
case '\t': case '\n': case ' ':
|
||||
case '!': case '"': case '#': case '$': case '%': case '&': case '\'':
|
||||
case '(': case ')': case '*': case ';':
|
||||
case '<': case '>': case '?': case '[': case '\\':
|
||||
case '^': case '`': case '|': case '~':
|
||||
{
|
||||
/* ARG has a shell metacharacter.
|
||||
Start over, quoting it this time. */
|
||||
|
||||
len = 0;
|
||||
c = *arg++;
|
||||
|
||||
/* If ARG is an option, quote just its argument.
|
||||
This is not necessary, but it looks nicer. */
|
||||
if (c == '-' && arg < a)
|
||||
{
|
||||
c = *arg++;
|
||||
|
||||
if (quoted)
|
||||
{
|
||||
quoted[len] = '-';
|
||||
quoted[len + 1] = c;
|
||||
}
|
||||
len += 2;
|
||||
|
||||
if (c == '-')
|
||||
while (arg < a)
|
||||
{
|
||||
c = *arg++;
|
||||
if (quoted)
|
||||
quoted[len] = c;
|
||||
len++;
|
||||
if (c == '=')
|
||||
break;
|
||||
}
|
||||
c = *arg++;
|
||||
}
|
||||
|
||||
if (quoted)
|
||||
quoted[len] = '\'';
|
||||
len++;
|
||||
|
||||
for (; c; c = *arg++)
|
||||
{
|
||||
if (c == '\'')
|
||||
{
|
||||
if (quoted)
|
||||
{
|
||||
quoted[len] = '\'';
|
||||
quoted[len + 1] = '\\';
|
||||
quoted[len + 2] = '\'';
|
||||
}
|
||||
len += 3;
|
||||
}
|
||||
if (quoted)
|
||||
quoted[len] = c;
|
||||
len++;
|
||||
}
|
||||
|
||||
if (quoted)
|
||||
quoted[len] = '\'';
|
||||
return len + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (quoted)
|
||||
quoted[len] = c;
|
||||
len++;
|
||||
}
|
||||
}
|
9
contrib/patch/quotearg.h
Normal file
9
contrib/patch/quotearg.h
Normal file
@ -0,0 +1,9 @@
|
||||
/* quote.h -- declarations for quoting system arguments */
|
||||
|
||||
#if defined __STDC__ || __GNUC__
|
||||
# define __QUOTEARG_P(args) args
|
||||
#else
|
||||
# define __QUOTEARG_P(args) ()
|
||||
#endif
|
||||
|
||||
size_t quote_system_arg __QUOTEARG_P ((char *, char const *));
|
112
contrib/patch/rename.c
Normal file
112
contrib/patch/rename.c
Normal file
@ -0,0 +1,112 @@
|
||||
/* BSD compatible rename and directory rename function for System V.
|
||||
Copyright (C) 1988, 1990 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#if STAT_MACROS_BROKEN
|
||||
# undef S_ISDIR
|
||||
#endif
|
||||
|
||||
#if !defined(S_ISDIR) && defined(S_IFDIR)
|
||||
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
||||
#endif
|
||||
|
||||
/* Rename file FROM to file TO.
|
||||
Return 0 if successful, -1 if not. */
|
||||
|
||||
int
|
||||
rename (from, to)
|
||||
char *from;
|
||||
char *to;
|
||||
{
|
||||
struct stat from_stats, to_stats;
|
||||
int pid, status;
|
||||
|
||||
if (stat (from, &from_stats))
|
||||
return -1;
|
||||
|
||||
/* Be careful not to unlink `from' if it happens to be equal to `to' or
|
||||
(on filesystems that silently truncate filenames after 14 characters)
|
||||
if `from' and `to' share the significant characters. */
|
||||
if (stat (to, &to_stats))
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((from_stats.st_dev == to_stats.st_dev)
|
||||
&& (from_stats.st_ino == to_stats.st_ino))
|
||||
/* `from' and `to' designate the same file on that filesystem. */
|
||||
return 0;
|
||||
|
||||
if (unlink (to) && errno != ENOENT)
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef MVDIR
|
||||
|
||||
/* If MVDIR is defined, it should be the full filename of a setuid root
|
||||
program able to link and unlink directories. If MVDIR is not defined,
|
||||
then the capability of renaming directories may be missing. */
|
||||
|
||||
if (S_ISDIR (from_stats.st_mode))
|
||||
{
|
||||
/* Need a setuid root process to link and unlink directories. */
|
||||
pid = fork ();
|
||||
switch (pid)
|
||||
{
|
||||
case -1: /* Error. */
|
||||
error (1, errno, "cannot fork");
|
||||
|
||||
case 0: /* Child. */
|
||||
execl (MVDIR, "mvdir", from, to, (char *) 0);
|
||||
error (255, errno, "cannot run `%s'", MVDIR);
|
||||
|
||||
default: /* Parent. */
|
||||
while (wait (&status) != pid)
|
||||
/* Do nothing. */ ;
|
||||
|
||||
errno = 0; /* mvdir printed the system error message. */
|
||||
if (status)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
#endif /* MVDIR */
|
||||
|
||||
{
|
||||
if (link (from, to))
|
||||
return -1;
|
||||
if (unlink (from) && errno != ENOENT)
|
||||
{
|
||||
unlink (to);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
1070
contrib/patch/util.c
Normal file
1070
contrib/patch/util.c
Normal file
File diff suppressed because it is too large
Load Diff
32
contrib/patch/util.h
Normal file
32
contrib/patch/util.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* utility functions for `patch' */
|
||||
|
||||
/* $Id: util.h,v 1.14 1997/06/13 06:28:37 eggert Exp $ */
|
||||
|
||||
int ok_to_reverse PARAMS ((char const *, ...)) __attribute__ ((format (printf, 1, 2)));
|
||||
void ask PARAMS ((char const *, ...)) __attribute__ ((format (printf, 1, 2)));
|
||||
void say PARAMS ((char const *, ...)) __attribute__ ((format (printf, 1, 2)));
|
||||
|
||||
void fatal PARAMS ((char const *, ...))
|
||||
__attribute__ ((noreturn, format (printf, 1, 2)));
|
||||
void pfatal PARAMS ((char const *, ...))
|
||||
__attribute__ ((noreturn, format (printf, 1, 2)));
|
||||
|
||||
char *fetchname PARAMS ((char *, int, time_t *));
|
||||
char *savebuf PARAMS ((char const *, size_t));
|
||||
char *savestr PARAMS ((char const *));
|
||||
char const *version_controller PARAMS ((char const *, int, struct stat const *, char **, char **));
|
||||
int version_get PARAMS ((char const *, char const *, int, int, char const *, struct stat *));
|
||||
int create_file PARAMS ((char const *, int, mode_t));
|
||||
int systemic PARAMS ((char const *));
|
||||
void Fseek PARAMS ((FILE *, file_offset, int));
|
||||
void copy_file PARAMS ((char const *, char const *, mode_t));
|
||||
void exit_with_signal PARAMS ((int)) __attribute__ ((noreturn));
|
||||
void ignore_signals PARAMS ((void));
|
||||
void init_time PARAMS ((void));
|
||||
void memory_fatal PARAMS ((void));
|
||||
void move_file PARAMS ((char const *, char *, mode_t, int));
|
||||
void read_fatal PARAMS ((void));
|
||||
void remove_prefix PARAMS ((char *, size_t));
|
||||
void removedirs PARAMS ((char *));
|
||||
void set_signals PARAMS ((int));
|
||||
void write_fatal PARAMS ((void));
|
30
contrib/patch/version.c
Normal file
30
contrib/patch/version.c
Normal file
@ -0,0 +1,30 @@
|
||||
/* Print the version number. */
|
||||
|
||||
/* $Id: version.c,v 1.5 1997/05/21 18:29:20 eggert Exp $ */
|
||||
|
||||
#define XTERN extern
|
||||
#include <common.h>
|
||||
#undef XTERN
|
||||
#define XTERN
|
||||
#include <patchlevel.h>
|
||||
#include <version.h>
|
||||
|
||||
static char const copyright_string[] = "\
|
||||
Copyright 1988 Larry Wall\n\
|
||||
Copyright 1997 Free Software Foundation, Inc.";
|
||||
|
||||
static char const free_software_msgid[] = "\
|
||||
This program comes with NO WARRANTY, to the extent permitted by law.\n\
|
||||
You may redistribute copies of this program\n\
|
||||
under the terms of the GNU General Public License.\n\
|
||||
For more information about these matters, see the file named COPYING.";
|
||||
|
||||
static char const authorship_msgid[] = "\
|
||||
written by Larry Wall with lots o' patches by Paul Eggert";
|
||||
|
||||
void
|
||||
version()
|
||||
{
|
||||
printf ("%s %s\n%s\n\n%s\n\n%s\n", program_name, PATCH_VERSION,
|
||||
copyright_string, free_software_msgid, authorship_msgid);
|
||||
}
|
5
contrib/patch/version.h
Normal file
5
contrib/patch/version.h
Normal file
@ -0,0 +1,5 @@
|
||||
/* Print the version number. */
|
||||
|
||||
/* $Id: version.h,v 1.3 1997/04/07 01:07:00 eggert Exp $ */
|
||||
|
||||
void version PARAMS ((void));
|
Loading…
Reference in New Issue
Block a user