mirror of
https://github.com/opnsense/src.git
synced 2026-02-18 18:20:26 -05:00
Updated GNU utilities
This commit is contained in:
parent
7c434002a4
commit
b76095a430
126 changed files with 74864 additions and 0 deletions
339
gnu/COPYING
Normal file
339
gnu/COPYING
Normal file
|
|
@ -0,0 +1,339 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
5
gnu/Makefile
Normal file
5
gnu/Makefile
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# @(#)Makefile 5.33.1.1 (Berkeley) 5/6/91
|
||||
|
||||
SUBDIR= gawk groff tar
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
21
gnu/usr.bin/awk/ACKNOWLEDGMENT
Normal file
21
gnu/usr.bin/awk/ACKNOWLEDGMENT
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
The current developers of Gawk would like to thank and acknowledge the
|
||||
many people who have contributed to the development through bug reports
|
||||
and fixes and suggestions. Unfortunately, we have not been organized
|
||||
enough to keep track of all the names -- for that we apologize.
|
||||
|
||||
Another group of people have assisted even more by porting Gawk to new
|
||||
platforms and providing a great deal of feedback. They are:
|
||||
|
||||
Hal Peterson <hrp@pecan.cray.com> (Cray)
|
||||
Pat Rankin <gawk.rankin@EQL.Caltech.Edu> (VMS)
|
||||
Michal Jaegermann <NTOMCZAK@vm.ucs.UAlberta.CA> (Atari, NeXT, DEC 3100)
|
||||
Mike Lijewski <mjlx@eagle.cnsf.cornell.edu> (IBM RS6000)
|
||||
Scott Deifik <scottd@amgen.com> (MSDOS 2.14)
|
||||
Kent Williams (MSDOS 2.11)
|
||||
Conrad Kwok (MSDOS earlier versions)
|
||||
Scott Garfinkle (MSDOS earlier versions)
|
||||
|
||||
Last, but far from least, we would like to thank Brian Kernighan who
|
||||
has helped to clear up many dark corners of the language and provided a
|
||||
restraining touch when we have been overly tempted by "feeping
|
||||
creaturism".
|
||||
340
gnu/usr.bin/awk/COPYING
Normal file
340
gnu/usr.bin/awk/COPYING
Normal file
|
|
@ -0,0 +1,340 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
|
||||
120
gnu/usr.bin/awk/FUTURES
Normal file
120
gnu/usr.bin/awk/FUTURES
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
This file lists future projects and enhancements for gawk. Items are listed
|
||||
in roughly the order they will be done for a given release. This file is
|
||||
mainly for use by the developers to help keep themselves on track, please
|
||||
don't bug us too much about schedules or what all this really means.
|
||||
|
||||
For 2.16
|
||||
========
|
||||
David:
|
||||
Move to autoconf-based configure system.
|
||||
|
||||
Allow RS to be a regexp.
|
||||
|
||||
RT variable to hold text of record terminator
|
||||
|
||||
RECLEN variable for fixed length records
|
||||
|
||||
Feedback alloca.s changes to FSF
|
||||
|
||||
Extensible hashing in memory of awk arrays
|
||||
|
||||
Split() with null string as third arg to split up strings
|
||||
|
||||
Analogously, setting FS="" would split the input record into individual
|
||||
characters.
|
||||
|
||||
Arnold:
|
||||
Generalize IGNORECASE
|
||||
any value makes it work, not just numeric non-zero
|
||||
make it apply to *all* string comparisons
|
||||
|
||||
Fix FILENAME to have an initial value of "", not "-"
|
||||
|
||||
Clean up code by isolating system-specific functions in separate files.
|
||||
|
||||
Undertake significant directory reorganization.
|
||||
|
||||
Extensive manual cleanup:
|
||||
Use of texinfo 2.0 features
|
||||
Lots more examples
|
||||
Document all of the above.
|
||||
|
||||
In 2.17
|
||||
=======
|
||||
David:
|
||||
|
||||
Incorporate newer dfa.c and regex.c (go to POSIX regexps)
|
||||
|
||||
Make regex + dfa less dependant on gawk header file includes
|
||||
|
||||
General sub functions:
|
||||
edit(line, pat, sub) and gedit(line, pat, sub)
|
||||
that return the substituted strings and allow \1 etc. in the sub string.
|
||||
|
||||
Arnold:
|
||||
DBM storage of awk arrays. Try to allow multiple dbm packages
|
||||
|
||||
? Have strftime() pay attention to the value of ENVIRON["TZ"]
|
||||
|
||||
Additional manual features:
|
||||
Document posix regexps
|
||||
Document use of dbm arrays
|
||||
? Add an error messages section to the manual
|
||||
? A section on where gawk is bounded
|
||||
regex
|
||||
i/o
|
||||
sun fp conversions
|
||||
|
||||
For 2.18
|
||||
========
|
||||
|
||||
Arnold:
|
||||
Add chdir and stat built-in functions.
|
||||
|
||||
Add function pointers as valid variable types.
|
||||
|
||||
Add an `ftw' built-in function that takes a function pointer.
|
||||
|
||||
David:
|
||||
|
||||
Do an optimization pass over parse tree?
|
||||
|
||||
For 2.19 or later:
|
||||
==================
|
||||
Add variables similar to C's __FILE__ and __LINE__ for better diagnostics
|
||||
from within awk programs.
|
||||
|
||||
Add an explicit concatenation operator and assignment version.
|
||||
|
||||
? Add a switch statement
|
||||
|
||||
Add the ability to seek on an open file and retrieve the current file position.
|
||||
|
||||
Add lint checking everywhere, including check for use of builtin vars.
|
||||
only in new awk.
|
||||
|
||||
"restart" keyword
|
||||
|
||||
Add |&
|
||||
|
||||
Make awk '/foo/' files... run at egrep speeds
|
||||
|
||||
Do a reference card
|
||||
|
||||
Allow OFMT to be other than a floating point format.
|
||||
|
||||
Allow redefining of builtin functions?
|
||||
|
||||
Make it faster and smaller.
|
||||
|
||||
For 3.x:
|
||||
========
|
||||
|
||||
Create a gawk compiler?
|
||||
|
||||
Create a gawk-to-C translator? (or C++??)
|
||||
|
||||
Provide awk profiling and debugging.
|
||||
|
||||
|
||||
|
||||
14
gnu/usr.bin/awk/LIMITATIONS
Normal file
14
gnu/usr.bin/awk/LIMITATIONS
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
This file describes limits of gawk on a Unix system (although it
|
||||
is variable even then). Non-Unix systems may have other limits.
|
||||
|
||||
# of fields in a record: MAX_INT
|
||||
Length of input record: MAX_INT
|
||||
Length of output record: unlimited
|
||||
Size of a field: MAX_INT
|
||||
Size of a printf string: MAX_INT
|
||||
Size of a literal string: MAX_INT
|
||||
Characters in a character class: 2^(# of bits per byte)
|
||||
# of file redirections: unlimited
|
||||
# of pipe redirections: min(# of processes per user, # of open files)
|
||||
double-precision floating point
|
||||
Length of source line: unlimited
|
||||
13
gnu/usr.bin/awk/Makefile
Normal file
13
gnu/usr.bin/awk/Makefile
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
PROG= awk
|
||||
SRCS= main.c eval.c builtin.c msg.c iop.c io.c field.c array.c \
|
||||
node.c version.c re.c awk.c regex.c dfa.c \
|
||||
getopt.c getopt1.c
|
||||
CFLAGS+= -DGAWK
|
||||
LDADD= -lm
|
||||
DPADD= ${LIBM}
|
||||
CLEANFILES+= awk.c y.tab.h
|
||||
|
||||
MAN1= awk.0
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
.include "../../usr.bin/Makefile.inc"
|
||||
1295
gnu/usr.bin/awk/NEWS
Normal file
1295
gnu/usr.bin/awk/NEWS
Normal file
File diff suppressed because it is too large
Load diff
32
gnu/usr.bin/awk/PORTS
Normal file
32
gnu/usr.bin/awk/PORTS
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
A recent version of gawk has been successfully compiled and run "make test"
|
||||
on the following:
|
||||
|
||||
Sun 4/490 running 4.1
|
||||
NeXT running 2.0
|
||||
DECstation 3100 running Ultrix 4.0 or Ultrix 3.1 (different config)
|
||||
AtariST (16-bit ints, gcc compiler, byacc, running under TOS)
|
||||
ESIX V.3.2 Rev D (== System V Release 3.2), the 386. compiler was gcc + bison
|
||||
IBM RS/6000 (see README.rs6000)
|
||||
486 running SVR4, using cc and bison
|
||||
SGI running IRIX 3.3 using gcc (fails with cc)
|
||||
Sequent Balance running Dynix V3.1
|
||||
Cray Y-MP8 running Unicos 6.0.11
|
||||
Cray 2 running Unicos 6.1 (modulo trailing zeroes in chem)
|
||||
VAX/VMS V5.x (should also work on 4.6 and 4.7)
|
||||
VMS POSIX V1.0, V1.1
|
||||
OpenVMS AXP V1.0
|
||||
MSDOS - Microsoft C 5.1, compiles and runs very simple testing
|
||||
BSD 4.4alpha
|
||||
|
||||
From: ghazi@caip.rutgers.edu (Kaveh R. Ghazi):
|
||||
|
||||
arch configured as:
|
||||
---- --------------
|
||||
Hpux 9.0 hpux8x
|
||||
NeXTStep 2.0 next20
|
||||
Sgi Irix 4.0.5 (/bin/cc) sgi405.cc (new file)
|
||||
Stardent Titan 1500 OSv2.5 sysv3
|
||||
Stardent Vistra (i860) SVR4 sysv4
|
||||
SunOS 4.1.2 sunos41
|
||||
Tektronix XD88 (UTekV 3.2e) sysv3
|
||||
Ultrix 4.2 ultrix41
|
||||
95
gnu/usr.bin/awk/POSIX
Normal file
95
gnu/usr.bin/awk/POSIX
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
Right now, the numeric vs. string comparisons are screwed up in draft
|
||||
11.2. What prompted me to check it out was the note in gnu.bug.utils
|
||||
which observed that gawk was doing the comparison $1 == "000"
|
||||
numerically. I think that we can agree that intuitively, this should
|
||||
be done as a string comparison. Version 2.13.2 of gawk follows the
|
||||
current POSIX draft. Following is how I (now) think this
|
||||
stuff should be done.
|
||||
|
||||
1. A numeric literal or the result of a numeric operation has the NUMERIC
|
||||
attribute.
|
||||
|
||||
2. A string literal or the result of a string operation has the STRING
|
||||
attribute.
|
||||
|
||||
3. Fields, getline input, FILENAME, ARGV elements, ENVIRON elements and the
|
||||
elements of an array created by split() that are numeric strings
|
||||
have the STRNUM attribute. Otherwise, they have the STRING attribute.
|
||||
Uninitialized variables also have the STRNUM attribute.
|
||||
|
||||
4. Attributes propagate across assignments, but are not changed by
|
||||
any use. (Although a use may cause the entity to acquire an additional
|
||||
value such that it has both a numeric and string value -- this leaves the
|
||||
attribute unchanged.)
|
||||
|
||||
When two operands are compared, either string comparison or numeric comparison
|
||||
may be used, depending on the attributes of the operands, according to the
|
||||
following (symmetric) matrix:
|
||||
|
||||
+----------------------------------------------
|
||||
| STRING NUMERIC STRNUM
|
||||
--------+----------------------------------------------
|
||||
|
|
||||
STRING | string string string
|
||||
|
|
||||
NUMERIC | string numeric numeric
|
||||
|
|
||||
STRNUM | string numeric numeric
|
||||
--------+----------------------------------------------
|
||||
|
||||
So, the following program should print all OKs.
|
||||
|
||||
echo '0e2 0a 0 0b
|
||||
0e2 0a 0 0b' |
|
||||
$AWK '
|
||||
NR == 1 {
|
||||
num = 0
|
||||
str = "0e2"
|
||||
|
||||
print ++test ": " ( (str == "0e2") ? "OK" : "OOPS" )
|
||||
print ++test ": " ( ("0e2" != 0) ? "OK" : "OOPS" )
|
||||
print ++test ": " ( ("0" != $2) ? "OK" : "OOPS" )
|
||||
print ++test ": " ( ("0e2" == $1) ? "OK" : "OOPS" )
|
||||
|
||||
print ++test ": " ( (0 == "0") ? "OK" : "OOPS" )
|
||||
print ++test ": " ( (0 == num) ? "OK" : "OOPS" )
|
||||
print ++test ": " ( (0 != $2) ? "OK" : "OOPS" )
|
||||
print ++test ": " ( (0 == $1) ? "OK" : "OOPS" )
|
||||
|
||||
print ++test ": " ( ($1 != "0") ? "OK" : "OOPS" )
|
||||
print ++test ": " ( ($1 == num) ? "OK" : "OOPS" )
|
||||
print ++test ": " ( ($2 != 0) ? "OK" : "OOPS" )
|
||||
print ++test ": " ( ($2 != $1) ? "OK" : "OOPS" )
|
||||
print ++test ": " ( ($3 == 0) ? "OK" : "OOPS" )
|
||||
print ++test ": " ( ($3 == $1) ? "OK" : "OOPS" )
|
||||
print ++test ": " ( ($2 != $4) ? "OK" : "OOPS" ) # 15
|
||||
}
|
||||
{
|
||||
a = "+2"
|
||||
b = 2
|
||||
if (NR % 2)
|
||||
c = a + b
|
||||
print ++test ": " ( (a != b) ? "OK" : "OOPS" ) # 16 and 22
|
||||
|
||||
d = "2a"
|
||||
b = 2
|
||||
if (NR % 2)
|
||||
c = d + b
|
||||
print ++test ": " ( (d != b) ? "OK" : "OOPS" )
|
||||
|
||||
print ++test ": " ( (d + 0 == b) ? "OK" : "OOPS" )
|
||||
|
||||
e = "2"
|
||||
print ++test ": " ( (e == b "") ? "OK" : "OOPS" )
|
||||
|
||||
a = "2.13"
|
||||
print ++test ": " ( (a == 2.13) ? "OK" : "OOPS" )
|
||||
|
||||
a = "2.130000"
|
||||
print ++test ": " ( (a != 2.13) ? "OK" : "OOPS" )
|
||||
|
||||
if (NR == 2) {
|
||||
CONVFMT = "%.6f"
|
||||
print ++test ": " ( (a == 2.13) ? "OK" : "OOPS" )
|
||||
}
|
||||
}'
|
||||
6
gnu/usr.bin/awk/PROBLEMS
Normal file
6
gnu/usr.bin/awk/PROBLEMS
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
This is a list of known problems in gawk 2.15.
|
||||
Hopefully they will all be fixed in the next major release of gawk.
|
||||
|
||||
Please keep in mind that the code is still undergoing significant evolution.
|
||||
|
||||
1. Gawk's printf is probably still not POSIX compliant.
|
||||
116
gnu/usr.bin/awk/README
Normal file
116
gnu/usr.bin/awk/README
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
README:
|
||||
|
||||
This is GNU Awk 2.15. It should be upwardly compatible with the
|
||||
System V Release 4 awk. It is almost completely compliant with draft 11.3
|
||||
of POSIX 1003.2.
|
||||
|
||||
This release adds new features -- see NEWS for details.
|
||||
|
||||
See the installation instructions, below.
|
||||
|
||||
Known problems are given in the PROBLEMS file. Work to be done is
|
||||
described briefly in the FUTURES file. Verified ports are listed in
|
||||
the PORTS file. Changes in this version are summarized in the CHANGES file.
|
||||
Please read the LIMITATIONS and ACKNOWLEDGMENT files.
|
||||
|
||||
Read the file POSIX for a discussion of how the standard says comparisons
|
||||
should be done vs. how they really should be done and how gawk does them.
|
||||
|
||||
To format the documentation with TeX, you must use texinfo.tex 2.53
|
||||
or later. Otherwise footnotes look unacceptable.
|
||||
|
||||
If you wish to remake the Info files, you should use makeinfo. The 2.15
|
||||
version of makeinfo works with no errors.
|
||||
|
||||
The man page is up to date.
|
||||
|
||||
INSTALLATION:
|
||||
|
||||
Check whether there is a system-specific README file for your system.
|
||||
|
||||
Makefile.in may need some tailoring. The only changes necessary should
|
||||
be to change installation targets or to change compiler flags.
|
||||
The changes to make in Makefile.in are commented and should be obvious.
|
||||
|
||||
All other changes should be made in a config file. Samples for
|
||||
various systems are included in the config directory. Starting with
|
||||
2.11, our intent has been to make the code conform to standards (ANSI,
|
||||
POSIX, SVID, in that order) whenever possible, and to not penalize
|
||||
standard conforming systems. We have included substitute versions of
|
||||
routines not universally available. Simply add the appropriate define
|
||||
for the missing feature(s) on your system.
|
||||
|
||||
If you have neither bison nor yacc, use the awktab.c file here. It was
|
||||
generated with bison, and should have no AT&T code in it. (Note that
|
||||
modifying awk.y without bison or yacc will be difficult, at best. You might
|
||||
want to get a copy of bison from the FSF too.)
|
||||
|
||||
If no config file is included for your system, start by copying one
|
||||
for a similar system. One way of determining the defines needed is to
|
||||
try to load gawk with nothing defined and see what routines are
|
||||
unresolved by the loader. This should give you a good idea of how to
|
||||
proceed.
|
||||
|
||||
The next release will use the FSF autoconfig program, so we are no longer
|
||||
soliciting new config files.
|
||||
|
||||
If you have an MS-DOS system, use the stuff in the pc directory.
|
||||
For an Atari there is an atari directory and similarly one for VMS.
|
||||
|
||||
Chapter 16 of The GAWK Manual discusses configuration in detail.
|
||||
|
||||
After successful compilation, do 'make test' to run a small test
|
||||
suite. There should be no output from the 'cmp' invocations except in
|
||||
the cases where there are small differences in floating point values.
|
||||
If there are other differences, please investigate and report the
|
||||
problem.
|
||||
|
||||
PRINTING THE MANUAL
|
||||
|
||||
The 'support' directory contains texinfo.tex 2.65, which will be necessary
|
||||
for printing the manual, and the texindex.c program from the texinfo
|
||||
distribution which is also necessary. See the makefile for the steps needed
|
||||
to get a DVI file from the manual.
|
||||
|
||||
CAVEATS
|
||||
|
||||
The existence of a patchlevel.h file does *N*O*T* imply a commitment on
|
||||
our part to issue bug fixes or patches. It is there in case we should
|
||||
decide to do so.
|
||||
|
||||
BUG REPORTS AND FIXES (Un*x systems):
|
||||
|
||||
Please coordinate changes through David Trueman and/or Arnold Robbins.
|
||||
|
||||
David Trueman
|
||||
Department of Mathematics, Statistics and Computing Science,
|
||||
Dalhousie University, Halifax, Nova Scotia, Canada
|
||||
|
||||
UUCP: {uunet utai watmath}!dalcs!david
|
||||
INTERNET: david@cs.dal.ca
|
||||
|
||||
Arnold Robbins
|
||||
1736 Reindeer Drive
|
||||
Atlanta, GA, 30329, USA
|
||||
|
||||
INTERNET: arnold@skeeve.atl.ga.us
|
||||
UUCP: { gatech, emory, emoryu1 }!skeeve!arnold
|
||||
|
||||
BUG REPORTS AND FIXES (non-Unix ports):
|
||||
|
||||
MS-DOS:
|
||||
Scott Deifik
|
||||
AMGEN Inc.
|
||||
Amgen Center, Bldg.17-Dept.393
|
||||
Thousand Oaks, CA 91320-1789
|
||||
Tel-805-499-5725 ext.4677
|
||||
Fax-805-498-0358
|
||||
scottd@amgen.com
|
||||
|
||||
VMS:
|
||||
Pat Rankin
|
||||
rankin@eql.caltech.edu (e-mail only)
|
||||
|
||||
Atari ST:
|
||||
Michal Jaegermann
|
||||
NTOMCZAK@vm.ucs.UAlberta.CA (e-mail only)
|
||||
293
gnu/usr.bin/awk/array.c
Normal file
293
gnu/usr.bin/awk/array.c
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
/*
|
||||
* array.c - routines for associative arrays.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GAWK, the GNU implementation of the
|
||||
* AWK Progamming Language.
|
||||
*
|
||||
* GAWK 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.
|
||||
*
|
||||
* GAWK 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 GAWK; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "awk.h"
|
||||
|
||||
static NODE *assoc_find P((NODE *symbol, NODE *subs, int hash1));
|
||||
|
||||
NODE *
|
||||
concat_exp(tree)
|
||||
register NODE *tree;
|
||||
{
|
||||
register NODE *r;
|
||||
char *str;
|
||||
char *s;
|
||||
unsigned len;
|
||||
int offset;
|
||||
int subseplen;
|
||||
char *subsep;
|
||||
|
||||
if (tree->type != Node_expression_list)
|
||||
return force_string(tree_eval(tree));
|
||||
r = force_string(tree_eval(tree->lnode));
|
||||
if (tree->rnode == NULL)
|
||||
return r;
|
||||
subseplen = SUBSEP_node->lnode->stlen;
|
||||
subsep = SUBSEP_node->lnode->stptr;
|
||||
len = r->stlen + subseplen + 2;
|
||||
emalloc(str, char *, len, "concat_exp");
|
||||
memcpy(str, r->stptr, r->stlen+1);
|
||||
s = str + r->stlen;
|
||||
free_temp(r);
|
||||
tree = tree->rnode;
|
||||
while (tree) {
|
||||
if (subseplen == 1)
|
||||
*s++ = *subsep;
|
||||
else {
|
||||
memcpy(s, subsep, subseplen+1);
|
||||
s += subseplen;
|
||||
}
|
||||
r = force_string(tree_eval(tree->lnode));
|
||||
len += r->stlen + subseplen;
|
||||
offset = s - str;
|
||||
erealloc(str, char *, len, "concat_exp");
|
||||
s = str + offset;
|
||||
memcpy(s, r->stptr, r->stlen+1);
|
||||
s += r->stlen;
|
||||
free_temp(r);
|
||||
tree = tree->rnode;
|
||||
}
|
||||
r = make_str_node(str, s - str, ALREADY_MALLOCED);
|
||||
r->flags |= TEMP;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Flush all the values in symbol[] before doing a split() */
|
||||
void
|
||||
assoc_clear(symbol)
|
||||
NODE *symbol;
|
||||
{
|
||||
int i;
|
||||
NODE *bucket, *next;
|
||||
|
||||
if (symbol->var_array == 0)
|
||||
return;
|
||||
for (i = 0; i < HASHSIZE; i++) {
|
||||
for (bucket = symbol->var_array[i]; bucket; bucket = next) {
|
||||
next = bucket->ahnext;
|
||||
unref(bucket->ahname);
|
||||
unref(bucket->ahvalue);
|
||||
freenode(bucket);
|
||||
}
|
||||
symbol->var_array[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* calculate the hash function of the string in subs
|
||||
*/
|
||||
unsigned int
|
||||
hash(s, len)
|
||||
register char *s;
|
||||
register int len;
|
||||
{
|
||||
register unsigned long h = 0, g;
|
||||
|
||||
while (len--) {
|
||||
h = (h << 4) + *s++;
|
||||
g = (h & 0xf0000000);
|
||||
if (g) {
|
||||
h = h ^ (g >> 24);
|
||||
h = h ^ g;
|
||||
}
|
||||
}
|
||||
if (h < HASHSIZE)
|
||||
return h;
|
||||
else
|
||||
return h%HASHSIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
* locate symbol[subs]
|
||||
*/
|
||||
static NODE * /* NULL if not found */
|
||||
assoc_find(symbol, subs, hash1)
|
||||
NODE *symbol;
|
||||
register NODE *subs;
|
||||
int hash1;
|
||||
{
|
||||
register NODE *bucket, *prev = 0;
|
||||
|
||||
for (bucket = symbol->var_array[hash1]; bucket; bucket = bucket->ahnext) {
|
||||
if (cmp_nodes(bucket->ahname, subs) == 0) {
|
||||
if (prev) { /* move found to front of chain */
|
||||
prev->ahnext = bucket->ahnext;
|
||||
bucket->ahnext = symbol->var_array[hash1];
|
||||
symbol->var_array[hash1] = bucket;
|
||||
}
|
||||
return bucket;
|
||||
} else
|
||||
prev = bucket; /* save previous list entry */
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* test whether the array element symbol[subs] exists or not
|
||||
*/
|
||||
int
|
||||
in_array(symbol, subs)
|
||||
NODE *symbol, *subs;
|
||||
{
|
||||
register int hash1;
|
||||
|
||||
if (symbol->type == Node_param_list)
|
||||
symbol = stack_ptr[symbol->param_cnt];
|
||||
if (symbol->var_array == 0)
|
||||
return 0;
|
||||
subs = concat_exp(subs); /* concat_exp returns a string node */
|
||||
hash1 = hash(subs->stptr, subs->stlen);
|
||||
if (assoc_find(symbol, subs, hash1) == NULL) {
|
||||
free_temp(subs);
|
||||
return 0;
|
||||
} else {
|
||||
free_temp(subs);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* SYMBOL is the address of the node (or other pointer) being dereferenced.
|
||||
* SUBS is a number or string used as the subscript.
|
||||
*
|
||||
* Find SYMBOL[SUBS] in the assoc array. Install it with value "" if it
|
||||
* isn't there. Returns a pointer ala get_lhs to where its value is stored
|
||||
*/
|
||||
NODE **
|
||||
assoc_lookup(symbol, subs)
|
||||
NODE *symbol, *subs;
|
||||
{
|
||||
register int hash1;
|
||||
register NODE *bucket;
|
||||
|
||||
(void) force_string(subs);
|
||||
hash1 = hash(subs->stptr, subs->stlen);
|
||||
|
||||
if (symbol->var_array == 0) { /* this table really should grow
|
||||
* dynamically */
|
||||
unsigned size;
|
||||
|
||||
size = sizeof(NODE *) * HASHSIZE;
|
||||
emalloc(symbol->var_array, NODE **, size, "assoc_lookup");
|
||||
memset((char *)symbol->var_array, 0, size);
|
||||
symbol->type = Node_var_array;
|
||||
} else {
|
||||
bucket = assoc_find(symbol, subs, hash1);
|
||||
if (bucket != NULL) {
|
||||
free_temp(subs);
|
||||
return &(bucket->ahvalue);
|
||||
}
|
||||
}
|
||||
|
||||
/* It's not there, install it. */
|
||||
if (do_lint && subs->stlen == 0)
|
||||
warning("subscript of array `%s' is null string",
|
||||
symbol->vname);
|
||||
getnode(bucket);
|
||||
bucket->type = Node_ahash;
|
||||
if (subs->flags & TEMP)
|
||||
bucket->ahname = dupnode(subs);
|
||||
else {
|
||||
unsigned int saveflags = subs->flags;
|
||||
|
||||
subs->flags &= ~MALLOC;
|
||||
bucket->ahname = dupnode(subs);
|
||||
subs->flags = saveflags;
|
||||
}
|
||||
free_temp(subs);
|
||||
|
||||
/* array subscripts are strings */
|
||||
bucket->ahname->flags &= ~NUMBER;
|
||||
bucket->ahname->flags |= STRING;
|
||||
bucket->ahvalue = Nnull_string;
|
||||
bucket->ahnext = symbol->var_array[hash1];
|
||||
symbol->var_array[hash1] = bucket;
|
||||
return &(bucket->ahvalue);
|
||||
}
|
||||
|
||||
void
|
||||
do_delete(symbol, tree)
|
||||
NODE *symbol, *tree;
|
||||
{
|
||||
register int hash1;
|
||||
register NODE *bucket, *last;
|
||||
NODE *subs;
|
||||
|
||||
if (symbol->type == Node_param_list)
|
||||
symbol = stack_ptr[symbol->param_cnt];
|
||||
if (symbol->var_array == 0)
|
||||
return;
|
||||
subs = concat_exp(tree); /* concat_exp returns string node */
|
||||
hash1 = hash(subs->stptr, subs->stlen);
|
||||
|
||||
last = NULL;
|
||||
for (bucket = symbol->var_array[hash1]; bucket; last = bucket, bucket = bucket->ahnext)
|
||||
if (cmp_nodes(bucket->ahname, subs) == 0)
|
||||
break;
|
||||
free_temp(subs);
|
||||
if (bucket == NULL)
|
||||
return;
|
||||
if (last)
|
||||
last->ahnext = bucket->ahnext;
|
||||
else
|
||||
symbol->var_array[hash1] = bucket->ahnext;
|
||||
unref(bucket->ahname);
|
||||
unref(bucket->ahvalue);
|
||||
freenode(bucket);
|
||||
}
|
||||
|
||||
void
|
||||
assoc_scan(symbol, lookat)
|
||||
NODE *symbol;
|
||||
struct search *lookat;
|
||||
{
|
||||
if (!symbol->var_array) {
|
||||
lookat->retval = NULL;
|
||||
return;
|
||||
}
|
||||
lookat->arr_ptr = symbol->var_array;
|
||||
lookat->arr_end = lookat->arr_ptr + HASHSIZE; /* added */
|
||||
lookat->bucket = symbol->var_array[0];
|
||||
assoc_next(lookat);
|
||||
}
|
||||
|
||||
void
|
||||
assoc_next(lookat)
|
||||
struct search *lookat;
|
||||
{
|
||||
while (lookat->arr_ptr < lookat->arr_end) {
|
||||
if (lookat->bucket != 0) {
|
||||
lookat->retval = lookat->bucket->ahname;
|
||||
lookat->bucket = lookat->bucket->ahnext;
|
||||
return;
|
||||
}
|
||||
lookat->arr_ptr++;
|
||||
if (lookat->arr_ptr < lookat->arr_end)
|
||||
lookat->bucket = *(lookat->arr_ptr);
|
||||
else
|
||||
lookat->retval = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
1873
gnu/usr.bin/awk/awk.1
Normal file
1873
gnu/usr.bin/awk/awk.1
Normal file
File diff suppressed because it is too large
Load diff
763
gnu/usr.bin/awk/awk.h
Normal file
763
gnu/usr.bin/awk/awk.h
Normal file
|
|
@ -0,0 +1,763 @@
|
|||
/*
|
||||
* awk.h -- Definitions for gawk.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GAWK, the GNU implementation of the
|
||||
* AWK Progamming Language.
|
||||
*
|
||||
* GAWK 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.
|
||||
*
|
||||
* GAWK 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 GAWK; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/* ------------------------------ Includes ------------------------------ */
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
#include <setjmp.h>
|
||||
#include <varargs.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#if !defined(errno) && !defined(MSDOS)
|
||||
extern int errno;
|
||||
#endif
|
||||
#ifdef __GNU_LIBRARY__
|
||||
#ifndef linux
|
||||
#include <signum.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* ----------------- System dependencies (with more includes) -----------*/
|
||||
|
||||
#if !defined(VMS) || (!defined(VAXC) && !defined(__DECC))
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#else /* VMS w/ VAXC or DECC */
|
||||
#include <types.h>
|
||||
#include <stat.h>
|
||||
#include <file.h> /* avoid <fcntl.h> in io.c */
|
||||
#endif
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef __STDC__
|
||||
#define P(s) s
|
||||
#define MALLOC_ARG_T size_t
|
||||
#else
|
||||
#define P(s) ()
|
||||
#define MALLOC_ARG_T unsigned
|
||||
#define volatile
|
||||
#define const
|
||||
#endif
|
||||
|
||||
#ifndef SIGTYPE
|
||||
#define SIGTYPE void
|
||||
#endif
|
||||
|
||||
#ifdef SIZE_T_MISSING
|
||||
typedef unsigned int size_t;
|
||||
#endif
|
||||
|
||||
#ifndef SZTC
|
||||
#define SZTC
|
||||
#define INTC
|
||||
#endif
|
||||
|
||||
#ifdef STDC_HEADERS
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef NeXT
|
||||
#include <libc.h>
|
||||
#undef atof
|
||||
#else
|
||||
#if defined(atarist) || defined(VMS)
|
||||
#include <unixlib.h>
|
||||
#else /* atarist || VMS */
|
||||
#ifndef MSDOS
|
||||
#include <unistd.h>
|
||||
#endif /* MSDOS */
|
||||
#endif /* atarist || VMS */
|
||||
#endif /* Next */
|
||||
#else /* STDC_HEADERS */
|
||||
#include "protos.h"
|
||||
#endif /* STDC_HEADERS */
|
||||
|
||||
#if defined(ultrix) && !defined(Ultrix41)
|
||||
extern char * getenv P((char *name));
|
||||
extern double atof P((char *s));
|
||||
#endif
|
||||
|
||||
#ifndef __GNUC__
|
||||
#ifdef sparc
|
||||
/* nasty nasty SunOS-ism */
|
||||
#include <alloca.h>
|
||||
#ifdef lint
|
||||
extern char *alloca();
|
||||
#endif
|
||||
#else /* not sparc */
|
||||
#if !defined(alloca) && !defined(ALLOCA_PROTO)
|
||||
extern char *alloca();
|
||||
#endif
|
||||
#endif /* sparc */
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
#ifdef HAVE_UNDERSCORE_SETJMP
|
||||
/* nasty nasty berkelixm */
|
||||
#define setjmp _setjmp
|
||||
#define longjmp _longjmp
|
||||
#endif
|
||||
|
||||
/*
|
||||
* if you don't have vprintf, try this and cross your fingers.
|
||||
*/
|
||||
#if defined(VPRINTF_MISSING)
|
||||
#define vfprintf(fp,fmt,arg) _doprnt((fmt), (arg), (fp))
|
||||
#endif
|
||||
|
||||
#ifdef VMS
|
||||
/* some macros to redirect to code in vms/vms_misc.c */
|
||||
#define exit vms_exit
|
||||
#define open vms_open
|
||||
#define strerror vms_strerror
|
||||
#define strdup vms_strdup
|
||||
extern void exit P((int));
|
||||
extern int open P((const char *,int,...));
|
||||
extern char *strerror P((int));
|
||||
extern char *strdup P((const char *str));
|
||||
extern int vms_devopen P((const char *,int));
|
||||
# ifndef NO_TTY_FWRITE
|
||||
#define fwrite tty_fwrite
|
||||
#define fclose tty_fclose
|
||||
extern size_t fwrite P((const void *,size_t,size_t,FILE *));
|
||||
extern int fclose P((FILE *));
|
||||
# endif
|
||||
extern FILE *popen P((const char *,const char *));
|
||||
extern int pclose P((FILE *));
|
||||
extern void vms_arg_fixup P((int *,char ***));
|
||||
/* some things not in STDC_HEADERS */
|
||||
extern int gnu_strftime P((char *,size_t,const char *,const struct tm *));
|
||||
extern int unlink P((const char *));
|
||||
extern int getopt P((int,char **,char *));
|
||||
extern int isatty P((int));
|
||||
#ifndef fileno
|
||||
extern int fileno P((FILE *));
|
||||
#endif
|
||||
extern int close(), dup(), dup2(), fstat(), read(), stat();
|
||||
#endif /*VMS*/
|
||||
|
||||
#ifdef MSDOS
|
||||
#include <io.h>
|
||||
extern FILE *popen P((char *, char *));
|
||||
extern int pclose P((FILE *));
|
||||
#endif
|
||||
|
||||
#define GNU_REGEX
|
||||
#ifdef GNU_REGEX
|
||||
#include "regex.h"
|
||||
#include "dfa.h"
|
||||
typedef struct Regexp {
|
||||
struct re_pattern_buffer pat;
|
||||
struct re_registers regs;
|
||||
struct regexp dfareg;
|
||||
int dfa;
|
||||
} Regexp;
|
||||
#define RESTART(rp,s) (rp)->regs.start[0]
|
||||
#define REEND(rp,s) (rp)->regs.end[0]
|
||||
#else /* GNU_REGEX */
|
||||
#endif /* GNU_REGEX */
|
||||
|
||||
#ifdef atarist
|
||||
#define read _text_read /* we do not want all these CR's to mess our input */
|
||||
extern int _text_read (int, char *, int);
|
||||
#endif
|
||||
|
||||
#ifndef DEFPATH
|
||||
#define DEFPATH ".:/usr/local/lib/awk:/usr/lib/awk"
|
||||
#endif
|
||||
|
||||
#ifndef ENVSEP
|
||||
#define ENVSEP ':'
|
||||
#endif
|
||||
|
||||
/* ------------------ Constants, Structures, Typedefs ------------------ */
|
||||
#define AWKNUM double
|
||||
|
||||
typedef enum {
|
||||
/* illegal entry == 0 */
|
||||
Node_illegal,
|
||||
|
||||
/* binary operators lnode and rnode are the expressions to work on */
|
||||
Node_times,
|
||||
Node_quotient,
|
||||
Node_mod,
|
||||
Node_plus,
|
||||
Node_minus,
|
||||
Node_cond_pair, /* conditional pair (see Node_line_range) */
|
||||
Node_subscript,
|
||||
Node_concat,
|
||||
Node_exp,
|
||||
|
||||
/* unary operators subnode is the expression to work on */
|
||||
/*10*/ Node_preincrement,
|
||||
Node_predecrement,
|
||||
Node_postincrement,
|
||||
Node_postdecrement,
|
||||
Node_unary_minus,
|
||||
Node_field_spec,
|
||||
|
||||
/* assignments lnode is the var to assign to, rnode is the exp */
|
||||
Node_assign,
|
||||
Node_assign_times,
|
||||
Node_assign_quotient,
|
||||
Node_assign_mod,
|
||||
/*20*/ Node_assign_plus,
|
||||
Node_assign_minus,
|
||||
Node_assign_exp,
|
||||
|
||||
/* boolean binaries lnode and rnode are expressions */
|
||||
Node_and,
|
||||
Node_or,
|
||||
|
||||
/* binary relationals compares lnode and rnode */
|
||||
Node_equal,
|
||||
Node_notequal,
|
||||
Node_less,
|
||||
Node_greater,
|
||||
Node_leq,
|
||||
/*30*/ Node_geq,
|
||||
Node_match,
|
||||
Node_nomatch,
|
||||
|
||||
/* unary relationals works on subnode */
|
||||
Node_not,
|
||||
|
||||
/* program structures */
|
||||
Node_rule_list, /* lnode is a rule, rnode is rest of list */
|
||||
Node_rule_node, /* lnode is pattern, rnode is statement */
|
||||
Node_statement_list, /* lnode is statement, rnode is more list */
|
||||
Node_if_branches, /* lnode is to run on true, rnode on false */
|
||||
Node_expression_list, /* lnode is an exp, rnode is more list */
|
||||
Node_param_list, /* lnode is a variable, rnode is more list */
|
||||
|
||||
/* keywords */
|
||||
/*40*/ Node_K_if, /* lnode is conditonal, rnode is if_branches */
|
||||
Node_K_while, /* lnode is condtional, rnode is stuff to run */
|
||||
Node_K_for, /* lnode is for_struct, rnode is stuff to run */
|
||||
Node_K_arrayfor, /* lnode is for_struct, rnode is stuff to run */
|
||||
Node_K_break, /* no subs */
|
||||
Node_K_continue, /* no stuff */
|
||||
Node_K_print, /* lnode is exp_list, rnode is redirect */
|
||||
Node_K_printf, /* lnode is exp_list, rnode is redirect */
|
||||
Node_K_next, /* no subs */
|
||||
Node_K_exit, /* subnode is return value, or NULL */
|
||||
/*50*/ Node_K_do, /* lnode is conditional, rnode stuff to run */
|
||||
Node_K_return,
|
||||
Node_K_delete,
|
||||
Node_K_getline,
|
||||
Node_K_function, /* lnode is statement list, rnode is params */
|
||||
|
||||
/* I/O redirection for print statements */
|
||||
Node_redirect_output, /* subnode is where to redirect */
|
||||
Node_redirect_append, /* subnode is where to redirect */
|
||||
Node_redirect_pipe, /* subnode is where to redirect */
|
||||
Node_redirect_pipein, /* subnode is where to redirect */
|
||||
Node_redirect_input, /* subnode is where to redirect */
|
||||
|
||||
/* Variables */
|
||||
/*60*/ Node_var, /* rnode is value, lnode is array stuff */
|
||||
Node_var_array, /* array is ptr to elements, asize num of
|
||||
* eles */
|
||||
Node_val, /* node is a value - type in flags */
|
||||
|
||||
/* Builtins subnode is explist to work on, proc is func to call */
|
||||
Node_builtin,
|
||||
|
||||
/*
|
||||
* pattern: conditional ',' conditional ; lnode of Node_line_range
|
||||
* is the two conditionals (Node_cond_pair), other word (rnode place)
|
||||
* is a flag indicating whether or not this range has been entered.
|
||||
*/
|
||||
Node_line_range,
|
||||
|
||||
/*
|
||||
* boolean test of membership in array lnode is string-valued
|
||||
* expression rnode is array name
|
||||
*/
|
||||
Node_in_array,
|
||||
|
||||
Node_func, /* lnode is param. list, rnode is body */
|
||||
Node_func_call, /* lnode is name, rnode is argument list */
|
||||
|
||||
Node_cond_exp, /* lnode is conditonal, rnode is if_branches */
|
||||
Node_regex,
|
||||
/*70*/ Node_hashnode,
|
||||
Node_ahash,
|
||||
Node_NF,
|
||||
Node_NR,
|
||||
Node_FNR,
|
||||
Node_FS,
|
||||
Node_RS,
|
||||
Node_FIELDWIDTHS,
|
||||
Node_IGNORECASE,
|
||||
Node_OFS,
|
||||
Node_ORS,
|
||||
Node_OFMT,
|
||||
Node_CONVFMT,
|
||||
Node_K_nextfile
|
||||
} NODETYPE;
|
||||
|
||||
/*
|
||||
* NOTE - this struct is a rather kludgey -- it is packed to minimize
|
||||
* space usage, at the expense of cleanliness. Alter at own risk.
|
||||
*/
|
||||
typedef struct exp_node {
|
||||
union {
|
||||
struct {
|
||||
union {
|
||||
struct exp_node *lptr;
|
||||
char *param_name;
|
||||
} l;
|
||||
union {
|
||||
struct exp_node *rptr;
|
||||
struct exp_node *(*pptr) ();
|
||||
Regexp *preg;
|
||||
struct for_loop_header *hd;
|
||||
struct exp_node **av;
|
||||
int r_ent; /* range entered */
|
||||
} r;
|
||||
union {
|
||||
char *name;
|
||||
struct exp_node *extra;
|
||||
} x;
|
||||
short number;
|
||||
unsigned char reflags;
|
||||
# define CASE 1
|
||||
# define CONST 2
|
||||
# define FS_DFLT 4
|
||||
} nodep;
|
||||
struct {
|
||||
AWKNUM fltnum; /* this is here for optimal packing of
|
||||
* the structure on many machines
|
||||
*/
|
||||
char *sp;
|
||||
size_t slen;
|
||||
unsigned char sref;
|
||||
char idx;
|
||||
} val;
|
||||
struct {
|
||||
struct exp_node *next;
|
||||
char *name;
|
||||
int length;
|
||||
struct exp_node *value;
|
||||
} hash;
|
||||
#define hnext sub.hash.next
|
||||
#define hname sub.hash.name
|
||||
#define hlength sub.hash.length
|
||||
#define hvalue sub.hash.value
|
||||
struct {
|
||||
struct exp_node *next;
|
||||
struct exp_node *name;
|
||||
struct exp_node *value;
|
||||
} ahash;
|
||||
#define ahnext sub.ahash.next
|
||||
#define ahname sub.ahash.name
|
||||
#define ahvalue sub.ahash.value
|
||||
} sub;
|
||||
NODETYPE type;
|
||||
unsigned short flags;
|
||||
# define MALLOC 1 /* can be free'd */
|
||||
# define TEMP 2 /* should be free'd */
|
||||
# define PERM 4 /* can't be free'd */
|
||||
# define STRING 8 /* assigned as string */
|
||||
# define STR 16 /* string value is current */
|
||||
# define NUM 32 /* numeric value is current */
|
||||
# define NUMBER 64 /* assigned as number */
|
||||
# define MAYBE_NUM 128 /* user input: if NUMERIC then
|
||||
* a NUMBER
|
||||
*/
|
||||
char *vname; /* variable's name */
|
||||
} NODE;
|
||||
|
||||
#define lnode sub.nodep.l.lptr
|
||||
#define nextp sub.nodep.l.lptr
|
||||
#define rnode sub.nodep.r.rptr
|
||||
#define source_file sub.nodep.x.name
|
||||
#define source_line sub.nodep.number
|
||||
#define param_cnt sub.nodep.number
|
||||
#define param sub.nodep.l.param_name
|
||||
|
||||
#define subnode lnode
|
||||
#define proc sub.nodep.r.pptr
|
||||
|
||||
#define re_reg sub.nodep.r.preg
|
||||
#define re_flags sub.nodep.reflags
|
||||
#define re_text lnode
|
||||
#define re_exp sub.nodep.x.extra
|
||||
#define re_cnt sub.nodep.number
|
||||
|
||||
#define forsub lnode
|
||||
#define forloop rnode->sub.nodep.r.hd
|
||||
|
||||
#define stptr sub.val.sp
|
||||
#define stlen sub.val.slen
|
||||
#define stref sub.val.sref
|
||||
#define stfmt sub.val.idx
|
||||
|
||||
#define numbr sub.val.fltnum
|
||||
|
||||
#define var_value lnode
|
||||
#define var_array sub.nodep.r.av
|
||||
|
||||
#define condpair lnode
|
||||
#define triggered sub.nodep.r.r_ent
|
||||
|
||||
#ifdef DONTDEF
|
||||
int primes[] = {31, 61, 127, 257, 509, 1021, 2053, 4099, 8191, 16381};
|
||||
#endif
|
||||
/* a quick profile suggests that the following is a good value */
|
||||
#define HASHSIZE 127
|
||||
|
||||
typedef struct for_loop_header {
|
||||
NODE *init;
|
||||
NODE *cond;
|
||||
NODE *incr;
|
||||
} FOR_LOOP_HEADER;
|
||||
|
||||
/* for "for(iggy in foo) {" */
|
||||
struct search {
|
||||
NODE **arr_ptr;
|
||||
NODE **arr_end;
|
||||
NODE *bucket;
|
||||
NODE *retval;
|
||||
};
|
||||
|
||||
/* for faster input, bypass stdio */
|
||||
typedef struct iobuf {
|
||||
int fd;
|
||||
char *buf;
|
||||
char *off;
|
||||
char *end;
|
||||
size_t size; /* this will be determined by an fstat() call */
|
||||
int cnt;
|
||||
long secsiz;
|
||||
int flag;
|
||||
# define IOP_IS_TTY 1
|
||||
# define IOP_IS_INTERNAL 2
|
||||
# define IOP_NO_FREE 4
|
||||
} IOBUF;
|
||||
|
||||
typedef void (*Func_ptr)();
|
||||
|
||||
/*
|
||||
* structure used to dynamically maintain a linked-list of open files/pipes
|
||||
*/
|
||||
struct redirect {
|
||||
unsigned int flag;
|
||||
# define RED_FILE 1
|
||||
# define RED_PIPE 2
|
||||
# define RED_READ 4
|
||||
# define RED_WRITE 8
|
||||
# define RED_APPEND 16
|
||||
# define RED_NOBUF 32
|
||||
# define RED_USED 64
|
||||
# define RED_EOF 128
|
||||
char *value;
|
||||
FILE *fp;
|
||||
IOBUF *iop;
|
||||
int pid;
|
||||
int status;
|
||||
struct redirect *prev;
|
||||
struct redirect *next;
|
||||
};
|
||||
|
||||
/* structure for our source, either a command line string or a source file */
|
||||
struct src {
|
||||
enum srctype { CMDLINE = 1, SOURCEFILE } stype;
|
||||
char *val;
|
||||
};
|
||||
|
||||
/* longjmp return codes, must be nonzero */
|
||||
/* Continue means either for loop/while continue, or next input record */
|
||||
#define TAG_CONTINUE 1
|
||||
/* Break means either for/while break, or stop reading input */
|
||||
#define TAG_BREAK 2
|
||||
/* Return means return from a function call; leave value in ret_node */
|
||||
#define TAG_RETURN 3
|
||||
|
||||
#define HUGE INT_MAX
|
||||
|
||||
/* -------------------------- External variables -------------------------- */
|
||||
/* gawk builtin variables */
|
||||
extern int NF;
|
||||
extern int NR;
|
||||
extern int FNR;
|
||||
extern int IGNORECASE;
|
||||
extern char *RS;
|
||||
extern char *OFS;
|
||||
extern int OFSlen;
|
||||
extern char *ORS;
|
||||
extern int ORSlen;
|
||||
extern char *OFMT;
|
||||
extern char *CONVFMT;
|
||||
extern int CONVFMTidx;
|
||||
extern int OFMTidx;
|
||||
extern NODE *FS_node, *NF_node, *RS_node, *NR_node;
|
||||
extern NODE *FILENAME_node, *OFS_node, *ORS_node, *OFMT_node;
|
||||
extern NODE *CONVFMT_node;
|
||||
extern NODE *FNR_node, *RLENGTH_node, *RSTART_node, *SUBSEP_node;
|
||||
extern NODE *IGNORECASE_node;
|
||||
extern NODE *FIELDWIDTHS_node;
|
||||
|
||||
extern NODE **stack_ptr;
|
||||
extern NODE *Nnull_string;
|
||||
extern NODE **fields_arr;
|
||||
extern int sourceline;
|
||||
extern char *source;
|
||||
extern NODE *expression_value;
|
||||
|
||||
extern NODE *_t; /* used as temporary in tree_eval */
|
||||
|
||||
extern const char *myname;
|
||||
|
||||
extern NODE *nextfree;
|
||||
extern int field0_valid;
|
||||
extern int do_unix;
|
||||
extern int do_posix;
|
||||
extern int do_lint;
|
||||
extern int in_begin_rule;
|
||||
extern int in_end_rule;
|
||||
|
||||
/* ------------------------- Pseudo-functions ------------------------- */
|
||||
|
||||
#define is_identchar(c) (isalnum(c) || (c) == '_')
|
||||
|
||||
|
||||
#ifndef MPROF
|
||||
#define getnode(n) if (nextfree) n = nextfree, nextfree = nextfree->nextp;\
|
||||
else n = more_nodes()
|
||||
#define freenode(n) ((n)->nextp = nextfree, nextfree = (n))
|
||||
#else
|
||||
#define getnode(n) emalloc(n, NODE *, sizeof(NODE), "getnode")
|
||||
#define freenode(n) free(n)
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#define tree_eval(t) r_tree_eval(t)
|
||||
#else
|
||||
#define tree_eval(t) (_t = (t),(_t) == NULL ? Nnull_string : \
|
||||
((_t)->type == Node_val ? (_t) : \
|
||||
((_t)->type == Node_var ? (_t)->var_value : \
|
||||
((_t)->type == Node_param_list ? \
|
||||
(stack_ptr[(_t)->param_cnt])->var_value : \
|
||||
r_tree_eval((_t))))))
|
||||
#endif
|
||||
|
||||
#define make_number(x) mk_number((x), (MALLOC|NUM|NUMBER))
|
||||
#define tmp_number(x) mk_number((x), (MALLOC|TEMP|NUM|NUMBER))
|
||||
|
||||
#define free_temp(n) do {if ((n)->flags&TEMP) { unref(n); }} while (0)
|
||||
#define make_string(s,l) make_str_node((s), SZTC (l),0)
|
||||
#define SCAN 1
|
||||
#define ALREADY_MALLOCED 2
|
||||
|
||||
#define cant_happen() fatal("internal error line %d, file: %s", \
|
||||
__LINE__, __FILE__);
|
||||
|
||||
#if defined(__STDC__) && !defined(NO_TOKEN_PASTING)
|
||||
#define emalloc(var,ty,x,str) (void)((var=(ty)malloc((MALLOC_ARG_T)(x))) ||\
|
||||
(fatal("%s: %s: can't allocate memory (%s)",\
|
||||
(str), #var, strerror(errno)),0))
|
||||
#define erealloc(var,ty,x,str) (void)((var=(ty)realloc((char *)var,\
|
||||
(MALLOC_ARG_T)(x))) ||\
|
||||
(fatal("%s: %s: can't allocate memory (%s)",\
|
||||
(str), #var, strerror(errno)),0))
|
||||
#else /* __STDC__ */
|
||||
#define emalloc(var,ty,x,str) (void)((var=(ty)malloc((MALLOC_ARG_T)(x))) ||\
|
||||
(fatal("%s: %s: can't allocate memory (%s)",\
|
||||
(str), "var", strerror(errno)),0))
|
||||
#define erealloc(var,ty,x,str) (void)((var=(ty)realloc((char *)var,\
|
||||
(MALLOC_ARG_T)(x))) ||\
|
||||
(fatal("%s: %s: can't allocate memory (%s)",\
|
||||
(str), "var", strerror(errno)),0))
|
||||
#endif /* __STDC__ */
|
||||
|
||||
#ifdef DEBUG
|
||||
#define force_number r_force_number
|
||||
#define force_string r_force_string
|
||||
#else /* not DEBUG */
|
||||
#ifdef lint
|
||||
extern AWKNUM force_number();
|
||||
#endif
|
||||
#ifdef MSDOS
|
||||
extern double _msc51bug;
|
||||
#define force_number(n) (_msc51bug=(_t = (n),(_t->flags & NUM) ? _t->numbr : r_force_number(_t)))
|
||||
#else /* not MSDOS */
|
||||
#define force_number(n) (_t = (n),(_t->flags & NUM) ? _t->numbr : r_force_number(_t))
|
||||
#endif /* MSDOS */
|
||||
#define force_string(s) (_t = (s),(_t->flags & STR) ? _t : r_force_string(_t))
|
||||
#endif /* not DEBUG */
|
||||
|
||||
#define STREQ(a,b) (*(a) == *(b) && strcmp((a), (b)) == 0)
|
||||
#define STREQN(a,b,n) ((n)&& *(a)== *(b) && strncmp((a), (b), SZTC (n)) == 0)
|
||||
|
||||
/* ------------- Function prototypes or defs (as appropriate) ------------- */
|
||||
|
||||
/* array.c */
|
||||
extern NODE *concat_exp P((NODE *tree));
|
||||
extern void assoc_clear P((NODE *symbol));
|
||||
extern unsigned int hash P((char *s, int len));
|
||||
extern int in_array P((NODE *symbol, NODE *subs));
|
||||
extern NODE **assoc_lookup P((NODE *symbol, NODE *subs));
|
||||
extern void do_delete P((NODE *symbol, NODE *tree));
|
||||
extern void assoc_scan P((NODE *symbol, struct search *lookat));
|
||||
extern void assoc_next P((struct search *lookat));
|
||||
/* awk.tab.c */
|
||||
extern char *tokexpand P((void));
|
||||
extern char nextc P((void));
|
||||
extern NODE *node P((NODE *left, NODETYPE op, NODE *right));
|
||||
extern NODE *install P((char *name, NODE *value));
|
||||
extern NODE *lookup P((char *name));
|
||||
extern NODE *variable P((char *name, int can_free));
|
||||
extern int yyparse P((void));
|
||||
/* builtin.c */
|
||||
extern NODE *do_exp P((NODE *tree));
|
||||
extern NODE *do_index P((NODE *tree));
|
||||
extern NODE *do_int P((NODE *tree));
|
||||
extern NODE *do_length P((NODE *tree));
|
||||
extern NODE *do_log P((NODE *tree));
|
||||
extern NODE *do_sprintf P((NODE *tree));
|
||||
extern void do_printf P((NODE *tree));
|
||||
extern void print_simple P((NODE *tree, FILE *fp));
|
||||
extern NODE *do_sqrt P((NODE *tree));
|
||||
extern NODE *do_substr P((NODE *tree));
|
||||
extern NODE *do_strftime P((NODE *tree));
|
||||
extern NODE *do_systime P((NODE *tree));
|
||||
extern NODE *do_system P((NODE *tree));
|
||||
extern void do_print P((NODE *tree));
|
||||
extern NODE *do_tolower P((NODE *tree));
|
||||
extern NODE *do_toupper P((NODE *tree));
|
||||
extern NODE *do_atan2 P((NODE *tree));
|
||||
extern NODE *do_sin P((NODE *tree));
|
||||
extern NODE *do_cos P((NODE *tree));
|
||||
extern NODE *do_rand P((NODE *tree));
|
||||
extern NODE *do_srand P((NODE *tree));
|
||||
extern NODE *do_match P((NODE *tree));
|
||||
extern NODE *do_gsub P((NODE *tree));
|
||||
extern NODE *do_sub P((NODE *tree));
|
||||
/* eval.c */
|
||||
extern int interpret P((NODE *volatile tree));
|
||||
extern NODE *r_tree_eval P((NODE *tree));
|
||||
extern int cmp_nodes P((NODE *t1, NODE *t2));
|
||||
extern NODE **get_lhs P((NODE *ptr, Func_ptr *assign));
|
||||
extern void set_IGNORECASE P((void));
|
||||
void set_OFS P((void));
|
||||
void set_ORS P((void));
|
||||
void set_OFMT P((void));
|
||||
void set_CONVFMT P((void));
|
||||
/* field.c */
|
||||
extern void init_fields P((void));
|
||||
extern void set_record P((char *buf, int cnt, int freeold));
|
||||
extern void reset_record P((void));
|
||||
extern void set_NF P((void));
|
||||
extern NODE **get_field P((int num, Func_ptr *assign));
|
||||
extern NODE *do_split P((NODE *tree));
|
||||
extern void set_FS P((void));
|
||||
extern void set_RS P((void));
|
||||
extern void set_FIELDWIDTHS P((void));
|
||||
/* io.c */
|
||||
extern void set_FNR P((void));
|
||||
extern void set_NR P((void));
|
||||
extern void do_input P((void));
|
||||
extern struct redirect *redirect P((NODE *tree, int *errflg));
|
||||
extern NODE *do_close P((NODE *tree));
|
||||
extern int flush_io P((void));
|
||||
extern int close_io P((void));
|
||||
extern int devopen P((char *name, char *mode));
|
||||
extern int pathopen P((char *file));
|
||||
extern NODE *do_getline P((NODE *tree));
|
||||
extern void do_nextfile P((void));
|
||||
/* iop.c */
|
||||
extern int optimal_bufsize P((int fd));
|
||||
extern IOBUF *iop_alloc P((int fd));
|
||||
extern int get_a_record P((char **out, IOBUF *iop, int rs, int *errcode));
|
||||
/* main.c */
|
||||
extern int main P((int argc, char **argv));
|
||||
extern Regexp *mk_re_parse P((char *s, int ignorecase));
|
||||
extern void load_environ P((void));
|
||||
extern char *arg_assign P((char *arg));
|
||||
extern SIGTYPE catchsig P((int sig, int code));
|
||||
/* msg.c */
|
||||
#ifdef MSDOS
|
||||
extern void err P((char *s, char *emsg, char *va_list, ...));
|
||||
extern void msg P((char *va_alist, ...));
|
||||
extern void warning P((char *va_alist, ...));
|
||||
extern void fatal P((char *va_alist, ...));
|
||||
#else
|
||||
extern void err ();
|
||||
extern void msg ();
|
||||
extern void warning ();
|
||||
extern void fatal ();
|
||||
#endif
|
||||
/* node.c */
|
||||
extern AWKNUM r_force_number P((NODE *n));
|
||||
extern NODE *r_force_string P((NODE *s));
|
||||
extern NODE *dupnode P((NODE *n));
|
||||
extern NODE *mk_number P((AWKNUM x, unsigned int flags));
|
||||
extern NODE *make_str_node P((char *s, size_t len, int scan ));
|
||||
extern NODE *tmp_string P((char *s, size_t len ));
|
||||
extern NODE *more_nodes P((void));
|
||||
#ifdef DEBUG
|
||||
extern void freenode P((NODE *it));
|
||||
#endif
|
||||
extern void unref P((NODE *tmp));
|
||||
extern int parse_escape P((char **string_ptr));
|
||||
/* re.c */
|
||||
extern Regexp *make_regexp P((char *s, int len, int ignorecase, int dfa));
|
||||
extern int research P((Regexp *rp, char *str, int start, int len, int need_start));
|
||||
extern void refree P((Regexp *rp));
|
||||
extern void reg_error P((const char *s));
|
||||
extern Regexp *re_update P((NODE *t));
|
||||
extern void resyntax P((int syntax));
|
||||
extern void resetup P((void));
|
||||
|
||||
/* strcase.c */
|
||||
extern int strcasecmp P((const char *s1, const char *s2));
|
||||
extern int strncasecmp P((const char *s1, const char *s2, register size_t n));
|
||||
|
||||
#ifdef atarist
|
||||
/* atari/tmpnam.c */
|
||||
extern char *tmpnam P((char *buf));
|
||||
extern char *tempnam P((const char *path, const char *base));
|
||||
#endif
|
||||
|
||||
/* Figure out what '\a' really is. */
|
||||
#ifdef __STDC__
|
||||
#define BELL '\a' /* sure makes life easy, don't it? */
|
||||
#else
|
||||
# if 'z' - 'a' == 25 /* ascii */
|
||||
# if 'a' != 97 /* machine is dumb enough to use mark parity */
|
||||
# define BELL '\207'
|
||||
# else
|
||||
# define BELL '\07'
|
||||
# endif
|
||||
# else
|
||||
# define BELL '\057'
|
||||
# endif
|
||||
#endif
|
||||
|
||||
extern char casetable[]; /* for case-independent regexp matching */
|
||||
1804
gnu/usr.bin/awk/awk.y
Normal file
1804
gnu/usr.bin/awk/awk.y
Normal file
File diff suppressed because it is too large
Load diff
1133
gnu/usr.bin/awk/builtin.c
Normal file
1133
gnu/usr.bin/awk/builtin.c
Normal file
File diff suppressed because it is too large
Load diff
272
gnu/usr.bin/awk/config.h
Normal file
272
gnu/usr.bin/awk/config.h
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
* config.h -- configuration definitions for gawk.
|
||||
*
|
||||
* For generic 4.4 alpha
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1991, 1992 the Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GAWK, the GNU implementation of the
|
||||
* AWK Progamming Language.
|
||||
*
|
||||
* GAWK 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.
|
||||
*
|
||||
* GAWK 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 GAWK; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file isolates configuration dependencies for gnu awk.
|
||||
* You should know something about your system, perhaps by having
|
||||
* a manual handy, when you edit this file. You should copy config.h-dist
|
||||
* to config.h, and edit config.h. Do not modify config.h-dist, so that
|
||||
* it will be easy to apply any patches that may be distributed.
|
||||
*
|
||||
* The general idea is that systems conforming to the various standards
|
||||
* should need to do the least amount of changing. Definining the various
|
||||
* items in ths file usually means that your system is missing that
|
||||
* particular feature.
|
||||
*
|
||||
* The order of preference in standard conformance is ANSI C, POSIX,
|
||||
* and the SVID.
|
||||
*
|
||||
* If you have no clue as to what's going on with your system, try
|
||||
* compiling gawk without editing this file and see what shows up
|
||||
* missing in the link stage. From there, you can probably figure out
|
||||
* which defines to turn on.
|
||||
*/
|
||||
|
||||
/**************************/
|
||||
/* Miscellanious features */
|
||||
/**************************/
|
||||
|
||||
/*
|
||||
* BLKSIZE_MISSING
|
||||
*
|
||||
* Check your /usr/include/sys/stat.h file. If the stat structure
|
||||
* does not have a member named st_blksize, define this. (This will
|
||||
* most likely be the case on most System V systems prior to V.4.)
|
||||
*/
|
||||
/* #define BLKSIZE_MISSING 1 */
|
||||
|
||||
/*
|
||||
* SIGTYPE
|
||||
*
|
||||
* The return type of the routines passed to the signal function.
|
||||
* Modern systems use `void', older systems use `int'.
|
||||
* If left undefined, it will default to void.
|
||||
*/
|
||||
/* #define SIGTYPE int */
|
||||
|
||||
/*
|
||||
* SIZE_T_MISSING
|
||||
*
|
||||
* If your system has no typedef for size_t, define this to get a default
|
||||
*/
|
||||
/* #define SIZE_T_MISSING 1 */
|
||||
|
||||
/*
|
||||
* CHAR_UNSIGNED
|
||||
*
|
||||
* If your machine uses unsigned characters (IBM RT and RS/6000 and others)
|
||||
* then define this for use in regex.c
|
||||
*/
|
||||
/* #define CHAR_UNSIGNED 1 */
|
||||
|
||||
/*
|
||||
* HAVE_UNDERSCORE_SETJMP
|
||||
*
|
||||
* Check in your /usr/include/setjmp.h file. If there are routines
|
||||
* there named _setjmp and _longjmp, then you should define this.
|
||||
* Typically only systems derived from Berkeley Unix have this.
|
||||
*/
|
||||
#define HAVE_UNDERSCORE_SETJMP 1
|
||||
|
||||
/***********************************************/
|
||||
/* Missing library subroutines or system calls */
|
||||
/***********************************************/
|
||||
|
||||
/*
|
||||
* MEMCMP_MISSING
|
||||
* MEMCPY_MISSING
|
||||
* MEMSET_MISSING
|
||||
*
|
||||
* These three routines are for manipulating blocks of memory. Most
|
||||
* likely they will either all three be present or all three be missing,
|
||||
* so they're grouped together.
|
||||
*/
|
||||
/* #define MEMCMP_MISSING 1 */
|
||||
/* #define MEMCPY_MISSING 1 */
|
||||
/* #define MEMSET_MISSING 1 */
|
||||
|
||||
/*
|
||||
* RANDOM_MISSING
|
||||
*
|
||||
* Your system does not have the random(3) suite of random number
|
||||
* generating routines. These are different than the old rand(3)
|
||||
* routines!
|
||||
*/
|
||||
/* #define RANDOM_MISSING 1 */
|
||||
|
||||
/*
|
||||
* STRCASE_MISSING
|
||||
*
|
||||
* Your system does not have the strcasemp() and strncasecmp()
|
||||
* routines that originated in Berkeley Unix.
|
||||
*/
|
||||
/* #define STRCASE_MISSING 1 */
|
||||
|
||||
/*
|
||||
* STRCHR_MISSING
|
||||
*
|
||||
* Your system does not have the strchr() and strrchr() functions.
|
||||
*/
|
||||
/* #define STRCHR_MISSING 1 */
|
||||
|
||||
/*
|
||||
* STRERROR_MISSING
|
||||
*
|
||||
* Your system lacks the ANSI C strerror() routine for returning the
|
||||
* strings associated with errno values.
|
||||
*/
|
||||
/* #define STRERROR_MISSING 1 */
|
||||
|
||||
/*
|
||||
* STRTOD_MISSING
|
||||
*
|
||||
* Your system does not have the strtod() routine for converting
|
||||
* strings to double precision floating point values.
|
||||
*/
|
||||
/* #define STRTOD_MISSING 1 */
|
||||
|
||||
/*
|
||||
* STRFTIME_MISSING
|
||||
*
|
||||
* Your system lacks the ANSI C strftime() routine for formatting
|
||||
* broken down time values.
|
||||
*/
|
||||
/* #define STRFTIME_MISSING 1 */
|
||||
|
||||
/*
|
||||
* TZSET_MISSING
|
||||
*
|
||||
* If you have a 4.2 BSD vintage system, then the strftime() routine
|
||||
* supplied in the missing directory won't be enough, because it relies on the
|
||||
* tzset() routine from System V / Posix. Fortunately, there is an
|
||||
* emulation for tzset() too that should do the trick. If you don't
|
||||
* have tzset(), define this.
|
||||
*/
|
||||
/* #define TZSET_MISSING 1 */
|
||||
|
||||
/*
|
||||
* TZNAME_MISSING
|
||||
*
|
||||
* Some systems do not support the external variables tzname and daylight.
|
||||
* If this is the case *and* strftime() is missing, define this.
|
||||
*/
|
||||
/* #define TZNAME_MISSING 1 */
|
||||
|
||||
/*
|
||||
* STDC_HEADERS
|
||||
*
|
||||
* If your system does have ANSI compliant header files that
|
||||
* provide prototypes for library routines, then define this.
|
||||
*/
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/*
|
||||
* NO_TOKEN_PASTING
|
||||
*
|
||||
* If your compiler define's __STDC__ but does not support token
|
||||
* pasting (tok##tok), then define this.
|
||||
*/
|
||||
/* #define NO_TOKEN_PASTING 1 */
|
||||
|
||||
/*****************************************************************/
|
||||
/* Stuff related to the Standard I/O Library. */
|
||||
/*****************************************************************/
|
||||
/* Much of this is (still, unfortunately) black magic in nature. */
|
||||
/* You may have to use some or all of these together to get gawk */
|
||||
/* to work correctly. */
|
||||
/*****************************************************************/
|
||||
|
||||
/*
|
||||
* NON_STD_SPRINTF
|
||||
*
|
||||
* Look in your /usr/include/stdio.h file. If the return type of the
|
||||
* sprintf() function is NOT `int', define this.
|
||||
*/
|
||||
/* #define NON_STD_SPRINTF 1 */
|
||||
|
||||
/*
|
||||
* VPRINTF_MISSING
|
||||
*
|
||||
* Define this if your system lacks vprintf() and the other routines
|
||||
* that go with it. This will trigger an attempt to use _doprnt().
|
||||
* If you don't have that, this attempt will fail and you are on your own.
|
||||
*/
|
||||
/* #define VPRINTF_MISSING 1 */
|
||||
|
||||
/*
|
||||
* Casts from size_t to int and back. These will become unnecessary
|
||||
* at some point in the future, but for now are required where the
|
||||
* two types are a different representation.
|
||||
*/
|
||||
/* #define SZTC */
|
||||
/* #define INTC */
|
||||
|
||||
/*
|
||||
* SYSTEM_MISSING
|
||||
*
|
||||
* Define this if your library does not provide a system function
|
||||
* or you are not entirely happy with it and would rather use
|
||||
* a provided replacement (atari only).
|
||||
*/
|
||||
/* #define SYSTEM_MISSING 1 */
|
||||
|
||||
/*
|
||||
* FMOD_MISSING
|
||||
*
|
||||
* Define this if your system lacks the fmod() function and modf() will
|
||||
* be used instead.
|
||||
*/
|
||||
/* #define FMOD_MISSING 1 */
|
||||
|
||||
|
||||
/*******************************/
|
||||
/* Gawk configuration options. */
|
||||
/*******************************/
|
||||
|
||||
/*
|
||||
* DEFPATH
|
||||
*
|
||||
* The default search path for the -f option of gawk. It is used
|
||||
* if the AWKPATH environment variable is undefined. The default
|
||||
* definition is provided here. Most likely you should not change
|
||||
* this.
|
||||
*/
|
||||
|
||||
/* #define DEFPATH ".:/usr/lib/awk:/usr/local/lib/awk" */
|
||||
/* #define ENVSEP ':' */
|
||||
|
||||
/*
|
||||
* alloca already has a prototype defined - don't redefine it
|
||||
*/
|
||||
#define ALLOCA_PROTO 1
|
||||
|
||||
/*
|
||||
* srandom already has a prototype defined - don't redefine it
|
||||
*/
|
||||
#define SRANDOM_PROTO 1
|
||||
|
||||
/* anything that follows is for system-specific short-term kludges */
|
||||
2291
gnu/usr.bin/awk/dfa.c
Normal file
2291
gnu/usr.bin/awk/dfa.c
Normal file
File diff suppressed because it is too large
Load diff
543
gnu/usr.bin/awk/dfa.h
Normal file
543
gnu/usr.bin/awk/dfa.h
Normal file
|
|
@ -0,0 +1,543 @@
|
|||
/* dfa.h - declarations for GNU deterministic regexp compiler
|
||||
Copyright (C) 1988 Free Software Foundation, Inc.
|
||||
Written June, 1988 by Mike Haertel
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
|
||||
NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
|
||||
WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
|
||||
RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS 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.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
|
||||
STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
|
||||
WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
|
||||
LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
|
||||
OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
|
||||
DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
|
||||
A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
|
||||
PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
|
||||
|
||||
GENERAL PUBLIC LICENSE TO COPY
|
||||
|
||||
1. You may copy and distribute verbatim copies of this source file
|
||||
as you receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy a valid copyright notice "Copyright
|
||||
(C) 1988 Free Software Foundation, Inc."; and include following the
|
||||
copyright notice a verbatim copy of the above disclaimer of warranty
|
||||
and of this License. You may charge a distribution fee for the
|
||||
physical act of transferring a copy.
|
||||
|
||||
2. You may modify your copy or copies of this source file or
|
||||
any portion of it, and copy and distribute such modifications under
|
||||
the terms of Paragraph 1 above, provided that you also do the following:
|
||||
|
||||
a) cause the modified files to carry prominent notices stating
|
||||
that you changed the files and the date of any change; and
|
||||
|
||||
b) cause the whole of any work that you distribute or publish,
|
||||
that in whole or in part contains or is a derivative of this
|
||||
program or any part thereof, to be licensed at no charge to all
|
||||
third parties on terms identical to those contained in this
|
||||
License Agreement (except that you may choose to grant more extensive
|
||||
warranty protection to some or all third parties, at your option).
|
||||
|
||||
c) You may charge a distribution fee for the physical act of
|
||||
transferring a copy, and you may at your option offer warranty
|
||||
protection in exchange for a fee.
|
||||
|
||||
Mere aggregation of another unrelated program with this program (or its
|
||||
derivative) on a volume of a storage or distribution medium does not bring
|
||||
the other program under the scope of these terms.
|
||||
|
||||
3. You may copy and distribute this program or any portion of it in
|
||||
compiled, executable or object code form under the terms of Paragraphs
|
||||
1 and 2 above provided that you do the following:
|
||||
|
||||
a) accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of
|
||||
Paragraphs 1 and 2 above; or,
|
||||
|
||||
b) accompany it with a written offer, valid for at least three
|
||||
years, to give any third party free (except for a nominal
|
||||
shipping charge) a complete machine-readable copy of the
|
||||
corresponding source code, to be distributed under the terms of
|
||||
Paragraphs 1 and 2 above; or,
|
||||
|
||||
c) accompany it with the information you received as to where the
|
||||
corresponding source code may be obtained. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form alone.)
|
||||
|
||||
For an executable file, complete source code means all the source code for
|
||||
all modules it contains; but, as a special exception, it need not include
|
||||
source code for modules which are standard libraries that accompany the
|
||||
operating system on which the executable file runs.
|
||||
|
||||
4. You may not copy, sublicense, distribute or transfer this program
|
||||
except as expressly provided under this License Agreement. Any attempt
|
||||
otherwise to copy, sublicense, distribute or transfer this program is void and
|
||||
your rights to use the program under this License agreement shall be
|
||||
automatically terminated. However, parties who have received computer
|
||||
software programs from you with this License Agreement will not have
|
||||
their licenses terminated so long as such parties remain in full compliance.
|
||||
|
||||
5. If you wish to incorporate parts of this program into other free
|
||||
programs whose distribution conditions are different, write to the Free
|
||||
Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet
|
||||
worked out a simple rule that can be stated here, but we will often permit
|
||||
this. We will be guided by the two goals of preserving the free status of
|
||||
all derivatives our free software and of promoting the sharing and reuse of
|
||||
software.
|
||||
|
||||
|
||||
In other words, you are welcome to use, share and improve this program.
|
||||
You are forbidden to forbid anyone else to use, share and improve
|
||||
what you give them. Help stamp out software-hoarding! */
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
#ifdef SOMEDAY
|
||||
#define ISALNUM(c) isalnum(c)
|
||||
#define ISALPHA(c) isalpha(c)
|
||||
#define ISUPPER(c) isupper(c)
|
||||
#else
|
||||
#define ISALNUM(c) (isascii(c) && isalnum(c))
|
||||
#define ISALPHA(c) (isascii(c) && isalpha(c))
|
||||
#define ISUPPER(c) (isascii(c) && isupper(c))
|
||||
#endif
|
||||
|
||||
#else /* ! __STDC__ */
|
||||
|
||||
#define const
|
||||
|
||||
#define ISALNUM(c) (isascii(c) && isalnum(c))
|
||||
#define ISALPHA(c) (isascii(c) && isalpha(c))
|
||||
#define ISUPPER(c) (isascii(c) && isupper(c))
|
||||
|
||||
#endif /* ! __STDC__ */
|
||||
|
||||
/* 1 means plain parentheses serve as grouping, and backslash
|
||||
parentheses are needed for literal searching.
|
||||
0 means backslash-parentheses are grouping, and plain parentheses
|
||||
are for literal searching. */
|
||||
#define RE_NO_BK_PARENS 1L
|
||||
|
||||
/* 1 means plain | serves as the "or"-operator, and \| is a literal.
|
||||
0 means \| serves as the "or"-operator, and | is a literal. */
|
||||
#define RE_NO_BK_VBAR (1L << 1)
|
||||
|
||||
/* 0 means plain + or ? serves as an operator, and \+, \? are literals.
|
||||
1 means \+, \? are operators and plain +, ? are literals. */
|
||||
#define RE_BK_PLUS_QM (1L << 2)
|
||||
|
||||
/* 1 means | binds tighter than ^ or $.
|
||||
0 means the contrary. */
|
||||
#define RE_TIGHT_VBAR (1L << 3)
|
||||
|
||||
/* 1 means treat \n as an _OR operator
|
||||
0 means treat it as a normal character */
|
||||
#define RE_NEWLINE_OR (1L << 4)
|
||||
|
||||
/* 0 means that a special characters (such as *, ^, and $) always have
|
||||
their special meaning regardless of the surrounding context.
|
||||
1 means that special characters may act as normal characters in some
|
||||
contexts. Specifically, this applies to:
|
||||
^ - only special at the beginning, or after ( or |
|
||||
$ - only special at the end, or before ) or |
|
||||
*, +, ? - only special when not after the beginning, (, or | */
|
||||
#define RE_CONTEXT_INDEP_OPS (1L << 5)
|
||||
|
||||
/* 1 means that \ in a character class escapes the next character (typically
|
||||
a hyphen. It also is overloaded to mean that hyphen at the end of the range
|
||||
is allowable and means that the hyphen is to be taken literally. */
|
||||
#define RE_AWK_CLASS_HACK (1L << 6)
|
||||
|
||||
/* Now define combinations of bits for the standard possibilities. */
|
||||
#ifdef notdef
|
||||
#define RE_SYNTAX_AWK (RE_NO_BK_PARENS | RE_NO_BK_VBAR | RE_CONTEXT_INDEP_OPS)
|
||||
#define RE_SYNTAX_EGREP (RE_SYNTAX_AWK | RE_NEWLINE_OR)
|
||||
#define RE_SYNTAX_GREP (RE_BK_PLUS_QM | RE_NEWLINE_OR)
|
||||
#define RE_SYNTAX_EMACS 0
|
||||
#endif
|
||||
|
||||
/* The NULL pointer. */
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
/* Number of bits in an unsigned char. */
|
||||
#ifndef CHARBITS
|
||||
#define CHARBITS 8
|
||||
#endif
|
||||
|
||||
/* First integer value that is greater than any character code. */
|
||||
#define _NOTCHAR (1 << CHARBITS)
|
||||
|
||||
/* INTBITS need not be exact, just a lower bound. */
|
||||
#ifndef INTBITS
|
||||
#define INTBITS (CHARBITS * sizeof (int))
|
||||
#endif
|
||||
|
||||
/* Number of ints required to hold a bit for every character. */
|
||||
#define _CHARSET_INTS ((_NOTCHAR + INTBITS - 1) / INTBITS)
|
||||
|
||||
/* Sets of unsigned characters are stored as bit vectors in arrays of ints. */
|
||||
typedef int _charset[_CHARSET_INTS];
|
||||
|
||||
/* The regexp is parsed into an array of tokens in postfix form. Some tokens
|
||||
are operators and others are terminal symbols. Most (but not all) of these
|
||||
codes are returned by the lexical analyzer. */
|
||||
#ifdef __STDC__
|
||||
|
||||
typedef enum
|
||||
{
|
||||
_END = -1, /* _END is a terminal symbol that matches the
|
||||
end of input; any value of _END or less in
|
||||
the parse tree is such a symbol. Accepting
|
||||
states of the DFA are those that would have
|
||||
a transition on _END. */
|
||||
|
||||
/* Ordinary character values are terminal symbols that match themselves. */
|
||||
|
||||
_EMPTY = _NOTCHAR, /* _EMPTY is a terminal symbol that matches
|
||||
the empty string. */
|
||||
|
||||
_BACKREF, /* _BACKREF is generated by \<digit>; it
|
||||
it not completely handled. If the scanner
|
||||
detects a transition on backref, it returns
|
||||
a kind of "semi-success" indicating that
|
||||
the match will have to be verified with
|
||||
a backtracking matcher. */
|
||||
|
||||
_BEGLINE, /* _BEGLINE is a terminal symbol that matches
|
||||
the empty string if it is at the beginning
|
||||
of a line. */
|
||||
|
||||
_ALLBEGLINE, /* _ALLBEGLINE is a terminal symbol that
|
||||
matches the empty string if it is at the
|
||||
beginning of a line; _ALLBEGLINE applies
|
||||
to the entire regexp and can only occur
|
||||
as the first token thereof. _ALLBEGLINE
|
||||
never appears in the parse tree; a _BEGLINE
|
||||
is prepended with _CAT to the entire
|
||||
regexp instead. */
|
||||
|
||||
_ENDLINE, /* _ENDLINE is a terminal symbol that matches
|
||||
the empty string if it is at the end of
|
||||
a line. */
|
||||
|
||||
_ALLENDLINE, /* _ALLENDLINE is to _ENDLINE as _ALLBEGLINE
|
||||
is to _BEGLINE. */
|
||||
|
||||
_BEGWORD, /* _BEGWORD is a terminal symbol that matches
|
||||
the empty string if it is at the beginning
|
||||
of a word. */
|
||||
|
||||
_ENDWORD, /* _ENDWORD is a terminal symbol that matches
|
||||
the empty string if it is at the end of
|
||||
a word. */
|
||||
|
||||
_LIMWORD, /* _LIMWORD is a terminal symbol that matches
|
||||
the empty string if it is at the beginning
|
||||
or the end of a word. */
|
||||
|
||||
_NOTLIMWORD, /* _NOTLIMWORD is a terminal symbol that
|
||||
matches the empty string if it is not at
|
||||
the beginning or end of a word. */
|
||||
|
||||
_QMARK, /* _QMARK is an operator of one argument that
|
||||
matches zero or one occurences of its
|
||||
argument. */
|
||||
|
||||
_STAR, /* _STAR is an operator of one argument that
|
||||
matches the Kleene closure (zero or more
|
||||
occurrences) of its argument. */
|
||||
|
||||
_PLUS, /* _PLUS is an operator of one argument that
|
||||
matches the positive closure (one or more
|
||||
occurrences) of its argument. */
|
||||
|
||||
_CAT, /* _CAT is an operator of two arguments that
|
||||
matches the concatenation of its
|
||||
arguments. _CAT is never returned by the
|
||||
lexical analyzer. */
|
||||
|
||||
_OR, /* _OR is an operator of two arguments that
|
||||
matches either of its arguments. */
|
||||
|
||||
_LPAREN, /* _LPAREN never appears in the parse tree,
|
||||
it is only a lexeme. */
|
||||
|
||||
_RPAREN, /* _RPAREN never appears in the parse tree. */
|
||||
|
||||
_SET /* _SET and (and any value greater) is a
|
||||
terminal symbol that matches any of a
|
||||
class of characters. */
|
||||
} _token;
|
||||
|
||||
#else /* ! __STDC__ */
|
||||
|
||||
typedef short _token;
|
||||
|
||||
#define _END -1
|
||||
#define _EMPTY _NOTCHAR
|
||||
#define _BACKREF (_EMPTY + 1)
|
||||
#define _BEGLINE (_EMPTY + 2)
|
||||
#define _ALLBEGLINE (_EMPTY + 3)
|
||||
#define _ENDLINE (_EMPTY + 4)
|
||||
#define _ALLENDLINE (_EMPTY + 5)
|
||||
#define _BEGWORD (_EMPTY + 6)
|
||||
#define _ENDWORD (_EMPTY + 7)
|
||||
#define _LIMWORD (_EMPTY + 8)
|
||||
#define _NOTLIMWORD (_EMPTY + 9)
|
||||
#define _QMARK (_EMPTY + 10)
|
||||
#define _STAR (_EMPTY + 11)
|
||||
#define _PLUS (_EMPTY + 12)
|
||||
#define _CAT (_EMPTY + 13)
|
||||
#define _OR (_EMPTY + 14)
|
||||
#define _LPAREN (_EMPTY + 15)
|
||||
#define _RPAREN (_EMPTY + 16)
|
||||
#define _SET (_EMPTY + 17)
|
||||
|
||||
#endif /* ! __STDC__ */
|
||||
|
||||
/* Sets are stored in an array in the compiled regexp; the index of the
|
||||
array corresponding to a given set token is given by _SET_INDEX(t). */
|
||||
#define _SET_INDEX(t) ((t) - _SET)
|
||||
|
||||
/* Sometimes characters can only be matched depending on the surrounding
|
||||
context. Such context decisions depend on what the previous character
|
||||
was, and the value of the current (lookahead) character. Context
|
||||
dependent constraints are encoded as 8 bit integers. Each bit that
|
||||
is set indicates that the constraint succeeds in the corresponding
|
||||
context.
|
||||
|
||||
bit 7 - previous and current are newlines
|
||||
bit 6 - previous was newline, current isn't
|
||||
bit 5 - previous wasn't newline, current is
|
||||
bit 4 - neither previous nor current is a newline
|
||||
bit 3 - previous and current are word-constituents
|
||||
bit 2 - previous was word-constituent, current isn't
|
||||
bit 1 - previous wasn't word-constituent, current is
|
||||
bit 0 - neither previous nor current is word-constituent
|
||||
|
||||
Word-constituent characters are those that satisfy isalnum().
|
||||
|
||||
The macro _SUCCEEDS_IN_CONTEXT determines whether a a given constraint
|
||||
succeeds in a particular context. Prevn is true if the previous character
|
||||
was a newline, currn is true if the lookahead character is a newline.
|
||||
Prevl and currl similarly depend upon whether the previous and current
|
||||
characters are word-constituent letters. */
|
||||
#define _MATCHES_NEWLINE_CONTEXT(constraint, prevn, currn) \
|
||||
((constraint) & (1 << (((prevn) ? 2 : 0) + ((currn) ? 1 : 0) + 4)))
|
||||
#define _MATCHES_LETTER_CONTEXT(constraint, prevl, currl) \
|
||||
((constraint) & (1 << (((prevl) ? 2 : 0) + ((currl) ? 1 : 0))))
|
||||
#define _SUCCEEDS_IN_CONTEXT(constraint, prevn, currn, prevl, currl) \
|
||||
(_MATCHES_NEWLINE_CONTEXT(constraint, prevn, currn) \
|
||||
&& _MATCHES_LETTER_CONTEXT(constraint, prevl, currl))
|
||||
|
||||
/* The following macros give information about what a constraint depends on. */
|
||||
#define _PREV_NEWLINE_DEPENDENT(constraint) \
|
||||
(((constraint) & 0xc0) >> 2 != ((constraint) & 0x30))
|
||||
#define _PREV_LETTER_DEPENDENT(constraint) \
|
||||
(((constraint) & 0x0c) >> 2 != ((constraint) & 0x03))
|
||||
|
||||
/* Tokens that match the empty string subject to some constraint actually
|
||||
work by applying that constraint to determine what may follow them,
|
||||
taking into account what has gone before. The following values are
|
||||
the constraints corresponding to the special tokens previously defined. */
|
||||
#define _NO_CONSTRAINT 0xff
|
||||
#define _BEGLINE_CONSTRAINT 0xcf
|
||||
#define _ENDLINE_CONSTRAINT 0xaf
|
||||
#define _BEGWORD_CONSTRAINT 0xf2
|
||||
#define _ENDWORD_CONSTRAINT 0xf4
|
||||
#define _LIMWORD_CONSTRAINT 0xf6
|
||||
#define _NOTLIMWORD_CONSTRAINT 0xf9
|
||||
|
||||
/* States of the recognizer correspond to sets of positions in the parse
|
||||
tree, together with the constraints under which they may be matched.
|
||||
So a position is encoded as an index into the parse tree together with
|
||||
a constraint. */
|
||||
typedef struct
|
||||
{
|
||||
unsigned index; /* Index into the parse array. */
|
||||
unsigned constraint; /* Constraint for matching this position. */
|
||||
} _position;
|
||||
|
||||
/* Sets of positions are stored as arrays. */
|
||||
typedef struct
|
||||
{
|
||||
_position *elems; /* Elements of this position set. */
|
||||
int nelem; /* Number of elements in this set. */
|
||||
} _position_set;
|
||||
|
||||
/* A state of the regexp consists of a set of positions, some flags,
|
||||
and the token value of the lowest-numbered position of the state that
|
||||
contains an _END token. */
|
||||
typedef struct
|
||||
{
|
||||
int hash; /* Hash of the positions of this state. */
|
||||
_position_set elems; /* Positions this state could match. */
|
||||
char newline; /* True if previous state matched newline. */
|
||||
char letter; /* True if previous state matched a letter. */
|
||||
char backref; /* True if this state matches a \<digit>. */
|
||||
unsigned char constraint; /* Constraint for this state to accept. */
|
||||
int first_end; /* Token value of the first _END in elems. */
|
||||
} _dfa_state;
|
||||
|
||||
/* If an r.e. is at most MUST_MAX characters long, we look for a string which
|
||||
must appear in it; whatever's found is dropped into the struct reg. */
|
||||
|
||||
#define MUST_MAX 50
|
||||
|
||||
/* A compiled regular expression. */
|
||||
struct regexp
|
||||
{
|
||||
/* Stuff built by the scanner. */
|
||||
_charset *charsets; /* Array of character sets for _SET tokens. */
|
||||
int cindex; /* Index for adding new charsets. */
|
||||
int calloc; /* Number of charsets currently allocated. */
|
||||
|
||||
/* Stuff built by the parser. */
|
||||
_token *tokens; /* Postfix parse array. */
|
||||
int tindex; /* Index for adding new tokens. */
|
||||
int talloc; /* Number of tokens currently allocated. */
|
||||
int depth; /* Depth required of an evaluation stack
|
||||
used for depth-first traversal of the
|
||||
parse tree. */
|
||||
int nleaves; /* Number of leaves on the parse tree. */
|
||||
int nregexps; /* Count of parallel regexps being built
|
||||
with regparse(). */
|
||||
|
||||
/* Stuff owned by the state builder. */
|
||||
_dfa_state *states; /* States of the regexp. */
|
||||
int sindex; /* Index for adding new states. */
|
||||
int salloc; /* Number of states currently allocated. */
|
||||
|
||||
/* Stuff built by the structure analyzer. */
|
||||
_position_set *follows; /* Array of follow sets, indexed by position
|
||||
index. The follow of a position is the set
|
||||
of positions containing characters that
|
||||
could conceivably follow a character
|
||||
matching the given position in a string
|
||||
matching the regexp. Allocated to the
|
||||
maximum possible position index. */
|
||||
int searchflag; /* True if we are supposed to build a searching
|
||||
as opposed to an exact matcher. A searching
|
||||
matcher finds the first and shortest string
|
||||
matching a regexp anywhere in the buffer,
|
||||
whereas an exact matcher finds the longest
|
||||
string matching, but anchored to the
|
||||
beginning of the buffer. */
|
||||
|
||||
/* Stuff owned by the executor. */
|
||||
int tralloc; /* Number of transition tables that have
|
||||
slots so far. */
|
||||
int trcount; /* Number of transition tables that have
|
||||
actually been built. */
|
||||
int **trans; /* Transition tables for states that can
|
||||
never accept. If the transitions for a
|
||||
state have not yet been computed, or the
|
||||
state could possibly accept, its entry in
|
||||
this table is NULL. */
|
||||
int **realtrans; /* Trans always points to realtrans + 1; this
|
||||
is so trans[-1] can contain NULL. */
|
||||
int **fails; /* Transition tables after failing to accept
|
||||
on a state that potentially could do so. */
|
||||
int *success; /* Table of acceptance conditions used in
|
||||
regexecute and computed in build_state. */
|
||||
int *newlines; /* Transitions on newlines. The entry for a
|
||||
newline in any transition table is always
|
||||
-1 so we can count lines without wasting
|
||||
too many cycles. The transition for a
|
||||
newline is stored separately and handled
|
||||
as a special case. Newline is also used
|
||||
as a sentinel at the end of the buffer. */
|
||||
char must[MUST_MAX];
|
||||
int mustn;
|
||||
};
|
||||
|
||||
/* Some macros for user access to regexp internals. */
|
||||
|
||||
/* ACCEPTING returns true if s could possibly be an accepting state of r. */
|
||||
#define ACCEPTING(s, r) ((r).states[s].constraint)
|
||||
|
||||
/* ACCEPTS_IN_CONTEXT returns true if the given state accepts in the
|
||||
specified context. */
|
||||
#define ACCEPTS_IN_CONTEXT(prevn, currn, prevl, currl, state, reg) \
|
||||
_SUCCEEDS_IN_CONTEXT((reg).states[state].constraint, \
|
||||
prevn, currn, prevl, currl)
|
||||
|
||||
/* FIRST_MATCHING_REGEXP returns the index number of the first of parallel
|
||||
regexps that a given state could accept. Parallel regexps are numbered
|
||||
starting at 1. */
|
||||
#define FIRST_MATCHING_REGEXP(state, reg) (-(reg).states[state].first_end)
|
||||
|
||||
/* Entry points. */
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
/* Regsyntax() takes two arguments; the first sets the syntax bits described
|
||||
earlier in this file, and the second sets the case-folding flag. */
|
||||
extern void regsyntax(long, int);
|
||||
|
||||
/* Compile the given string of the given length into the given struct regexp.
|
||||
Final argument is a flag specifying whether to build a searching or an
|
||||
exact matcher. */
|
||||
extern void regcompile(const char *, size_t, struct regexp *, int);
|
||||
|
||||
/* Execute the given struct regexp on the buffer of characters. The
|
||||
first char * points to the beginning, and the second points to the
|
||||
first character after the end of the buffer, which must be a writable
|
||||
place so a sentinel end-of-buffer marker can be stored there. The
|
||||
second-to-last argument is a flag telling whether to allow newlines to
|
||||
be part of a string matching the regexp. The next-to-last argument,
|
||||
if non-NULL, points to a place to increment every time we see a
|
||||
newline. The final argument, if non-NULL, points to a flag that will
|
||||
be set if further examination by a backtracking matcher is needed in
|
||||
order to verify backreferencing; otherwise the flag will be cleared.
|
||||
Returns NULL if no match is found, or a pointer to the first
|
||||
character after the first & shortest matching string in the buffer. */
|
||||
extern char *regexecute(struct regexp *, char *, char *, int, int *, int *);
|
||||
|
||||
/* Free the storage held by the components of a struct regexp. */
|
||||
extern void reg_free(struct regexp *);
|
||||
|
||||
/* Entry points for people who know what they're doing. */
|
||||
|
||||
/* Initialize the components of a struct regexp. */
|
||||
extern void reginit(struct regexp *);
|
||||
|
||||
/* Incrementally parse a string of given length into a struct regexp. */
|
||||
extern void regparse(const char *, size_t, struct regexp *);
|
||||
|
||||
/* Analyze a parsed regexp; second argument tells whether to build a searching
|
||||
or an exact matcher. */
|
||||
extern void reganalyze(struct regexp *, int);
|
||||
|
||||
/* Compute, for each possible character, the transitions out of a given
|
||||
state, storing them in an array of integers. */
|
||||
extern void regstate(int, struct regexp *, int []);
|
||||
|
||||
/* Error handling. */
|
||||
|
||||
/* Regerror() is called by the regexp routines whenever an error occurs. It
|
||||
takes a single argument, a NUL-terminated string describing the error.
|
||||
The default reg_error() prints the error message to stderr and exits.
|
||||
The user can provide a different reg_free() if so desired. */
|
||||
extern void reg_error(const char *);
|
||||
|
||||
#else /* ! __STDC__ */
|
||||
extern void regsyntax(), regcompile(), reg_free(), reginit(), regparse();
|
||||
extern void reganalyze(), regstate(), reg_error();
|
||||
extern char *regexecute();
|
||||
#endif
|
||||
1225
gnu/usr.bin/awk/eval.c
Normal file
1225
gnu/usr.bin/awk/eval.c
Normal file
File diff suppressed because it is too large
Load diff
645
gnu/usr.bin/awk/field.c
Normal file
645
gnu/usr.bin/awk/field.c
Normal file
|
|
@ -0,0 +1,645 @@
|
|||
/*
|
||||
* field.c - routines for dealing with fields and record parsing
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GAWK, the GNU implementation of the
|
||||
* AWK Progamming Language.
|
||||
*
|
||||
* GAWK 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.
|
||||
*
|
||||
* GAWK 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 GAWK; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "awk.h"
|
||||
|
||||
static int (*parse_field) P((int, char **, int, NODE *,
|
||||
Regexp *, void (*)(), NODE *));
|
||||
static void rebuild_record P((void));
|
||||
static int re_parse_field P((int, char **, int, NODE *,
|
||||
Regexp *, void (*)(), NODE *));
|
||||
static int def_parse_field P((int, char **, int, NODE *,
|
||||
Regexp *, void (*)(), NODE *));
|
||||
static int sc_parse_field P((int, char **, int, NODE *,
|
||||
Regexp *, void (*)(), NODE *));
|
||||
static int fw_parse_field P((int, char **, int, NODE *,
|
||||
Regexp *, void (*)(), NODE *));
|
||||
static void set_element P((int, char *, int, NODE *));
|
||||
static void grow_fields_arr P((int num));
|
||||
static void set_field P((int num, char *str, int len, NODE *dummy));
|
||||
|
||||
|
||||
static Regexp *FS_regexp = NULL;
|
||||
static char *parse_extent; /* marks where to restart parse of record */
|
||||
static int parse_high_water=0; /* field number that we have parsed so far */
|
||||
static int nf_high_water = 0; /* size of fields_arr */
|
||||
static int resave_fs;
|
||||
static NODE *save_FS; /* save current value of FS when line is read,
|
||||
* to be used in deferred parsing
|
||||
*/
|
||||
|
||||
NODE **fields_arr; /* array of pointers to the field nodes */
|
||||
int field0_valid; /* $(>0) has not been changed yet */
|
||||
int default_FS;
|
||||
static NODE **nodes; /* permanent repository of field nodes */
|
||||
static int *FIELDWIDTHS = NULL;
|
||||
|
||||
void
|
||||
init_fields()
|
||||
{
|
||||
NODE *n;
|
||||
|
||||
emalloc(fields_arr, NODE **, sizeof(NODE *), "init_fields");
|
||||
emalloc(nodes, NODE **, sizeof(NODE *), "init_fields");
|
||||
getnode(n);
|
||||
*n = *Nnull_string;
|
||||
fields_arr[0] = nodes[0] = n;
|
||||
parse_extent = fields_arr[0]->stptr;
|
||||
save_FS = dupnode(FS_node->var_value);
|
||||
field0_valid = 1;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
grow_fields_arr(num)
|
||||
int num;
|
||||
{
|
||||
register int t;
|
||||
register NODE *n;
|
||||
|
||||
erealloc(fields_arr, NODE **, (num + 1) * sizeof(NODE *), "set_field");
|
||||
erealloc(nodes, NODE **, (num+1) * sizeof(NODE *), "set_field");
|
||||
for (t = nf_high_water+1; t <= num; t++) {
|
||||
getnode(n);
|
||||
*n = *Nnull_string;
|
||||
fields_arr[t] = nodes[t] = n;
|
||||
}
|
||||
nf_high_water = num;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static void
|
||||
set_field(num, str, len, dummy)
|
||||
int num;
|
||||
char *str;
|
||||
int len;
|
||||
NODE *dummy; /* not used -- just to make interface same as set_element */
|
||||
{
|
||||
register NODE *n;
|
||||
|
||||
if (num > nf_high_water)
|
||||
grow_fields_arr(num);
|
||||
n = nodes[num];
|
||||
n->stptr = str;
|
||||
n->stlen = len;
|
||||
n->flags = (PERM|STR|STRING|MAYBE_NUM);
|
||||
fields_arr[num] = n;
|
||||
}
|
||||
|
||||
/* Someone assigned a value to $(something). Fix up $0 to be right */
|
||||
static void
|
||||
rebuild_record()
|
||||
{
|
||||
register int tlen;
|
||||
register NODE *tmp;
|
||||
NODE *ofs;
|
||||
char *ops;
|
||||
register char *cops;
|
||||
register NODE **ptr;
|
||||
register int ofslen;
|
||||
|
||||
tlen = 0;
|
||||
ofs = force_string(OFS_node->var_value);
|
||||
ofslen = ofs->stlen;
|
||||
ptr = &fields_arr[NF];
|
||||
while (ptr > &fields_arr[0]) {
|
||||
tmp = force_string(*ptr);
|
||||
tlen += tmp->stlen;
|
||||
ptr--;
|
||||
}
|
||||
tlen += (NF - 1) * ofslen;
|
||||
if (tlen < 0)
|
||||
tlen = 0;
|
||||
emalloc(ops, char *, tlen + 2, "fix_fields");
|
||||
cops = ops;
|
||||
ops[0] = '\0';
|
||||
for (ptr = &fields_arr[1]; ptr <= &fields_arr[NF]; ptr++) {
|
||||
tmp = *ptr;
|
||||
if (tmp->stlen == 1)
|
||||
*cops++ = tmp->stptr[0];
|
||||
else if (tmp->stlen != 0) {
|
||||
memcpy(cops, tmp->stptr, tmp->stlen);
|
||||
cops += tmp->stlen;
|
||||
}
|
||||
if (ptr != &fields_arr[NF]) {
|
||||
if (ofslen == 1)
|
||||
*cops++ = ofs->stptr[0];
|
||||
else if (ofslen != 0) {
|
||||
memcpy(cops, ofs->stptr, ofslen);
|
||||
cops += ofslen;
|
||||
}
|
||||
}
|
||||
}
|
||||
tmp = make_str_node(ops, tlen, ALREADY_MALLOCED);
|
||||
unref(fields_arr[0]);
|
||||
fields_arr[0] = tmp;
|
||||
field0_valid = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* setup $0, but defer parsing rest of line until reference is made to $(>0)
|
||||
* or to NF. At that point, parse only as much as necessary.
|
||||
*/
|
||||
void
|
||||
set_record(buf, cnt, freeold)
|
||||
char *buf;
|
||||
int cnt;
|
||||
int freeold;
|
||||
{
|
||||
register int i;
|
||||
|
||||
NF = -1;
|
||||
for (i = 1; i <= parse_high_water; i++) {
|
||||
unref(fields_arr[i]);
|
||||
}
|
||||
parse_high_water = 0;
|
||||
if (freeold) {
|
||||
unref(fields_arr[0]);
|
||||
if (resave_fs) {
|
||||
resave_fs = 0;
|
||||
unref(save_FS);
|
||||
save_FS = dupnode(FS_node->var_value);
|
||||
}
|
||||
nodes[0]->stptr = buf;
|
||||
nodes[0]->stlen = cnt;
|
||||
nodes[0]->stref = 1;
|
||||
nodes[0]->flags = (STRING|STR|PERM|MAYBE_NUM);
|
||||
fields_arr[0] = nodes[0];
|
||||
}
|
||||
fields_arr[0]->flags |= MAYBE_NUM;
|
||||
field0_valid = 1;
|
||||
}
|
||||
|
||||
void
|
||||
reset_record()
|
||||
{
|
||||
(void) force_string(fields_arr[0]);
|
||||
set_record(fields_arr[0]->stptr, fields_arr[0]->stlen, 0);
|
||||
}
|
||||
|
||||
void
|
||||
set_NF()
|
||||
{
|
||||
register int i;
|
||||
|
||||
NF = (int) force_number(NF_node->var_value);
|
||||
if (NF > nf_high_water)
|
||||
grow_fields_arr(NF);
|
||||
for (i = parse_high_water + 1; i <= NF; i++) {
|
||||
unref(fields_arr[i]);
|
||||
fields_arr[i] = Nnull_string;
|
||||
}
|
||||
field0_valid = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* this is called both from get_field() and from do_split()
|
||||
* via (*parse_field)(). This variation is for when FS is a regular
|
||||
* expression -- either user-defined or because RS=="" and FS==" "
|
||||
*/
|
||||
static int
|
||||
re_parse_field(up_to, buf, len, fs, rp, set, n)
|
||||
int up_to; /* parse only up to this field number */
|
||||
char **buf; /* on input: string to parse; on output: point to start next */
|
||||
int len;
|
||||
NODE *fs;
|
||||
Regexp *rp;
|
||||
void (*set) (); /* routine to set the value of the parsed field */
|
||||
NODE *n;
|
||||
{
|
||||
register char *scan = *buf;
|
||||
register int nf = parse_high_water;
|
||||
register char *field;
|
||||
register char *end = scan + len;
|
||||
|
||||
if (up_to == HUGE)
|
||||
nf = 0;
|
||||
if (len == 0)
|
||||
return nf;
|
||||
|
||||
if (*RS == 0 && default_FS)
|
||||
while (scan < end && isspace(*scan))
|
||||
scan++;
|
||||
field = scan;
|
||||
while (scan < end
|
||||
&& research(rp, scan, 0, (int)(end - scan), 1) != -1
|
||||
&& nf < up_to) {
|
||||
if (REEND(rp, scan) == RESTART(rp, scan)) { /* null match */
|
||||
scan++;
|
||||
if (scan == end) {
|
||||
(*set)(++nf, field, scan - field, n);
|
||||
up_to = nf;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
(*set)(++nf, field, scan + RESTART(rp, scan) - field, n);
|
||||
scan += REEND(rp, scan);
|
||||
field = scan;
|
||||
if (scan == end) /* FS at end of record */
|
||||
(*set)(++nf, field, 0, n);
|
||||
}
|
||||
if (nf != up_to && scan < end) {
|
||||
(*set)(++nf, scan, (int)(end - scan), n);
|
||||
scan = end;
|
||||
}
|
||||
*buf = scan;
|
||||
return (nf);
|
||||
}
|
||||
|
||||
/*
|
||||
* this is called both from get_field() and from do_split()
|
||||
* via (*parse_field)(). This variation is for when FS is a single space
|
||||
* character.
|
||||
*/
|
||||
static int
|
||||
def_parse_field(up_to, buf, len, fs, rp, set, n)
|
||||
int up_to; /* parse only up to this field number */
|
||||
char **buf; /* on input: string to parse; on output: point to start next */
|
||||
int len;
|
||||
NODE *fs;
|
||||
Regexp *rp;
|
||||
void (*set) (); /* routine to set the value of the parsed field */
|
||||
NODE *n;
|
||||
{
|
||||
register char *scan = *buf;
|
||||
register int nf = parse_high_water;
|
||||
register char *field;
|
||||
register char *end = scan + len;
|
||||
char sav;
|
||||
|
||||
if (up_to == HUGE)
|
||||
nf = 0;
|
||||
if (len == 0)
|
||||
return nf;
|
||||
|
||||
/* before doing anything save the char at *end */
|
||||
sav = *end;
|
||||
/* because it will be destroyed now: */
|
||||
|
||||
*end = ' '; /* sentinel character */
|
||||
for (; nf < up_to; scan++) {
|
||||
/*
|
||||
* special case: fs is single space, strip leading whitespace
|
||||
*/
|
||||
while (scan < end && (*scan == ' ' || *scan == '\t'))
|
||||
scan++;
|
||||
if (scan >= end)
|
||||
break;
|
||||
field = scan;
|
||||
while (*scan != ' ' && *scan != '\t')
|
||||
scan++;
|
||||
(*set)(++nf, field, (int)(scan - field), n);
|
||||
if (scan == end)
|
||||
break;
|
||||
}
|
||||
|
||||
/* everything done, restore original char at *end */
|
||||
*end = sav;
|
||||
|
||||
*buf = scan;
|
||||
return nf;
|
||||
}
|
||||
|
||||
/*
|
||||
* this is called both from get_field() and from do_split()
|
||||
* via (*parse_field)(). This variation is for when FS is a single character
|
||||
* other than space.
|
||||
*/
|
||||
static int
|
||||
sc_parse_field(up_to, buf, len, fs, rp, set, n)
|
||||
int up_to; /* parse only up to this field number */
|
||||
char **buf; /* on input: string to parse; on output: point to start next */
|
||||
int len;
|
||||
NODE *fs;
|
||||
Regexp *rp;
|
||||
void (*set) (); /* routine to set the value of the parsed field */
|
||||
NODE *n;
|
||||
{
|
||||
register char *scan = *buf;
|
||||
register char fschar;
|
||||
register int nf = parse_high_water;
|
||||
register char *field;
|
||||
register char *end = scan + len;
|
||||
char sav;
|
||||
|
||||
if (up_to == HUGE)
|
||||
nf = 0;
|
||||
if (len == 0)
|
||||
return nf;
|
||||
|
||||
if (*RS == 0 && fs->stlen == 0)
|
||||
fschar = '\n';
|
||||
else
|
||||
fschar = fs->stptr[0];
|
||||
|
||||
/* before doing anything save the char at *end */
|
||||
sav = *end;
|
||||
/* because it will be destroyed now: */
|
||||
*end = fschar; /* sentinel character */
|
||||
|
||||
for (; nf < up_to; scan++) {
|
||||
field = scan;
|
||||
while (*scan++ != fschar)
|
||||
;
|
||||
scan--;
|
||||
(*set)(++nf, field, (int)(scan - field), n);
|
||||
if (scan == end)
|
||||
break;
|
||||
}
|
||||
|
||||
/* everything done, restore original char at *end */
|
||||
*end = sav;
|
||||
|
||||
*buf = scan;
|
||||
return nf;
|
||||
}
|
||||
|
||||
/*
|
||||
* this is called both from get_field() and from do_split()
|
||||
* via (*parse_field)(). This variation is for fields are fixed widths.
|
||||
*/
|
||||
static int
|
||||
fw_parse_field(up_to, buf, len, fs, rp, set, n)
|
||||
int up_to; /* parse only up to this field number */
|
||||
char **buf; /* on input: string to parse; on output: point to start next */
|
||||
int len;
|
||||
NODE *fs;
|
||||
Regexp *rp;
|
||||
void (*set) (); /* routine to set the value of the parsed field */
|
||||
NODE *n;
|
||||
{
|
||||
register char *scan = *buf;
|
||||
register int nf = parse_high_water;
|
||||
register char *end = scan + len;
|
||||
|
||||
if (up_to == HUGE)
|
||||
nf = 0;
|
||||
if (len == 0)
|
||||
return nf;
|
||||
for (; nf < up_to && (len = FIELDWIDTHS[nf+1]) != -1; ) {
|
||||
if (len > end - scan)
|
||||
len = end - scan;
|
||||
(*set)(++nf, scan, len, n);
|
||||
scan += len;
|
||||
}
|
||||
if (len == -1)
|
||||
*buf = end;
|
||||
else
|
||||
*buf = scan;
|
||||
return nf;
|
||||
}
|
||||
|
||||
NODE **
|
||||
get_field(requested, assign)
|
||||
register int requested;
|
||||
Func_ptr *assign; /* this field is on the LHS of an assign */
|
||||
{
|
||||
/*
|
||||
* if requesting whole line but some other field has been altered,
|
||||
* then the whole line must be rebuilt
|
||||
*/
|
||||
if (requested == 0) {
|
||||
if (!field0_valid) {
|
||||
/* first, parse remainder of input record */
|
||||
if (NF == -1) {
|
||||
NF = (*parse_field)(HUGE-1, &parse_extent,
|
||||
fields_arr[0]->stlen -
|
||||
(parse_extent - fields_arr[0]->stptr),
|
||||
save_FS, FS_regexp, set_field,
|
||||
(NODE *)NULL);
|
||||
parse_high_water = NF;
|
||||
}
|
||||
rebuild_record();
|
||||
}
|
||||
if (assign)
|
||||
*assign = reset_record;
|
||||
return &fields_arr[0];
|
||||
}
|
||||
|
||||
/* assert(requested > 0); */
|
||||
|
||||
if (assign)
|
||||
field0_valid = 0; /* $0 needs reconstruction */
|
||||
|
||||
if (requested <= parse_high_water) /* already parsed this field */
|
||||
return &fields_arr[requested];
|
||||
|
||||
if (NF == -1) { /* have not yet parsed to end of record */
|
||||
/*
|
||||
* parse up to requested fields, calling set_field() for each,
|
||||
* saving in parse_extent the point where the parse left off
|
||||
*/
|
||||
if (parse_high_water == 0) /* starting at the beginning */
|
||||
parse_extent = fields_arr[0]->stptr;
|
||||
parse_high_water = (*parse_field)(requested, &parse_extent,
|
||||
fields_arr[0]->stlen - (parse_extent-fields_arr[0]->stptr),
|
||||
save_FS, FS_regexp, set_field, (NODE *)NULL);
|
||||
|
||||
/*
|
||||
* if we reached the end of the record, set NF to the number of
|
||||
* fields so far. Note that requested might actually refer to
|
||||
* a field that is beyond the end of the record, but we won't
|
||||
* set NF to that value at this point, since this is only a
|
||||
* reference to the field and NF only gets set if the field
|
||||
* is assigned to -- this case is handled below
|
||||
*/
|
||||
if (parse_extent == fields_arr[0]->stptr + fields_arr[0]->stlen)
|
||||
NF = parse_high_water;
|
||||
if (requested == HUGE-1) /* HUGE-1 means set NF */
|
||||
requested = parse_high_water;
|
||||
}
|
||||
if (parse_high_water < requested) { /* requested beyond end of record */
|
||||
if (assign) { /* expand record */
|
||||
register int i;
|
||||
|
||||
if (requested > nf_high_water)
|
||||
grow_fields_arr(requested);
|
||||
|
||||
/* fill in fields that don't exist */
|
||||
for (i = parse_high_water + 1; i <= requested; i++)
|
||||
fields_arr[i] = Nnull_string;
|
||||
|
||||
NF = requested;
|
||||
parse_high_water = requested;
|
||||
} else
|
||||
return &Nnull_string;
|
||||
}
|
||||
|
||||
return &fields_arr[requested];
|
||||
}
|
||||
|
||||
static void
|
||||
set_element(num, s, len, n)
|
||||
int num;
|
||||
char *s;
|
||||
int len;
|
||||
NODE *n;
|
||||
{
|
||||
register NODE *it;
|
||||
|
||||
it = make_string(s, len);
|
||||
it->flags |= MAYBE_NUM;
|
||||
*assoc_lookup(n, tmp_number((AWKNUM) (num))) = it;
|
||||
}
|
||||
|
||||
NODE *
|
||||
do_split(tree)
|
||||
NODE *tree;
|
||||
{
|
||||
NODE *t1, *t2, *t3, *tmp;
|
||||
NODE *fs;
|
||||
char *s;
|
||||
int (*parseit)P((int, char **, int, NODE *,
|
||||
Regexp *, void (*)(), NODE *));
|
||||
Regexp *rp = NULL;
|
||||
|
||||
t1 = tree_eval(tree->lnode);
|
||||
t2 = tree->rnode->lnode;
|
||||
t3 = tree->rnode->rnode->lnode;
|
||||
|
||||
(void) force_string(t1);
|
||||
|
||||
if (t2->type == Node_param_list)
|
||||
t2 = stack_ptr[t2->param_cnt];
|
||||
if (t2->type != Node_var && t2->type != Node_var_array)
|
||||
fatal("second argument of split is not a variable");
|
||||
assoc_clear(t2);
|
||||
|
||||
if (t3->re_flags & FS_DFLT) {
|
||||
parseit = parse_field;
|
||||
fs = force_string(FS_node->var_value);
|
||||
rp = FS_regexp;
|
||||
} else {
|
||||
tmp = force_string(tree_eval(t3->re_exp));
|
||||
if (tmp->stlen == 1) {
|
||||
if (tmp->stptr[0] == ' ')
|
||||
parseit = def_parse_field;
|
||||
else
|
||||
parseit = sc_parse_field;
|
||||
} else {
|
||||
parseit = re_parse_field;
|
||||
rp = re_update(t3);
|
||||
}
|
||||
fs = tmp;
|
||||
}
|
||||
|
||||
s = t1->stptr;
|
||||
tmp = tmp_number((AWKNUM) (*parseit)(HUGE, &s, (int)t1->stlen,
|
||||
fs, rp, set_element, t2));
|
||||
free_temp(t1);
|
||||
free_temp(t3);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void
|
||||
set_FS()
|
||||
{
|
||||
NODE *tmp = NULL;
|
||||
char buf[10];
|
||||
NODE *fs;
|
||||
|
||||
buf[0] = '\0';
|
||||
default_FS = 0;
|
||||
if (FS_regexp) {
|
||||
refree(FS_regexp);
|
||||
FS_regexp = NULL;
|
||||
}
|
||||
fs = force_string(FS_node->var_value);
|
||||
if (fs->stlen > 1)
|
||||
parse_field = re_parse_field;
|
||||
else if (*RS == 0) {
|
||||
parse_field = sc_parse_field;
|
||||
if (fs->stlen == 1) {
|
||||
if (fs->stptr[0] == ' ') {
|
||||
default_FS = 1;
|
||||
strcpy(buf, "[ \t\n]+");
|
||||
} else if (fs->stptr[0] != '\n')
|
||||
sprintf(buf, "[%c\n]", fs->stptr[0]);
|
||||
}
|
||||
} else {
|
||||
parse_field = def_parse_field;
|
||||
if (fs->stptr[0] == ' ' && fs->stlen == 1)
|
||||
default_FS = 1;
|
||||
else if (fs->stptr[0] != ' ' && fs->stlen == 1) {
|
||||
if (IGNORECASE == 0)
|
||||
parse_field = sc_parse_field;
|
||||
else
|
||||
sprintf(buf, "[%c]", fs->stptr[0]);
|
||||
}
|
||||
}
|
||||
if (buf[0]) {
|
||||
FS_regexp = make_regexp(buf, strlen(buf), IGNORECASE, 1);
|
||||
parse_field = re_parse_field;
|
||||
} else if (parse_field == re_parse_field) {
|
||||
FS_regexp = make_regexp(fs->stptr, fs->stlen, IGNORECASE, 1);
|
||||
} else
|
||||
FS_regexp = NULL;
|
||||
resave_fs = 1;
|
||||
}
|
||||
|
||||
void
|
||||
set_RS()
|
||||
{
|
||||
(void) force_string(RS_node->var_value);
|
||||
RS = RS_node->var_value->stptr;
|
||||
set_FS();
|
||||
}
|
||||
|
||||
void
|
||||
set_FIELDWIDTHS()
|
||||
{
|
||||
register char *scan;
|
||||
char *end;
|
||||
register int i;
|
||||
static int fw_alloc = 1;
|
||||
static int warned = 0;
|
||||
extern double strtod();
|
||||
|
||||
if (do_lint && ! warned) {
|
||||
warned = 1;
|
||||
warning("use of FIELDWIDTHS is a gawk extension");
|
||||
}
|
||||
if (do_unix) /* quick and dirty, does the trick */
|
||||
return;
|
||||
|
||||
parse_field = fw_parse_field;
|
||||
scan = force_string(FIELDWIDTHS_node->var_value)->stptr;
|
||||
end = scan + 1;
|
||||
if (FIELDWIDTHS == NULL)
|
||||
emalloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS");
|
||||
FIELDWIDTHS[0] = 0;
|
||||
for (i = 1; ; i++) {
|
||||
if (i >= fw_alloc) {
|
||||
fw_alloc *= 2;
|
||||
erealloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS");
|
||||
}
|
||||
FIELDWIDTHS[i] = (int) strtod(scan, &end);
|
||||
if (end == scan)
|
||||
break;
|
||||
scan = end;
|
||||
}
|
||||
FIELDWIDTHS[i] = -1;
|
||||
}
|
||||
11270
gnu/usr.bin/awk/gawk.texi
Normal file
11270
gnu/usr.bin/awk/gawk.texi
Normal file
File diff suppressed because it is too large
Load diff
662
gnu/usr.bin/awk/getopt.c
Normal file
662
gnu/usr.bin/awk/getopt.c
Normal file
|
|
@ -0,0 +1,662 @@
|
|||
/* Getopt for GNU.
|
||||
NOTE: getopt is now part of the C library, so if you don't know what
|
||||
"Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
|
||||
before changing it!
|
||||
|
||||
Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Library 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 Library General Public
|
||||
License along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifdef GAWK
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* This needs to come after some library #include
|
||||
to get __GNU_LIBRARY__ defined. */
|
||||
#ifdef __GNU_LIBRARY__
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#endif /* GNU C library. */
|
||||
|
||||
|
||||
#ifndef __STDC__
|
||||
#define const
|
||||
#endif
|
||||
|
||||
/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
|
||||
long-named option. Because this is not POSIX.2 compliant, it is
|
||||
being phased out. */
|
||||
#define GETOPT_COMPAT
|
||||
|
||||
/* This version of `getopt' appears to the caller like standard Unix `getopt'
|
||||
but it behaves differently for the user, since it allows the user
|
||||
to intersperse the options with the other arguments.
|
||||
|
||||
As `getopt' works, it permutes the elements of ARGV so that,
|
||||
when it is done, all the options precede everything else. Thus
|
||||
all application programs are extended to handle flexible argument order.
|
||||
|
||||
Setting the environment variable POSIXLY_CORRECT disables permutation.
|
||||
Then the behavior is completely standard.
|
||||
|
||||
GNU application programs can use a third alternative mode in which
|
||||
they can distinguish the relative order of options and other arguments. */
|
||||
|
||||
#include "getopt.h"
|
||||
|
||||
/* For communication from `getopt' to the caller.
|
||||
When `getopt' finds an option that takes an argument,
|
||||
the argument value is returned here.
|
||||
Also, when `ordering' is RETURN_IN_ORDER,
|
||||
each non-option ARGV-element is returned here. */
|
||||
|
||||
char *optarg = 0;
|
||||
|
||||
/* Index in ARGV of the next element to be scanned.
|
||||
This is used for communication to and from the caller
|
||||
and for communication between successive calls to `getopt'.
|
||||
|
||||
On entry to `getopt', zero means this is the first call; initialize.
|
||||
|
||||
When `getopt' returns EOF, this is the index of the first of the
|
||||
non-option elements that the caller should itself scan.
|
||||
|
||||
Otherwise, `optind' communicates from one call to the next
|
||||
how much of ARGV has been scanned so far. */
|
||||
|
||||
int optind = 0;
|
||||
|
||||
/* The next char to be scanned in the option-element
|
||||
in which the last option character we returned was found.
|
||||
This allows us to pick up the scan where we left off.
|
||||
|
||||
If this is zero, or a null string, it means resume the scan
|
||||
by advancing to the next ARGV-element. */
|
||||
|
||||
static char *nextchar;
|
||||
|
||||
/* Callers store zero here to inhibit the error message
|
||||
for unrecognized options. */
|
||||
|
||||
int opterr = 1;
|
||||
|
||||
/* Describe how to deal with options that follow non-option ARGV-elements.
|
||||
|
||||
If the caller did not specify anything,
|
||||
the default is REQUIRE_ORDER if the environment variable
|
||||
POSIXLY_CORRECT is defined, PERMUTE otherwise.
|
||||
|
||||
REQUIRE_ORDER means don't recognize them as options;
|
||||
stop option processing when the first non-option is seen.
|
||||
This is what Unix does.
|
||||
This mode of operation is selected by either setting the environment
|
||||
variable POSIXLY_CORRECT, or using `+' as the first character
|
||||
of the list of option characters.
|
||||
|
||||
PERMUTE is the default. We permute the contents of ARGV as we scan,
|
||||
so that eventually all the non-options are at the end. This allows options
|
||||
to be given in any order, even with programs that were not written to
|
||||
expect this.
|
||||
|
||||
RETURN_IN_ORDER is an option available to programs that were written
|
||||
to expect options and other ARGV-elements in any order and that care about
|
||||
the ordering of the two. We describe each non-option ARGV-element
|
||||
as if it were the argument of an option with character code 1.
|
||||
Using `-' as the first character of the list of option characters
|
||||
selects this mode of operation.
|
||||
|
||||
The special argument `--' forces an end of option-scanning regardless
|
||||
of the value of `ordering'. In the case of RETURN_IN_ORDER, only
|
||||
`--' can cause `getopt' to return EOF with `optind' != ARGC. */
|
||||
|
||||
static enum
|
||||
{
|
||||
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
|
||||
} ordering;
|
||||
|
||||
#ifdef __GNU_LIBRARY__
|
||||
#include <string.h>
|
||||
#define my_index strchr
|
||||
#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n))
|
||||
#else
|
||||
|
||||
/* Avoid depending on library functions or files
|
||||
whose names are inconsistent. */
|
||||
|
||||
char *getenv ();
|
||||
|
||||
static char *
|
||||
my_index (string, chr)
|
||||
char *string;
|
||||
int chr;
|
||||
{
|
||||
while (*string)
|
||||
{
|
||||
if (*string == chr)
|
||||
return string;
|
||||
string++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
my_bcopy (from, to, size)
|
||||
char *from, *to;
|
||||
int size;
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < size; i++)
|
||||
to[i] = from[i];
|
||||
}
|
||||
#endif /* GNU C library. */
|
||||
|
||||
/* Handle permutation of arguments. */
|
||||
|
||||
/* Describe the part of ARGV that contains non-options that have
|
||||
been skipped. `first_nonopt' is the index in ARGV of the first of them;
|
||||
`last_nonopt' is the index after the last of them. */
|
||||
|
||||
static int first_nonopt;
|
||||
static int last_nonopt;
|
||||
|
||||
/* Exchange two adjacent subsequences of ARGV.
|
||||
One subsequence is elements [first_nonopt,last_nonopt)
|
||||
which contains all the non-options that have been skipped so far.
|
||||
The other is elements [last_nonopt,optind), which contains all
|
||||
the options processed since those non-options were skipped.
|
||||
|
||||
`first_nonopt' and `last_nonopt' are relocated so that they describe
|
||||
the new indices of the non-options in ARGV after they are moved. */
|
||||
|
||||
static void
|
||||
exchange (argv)
|
||||
char **argv;
|
||||
{
|
||||
int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
|
||||
char **temp = (char **) malloc (nonopts_size);
|
||||
|
||||
/* Interchange the two blocks of data in ARGV. */
|
||||
|
||||
my_bcopy (&argv[first_nonopt], temp, nonopts_size);
|
||||
my_bcopy (&argv[last_nonopt], &argv[first_nonopt],
|
||||
(optind - last_nonopt) * sizeof (char *));
|
||||
my_bcopy (temp, &argv[first_nonopt + optind - last_nonopt], nonopts_size);
|
||||
|
||||
free(temp);
|
||||
|
||||
/* Update records for the slots the non-options now occupy. */
|
||||
|
||||
first_nonopt += (optind - last_nonopt);
|
||||
last_nonopt = optind;
|
||||
}
|
||||
|
||||
/* Scan elements of ARGV (whose length is ARGC) for option characters
|
||||
given in OPTSTRING.
|
||||
|
||||
If an element of ARGV starts with '-', and is not exactly "-" or "--",
|
||||
then it is an option element. The characters of this element
|
||||
(aside from the initial '-') are option characters. If `getopt'
|
||||
is called repeatedly, it returns successively each of the option characters
|
||||
from each of the option elements.
|
||||
|
||||
If `getopt' finds another option character, it returns that character,
|
||||
updating `optind' and `nextchar' so that the next call to `getopt' can
|
||||
resume the scan with the following option character or ARGV-element.
|
||||
|
||||
If there are no more option characters, `getopt' returns `EOF'.
|
||||
Then `optind' is the index in ARGV of the first ARGV-element
|
||||
that is not an option. (The ARGV-elements have been permuted
|
||||
so that those that are not options now come last.)
|
||||
|
||||
OPTSTRING is a string containing the legitimate option characters.
|
||||
If an option character is seen that is not listed in OPTSTRING,
|
||||
return '?' after printing an error message. If you set `opterr' to
|
||||
zero, the error message is suppressed but we still return '?'.
|
||||
|
||||
If a char in OPTSTRING is followed by a colon, that means it wants an arg,
|
||||
so the following text in the same ARGV-element, or the text of the following
|
||||
ARGV-element, is returned in `optarg'. Two colons mean an option that
|
||||
wants an optional arg; if there is text in the current ARGV-element,
|
||||
it is returned in `optarg', otherwise `optarg' is set to zero.
|
||||
|
||||
If OPTSTRING starts with `-' or `+', it requests different methods of
|
||||
handling the non-option ARGV-elements.
|
||||
See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
|
||||
|
||||
Long-named options begin with `--' instead of `-'.
|
||||
Their names may be abbreviated as long as the abbreviation is unique
|
||||
or is an exact match for some defined option. If they have an
|
||||
argument, it follows the option name in the same ARGV-element, separated
|
||||
from the option name by a `=', or else the in next ARGV-element.
|
||||
When `getopt' finds a long-named option, it returns 0 if that option's
|
||||
`flag' field is nonzero, the value of the option's `val' field
|
||||
if the `flag' field is zero.
|
||||
|
||||
The elements of ARGV aren't really const, because we permute them.
|
||||
But we pretend they're const in the prototype to be compatible
|
||||
with other systems.
|
||||
|
||||
LONGOPTS is a vector of `struct option' terminated by an
|
||||
element containing a name which is zero.
|
||||
|
||||
LONGIND returns the index in LONGOPT of the long-named option found.
|
||||
It is only valid when a long-named option has been found by the most
|
||||
recent call.
|
||||
|
||||
If LONG_ONLY is nonzero, '-' as well as '--' can introduce
|
||||
long-named options. */
|
||||
|
||||
int
|
||||
_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
|
||||
int argc;
|
||||
char *const *argv;
|
||||
const char *optstring;
|
||||
const struct option *longopts;
|
||||
int *longind;
|
||||
int long_only;
|
||||
{
|
||||
int option_index;
|
||||
|
||||
optarg = 0;
|
||||
|
||||
/* Initialize the internal data when the first call is made.
|
||||
Start processing options with ARGV-element 1 (since ARGV-element 0
|
||||
is the program name); the sequence of previously skipped
|
||||
non-option ARGV-elements is empty. */
|
||||
|
||||
if (optind == 0)
|
||||
{
|
||||
first_nonopt = last_nonopt = optind = 1;
|
||||
|
||||
nextchar = NULL;
|
||||
|
||||
/* Determine how to handle the ordering of options and nonoptions. */
|
||||
|
||||
if (optstring[0] == '-')
|
||||
{
|
||||
ordering = RETURN_IN_ORDER;
|
||||
++optstring;
|
||||
}
|
||||
else if (optstring[0] == '+')
|
||||
{
|
||||
ordering = REQUIRE_ORDER;
|
||||
++optstring;
|
||||
}
|
||||
else if (getenv ("POSIXLY_CORRECT") != NULL)
|
||||
ordering = REQUIRE_ORDER;
|
||||
else
|
||||
ordering = PERMUTE;
|
||||
}
|
||||
|
||||
if (nextchar == NULL || *nextchar == '\0')
|
||||
{
|
||||
if (ordering == PERMUTE)
|
||||
{
|
||||
/* If we have just processed some options following some non-options,
|
||||
exchange them so that the options come first. */
|
||||
|
||||
if (first_nonopt != last_nonopt && last_nonopt != optind)
|
||||
exchange ((char **) argv);
|
||||
else if (last_nonopt != optind)
|
||||
first_nonopt = optind;
|
||||
|
||||
/* Now skip any additional non-options
|
||||
and extend the range of non-options previously skipped. */
|
||||
|
||||
while (optind < argc
|
||||
&& (argv[optind][0] != '-' || argv[optind][1] == '\0')
|
||||
#ifdef GETOPT_COMPAT
|
||||
&& (longopts == NULL
|
||||
|| argv[optind][0] != '+' || argv[optind][1] == '\0')
|
||||
#endif /* GETOPT_COMPAT */
|
||||
)
|
||||
optind++;
|
||||
last_nonopt = optind;
|
||||
}
|
||||
|
||||
/* Special ARGV-element `--' means premature end of options.
|
||||
Skip it like a null option,
|
||||
then exchange with previous non-options as if it were an option,
|
||||
then skip everything else like a non-option. */
|
||||
|
||||
if (optind != argc && !strcmp (argv[optind], "--"))
|
||||
{
|
||||
optind++;
|
||||
|
||||
if (first_nonopt != last_nonopt && last_nonopt != optind)
|
||||
exchange ((char **) argv);
|
||||
else if (first_nonopt == last_nonopt)
|
||||
first_nonopt = optind;
|
||||
last_nonopt = argc;
|
||||
|
||||
optind = argc;
|
||||
}
|
||||
|
||||
/* If we have done all the ARGV-elements, stop the scan
|
||||
and back over any non-options that we skipped and permuted. */
|
||||
|
||||
if (optind == argc)
|
||||
{
|
||||
/* Set the next-arg-index to point at the non-options
|
||||
that we previously skipped, so the caller will digest them. */
|
||||
if (first_nonopt != last_nonopt)
|
||||
optind = first_nonopt;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
/* If we have come to a non-option and did not permute it,
|
||||
either stop the scan or describe it to the caller and pass it by. */
|
||||
|
||||
if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
|
||||
#ifdef GETOPT_COMPAT
|
||||
&& (longopts == NULL
|
||||
|| argv[optind][0] != '+' || argv[optind][1] == '\0')
|
||||
#endif /* GETOPT_COMPAT */
|
||||
)
|
||||
{
|
||||
if (ordering == REQUIRE_ORDER)
|
||||
return EOF;
|
||||
optarg = argv[optind++];
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We have found another option-ARGV-element.
|
||||
Start decoding its characters. */
|
||||
|
||||
nextchar = (argv[optind] + 1
|
||||
+ (longopts != NULL && argv[optind][1] == '-'));
|
||||
}
|
||||
|
||||
if (longopts != NULL
|
||||
&& ((argv[optind][0] == '-'
|
||||
&& (argv[optind][1] == '-' || long_only))
|
||||
#ifdef GETOPT_COMPAT
|
||||
|| argv[optind][0] == '+'
|
||||
#endif /* GETOPT_COMPAT */
|
||||
))
|
||||
{
|
||||
const struct option *p;
|
||||
char *s = nextchar;
|
||||
int exact = 0;
|
||||
int ambig = 0;
|
||||
const struct option *pfound = NULL;
|
||||
int indfound = 0;
|
||||
extern int strncmp();
|
||||
|
||||
while (*s && *s != '=')
|
||||
s++;
|
||||
|
||||
/* Test all options for either exact match or abbreviated matches. */
|
||||
for (p = longopts, option_index = 0; p->name;
|
||||
p++, option_index++)
|
||||
if (!strncmp (p->name, nextchar, s - nextchar))
|
||||
{
|
||||
if (s - nextchar == strlen (p->name))
|
||||
{
|
||||
/* Exact match found. */
|
||||
pfound = p;
|
||||
indfound = option_index;
|
||||
exact = 1;
|
||||
break;
|
||||
}
|
||||
else if (pfound == NULL)
|
||||
{
|
||||
/* First nonexact match found. */
|
||||
pfound = p;
|
||||
indfound = option_index;
|
||||
}
|
||||
else
|
||||
/* Second nonexact match found. */
|
||||
ambig = 1;
|
||||
}
|
||||
|
||||
if (ambig && !exact)
|
||||
{
|
||||
if (opterr)
|
||||
fprintf (stderr, "%s: option `%s' is ambiguous\n",
|
||||
argv[0], argv[optind]);
|
||||
nextchar += strlen (nextchar);
|
||||
optind++;
|
||||
return '?';
|
||||
}
|
||||
|
||||
if (pfound != NULL)
|
||||
{
|
||||
option_index = indfound;
|
||||
optind++;
|
||||
if (*s)
|
||||
{
|
||||
/* Don't test has_arg with >, because some C compilers don't
|
||||
allow it to be used on enums. */
|
||||
if (pfound->has_arg)
|
||||
optarg = s + 1;
|
||||
else
|
||||
{
|
||||
if (opterr)
|
||||
{
|
||||
if (argv[optind - 1][1] == '-')
|
||||
/* --option */
|
||||
fprintf (stderr,
|
||||
"%s: option `--%s' doesn't allow an argument\n",
|
||||
argv[0], pfound->name);
|
||||
else
|
||||
/* +option or -option */
|
||||
fprintf (stderr,
|
||||
"%s: option `%c%s' doesn't allow an argument\n",
|
||||
argv[0], argv[optind - 1][0], pfound->name);
|
||||
}
|
||||
nextchar += strlen (nextchar);
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
else if (pfound->has_arg == 1)
|
||||
{
|
||||
if (optind < argc)
|
||||
optarg = argv[optind++];
|
||||
else
|
||||
{
|
||||
if (opterr)
|
||||
fprintf (stderr, "%s: option `%s' requires an argument\n",
|
||||
argv[0], argv[optind - 1]);
|
||||
nextchar += strlen (nextchar);
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
nextchar += strlen (nextchar);
|
||||
if (longind != NULL)
|
||||
*longind = option_index;
|
||||
if (pfound->flag)
|
||||
{
|
||||
*(pfound->flag) = pfound->val;
|
||||
return 0;
|
||||
}
|
||||
return pfound->val;
|
||||
}
|
||||
/* Can't find it as a long option. If this is not getopt_long_only,
|
||||
or the option starts with '--' or is not a valid short
|
||||
option, then it's an error.
|
||||
Otherwise interpret it as a short option. */
|
||||
if (!long_only || argv[optind][1] == '-'
|
||||
#ifdef GETOPT_COMPAT
|
||||
|| argv[optind][0] == '+'
|
||||
#endif /* GETOPT_COMPAT */
|
||||
|| my_index (optstring, *nextchar) == NULL)
|
||||
{
|
||||
if (opterr)
|
||||
{
|
||||
if (argv[optind][1] == '-')
|
||||
/* --option */
|
||||
fprintf (stderr, "%s: unrecognized option `--%s'\n",
|
||||
argv[0], nextchar);
|
||||
else
|
||||
/* +option or -option */
|
||||
fprintf (stderr, "%s: unrecognized option `%c%s'\n",
|
||||
argv[0], argv[optind][0], nextchar);
|
||||
}
|
||||
nextchar = (char *) "";
|
||||
optind++;
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
/* Look at and handle the next option-character. */
|
||||
|
||||
{
|
||||
char c = *nextchar++;
|
||||
char *temp = my_index (optstring, c);
|
||||
|
||||
/* Increment `optind' when we start to process its last character. */
|
||||
if (*nextchar == '\0')
|
||||
++optind;
|
||||
|
||||
if (temp == NULL || c == ':')
|
||||
{
|
||||
if (opterr)
|
||||
{
|
||||
if (c < 040 || c >= 0177)
|
||||
fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
|
||||
argv[0], c);
|
||||
else
|
||||
fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
|
||||
}
|
||||
return '?';
|
||||
}
|
||||
if (temp[1] == ':')
|
||||
{
|
||||
if (temp[2] == ':')
|
||||
{
|
||||
/* This is an option that accepts an argument optionally. */
|
||||
if (*nextchar != '\0')
|
||||
{
|
||||
optarg = nextchar;
|
||||
optind++;
|
||||
}
|
||||
else
|
||||
optarg = 0;
|
||||
nextchar = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is an option that requires an argument. */
|
||||
if (*nextchar != '\0')
|
||||
{
|
||||
optarg = nextchar;
|
||||
/* If we end this ARGV-element by taking the rest as an arg,
|
||||
we must advance to the next element now. */
|
||||
optind++;
|
||||
}
|
||||
else if (optind == argc)
|
||||
{
|
||||
if (opterr)
|
||||
fprintf (stderr, "%s: option `-%c' requires an argument\n",
|
||||
argv[0], c);
|
||||
c = '?';
|
||||
}
|
||||
else
|
||||
/* We already incremented `optind' once;
|
||||
increment it again when taking next ARGV-elt as argument. */
|
||||
optarg = argv[optind++];
|
||||
nextchar = NULL;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
getopt (argc, argv, optstring)
|
||||
int argc;
|
||||
char *const *argv;
|
||||
const char *optstring;
|
||||
{
|
||||
return _getopt_internal (argc, argv, optstring,
|
||||
(const struct option *) 0,
|
||||
(int *) 0,
|
||||
0);
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
/* Compile with -DTEST to make an executable for use in testing
|
||||
the above definition of `getopt'. */
|
||||
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int c;
|
||||
int digit_optind = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int this_option_optind = optind ? optind : 1;
|
||||
|
||||
c = getopt (argc, argv, "abc:d:0123456789");
|
||||
if (c == EOF)
|
||||
break;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
if (digit_optind != 0 && digit_optind != this_option_optind)
|
||||
printf ("digits occur in two different argv-elements.\n");
|
||||
digit_optind = this_option_optind;
|
||||
printf ("option %c\n", c);
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
printf ("option a\n");
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
printf ("option b\n");
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
printf ("option c with value `%s'\n", optarg);
|
||||
break;
|
||||
|
||||
case '?':
|
||||
break;
|
||||
|
||||
default:
|
||||
printf ("?? getopt returned character code 0%o ??\n", c);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
{
|
||||
printf ("non-option ARGV-elements: ");
|
||||
while (optind < argc)
|
||||
printf ("%s ", argv[optind++]);
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
#endif /* TEST */
|
||||
128
gnu/usr.bin/awk/getopt.h
Normal file
128
gnu/usr.bin/awk/getopt.h
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
/* Declarations for getopt.
|
||||
Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Library 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 Library General Public
|
||||
License along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifndef _GETOPT_H
|
||||
#define _GETOPT_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* For communication from `getopt' to the caller.
|
||||
When `getopt' finds an option that takes an argument,
|
||||
the argument value is returned here.
|
||||
Also, when `ordering' is RETURN_IN_ORDER,
|
||||
each non-option ARGV-element is returned here. */
|
||||
|
||||
extern char *optarg;
|
||||
|
||||
/* Index in ARGV of the next element to be scanned.
|
||||
This is used for communication to and from the caller
|
||||
and for communication between successive calls to `getopt'.
|
||||
|
||||
On entry to `getopt', zero means this is the first call; initialize.
|
||||
|
||||
When `getopt' returns EOF, this is the index of the first of the
|
||||
non-option elements that the caller should itself scan.
|
||||
|
||||
Otherwise, `optind' communicates from one call to the next
|
||||
how much of ARGV has been scanned so far. */
|
||||
|
||||
extern int optind;
|
||||
|
||||
/* Callers store zero here to inhibit the error message `getopt' prints
|
||||
for unrecognized options. */
|
||||
|
||||
extern int opterr;
|
||||
|
||||
/* Describe the long-named options requested by the application.
|
||||
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
|
||||
of `struct option' terminated by an element containing a name which is
|
||||
zero.
|
||||
|
||||
The field `has_arg' is:
|
||||
no_argument (or 0) if the option does not take an argument,
|
||||
required_argument (or 1) if the option requires an argument,
|
||||
optional_argument (or 2) if the option takes an optional argument.
|
||||
|
||||
If the field `flag' is not NULL, it points to a variable that is set
|
||||
to the value given in the field `val' when the option is found, but
|
||||
left unchanged if the option is not found.
|
||||
|
||||
To have a long-named option do something other than set an `int' to
|
||||
a compiled-in constant, such as set a value from `optarg', set the
|
||||
option's `flag' field to zero and its `val' field to a nonzero
|
||||
value (the equivalent single-letter option character, if there is
|
||||
one). For long options that have a zero `flag' field, `getopt'
|
||||
returns the contents of the `val' field. */
|
||||
|
||||
struct option
|
||||
{
|
||||
#if __STDC__
|
||||
const char *name;
|
||||
#else
|
||||
char *name;
|
||||
#endif
|
||||
/* has_arg can't be an enum because some compilers complain about
|
||||
type mismatches in all the code that assumes it is an int. */
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
|
||||
/* Names for the values of the `has_arg' field of `struct option'. */
|
||||
|
||||
enum _argtype
|
||||
{
|
||||
no_argument,
|
||||
required_argument,
|
||||
optional_argument
|
||||
};
|
||||
|
||||
#if __STDC__
|
||||
#if defined(__GNU_LIBRARY__)
|
||||
/* Many other libraries have conflicting prototypes for getopt, with
|
||||
differences in the consts, in stdlib.h. To avoid compilation
|
||||
errors, only prototype getopt for the GNU C library. */
|
||||
extern int getopt (int argc, char *const *argv, const char *shortopts);
|
||||
#else /* not __GNU_LIBRARY__ */
|
||||
extern int getopt ();
|
||||
#endif /* not __GNU_LIBRARY__ */
|
||||
extern int getopt_long (int argc, char *const *argv, const char *shortopts,
|
||||
const struct option *longopts, int *longind);
|
||||
extern int getopt_long_only (int argc, char *const *argv,
|
||||
const char *shortopts,
|
||||
const struct option *longopts, int *longind);
|
||||
|
||||
/* Internal only. Users should not call this directly. */
|
||||
extern int _getopt_internal (int argc, char *const *argv,
|
||||
const char *shortopts,
|
||||
const struct option *longopts, int *longind,
|
||||
int long_only);
|
||||
#else /* not __STDC__ */
|
||||
extern int getopt ();
|
||||
extern int getopt_long ();
|
||||
extern int getopt_long_only ();
|
||||
|
||||
extern int _getopt_internal ();
|
||||
#endif /* not __STDC__ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _GETOPT_H */
|
||||
160
gnu/usr.bin/awk/getopt1.c
Normal file
160
gnu/usr.bin/awk/getopt1.c
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
/* Getopt for GNU.
|
||||
Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the libiberty library.
|
||||
Libiberty is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
Libiberty 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with libiberty; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifdef LIBC
|
||||
/* For when compiled as part of the GNU C library. */
|
||||
#include <ansidecl.h>
|
||||
#endif
|
||||
|
||||
#include "getopt.h"
|
||||
|
||||
#ifndef __STDC__
|
||||
#define const
|
||||
#endif
|
||||
|
||||
#if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__) || defined (LIBC)
|
||||
#include <stdlib.h>
|
||||
#else /* STDC_HEADERS or __GNU_LIBRARY__ */
|
||||
char *getenv ();
|
||||
#endif /* STDC_HEADERS or __GNU_LIBRARY__ */
|
||||
|
||||
#if !defined (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);
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int c;
|
||||
int digit_optind = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int this_option_optind = optind ? optind : 1;
|
||||
int option_index = 0;
|
||||
static struct option long_options[] =
|
||||
{
|
||||
{"add", 1, 0, 0},
|
||||
{"append", 0, 0, 0},
|
||||
{"delete", 1, 0, 0},
|
||||
{"verbose", 0, 0, 0},
|
||||
{"create", 0, 0, 0},
|
||||
{"file", 1, 0, 0},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
c = getopt_long (argc, argv, "abc:d:0123456789",
|
||||
long_options, &option_index);
|
||||
if (c == EOF)
|
||||
break;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 0:
|
||||
printf ("option %s", long_options[option_index].name);
|
||||
if (optarg)
|
||||
printf (" with arg %s", optarg);
|
||||
printf ("\n");
|
||||
break;
|
||||
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
if (digit_optind != 0 && digit_optind != this_option_optind)
|
||||
printf ("digits occur in two different argv-elements.\n");
|
||||
digit_optind = this_option_optind;
|
||||
printf ("option %c\n", c);
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
printf ("option a\n");
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
printf ("option b\n");
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
printf ("option c with value `%s'\n", optarg);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
printf ("option d with value `%s'\n", optarg);
|
||||
break;
|
||||
|
||||
case '?':
|
||||
break;
|
||||
|
||||
default:
|
||||
printf ("?? getopt returned character code 0%o ??\n", c);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
{
|
||||
printf ("non-option ARGV-elements: ");
|
||||
while (optind < argc)
|
||||
printf ("%s ", argv[optind++]);
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
#endif /* TEST */
|
||||
1207
gnu/usr.bin/awk/io.c
Normal file
1207
gnu/usr.bin/awk/io.c
Normal file
File diff suppressed because it is too large
Load diff
318
gnu/usr.bin/awk/iop.c
Normal file
318
gnu/usr.bin/awk/iop.c
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
* iop.c - do i/o related things.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GAWK, the GNU implementation of the
|
||||
* AWK Progamming Language.
|
||||
*
|
||||
* GAWK 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.
|
||||
*
|
||||
* GAWK 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 GAWK; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "awk.h"
|
||||
|
||||
#ifndef atarist
|
||||
#define INVALID_HANDLE (-1)
|
||||
#else
|
||||
#include <stddef.h>
|
||||
#include <fcntl.h>
|
||||
#define INVALID_HANDLE (__SMALLEST_VALID_HANDLE - 1)
|
||||
#endif /* atarist */
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
int bufsize = 8192;
|
||||
|
||||
void
|
||||
fatal(s)
|
||||
char *s;
|
||||
{
|
||||
printf("%s\n", s);
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
optimal_bufsize(fd)
|
||||
int fd;
|
||||
{
|
||||
struct stat stb;
|
||||
|
||||
#ifdef VMS
|
||||
/*
|
||||
* These values correspond with the RMS multi-block count used by
|
||||
* vms_open() in vms/vms_misc.c.
|
||||
*/
|
||||
if (isatty(fd) > 0)
|
||||
return BUFSIZ;
|
||||
else if (fstat(fd, &stb) < 0)
|
||||
return 8*512; /* conservative in case of DECnet access */
|
||||
else
|
||||
return 24*512;
|
||||
|
||||
#else
|
||||
/*
|
||||
* System V doesn't have the file system block size in the
|
||||
* stat structure. So we have to make some sort of reasonable
|
||||
* guess. We use stdio's BUFSIZ, since that is what it was
|
||||
* meant for in the first place.
|
||||
*/
|
||||
#ifdef BLKSIZE_MISSING
|
||||
#define DEFBLKSIZE BUFSIZ
|
||||
#else
|
||||
#define DEFBLKSIZE (stb.st_blksize ? stb.st_blksize : BUFSIZ)
|
||||
#endif
|
||||
|
||||
#ifdef TEST
|
||||
return bufsize;
|
||||
#else
|
||||
#ifndef atarist
|
||||
if (isatty(fd))
|
||||
#else
|
||||
/*
|
||||
* On ST redirected stdin does not have a name attached
|
||||
* (this could be hard to do to) and fstat would fail
|
||||
*/
|
||||
if (0 == fd || isatty(fd))
|
||||
#endif /*atarist */
|
||||
return BUFSIZ;
|
||||
#ifndef BLKSIZE_MISSING
|
||||
/* VMS POSIX 1.0: st_blksize is never assigned a value, so zero it */
|
||||
stb.st_blksize = 0;
|
||||
#endif
|
||||
if (fstat(fd, &stb) == -1)
|
||||
fatal("can't stat fd %d (%s)", fd, strerror(errno));
|
||||
if (lseek(fd, (off_t)0, 0) == -1)
|
||||
return DEFBLKSIZE;
|
||||
return ((int) (stb.st_size < DEFBLKSIZE ? stb.st_size : DEFBLKSIZE));
|
||||
#endif /*! TEST */
|
||||
#endif /*! VMS */
|
||||
}
|
||||
|
||||
IOBUF *
|
||||
iop_alloc(fd)
|
||||
int fd;
|
||||
{
|
||||
IOBUF *iop;
|
||||
|
||||
if (fd == INVALID_HANDLE)
|
||||
return NULL;
|
||||
emalloc(iop, IOBUF *, sizeof(IOBUF), "iop_alloc");
|
||||
iop->flag = 0;
|
||||
if (isatty(fd))
|
||||
iop->flag |= IOP_IS_TTY;
|
||||
iop->size = optimal_bufsize(fd);
|
||||
iop->secsiz = -2;
|
||||
errno = 0;
|
||||
iop->fd = fd;
|
||||
iop->off = iop->buf = NULL;
|
||||
iop->cnt = 0;
|
||||
return iop;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the next record. Uses a "split buffer" where the latter part is
|
||||
* the normal read buffer and the head part is an "overflow" area that is used
|
||||
* when a record spans the end of the normal buffer, in which case the first
|
||||
* part of the record is copied into the overflow area just before the
|
||||
* normal buffer. Thus, the eventual full record can be returned as a
|
||||
* contiguous area of memory with a minimum of copying. The overflow area
|
||||
* is expanded as needed, so that records are unlimited in length.
|
||||
* We also mark both the end of the buffer and the end of the read() with
|
||||
* a sentinel character (the current record separator) so that the inside
|
||||
* loop can run as a single test.
|
||||
*/
|
||||
int
|
||||
get_a_record(out, iop, grRS, errcode)
|
||||
char **out;
|
||||
IOBUF *iop;
|
||||
register int grRS;
|
||||
int *errcode;
|
||||
{
|
||||
register char *bp = iop->off;
|
||||
char *bufend;
|
||||
char *start = iop->off; /* beginning of record */
|
||||
int saw_newline;
|
||||
char rs;
|
||||
int eat_whitespace;
|
||||
|
||||
if (iop->cnt == EOF) /* previous read hit EOF */
|
||||
return EOF;
|
||||
|
||||
if (grRS == 0) { /* special case: grRS == "" */
|
||||
rs = '\n';
|
||||
eat_whitespace = 0;
|
||||
saw_newline = 0;
|
||||
} else
|
||||
rs = (char) grRS;
|
||||
|
||||
/* set up sentinel */
|
||||
if (iop->buf) {
|
||||
bufend = iop->buf + iop->size + iop->secsiz;
|
||||
*bufend = rs;
|
||||
} else
|
||||
bufend = NULL;
|
||||
|
||||
for (;;) { /* break on end of record, read error or EOF */
|
||||
|
||||
/* Following code is entered on the first call of this routine
|
||||
* for a new iop, or when we scan to the end of the buffer.
|
||||
* In the latter case, we copy the current partial record to
|
||||
* the space preceding the normal read buffer. If necessary,
|
||||
* we expand this space. This is done so that we can return
|
||||
* the record as a contiguous area of memory.
|
||||
*/
|
||||
if ((iop->flag & IOP_IS_INTERNAL) == 0 && bp >= bufend) {
|
||||
char *oldbuf = NULL;
|
||||
char *oldsplit = iop->buf + iop->secsiz;
|
||||
long len; /* record length so far */
|
||||
|
||||
if ((iop->flag & IOP_IS_INTERNAL) != 0)
|
||||
cant_happen();
|
||||
|
||||
len = bp - start;
|
||||
if (len > iop->secsiz) {
|
||||
/* expand secondary buffer */
|
||||
if (iop->secsiz == -2)
|
||||
iop->secsiz = 256;
|
||||
while (len > iop->secsiz)
|
||||
iop->secsiz *= 2;
|
||||
oldbuf = iop->buf;
|
||||
emalloc(iop->buf, char *,
|
||||
iop->size+iop->secsiz+2, "get_a_record");
|
||||
bufend = iop->buf + iop->size + iop->secsiz;
|
||||
*bufend = rs;
|
||||
}
|
||||
if (len > 0) {
|
||||
char *newsplit = iop->buf + iop->secsiz;
|
||||
|
||||
if (start < oldsplit) {
|
||||
memcpy(newsplit - len, start,
|
||||
oldsplit - start);
|
||||
memcpy(newsplit - (bp - oldsplit),
|
||||
oldsplit, bp - oldsplit);
|
||||
} else
|
||||
memcpy(newsplit - len, start, len);
|
||||
}
|
||||
bp = iop->end = iop->off = iop->buf + iop->secsiz;
|
||||
start = bp - len;
|
||||
if (oldbuf) {
|
||||
free(oldbuf);
|
||||
oldbuf = NULL;
|
||||
}
|
||||
}
|
||||
/* Following code is entered whenever we have no more data to
|
||||
* scan. In most cases this will read into the beginning of
|
||||
* the main buffer, but in some cases (terminal, pipe etc.)
|
||||
* we may be doing smallish reads into more advanced positions.
|
||||
*/
|
||||
if (bp >= iop->end) {
|
||||
if ((iop->flag & IOP_IS_INTERNAL) != 0) {
|
||||
iop->cnt = EOF;
|
||||
break;
|
||||
}
|
||||
iop->cnt = read(iop->fd, iop->end, bufend - iop->end);
|
||||
if (iop->cnt == -1) {
|
||||
if (! do_unix && errcode != NULL) {
|
||||
*errcode = errno;
|
||||
iop->cnt = EOF;
|
||||
break;
|
||||
} else
|
||||
fatal("error reading input: %s",
|
||||
strerror(errno));
|
||||
} else if (iop->cnt == 0) {
|
||||
iop->cnt = EOF;
|
||||
break;
|
||||
}
|
||||
iop->end += iop->cnt;
|
||||
*iop->end = rs;
|
||||
}
|
||||
if (grRS == 0) {
|
||||
extern int default_FS;
|
||||
|
||||
if (default_FS && (bp == start || eat_whitespace)) {
|
||||
while (bp < iop->end && isspace(*bp))
|
||||
bp++;
|
||||
if (bp == iop->end) {
|
||||
eat_whitespace = 1;
|
||||
continue;
|
||||
} else
|
||||
eat_whitespace = 0;
|
||||
}
|
||||
if (saw_newline && *bp == rs) {
|
||||
bp++;
|
||||
break;
|
||||
}
|
||||
saw_newline = 0;
|
||||
}
|
||||
|
||||
while (*bp++ != rs)
|
||||
;
|
||||
|
||||
if (bp <= iop->end) {
|
||||
if (grRS == 0)
|
||||
saw_newline = 1;
|
||||
else
|
||||
break;
|
||||
} else
|
||||
bp--;
|
||||
|
||||
if ((iop->flag & IOP_IS_INTERNAL) != 0)
|
||||
iop->cnt = bp - start;
|
||||
}
|
||||
if (iop->cnt == EOF
|
||||
&& (((iop->flag & IOP_IS_INTERNAL) != 0) || start == bp))
|
||||
return EOF;
|
||||
|
||||
iop->off = bp;
|
||||
bp--;
|
||||
if (*bp != rs)
|
||||
bp++;
|
||||
*bp = '\0';
|
||||
if (grRS == 0) {
|
||||
if (*--bp == rs)
|
||||
*bp = '\0';
|
||||
else
|
||||
bp++;
|
||||
}
|
||||
|
||||
*out = start;
|
||||
return bp - start;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
IOBUF *iop;
|
||||
char *out;
|
||||
int cnt;
|
||||
char rs[2];
|
||||
|
||||
rs[0] = 0;
|
||||
if (argc > 1)
|
||||
bufsize = atoi(argv[1]);
|
||||
if (argc > 2)
|
||||
rs[0] = *argv[2];
|
||||
iop = iop_alloc(0);
|
||||
while ((cnt = get_a_record(&out, iop, rs[0], NULL)) > 0) {
|
||||
fwrite(out, 1, cnt, stdout);
|
||||
fwrite(rs, 1, 1, stdout);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
731
gnu/usr.bin/awk/main.c
Normal file
731
gnu/usr.bin/awk/main.c
Normal file
|
|
@ -0,0 +1,731 @@
|
|||
/*
|
||||
* main.c -- Expression tree constructors and main program for gawk.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GAWK, the GNU implementation of the
|
||||
* AWK Progamming Language.
|
||||
*
|
||||
* GAWK 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.
|
||||
*
|
||||
* GAWK 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 GAWK; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "getopt.h"
|
||||
#include "awk.h"
|
||||
#include "patchlevel.h"
|
||||
|
||||
static void usage P((int exitval));
|
||||
static void copyleft P((void));
|
||||
static void cmdline_fs P((char *str));
|
||||
static void init_args P((int argc0, int argc, char *argv0, char **argv));
|
||||
static void init_vars P((void));
|
||||
static void pre_assign P((char *v));
|
||||
SIGTYPE catchsig P((int sig, int code));
|
||||
static void gawk_option P((char *optstr));
|
||||
static void nostalgia P((void));
|
||||
static void version P((void));
|
||||
char *gawk_name P((char *filespec));
|
||||
|
||||
#ifdef MSDOS
|
||||
extern int isatty P((int));
|
||||
#endif
|
||||
|
||||
extern void resetup P((void));
|
||||
|
||||
/* These nodes store all the special variables AWK uses */
|
||||
NODE *FS_node, *NF_node, *RS_node, *NR_node;
|
||||
NODE *FILENAME_node, *OFS_node, *ORS_node, *OFMT_node;
|
||||
NODE *CONVFMT_node;
|
||||
NODE *ERRNO_node;
|
||||
NODE *FNR_node, *RLENGTH_node, *RSTART_node, *SUBSEP_node;
|
||||
NODE *ENVIRON_node, *IGNORECASE_node;
|
||||
NODE *ARGC_node, *ARGV_node, *ARGIND_node;
|
||||
NODE *FIELDWIDTHS_node;
|
||||
|
||||
int NF;
|
||||
int NR;
|
||||
int FNR;
|
||||
int IGNORECASE;
|
||||
char *RS;
|
||||
char *OFS;
|
||||
char *ORS;
|
||||
char *OFMT;
|
||||
char *CONVFMT;
|
||||
|
||||
/*
|
||||
* The parse tree and field nodes are stored here. Parse_end is a dummy item
|
||||
* used to free up unneeded fields without freeing the program being run
|
||||
*/
|
||||
int errcount = 0; /* error counter, used by yyerror() */
|
||||
|
||||
/* The global null string */
|
||||
NODE *Nnull_string;
|
||||
|
||||
/* The name the program was invoked under, for error messages */
|
||||
const char *myname;
|
||||
|
||||
/* A block of AWK code to be run before running the program */
|
||||
NODE *begin_block = 0;
|
||||
|
||||
/* A block of AWK code to be run after the last input file */
|
||||
NODE *end_block = 0;
|
||||
|
||||
int exiting = 0; /* Was an "exit" statement executed? */
|
||||
int exit_val = 0; /* optional exit value */
|
||||
|
||||
#if defined(YYDEBUG) || defined(DEBUG)
|
||||
extern int yydebug;
|
||||
#endif
|
||||
|
||||
struct src *srcfiles = NULL; /* source file name(s) */
|
||||
int numfiles = -1; /* how many source files */
|
||||
|
||||
int do_unix = 0; /* turn off gnu extensions */
|
||||
int do_posix = 0; /* turn off gnu and unix extensions */
|
||||
int do_lint = 0; /* provide warnings about questionable stuff */
|
||||
int do_nostalgia = 0; /* provide a blast from the past */
|
||||
|
||||
int in_begin_rule = 0; /* we're in a BEGIN rule */
|
||||
int in_end_rule = 0; /* we're in a END rule */
|
||||
|
||||
int output_is_tty = 0; /* control flushing of output */
|
||||
|
||||
extern char *version_string; /* current version, for printing */
|
||||
|
||||
NODE *expression_value;
|
||||
|
||||
static struct option optab[] = {
|
||||
{ "compat", no_argument, & do_unix, 1 },
|
||||
{ "lint", no_argument, & do_lint, 1 },
|
||||
{ "posix", no_argument, & do_posix, 1 },
|
||||
{ "nostalgia", no_argument, & do_nostalgia, 1 },
|
||||
{ "copyleft", no_argument, NULL, 'C' },
|
||||
{ "copyright", no_argument, NULL, 'C' },
|
||||
{ "field-separator", required_argument, NULL, 'F' },
|
||||
{ "file", required_argument, NULL, 'f' },
|
||||
{ "assign", required_argument, NULL, 'v' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ "usage", no_argument, NULL, 'u' },
|
||||
{ "help", no_argument, NULL, 'u' },
|
||||
{ "source", required_argument, NULL, 's' },
|
||||
#ifdef DEBUG
|
||||
{ "parsedebug", no_argument, NULL, 'D' },
|
||||
#endif
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int c;
|
||||
char *scan;
|
||||
extern int optind;
|
||||
extern int opterr;
|
||||
extern char *optarg;
|
||||
int i;
|
||||
|
||||
(void) signal(SIGFPE, (SIGTYPE (*) P((int))) catchsig);
|
||||
(void) signal(SIGSEGV, (SIGTYPE (*) P((int))) catchsig);
|
||||
#ifdef SIGBUS
|
||||
(void) signal(SIGBUS, (SIGTYPE (*) P((int))) catchsig);
|
||||
#endif
|
||||
|
||||
myname = gawk_name(argv[0]);
|
||||
argv[0] = (char *)myname;
|
||||
#ifdef VMS
|
||||
vms_arg_fixup(&argc, &argv); /* emulate redirection, expand wildcards */
|
||||
#endif
|
||||
|
||||
/* remove sccs gunk */
|
||||
if (strncmp(version_string, "@(#)", 4) == 0)
|
||||
version_string += 4;
|
||||
|
||||
if (argc < 2)
|
||||
usage(1);
|
||||
|
||||
/* initialize the null string */
|
||||
Nnull_string = make_string("", 0);
|
||||
Nnull_string->numbr = 0.0;
|
||||
Nnull_string->type = Node_val;
|
||||
Nnull_string->flags = (PERM|STR|STRING|NUM|NUMBER);
|
||||
|
||||
/* Set up the special variables */
|
||||
|
||||
/*
|
||||
* Note that this must be done BEFORE arg parsing else -F
|
||||
* breaks horribly
|
||||
*/
|
||||
init_vars();
|
||||
|
||||
/* worst case */
|
||||
emalloc(srcfiles, struct src *, argc * sizeof(struct src), "main");
|
||||
memset(srcfiles, '\0', argc * sizeof(struct src));
|
||||
|
||||
/* Tell the regex routines how they should work. . . */
|
||||
resetup();
|
||||
|
||||
/* we do error messages ourselves on invalid options */
|
||||
opterr = 0;
|
||||
|
||||
/* the + on the front tells GNU getopt not to rearrange argv */
|
||||
while ((c = getopt_long(argc, argv, "+F:f:v:W:", optab, NULL)) != EOF) {
|
||||
if (do_posix)
|
||||
opterr = 1;
|
||||
switch (c) {
|
||||
case 'F':
|
||||
cmdline_fs(optarg);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
/*
|
||||
* a la MKS awk, allow multiple -f options.
|
||||
* this makes function libraries real easy.
|
||||
* most of the magic is in the scanner.
|
||||
*/
|
||||
/* The following is to allow for whitespace at the end
|
||||
* of a #! /bin/gawk line in an executable file
|
||||
*/
|
||||
scan = optarg;
|
||||
while (isspace(*scan))
|
||||
scan++;
|
||||
++numfiles;
|
||||
srcfiles[numfiles].stype = SOURCEFILE;
|
||||
if (*scan == '\0')
|
||||
srcfiles[numfiles].val = argv[optind++];
|
||||
else
|
||||
srcfiles[numfiles].val = optarg;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
pre_assign(optarg);
|
||||
break;
|
||||
|
||||
case 'W': /* gawk specific options */
|
||||
gawk_option(optarg);
|
||||
break;
|
||||
|
||||
/* These can only come from long form options */
|
||||
case 'V':
|
||||
version();
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
copyleft();
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
usage(0);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if (strlen(optarg) == 0)
|
||||
warning("empty argument to --source ignored");
|
||||
else {
|
||||
srcfiles[++numfiles].stype = CMDLINE;
|
||||
srcfiles[numfiles].val = optarg;
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef DEBUG
|
||||
case 'D':
|
||||
yydebug = 2;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case '?':
|
||||
default:
|
||||
/*
|
||||
* New behavior. If not posix, an unrecognized
|
||||
* option stops argument processing so that it can
|
||||
* go into ARGV for the awk program to see. This
|
||||
* makes use of ``#! /bin/gawk -f'' easier.
|
||||
*/
|
||||
if (! do_posix)
|
||||
goto out;
|
||||
/* else
|
||||
let getopt print error message for us */
|
||||
break;
|
||||
}
|
||||
}
|
||||
out:
|
||||
|
||||
if (do_nostalgia)
|
||||
nostalgia();
|
||||
|
||||
/* POSIX compliance also implies no Unix extensions either */
|
||||
if (do_posix)
|
||||
do_unix = 1;
|
||||
|
||||
#ifdef DEBUG
|
||||
setbuf(stdout, (char *) NULL); /* make debugging easier */
|
||||
#endif
|
||||
if (isatty(fileno(stdout)))
|
||||
output_is_tty = 1;
|
||||
/* No -f or --source options, use next arg */
|
||||
if (numfiles == -1) {
|
||||
if (optind > argc - 1) /* no args left */
|
||||
usage(1);
|
||||
srcfiles[++numfiles].stype = CMDLINE;
|
||||
srcfiles[numfiles].val = argv[optind];
|
||||
optind++;
|
||||
}
|
||||
init_args(optind, argc, (char *) myname, argv);
|
||||
(void) tokexpand();
|
||||
|
||||
/* Read in the program */
|
||||
if (yyparse() || errcount)
|
||||
exit(1);
|
||||
|
||||
/* Set up the field variables */
|
||||
init_fields();
|
||||
|
||||
if (begin_block) {
|
||||
in_begin_rule = 1;
|
||||
(void) interpret(begin_block);
|
||||
}
|
||||
in_begin_rule = 0;
|
||||
if (!exiting && (expression_value || end_block))
|
||||
do_input();
|
||||
if (end_block) {
|
||||
in_end_rule = 1;
|
||||
(void) interpret(end_block);
|
||||
}
|
||||
in_end_rule = 0;
|
||||
if (close_io() != 0 && exit_val == 0)
|
||||
exit_val = 1;
|
||||
exit(exit_val); /* more portable */
|
||||
return exit_val; /* to suppress warnings */
|
||||
}
|
||||
|
||||
/* usage --- print usage information and exit */
|
||||
|
||||
static void
|
||||
usage(exitval)
|
||||
int exitval;
|
||||
{
|
||||
char *opt1 = " -f progfile [--]";
|
||||
char *opt2 = " [--] 'program'";
|
||||
char *regops = " [POSIX or GNU style options]";
|
||||
|
||||
version();
|
||||
fprintf(stderr, "usage: %s%s%s file ...\n %s%s%s file ...\n",
|
||||
myname, regops, opt1, myname, regops, opt2);
|
||||
|
||||
/* GNU long options info. Gack. */
|
||||
fputs("\nPOSIX options:\t\tGNU long options:\n", stderr);
|
||||
fputs("\t-f progfile\t\t--file=progfile\n", stderr);
|
||||
fputs("\t-F fs\t\t\t--field-separator=fs\n", stderr);
|
||||
fputs("\t-v var=val\t\t--assign=var=val\n", stderr);
|
||||
fputs("\t-W compat\t\t--compat\n", stderr);
|
||||
fputs("\t-W copyleft\t\t--copyleft\n", stderr);
|
||||
fputs("\t-W copyright\t\t--copyright\n", stderr);
|
||||
fputs("\t-W help\t\t\t--help\n", stderr);
|
||||
fputs("\t-W lint\t\t\t--lint\n", stderr);
|
||||
#if 0
|
||||
fputs("\t-W nostalgia\t\t--nostalgia\n", stderr);
|
||||
#endif
|
||||
#ifdef DEBUG
|
||||
fputs("\t-W parsedebug\t\t--parsedebug\n", stderr);
|
||||
#endif
|
||||
fputs("\t-W posix\t\t--posix\n", stderr);
|
||||
fputs("\t-W source=program-text\t--source=program-text\n", stderr);
|
||||
fputs("\t-W usage\t\t--usage\n", stderr);
|
||||
fputs("\t-W version\t\t--version\n", stderr);
|
||||
exit(exitval);
|
||||
}
|
||||
|
||||
static void
|
||||
copyleft ()
|
||||
{
|
||||
static char blurb_part1[] =
|
||||
"Copyright (C) 1989, 1991, 1992, Free Software Foundation.\n\
|
||||
\n\
|
||||
This program is free software; you can redistribute it and/or modify\n\
|
||||
it under the terms of the GNU General Public License as published by\n\
|
||||
the Free Software Foundation; either version 2 of the License, or\n\
|
||||
(at your option) any later version.\n\
|
||||
\n";
|
||||
static char blurb_part2[] =
|
||||
"This program is distributed in the hope that it will be useful,\n\
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\
|
||||
GNU General Public License for more details.\n\
|
||||
\n";
|
||||
static char blurb_part3[] =
|
||||
"You should have received a copy of the GNU General Public License\n\
|
||||
along with this program; if not, write to the Free Software\n\
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n";
|
||||
|
||||
version();
|
||||
fputs(blurb_part1, stderr);
|
||||
fputs(blurb_part2, stderr);
|
||||
fputs(blurb_part3, stderr);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
static void
|
||||
cmdline_fs(str)
|
||||
char *str;
|
||||
{
|
||||
register NODE **tmp;
|
||||
int len = strlen(str);
|
||||
|
||||
tmp = get_lhs(FS_node, (Func_ptr *) 0);
|
||||
unref(*tmp);
|
||||
/*
|
||||
* Only if in full compatibility mode check for the stupid special
|
||||
* case so -F\t works as documented in awk even though the shell
|
||||
* hands us -Ft. Bleah!
|
||||
*
|
||||
* Thankfully, Posix didn't propogate this "feature".
|
||||
*/
|
||||
if (str[0] == 't' && str[1] == '\0') {
|
||||
if (do_lint)
|
||||
warning("-Ft does not set FS to tab in POSIX awk");
|
||||
if (do_unix && ! do_posix)
|
||||
str[0] = '\t';
|
||||
}
|
||||
*tmp = make_str_node(str, len, SCAN); /* do process escapes */
|
||||
set_FS();
|
||||
}
|
||||
|
||||
static void
|
||||
init_args(argc0, argc, argv0, argv)
|
||||
int argc0, argc;
|
||||
char *argv0;
|
||||
char **argv;
|
||||
{
|
||||
int i, j;
|
||||
NODE **aptr;
|
||||
|
||||
ARGV_node = install("ARGV", node(Nnull_string, Node_var, (NODE *)NULL));
|
||||
aptr = assoc_lookup(ARGV_node, tmp_number(0.0));
|
||||
*aptr = make_string(argv0, strlen(argv0));
|
||||
(*aptr)->flags |= MAYBE_NUM;
|
||||
for (i = argc0, j = 1; i < argc; i++) {
|
||||
aptr = assoc_lookup(ARGV_node, tmp_number((AWKNUM) j));
|
||||
*aptr = make_string(argv[i], strlen(argv[i]));
|
||||
(*aptr)->flags |= MAYBE_NUM;
|
||||
j++;
|
||||
}
|
||||
ARGC_node = install("ARGC",
|
||||
node(make_number((AWKNUM) j), Node_var, (NODE *) NULL));
|
||||
}
|
||||
|
||||
/*
|
||||
* Set all the special variables to their initial values.
|
||||
*/
|
||||
struct varinit {
|
||||
NODE **spec;
|
||||
char *name;
|
||||
NODETYPE type;
|
||||
char *strval;
|
||||
AWKNUM numval;
|
||||
Func_ptr assign;
|
||||
};
|
||||
static struct varinit varinit[] = {
|
||||
{&NF_node, "NF", Node_NF, 0, -1, set_NF },
|
||||
{&FIELDWIDTHS_node, "FIELDWIDTHS", Node_FIELDWIDTHS, "", 0, 0 },
|
||||
{&NR_node, "NR", Node_NR, 0, 0, set_NR },
|
||||
{&FNR_node, "FNR", Node_FNR, 0, 0, set_FNR },
|
||||
{&FS_node, "FS", Node_FS, " ", 0, 0 },
|
||||
{&RS_node, "RS", Node_RS, "\n", 0, set_RS },
|
||||
{&IGNORECASE_node, "IGNORECASE", Node_IGNORECASE, 0, 0, set_IGNORECASE },
|
||||
{&FILENAME_node, "FILENAME", Node_var, "-", 0, 0 },
|
||||
{&OFS_node, "OFS", Node_OFS, " ", 0, set_OFS },
|
||||
{&ORS_node, "ORS", Node_ORS, "\n", 0, set_ORS },
|
||||
{&OFMT_node, "OFMT", Node_OFMT, "%.6g", 0, set_OFMT },
|
||||
{&CONVFMT_node, "CONVFMT", Node_CONVFMT, "%.6g", 0, set_CONVFMT },
|
||||
{&RLENGTH_node, "RLENGTH", Node_var, 0, 0, 0 },
|
||||
{&RSTART_node, "RSTART", Node_var, 0, 0, 0 },
|
||||
{&SUBSEP_node, "SUBSEP", Node_var, "\034", 0, 0 },
|
||||
{&ARGIND_node, "ARGIND", Node_var, 0, 0, 0 },
|
||||
{&ERRNO_node, "ERRNO", Node_var, 0, 0, 0 },
|
||||
{0, 0, Node_illegal, 0, 0, 0 },
|
||||
};
|
||||
|
||||
static void
|
||||
init_vars()
|
||||
{
|
||||
register struct varinit *vp;
|
||||
|
||||
for (vp = varinit; vp->name; vp++) {
|
||||
*(vp->spec) = install(vp->name,
|
||||
node(vp->strval == 0 ? make_number(vp->numval)
|
||||
: make_string(vp->strval, strlen(vp->strval)),
|
||||
vp->type, (NODE *) NULL));
|
||||
if (vp->assign)
|
||||
(*(vp->assign))();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
load_environ()
|
||||
{
|
||||
#if !defined(MSDOS) && !(defined(VMS) && defined(__DECC))
|
||||
extern char **environ;
|
||||
#endif
|
||||
register char *var, *val;
|
||||
NODE **aptr;
|
||||
register int i;
|
||||
|
||||
ENVIRON_node = install("ENVIRON",
|
||||
node(Nnull_string, Node_var, (NODE *) NULL));
|
||||
for (i = 0; environ[i]; i++) {
|
||||
static char nullstr[] = "";
|
||||
|
||||
var = environ[i];
|
||||
val = strchr(var, '=');
|
||||
if (val)
|
||||
*val++ = '\0';
|
||||
else
|
||||
val = nullstr;
|
||||
aptr = assoc_lookup(ENVIRON_node, tmp_string(var, strlen (var)));
|
||||
*aptr = make_string(val, strlen (val));
|
||||
(*aptr)->flags |= MAYBE_NUM;
|
||||
|
||||
/* restore '=' so that system() gets a valid environment */
|
||||
if (val != nullstr)
|
||||
*--val = '=';
|
||||
}
|
||||
}
|
||||
|
||||
/* Process a command-line assignment */
|
||||
char *
|
||||
arg_assign(arg)
|
||||
char *arg;
|
||||
{
|
||||
char *cp;
|
||||
Func_ptr after_assign = NULL;
|
||||
NODE *var;
|
||||
NODE *it;
|
||||
NODE **lhs;
|
||||
|
||||
cp = strchr(arg, '=');
|
||||
if (cp != NULL) {
|
||||
*cp++ = '\0';
|
||||
/*
|
||||
* Recent versions of nawk expand escapes inside assignments.
|
||||
* This makes sense, so we do it too.
|
||||
*/
|
||||
it = make_str_node(cp, strlen(cp), SCAN);
|
||||
it->flags |= MAYBE_NUM;
|
||||
var = variable(arg, 0);
|
||||
lhs = get_lhs(var, &after_assign);
|
||||
unref(*lhs);
|
||||
*lhs = it;
|
||||
if (after_assign)
|
||||
(*after_assign)();
|
||||
*--cp = '='; /* restore original text of ARGV */
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
|
||||
static void
|
||||
pre_assign(v)
|
||||
char *v;
|
||||
{
|
||||
if (!arg_assign(v)) {
|
||||
fprintf (stderr,
|
||||
"%s: '%s' argument to -v not in 'var=value' form\n",
|
||||
myname, v);
|
||||
usage(1);
|
||||
}
|
||||
}
|
||||
|
||||
SIGTYPE
|
||||
catchsig(sig, code)
|
||||
int sig, code;
|
||||
{
|
||||
#ifdef lint
|
||||
code = 0; sig = code; code = sig;
|
||||
#endif
|
||||
if (sig == SIGFPE) {
|
||||
fatal("floating point exception");
|
||||
} else if (sig == SIGSEGV
|
||||
#ifdef SIGBUS
|
||||
|| sig == SIGBUS
|
||||
#endif
|
||||
) {
|
||||
msg("fatal error: internal error");
|
||||
/* fatal won't abort() if not compiled for debugging */
|
||||
abort();
|
||||
} else
|
||||
cant_happen();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/* gawk_option --- do gawk specific things */
|
||||
|
||||
static void
|
||||
gawk_option(optstr)
|
||||
char *optstr;
|
||||
{
|
||||
char *cp;
|
||||
|
||||
for (cp = optstr; *cp; cp++) {
|
||||
switch (*cp) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case ',':
|
||||
break;
|
||||
case 'v':
|
||||
case 'V':
|
||||
/* print version */
|
||||
if (strncasecmp(cp, "version", 7) != 0)
|
||||
goto unknown;
|
||||
else
|
||||
cp += 6;
|
||||
version();
|
||||
break;
|
||||
case 'c':
|
||||
case 'C':
|
||||
if (strncasecmp(cp, "copyright", 9) == 0) {
|
||||
cp += 8;
|
||||
copyleft();
|
||||
} else if (strncasecmp(cp, "copyleft", 8) == 0) {
|
||||
cp += 7;
|
||||
copyleft();
|
||||
} else if (strncasecmp(cp, "compat", 6) == 0) {
|
||||
cp += 5;
|
||||
do_unix = 1;
|
||||
} else
|
||||
goto unknown;
|
||||
break;
|
||||
case 'n':
|
||||
case 'N':
|
||||
/*
|
||||
* Undocumented feature,
|
||||
* inspired by nostalgia, and a T-shirt
|
||||
*/
|
||||
if (strncasecmp(cp, "nostalgia", 9) != 0)
|
||||
goto unknown;
|
||||
nostalgia();
|
||||
break;
|
||||
case 'p':
|
||||
case 'P':
|
||||
#ifdef DEBUG
|
||||
if (strncasecmp(cp, "parsedebug", 10) == 0) {
|
||||
cp += 9;
|
||||
yydebug = 2;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (strncasecmp(cp, "posix", 5) != 0)
|
||||
goto unknown;
|
||||
cp += 4;
|
||||
do_posix = do_unix = 1;
|
||||
break;
|
||||
case 'l':
|
||||
case 'L':
|
||||
if (strncasecmp(cp, "lint", 4) != 0)
|
||||
goto unknown;
|
||||
cp += 3;
|
||||
do_lint = 1;
|
||||
break;
|
||||
case 'H':
|
||||
case 'h':
|
||||
if (strncasecmp(cp, "help", 4) != 0)
|
||||
goto unknown;
|
||||
cp += 3;
|
||||
usage(0);
|
||||
break;
|
||||
case 'U':
|
||||
case 'u':
|
||||
if (strncasecmp(cp, "usage", 5) != 0)
|
||||
goto unknown;
|
||||
cp += 4;
|
||||
usage(0);
|
||||
break;
|
||||
case 's':
|
||||
case 'S':
|
||||
if (strncasecmp(cp, "source=", 7) != 0)
|
||||
goto unknown;
|
||||
cp += 7;
|
||||
if (strlen(cp) == 0)
|
||||
warning("empty argument to -Wsource ignored");
|
||||
else {
|
||||
srcfiles[++numfiles].stype = CMDLINE;
|
||||
srcfiles[numfiles].val = cp;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
unknown:
|
||||
fprintf(stderr, "'%c' -- unknown option, ignored\n",
|
||||
*cp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* nostalgia --- print the famous error message and die */
|
||||
|
||||
static void
|
||||
nostalgia()
|
||||
{
|
||||
fprintf(stderr, "awk: bailing out near line 1\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
/* version --- print version message */
|
||||
|
||||
static void
|
||||
version()
|
||||
{
|
||||
fprintf(stderr, "%s, patchlevel %d\n", version_string, PATCHLEVEL);
|
||||
}
|
||||
|
||||
/* static */
|
||||
char *
|
||||
gawk_name(filespec)
|
||||
char *filespec;
|
||||
{
|
||||
char *p;
|
||||
|
||||
#ifdef VMS /* "device:[root.][directory.subdir]GAWK.EXE;n" -> "GAWK" */
|
||||
char *q;
|
||||
|
||||
p = strrchr(filespec, ']'); /* directory punctuation */
|
||||
q = strrchr(filespec, '>'); /* alternate <international> punct */
|
||||
|
||||
if (p == NULL || q > p) p = q;
|
||||
p = strdup(p == NULL ? filespec : (p + 1));
|
||||
if ((q = strrchr(p, '.')) != NULL) *q = '\0'; /* strip .typ;vers */
|
||||
|
||||
return p;
|
||||
#endif /*VMS*/
|
||||
|
||||
#if defined(MSDOS) || defined(atarist)
|
||||
char *q;
|
||||
|
||||
p = filespec;
|
||||
|
||||
if (q = strrchr(p, '\\'))
|
||||
p = q + 1;
|
||||
if (q = strchr(p, '.'))
|
||||
*q = '\0';
|
||||
strlwr(p);
|
||||
|
||||
return (p == NULL ? filespec : p);
|
||||
#endif /* MSDOS || atarist */
|
||||
|
||||
/* "path/name" -> "name" */
|
||||
p = strrchr(filespec, '/');
|
||||
return (p == NULL ? filespec : p + 1);
|
||||
}
|
||||
106
gnu/usr.bin/awk/msg.c
Normal file
106
gnu/usr.bin/awk/msg.c
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* msg.c - routines for error messages
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GAWK, the GNU implementation of the
|
||||
* AWK Progamming Language.
|
||||
*
|
||||
* GAWK 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.
|
||||
*
|
||||
* GAWK 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 GAWK; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "awk.h"
|
||||
|
||||
int sourceline = 0;
|
||||
char *source = NULL;
|
||||
|
||||
/* VARARGS2 */
|
||||
void
|
||||
err(s, emsg, argp)
|
||||
char *s;
|
||||
char *emsg;
|
||||
va_list argp;
|
||||
{
|
||||
char *file;
|
||||
|
||||
(void) fflush(stdout);
|
||||
(void) fprintf(stderr, "%s: ", myname);
|
||||
if (sourceline) {
|
||||
if (source)
|
||||
(void) fprintf(stderr, "%s:", source);
|
||||
else
|
||||
(void) fprintf(stderr, "cmd. line:");
|
||||
|
||||
(void) fprintf(stderr, "%d: ", sourceline);
|
||||
}
|
||||
if (FNR) {
|
||||
file = FILENAME_node->var_value->stptr;
|
||||
if (file)
|
||||
(void) fprintf(stderr, "(FILENAME=%s ", file);
|
||||
(void) fprintf(stderr, "FNR=%d) ", FNR);
|
||||
}
|
||||
(void) fprintf(stderr, s);
|
||||
vfprintf(stderr, emsg, argp);
|
||||
(void) fprintf(stderr, "\n");
|
||||
(void) fflush(stderr);
|
||||
}
|
||||
|
||||
/*VARARGS0*/
|
||||
void
|
||||
msg(va_alist)
|
||||
va_dcl
|
||||
{
|
||||
va_list args;
|
||||
char *mesg;
|
||||
|
||||
va_start(args);
|
||||
mesg = va_arg(args, char *);
|
||||
err("", mesg, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/*VARARGS0*/
|
||||
void
|
||||
warning(va_alist)
|
||||
va_dcl
|
||||
{
|
||||
va_list args;
|
||||
char *mesg;
|
||||
|
||||
va_start(args);
|
||||
mesg = va_arg(args, char *);
|
||||
err("warning: ", mesg, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/*VARARGS0*/
|
||||
void
|
||||
fatal(va_alist)
|
||||
va_dcl
|
||||
{
|
||||
va_list args;
|
||||
char *mesg;
|
||||
|
||||
va_start(args);
|
||||
mesg = va_arg(args, char *);
|
||||
err("fatal: ", mesg, args);
|
||||
va_end(args);
|
||||
#ifdef DEBUG
|
||||
abort();
|
||||
#endif
|
||||
exit(2);
|
||||
}
|
||||
429
gnu/usr.bin/awk/node.c
Normal file
429
gnu/usr.bin/awk/node.c
Normal file
|
|
@ -0,0 +1,429 @@
|
|||
/*
|
||||
* node.c -- routines for node management
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GAWK, the GNU implementation of the
|
||||
* AWK Progamming Language.
|
||||
*
|
||||
* GAWK 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.
|
||||
*
|
||||
* GAWK 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 GAWK; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "awk.h"
|
||||
|
||||
extern double strtod();
|
||||
|
||||
AWKNUM
|
||||
r_force_number(n)
|
||||
register NODE *n;
|
||||
{
|
||||
register char *cp;
|
||||
register char *cpend;
|
||||
char save;
|
||||
char *ptr;
|
||||
unsigned int newflags = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (n == NULL)
|
||||
cant_happen();
|
||||
if (n->type != Node_val)
|
||||
cant_happen();
|
||||
if(n->flags == 0)
|
||||
cant_happen();
|
||||
if (n->flags & NUM)
|
||||
return n->numbr;
|
||||
#endif
|
||||
|
||||
/* all the conditionals are an attempt to avoid the expensive strtod */
|
||||
|
||||
n->numbr = 0.0;
|
||||
n->flags |= NUM;
|
||||
|
||||
if (n->stlen == 0)
|
||||
return 0.0;
|
||||
|
||||
cp = n->stptr;
|
||||
if (isalpha(*cp))
|
||||
return 0.0;
|
||||
|
||||
cpend = cp + n->stlen;
|
||||
while (cp < cpend && isspace(*cp))
|
||||
cp++;
|
||||
if (cp == cpend || isalpha(*cp))
|
||||
return 0.0;
|
||||
|
||||
if (n->flags & MAYBE_NUM) {
|
||||
newflags = NUMBER;
|
||||
n->flags &= ~MAYBE_NUM;
|
||||
}
|
||||
if (cpend - cp == 1) {
|
||||
if (isdigit(*cp)) {
|
||||
n->numbr = (AWKNUM)(*cp - '0');
|
||||
n->flags |= newflags;
|
||||
}
|
||||
return n->numbr;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
save = *cpend;
|
||||
*cpend = '\0';
|
||||
n->numbr = (AWKNUM) strtod((const char *)cp, &ptr);
|
||||
|
||||
/* POSIX says trailing space is OK for NUMBER */
|
||||
while (isspace(*ptr))
|
||||
ptr++;
|
||||
*cpend = save;
|
||||
/* the >= should be ==, but for SunOS 3.5 strtod() */
|
||||
if (errno == 0 && ptr >= cpend)
|
||||
n->flags |= newflags;
|
||||
else
|
||||
errno = 0;
|
||||
|
||||
return n->numbr;
|
||||
}
|
||||
|
||||
/*
|
||||
* the following lookup table is used as an optimization in force_string
|
||||
* (more complicated) variations on this theme didn't seem to pay off, but
|
||||
* systematic testing might be in order at some point
|
||||
*/
|
||||
static char *values[] = {
|
||||
"0",
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9",
|
||||
};
|
||||
#define NVAL (sizeof(values)/sizeof(values[0]))
|
||||
|
||||
NODE *
|
||||
r_force_string(s)
|
||||
register NODE *s;
|
||||
{
|
||||
char buf[128];
|
||||
register char *sp = buf;
|
||||
register long num = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (s == NULL) cant_happen();
|
||||
if (s->type != Node_val) cant_happen();
|
||||
if (s->flags & STR) return s;
|
||||
if (!(s->flags & NUM)) cant_happen();
|
||||
if (s->stref != 0) ; /*cant_happen();*/
|
||||
#endif
|
||||
|
||||
/* avoids floating point exception in DOS*/
|
||||
if ( s->numbr <= LONG_MAX && s->numbr >= -LONG_MAX)
|
||||
num = (long)s->numbr;
|
||||
if ((AWKNUM) num == s->numbr) { /* integral value */
|
||||
if (num < NVAL && num >= 0) {
|
||||
sp = values[num];
|
||||
s->stlen = 1;
|
||||
} else {
|
||||
(void) sprintf(sp, "%ld", num);
|
||||
s->stlen = strlen(sp);
|
||||
}
|
||||
s->stfmt = -1;
|
||||
} else {
|
||||
(void) sprintf(sp, CONVFMT, s->numbr);
|
||||
s->stlen = strlen(sp);
|
||||
s->stfmt = (char)CONVFMTidx;
|
||||
}
|
||||
s->stref = 1;
|
||||
emalloc(s->stptr, char *, s->stlen + 2, "force_string");
|
||||
memcpy(s->stptr, sp, s->stlen+1);
|
||||
s->flags |= STR;
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Duplicate a node. (For strings, "duplicate" means crank up the
|
||||
* reference count.)
|
||||
*/
|
||||
NODE *
|
||||
dupnode(n)
|
||||
NODE *n;
|
||||
{
|
||||
register NODE *r;
|
||||
|
||||
if (n->flags & TEMP) {
|
||||
n->flags &= ~TEMP;
|
||||
n->flags |= MALLOC;
|
||||
return n;
|
||||
}
|
||||
if ((n->flags & (MALLOC|STR)) == (MALLOC|STR)) {
|
||||
if (n->stref < 255)
|
||||
n->stref++;
|
||||
return n;
|
||||
}
|
||||
getnode(r);
|
||||
*r = *n;
|
||||
r->flags &= ~(PERM|TEMP);
|
||||
r->flags |= MALLOC;
|
||||
if (n->type == Node_val && (n->flags & STR)) {
|
||||
r->stref = 1;
|
||||
emalloc(r->stptr, char *, r->stlen + 2, "dupnode");
|
||||
memcpy(r->stptr, n->stptr, r->stlen+1);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* this allocates a node with defined numbr */
|
||||
NODE *
|
||||
mk_number(x, flags)
|
||||
AWKNUM x;
|
||||
unsigned int flags;
|
||||
{
|
||||
register NODE *r;
|
||||
|
||||
getnode(r);
|
||||
r->type = Node_val;
|
||||
r->numbr = x;
|
||||
r->flags = flags;
|
||||
#ifdef DEBUG
|
||||
r->stref = 1;
|
||||
r->stptr = 0;
|
||||
r->stlen = 0;
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a string node.
|
||||
*/
|
||||
NODE *
|
||||
make_str_node(s, len, flags)
|
||||
char *s;
|
||||
size_t len;
|
||||
int flags;
|
||||
{
|
||||
register NODE *r;
|
||||
|
||||
getnode(r);
|
||||
r->type = Node_val;
|
||||
r->flags = (STRING|STR|MALLOC);
|
||||
if (flags & ALREADY_MALLOCED)
|
||||
r->stptr = s;
|
||||
else {
|
||||
emalloc(r->stptr, char *, len + 2, s);
|
||||
memcpy(r->stptr, s, len);
|
||||
}
|
||||
r->stptr[len] = '\0';
|
||||
|
||||
if (flags & SCAN) { /* scan for escape sequences */
|
||||
char *pf;
|
||||
register char *ptm;
|
||||
register int c;
|
||||
register char *end;
|
||||
|
||||
end = &(r->stptr[len]);
|
||||
for (pf = ptm = r->stptr; pf < end;) {
|
||||
c = *pf++;
|
||||
if (c == '\\') {
|
||||
c = parse_escape(&pf);
|
||||
if (c < 0) {
|
||||
if (do_lint)
|
||||
warning("backslash at end of string");
|
||||
c = '\\';
|
||||
}
|
||||
*ptm++ = c;
|
||||
} else
|
||||
*ptm++ = c;
|
||||
}
|
||||
len = ptm - r->stptr;
|
||||
erealloc(r->stptr, char *, len + 1, "make_str_node");
|
||||
r->stptr[len] = '\0';
|
||||
r->flags |= PERM;
|
||||
}
|
||||
r->stlen = len;
|
||||
r->stref = 1;
|
||||
r->stfmt = -1;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
NODE *
|
||||
tmp_string(s, len)
|
||||
char *s;
|
||||
size_t len;
|
||||
{
|
||||
register NODE *r;
|
||||
|
||||
r = make_string(s, len);
|
||||
r->flags |= TEMP;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
#define NODECHUNK 100
|
||||
|
||||
NODE *nextfree = NULL;
|
||||
|
||||
NODE *
|
||||
more_nodes()
|
||||
{
|
||||
register NODE *np;
|
||||
|
||||
/* get more nodes and initialize list */
|
||||
emalloc(nextfree, NODE *, NODECHUNK * sizeof(NODE), "newnode");
|
||||
for (np = nextfree; np < &nextfree[NODECHUNK - 1]; np++)
|
||||
np->nextp = np + 1;
|
||||
np->nextp = NULL;
|
||||
np = nextfree;
|
||||
nextfree = nextfree->nextp;
|
||||
return np;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
freenode(it)
|
||||
NODE *it;
|
||||
{
|
||||
#ifdef MPROF
|
||||
it->stref = 0;
|
||||
free((char *) it);
|
||||
#else /* not MPROF */
|
||||
/* add it to head of freelist */
|
||||
it->nextp = nextfree;
|
||||
nextfree = it;
|
||||
#endif /* not MPROF */
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
void
|
||||
unref(tmp)
|
||||
register NODE *tmp;
|
||||
{
|
||||
if (tmp == NULL)
|
||||
return;
|
||||
if (tmp->flags & PERM)
|
||||
return;
|
||||
if (tmp->flags & (MALLOC|TEMP)) {
|
||||
tmp->flags &= ~TEMP;
|
||||
if (tmp->flags & STR) {
|
||||
if (tmp->stref > 1) {
|
||||
if (tmp->stref != 255)
|
||||
tmp->stref--;
|
||||
return;
|
||||
}
|
||||
free(tmp->stptr);
|
||||
}
|
||||
freenode(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a C escape sequence. STRING_PTR points to a variable containing a
|
||||
* pointer to the string to parse. That pointer is updated past the
|
||||
* characters we use. The value of the escape sequence is returned.
|
||||
*
|
||||
* A negative value means the sequence \ newline was seen, which is supposed to
|
||||
* be equivalent to nothing at all.
|
||||
*
|
||||
* If \ is followed by a null character, we return a negative value and leave
|
||||
* the string pointer pointing at the null character.
|
||||
*
|
||||
* If \ is followed by 000, we return 0 and leave the string pointer after the
|
||||
* zeros. A value of 0 does not mean end of string.
|
||||
*
|
||||
* Posix doesn't allow \x.
|
||||
*/
|
||||
|
||||
int
|
||||
parse_escape(string_ptr)
|
||||
char **string_ptr;
|
||||
{
|
||||
register int c = *(*string_ptr)++;
|
||||
register int i;
|
||||
register int count;
|
||||
|
||||
switch (c) {
|
||||
case 'a':
|
||||
return BELL;
|
||||
case 'b':
|
||||
return '\b';
|
||||
case 'f':
|
||||
return '\f';
|
||||
case 'n':
|
||||
return '\n';
|
||||
case 'r':
|
||||
return '\r';
|
||||
case 't':
|
||||
return '\t';
|
||||
case 'v':
|
||||
return '\v';
|
||||
case '\n':
|
||||
return -2;
|
||||
case 0:
|
||||
(*string_ptr)--;
|
||||
return -1;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
i = c - '0';
|
||||
count = 0;
|
||||
while (++count < 3) {
|
||||
if ((c = *(*string_ptr)++) >= '0' && c <= '7') {
|
||||
i *= 8;
|
||||
i += c - '0';
|
||||
} else {
|
||||
(*string_ptr)--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
case 'x':
|
||||
if (do_lint) {
|
||||
static int didwarn;
|
||||
|
||||
if (! didwarn) {
|
||||
didwarn = 1;
|
||||
warning("Posix does not allow \"\\x\" escapes");
|
||||
}
|
||||
}
|
||||
if (do_posix)
|
||||
return ('x');
|
||||
i = 0;
|
||||
while (1) {
|
||||
if (isxdigit((c = *(*string_ptr)++))) {
|
||||
i *= 16;
|
||||
if (isdigit(c))
|
||||
i += c - '0';
|
||||
else if (isupper(c))
|
||||
i += c - 'A' + 10;
|
||||
else
|
||||
i += c - 'a' + 10;
|
||||
} else {
|
||||
(*string_ptr)--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
default:
|
||||
return c;
|
||||
}
|
||||
}
|
||||
1
gnu/usr.bin/awk/patchlevel.h
Normal file
1
gnu/usr.bin/awk/patchlevel.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
#define PATCHLEVEL 2
|
||||
115
gnu/usr.bin/awk/protos.h
Normal file
115
gnu/usr.bin/awk/protos.h
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* protos.h -- function prototypes for when the headers don't have them.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1991, 1992, the Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GAWK, the GNU implementation of the
|
||||
* AWK Progamming Language.
|
||||
*
|
||||
* GAWK 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.
|
||||
*
|
||||
* GAWK 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 GAWK; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifdef __STDC__
|
||||
#define aptr_t void * /* arbitrary pointer type */
|
||||
#else
|
||||
#define aptr_t char *
|
||||
#endif
|
||||
extern aptr_t malloc P((MALLOC_ARG_T));
|
||||
extern aptr_t realloc P((aptr_t, MALLOC_ARG_T));
|
||||
extern aptr_t calloc P((MALLOC_ARG_T, MALLOC_ARG_T));
|
||||
|
||||
extern void free P((aptr_t));
|
||||
extern char *getenv P((char *));
|
||||
|
||||
extern char *strcpy P((char *, const char *));
|
||||
extern char *strcat P((char *, const char *));
|
||||
extern char *strncpy P((char *, const char *, int));
|
||||
extern int strcmp P((const char *, const char *));
|
||||
extern int strncmp P((const char *, const char *, int));
|
||||
#ifndef VMS
|
||||
extern char *strerror P((int));
|
||||
#else
|
||||
extern char *strerror P((int,...));
|
||||
#endif
|
||||
extern char *strchr P((const char *, int));
|
||||
extern char *strrchr P((const char *, int));
|
||||
extern char *strstr P((const char *s1, const char *s2));
|
||||
extern int strlen P((const char *));
|
||||
extern long strtol P((const char *, char **, int));
|
||||
#if !defined(_MSC_VER) && !defined(__GNU_LIBRARY__)
|
||||
extern int strftime P((char *, int, const char *, const struct tm *));
|
||||
#endif
|
||||
extern time_t time P((time_t *));
|
||||
extern aptr_t memset P((aptr_t, int, size_t));
|
||||
extern aptr_t memcpy P((aptr_t, const aptr_t, size_t));
|
||||
extern aptr_t memmove P((aptr_t, const aptr_t, size_t));
|
||||
extern aptr_t memchr P((const aptr_t, int, size_t));
|
||||
extern int memcmp P((const aptr_t, const aptr_t, size_t));
|
||||
|
||||
/* extern int fprintf P((FILE *, char *, ...)); */
|
||||
extern int fprintf P(());
|
||||
#if !defined(MSDOS) && !defined(__GNU_LIBRARY__)
|
||||
extern int fwrite P((const char *, int, int, FILE *));
|
||||
extern int fputs P((const char *, FILE *));
|
||||
extern int unlink P((const char *));
|
||||
#endif
|
||||
extern int fflush P((FILE *));
|
||||
extern int fclose P((FILE *));
|
||||
extern FILE *popen P((const char *, const char *));
|
||||
extern int pclose P((FILE *));
|
||||
extern void abort P(());
|
||||
extern int isatty P((int));
|
||||
extern void exit P((int));
|
||||
extern int system P((const char *));
|
||||
extern int sscanf P((/* char *, char *, ... */));
|
||||
#ifndef toupper
|
||||
extern int toupper P((int));
|
||||
#endif
|
||||
#ifndef tolower
|
||||
extern int tolower P((int));
|
||||
#endif
|
||||
|
||||
extern double pow P((double x, double y));
|
||||
extern double atof P((char *));
|
||||
extern double strtod P((const char *, char **));
|
||||
extern int fstat P((int, struct stat *));
|
||||
extern int stat P((const char *, struct stat *));
|
||||
extern off_t lseek P((int, off_t, int));
|
||||
extern int fseek P((FILE *, long, int));
|
||||
extern int close P((int));
|
||||
extern int creat P(());
|
||||
extern int open P(());
|
||||
extern int pipe P((int *));
|
||||
extern int dup P((int));
|
||||
extern int dup2 P((int,int));
|
||||
extern int fork P(());
|
||||
extern int execl P((/* char *, char *, ... */));
|
||||
extern int read P((int, char *, int));
|
||||
extern int wait P((int *));
|
||||
extern void _exit P((int));
|
||||
|
||||
#ifndef __STDC__
|
||||
extern long time P((long *));
|
||||
#endif
|
||||
|
||||
#ifdef NON_STD_SPRINTF
|
||||
extern char *sprintf();
|
||||
#else
|
||||
extern int sprintf();
|
||||
#endif /* SPRINTF_INT */
|
||||
|
||||
#undef aptr_t
|
||||
208
gnu/usr.bin/awk/re.c
Normal file
208
gnu/usr.bin/awk/re.c
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* re.c - compile regular expressions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1991, 1992 the Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GAWK, the GNU implementation of the
|
||||
* AWK Progamming Language.
|
||||
*
|
||||
* GAWK 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.
|
||||
*
|
||||
* GAWK 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 GAWK; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "awk.h"
|
||||
|
||||
/* Generate compiled regular expressions */
|
||||
|
||||
Regexp *
|
||||
make_regexp(s, len, ignorecase, dfa)
|
||||
char *s;
|
||||
int len;
|
||||
int ignorecase;
|
||||
int dfa;
|
||||
{
|
||||
Regexp *rp;
|
||||
char *err;
|
||||
char *src = s;
|
||||
char *temp;
|
||||
char *end = s + len;
|
||||
register char *dest;
|
||||
register int c;
|
||||
|
||||
/* Handle escaped characters first. */
|
||||
|
||||
/* Build a copy of the string (in dest) with the
|
||||
escaped characters translated, and generate the regex
|
||||
from that.
|
||||
*/
|
||||
emalloc(dest, char *, len + 2, "make_regexp");
|
||||
temp = dest;
|
||||
|
||||
while (src < end) {
|
||||
if (*src == '\\') {
|
||||
c = *++src;
|
||||
switch (c) {
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'f':
|
||||
case 'n':
|
||||
case 'r':
|
||||
case 't':
|
||||
case 'v':
|
||||
case 'x':
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
c = parse_escape(&src);
|
||||
if (c < 0)
|
||||
cant_happen();
|
||||
*dest++ = (char)c;
|
||||
break;
|
||||
default:
|
||||
*dest++ = '\\';
|
||||
*dest++ = (char)c;
|
||||
src++;
|
||||
break;
|
||||
} /* switch */
|
||||
} else {
|
||||
*dest++ = *src++; /* not '\\' */
|
||||
}
|
||||
} /* for */
|
||||
|
||||
*dest = '\0' ; /* Only necessary if we print dest ? */
|
||||
emalloc(rp, Regexp *, sizeof(*rp), "make_regexp");
|
||||
memset((char *) rp, 0, sizeof(*rp));
|
||||
emalloc(rp->pat.buffer, char *, 16, "make_regexp");
|
||||
rp->pat.allocated = 16;
|
||||
emalloc(rp->pat.fastmap, char *, 256, "make_regexp");
|
||||
|
||||
if (ignorecase)
|
||||
rp->pat.translate = casetable;
|
||||
else
|
||||
rp->pat.translate = NULL;
|
||||
len = dest - temp;
|
||||
if ((err = re_compile_pattern(temp, (size_t) len, &(rp->pat))) != NULL)
|
||||
fatal("%s: /%s/", err, temp);
|
||||
if (dfa && !ignorecase) {
|
||||
regcompile(temp, len, &(rp->dfareg), 1);
|
||||
rp->dfa = 1;
|
||||
} else
|
||||
rp->dfa = 0;
|
||||
free(temp);
|
||||
return rp;
|
||||
}
|
||||
|
||||
int
|
||||
research(rp, str, start, len, need_start)
|
||||
Regexp *rp;
|
||||
register char *str;
|
||||
int start;
|
||||
register int len;
|
||||
int need_start;
|
||||
{
|
||||
char *ret = str;
|
||||
|
||||
if (rp->dfa) {
|
||||
char save1;
|
||||
char save2;
|
||||
int count = 0;
|
||||
int try_backref;
|
||||
|
||||
save1 = str[start+len];
|
||||
str[start+len] = '\n';
|
||||
save2 = str[start+len+1];
|
||||
ret = regexecute(&(rp->dfareg), str+start, str+start+len+1, 1,
|
||||
&count, &try_backref);
|
||||
str[start+len] = save1;
|
||||
str[start+len+1] = save2;
|
||||
}
|
||||
if (ret) {
|
||||
if (need_start || rp->dfa == 0)
|
||||
return re_search(&(rp->pat), str, start+len, start,
|
||||
len, &(rp->regs));
|
||||
else
|
||||
return 1;
|
||||
} else
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
refree(rp)
|
||||
Regexp *rp;
|
||||
{
|
||||
free(rp->pat.buffer);
|
||||
free(rp->pat.fastmap);
|
||||
if (rp->dfa)
|
||||
reg_free(&(rp->dfareg));
|
||||
free(rp);
|
||||
}
|
||||
|
||||
void
|
||||
reg_error(s)
|
||||
const char *s;
|
||||
{
|
||||
fatal(s);
|
||||
}
|
||||
|
||||
Regexp *
|
||||
re_update(t)
|
||||
NODE *t;
|
||||
{
|
||||
NODE *t1;
|
||||
|
||||
# define CASE 1
|
||||
if ((t->re_flags & CASE) == IGNORECASE) {
|
||||
if (t->re_flags & CONST)
|
||||
return t->re_reg;
|
||||
t1 = force_string(tree_eval(t->re_exp));
|
||||
if (t->re_text) {
|
||||
if (cmp_nodes(t->re_text, t1) == 0) {
|
||||
free_temp(t1);
|
||||
return t->re_reg;
|
||||
}
|
||||
unref(t->re_text);
|
||||
}
|
||||
t->re_text = dupnode(t1);
|
||||
free_temp(t1);
|
||||
}
|
||||
if (t->re_reg)
|
||||
refree(t->re_reg);
|
||||
if (t->re_cnt)
|
||||
t->re_cnt++;
|
||||
if (t->re_cnt > 10)
|
||||
t->re_cnt = 0;
|
||||
if (!t->re_text) {
|
||||
t1 = force_string(tree_eval(t->re_exp));
|
||||
t->re_text = dupnode(t1);
|
||||
free_temp(t1);
|
||||
}
|
||||
t->re_reg = make_regexp(t->re_text->stptr, t->re_text->stlen, IGNORECASE, t->re_cnt);
|
||||
t->re_flags &= ~CASE;
|
||||
t->re_flags |= IGNORECASE;
|
||||
return t->re_reg;
|
||||
}
|
||||
|
||||
void
|
||||
resetup()
|
||||
{
|
||||
(void) re_set_syntax(RE_SYNTAX_AWK);
|
||||
regsyntax(RE_SYNTAX_AWK, 0);
|
||||
}
|
||||
2854
gnu/usr.bin/awk/regex.c
Normal file
2854
gnu/usr.bin/awk/regex.c
Normal file
File diff suppressed because it is too large
Load diff
260
gnu/usr.bin/awk/regex.h
Normal file
260
gnu/usr.bin/awk/regex.h
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
/* Definitions for data structures callers pass the regex library.
|
||||
|
||||
Copyright (C) 1985, 1989-90 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 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
|
||||
#ifndef __REGEXP_LIBRARY
|
||||
#define __REGEXP_LIBRARY
|
||||
|
||||
/* Define number of parens for which we record the beginnings and ends.
|
||||
This affects how much space the `struct re_registers' type takes up. */
|
||||
#ifndef RE_NREGS
|
||||
#define RE_NREGS 10
|
||||
#endif
|
||||
|
||||
#define BYTEWIDTH 8
|
||||
|
||||
|
||||
/* Maximum number of duplicates an interval can allow. */
|
||||
#ifndef RE_DUP_MAX
|
||||
#define RE_DUP_MAX ((1 << 15) - 1)
|
||||
#endif
|
||||
|
||||
|
||||
/* This defines the various regexp syntaxes. */
|
||||
extern long obscure_syntax;
|
||||
|
||||
|
||||
/* The following bits are used in the obscure_syntax variable to choose among
|
||||
alternative regexp syntaxes. */
|
||||
|
||||
/* If this bit is set, plain parentheses serve as grouping, and backslash
|
||||
parentheses are needed for literal searching.
|
||||
If not set, backslash-parentheses are grouping, and plain parentheses
|
||||
are for literal searching. */
|
||||
#define RE_NO_BK_PARENS 1L
|
||||
|
||||
/* If this bit is set, plain | serves as the `or'-operator, and \| is a
|
||||
literal.
|
||||
If not set, \| serves as the `or'-operator, and | is a literal. */
|
||||
#define RE_NO_BK_VBAR (1L << 1)
|
||||
|
||||
/* If this bit is not set, plain + or ? serves as an operator, and \+, \? are
|
||||
literals.
|
||||
If set, \+, \? are operators and plain +, ? are literals. */
|
||||
#define RE_BK_PLUS_QM (1L << 2)
|
||||
|
||||
/* If this bit is set, | binds tighter than ^ or $.
|
||||
If not set, the contrary. */
|
||||
#define RE_TIGHT_VBAR (1L << 3)
|
||||
|
||||
/* If this bit is set, then treat newline as an OR operator.
|
||||
If not set, treat it as a normal character. */
|
||||
#define RE_NEWLINE_OR (1L << 4)
|
||||
|
||||
/* If this bit is set, then special characters may act as normal
|
||||
characters in some contexts. Specifically, this applies to:
|
||||
^ -- only special at the beginning, or after ( or |;
|
||||
$ -- only special at the end, or before ) or |;
|
||||
*, +, ? -- only special when not after the beginning, (, or |.
|
||||
If this bit is not set, special characters (such as *, ^, and $)
|
||||
always have their special meaning regardless of the surrounding
|
||||
context. */
|
||||
#define RE_CONTEXT_INDEP_OPS (1L << 5)
|
||||
|
||||
/* If this bit is not set, then \ before anything inside [ and ] is taken as
|
||||
a real \.
|
||||
If set, then such a \ escapes the following character. This is a
|
||||
special case for awk. */
|
||||
#define RE_AWK_CLASS_HACK (1L << 6)
|
||||
|
||||
/* If this bit is set, then \{ and \} or { and } serve as interval operators.
|
||||
If not set, then \{ and \} and { and } are treated as literals. */
|
||||
#define RE_INTERVALS (1L << 7)
|
||||
|
||||
/* If this bit is not set, then \{ and \} serve as interval operators and
|
||||
{ and } are literals.
|
||||
If set, then { and } serve as interval operators and \{ and \} are
|
||||
literals. */
|
||||
#define RE_NO_BK_CURLY_BRACES (1L << 8)
|
||||
|
||||
/* If this bit is set, then character classes are supported; they are:
|
||||
[:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:],
|
||||
[:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
|
||||
If not set, then character classes are not supported. */
|
||||
#define RE_CHAR_CLASSES (1L << 9)
|
||||
|
||||
/* If this bit is set, then the dot re doesn't match a null byte.
|
||||
If not set, it does. */
|
||||
#define RE_DOT_NOT_NULL (1L << 10)
|
||||
|
||||
/* If this bit is set, then [^...] doesn't match a newline.
|
||||
If not set, it does. */
|
||||
#define RE_HAT_NOT_NEWLINE (1L << 11)
|
||||
|
||||
/* If this bit is set, back references are recognized.
|
||||
If not set, they aren't. */
|
||||
#define RE_NO_BK_REFS (1L << 12)
|
||||
|
||||
/* If this bit is set, back references must refer to a preceding
|
||||
subexpression. If not set, a back reference to a nonexistent
|
||||
subexpression is treated as literal characters. */
|
||||
#define RE_NO_EMPTY_BK_REF (1L << 13)
|
||||
|
||||
/* If this bit is set, bracket expressions can't be empty.
|
||||
If it is set, they can be empty. */
|
||||
#define RE_NO_EMPTY_BRACKETS (1L << 14)
|
||||
|
||||
/* If this bit is set, then *, +, ? and { cannot be first in an re or
|
||||
immediately after a |, or a (. Furthermore, a | cannot be first or
|
||||
last in an re, or immediately follow another | or a (. Also, a ^
|
||||
cannot appear in a nonleading position and a $ cannot appear in a
|
||||
nontrailing position (outside of bracket expressions, that is). */
|
||||
#define RE_CONTEXTUAL_INVALID_OPS (1L << 15)
|
||||
|
||||
/* If this bit is set, then +, ? and | aren't recognized as operators.
|
||||
If it's not, they are. */
|
||||
#define RE_LIMITED_OPS (1L << 16)
|
||||
|
||||
/* If this bit is set, then an ending range point has to collate higher
|
||||
or equal to the starting range point.
|
||||
If it's not set, then when the ending range point collates higher
|
||||
than the starting range point, the range is just considered empty. */
|
||||
#define RE_NO_EMPTY_RANGES (1L << 17)
|
||||
|
||||
/* If this bit is set, then a hyphen (-) can't be an ending range point.
|
||||
If it isn't, then it can. */
|
||||
#define RE_NO_HYPHEN_RANGE_END (1L << 18)
|
||||
|
||||
|
||||
/* Define combinations of bits for the standard possibilities. */
|
||||
#define RE_SYNTAX_POSIX_AWK (RE_NO_BK_PARENS | RE_NO_BK_VBAR \
|
||||
| RE_CONTEXT_INDEP_OPS)
|
||||
#define RE_SYNTAX_AWK (RE_NO_BK_PARENS | RE_NO_BK_VBAR | RE_AWK_CLASS_HACK)
|
||||
#define RE_SYNTAX_EGREP (RE_NO_BK_PARENS | RE_NO_BK_VBAR \
|
||||
| RE_CONTEXT_INDEP_OPS | RE_NEWLINE_OR)
|
||||
#define RE_SYNTAX_GREP (RE_BK_PLUS_QM | RE_NEWLINE_OR)
|
||||
#define RE_SYNTAX_EMACS 0
|
||||
#define RE_SYNTAX_POSIX_BASIC (RE_INTERVALS | RE_BK_PLUS_QM \
|
||||
| RE_CHAR_CLASSES | RE_DOT_NOT_NULL \
|
||||
| RE_HAT_NOT_NEWLINE | RE_NO_EMPTY_BK_REF \
|
||||
| RE_NO_EMPTY_BRACKETS | RE_LIMITED_OPS \
|
||||
| RE_NO_EMPTY_RANGES | RE_NO_HYPHEN_RANGE_END)
|
||||
|
||||
#define RE_SYNTAX_POSIX_EXTENDED (RE_INTERVALS | RE_NO_BK_CURLY_BRACES \
|
||||
| RE_NO_BK_VBAR | RE_NO_BK_PARENS \
|
||||
| RE_HAT_NOT_NEWLINE | RE_CHAR_CLASSES \
|
||||
| RE_NO_EMPTY_BRACKETS | RE_CONTEXTUAL_INVALID_OPS \
|
||||
| RE_NO_BK_REFS | RE_NO_EMPTY_RANGES \
|
||||
| RE_NO_HYPHEN_RANGE_END)
|
||||
|
||||
|
||||
/* This data structure is used to represent a compiled pattern. */
|
||||
|
||||
struct re_pattern_buffer
|
||||
{
|
||||
char *buffer; /* Space holding the compiled pattern commands. */
|
||||
long allocated; /* Size of space that `buffer' points to. */
|
||||
long used; /* Length of portion of buffer actually occupied */
|
||||
char *fastmap; /* Pointer to fastmap, if any, or zero if none. */
|
||||
/* re_search uses the fastmap, if there is one,
|
||||
to skip over totally implausible characters. */
|
||||
char *translate; /* Translate table to apply to all characters before
|
||||
comparing, or zero for no translation.
|
||||
The translation is applied to a pattern when it is
|
||||
compiled and to data when it is matched. */
|
||||
char fastmap_accurate;
|
||||
/* Set to zero when a new pattern is stored,
|
||||
set to one when the fastmap is updated from it. */
|
||||
char can_be_null; /* Set to one by compiling fastmap
|
||||
if this pattern might match the null string.
|
||||
It does not necessarily match the null string
|
||||
in that case, but if this is zero, it cannot.
|
||||
2 as value means can match null string
|
||||
but at end of range or before a character
|
||||
listed in the fastmap. */
|
||||
};
|
||||
|
||||
|
||||
/* search.c (search_buffer) needs this one value. It is defined both in
|
||||
regex.c and here. */
|
||||
#define RE_EXACTN_VALUE 1
|
||||
|
||||
|
||||
/* Structure to store register contents data in.
|
||||
|
||||
Pass the address of such a structure as an argument to re_match, etc.,
|
||||
if you want this information back.
|
||||
|
||||
For i from 1 to RE_NREGS - 1, start[i] records the starting index in
|
||||
the string of where the ith subexpression matched, and end[i] records
|
||||
one after the ending index. start[0] and end[0] are analogous, for
|
||||
the entire pattern. */
|
||||
|
||||
struct re_registers
|
||||
{
|
||||
int start[RE_NREGS];
|
||||
int end[RE_NREGS];
|
||||
};
|
||||
|
||||
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
extern char *re_compile_pattern (char *, size_t, struct re_pattern_buffer *);
|
||||
/* Is this really advertised? */
|
||||
extern void re_compile_fastmap (struct re_pattern_buffer *);
|
||||
extern int re_search (struct re_pattern_buffer *, char*, int, int, int,
|
||||
struct re_registers *);
|
||||
extern int re_search_2 (struct re_pattern_buffer *, char *, int,
|
||||
char *, int, int, int,
|
||||
struct re_registers *, int);
|
||||
extern int re_match (struct re_pattern_buffer *, char *, int, int,
|
||||
struct re_registers *);
|
||||
extern int re_match_2 (struct re_pattern_buffer *, char *, int,
|
||||
char *, int, int, struct re_registers *, int);
|
||||
extern long re_set_syntax (long syntax);
|
||||
|
||||
#ifndef GAWK
|
||||
/* 4.2 bsd compatibility. */
|
||||
extern char *re_comp (char *);
|
||||
extern int re_exec (char *);
|
||||
#endif
|
||||
|
||||
#else /* !__STDC__ */
|
||||
|
||||
extern char *re_compile_pattern ();
|
||||
/* Is this really advertised? */
|
||||
extern void re_compile_fastmap ();
|
||||
extern int re_search (), re_search_2 ();
|
||||
extern int re_match (), re_match_2 ();
|
||||
extern long re_set_syntax();
|
||||
|
||||
#ifndef GAWK
|
||||
/* 4.2 bsd compatibility. */
|
||||
extern char *re_comp ();
|
||||
extern int re_exec ();
|
||||
#endif
|
||||
|
||||
#endif /* __STDC__ */
|
||||
|
||||
|
||||
#ifdef SYNTAX_TABLE
|
||||
extern char *re_syntax_table;
|
||||
#endif
|
||||
|
||||
#endif /* !__REGEXP_LIBRARY */
|
||||
46
gnu/usr.bin/awk/version.c
Normal file
46
gnu/usr.bin/awk/version.c
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
char *version_string = "@(#)Gnu Awk (gawk) 2.15";
|
||||
|
||||
/* 1.02 fixed /= += *= etc to return the new Left Hand Side instead
|
||||
of the Right Hand Side */
|
||||
|
||||
/* 1.03 Fixed split() to treat strings of space and tab as FS if
|
||||
the split char is ' '.
|
||||
|
||||
Added -v option to print version number
|
||||
|
||||
Fixed bug that caused rounding when printing large numbers */
|
||||
|
||||
/* 2.00beta Incorporated the functionality of the "new" awk as described
|
||||
the book (reference not handy). Extensively tested, but no
|
||||
doubt still buggy. Badly needs tuning and cleanup, in
|
||||
particular in memory management which is currently almost
|
||||
non-existent. */
|
||||
|
||||
/* 2.01 JF: Modified to compile under GCC, and fixed a few
|
||||
bugs while I was at it. I hope I didn't add any more.
|
||||
I modified parse.y to reduce the number of reduce/reduce
|
||||
conflicts. There are still a few left. */
|
||||
|
||||
/* 2.02 Fixed JF's bugs; improved memory management, still needs
|
||||
lots of work. */
|
||||
|
||||
/* 2.10 Major grammar rework and lots of bug fixes from David.
|
||||
Major changes for performance enhancements from David.
|
||||
A number of minor bug fixes and new features from Arnold.
|
||||
Changes for MSDOS from Conrad Kwok and Scott Garfinkle.
|
||||
The gawk.texinfo and info files included! */
|
||||
|
||||
/* 2.11 Bug fix release to 2.10. Lots of changes for portability,
|
||||
speed, and configurability. */
|
||||
|
||||
/* 2.12 Lots of changes for portability, speed, and configurability.
|
||||
Several bugs fixed. POSIX compliance. Removal of last set
|
||||
of hard-wired limits. Atari and VMS ports added. */
|
||||
|
||||
/* 2.13 Public release of 2.12 */
|
||||
|
||||
/* 2.14 Mostly bug fixes. */
|
||||
|
||||
/* 2.15 Bug fixes plus intermixing of command-line source and files,
|
||||
GNU long options, ARGIND, ERRNO and Plan 9 style /dev/ files. */
|
||||
|
||||
3
gnu/usr.bin/rcs/Makefile
Normal file
3
gnu/usr.bin/rcs/Makefile
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
SUBDIR= lib ci co ident merge rcs rcsdiff rcsmerge rlog rcsfreeze
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
3
gnu/usr.bin/rcs/Makefile.inc
Normal file
3
gnu/usr.bin/rcs/Makefile.inc
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# @(#)Makefile.inc 5.1 (Berkeley) 5/11/90
|
||||
|
||||
BINDIR?= /usr/bin
|
||||
7
gnu/usr.bin/rcs/ci/Makefile
Normal file
7
gnu/usr.bin/rcs/ci/Makefile
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
PROG= ci
|
||||
|
||||
SRCS= ci.c
|
||||
LDADD= -L${.CURDIR}/../lib/obj -lrcs
|
||||
CFLAGS+= -I${.CURDIR}/../lib
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
772
gnu/usr.bin/rcs/ci/ci.1
Normal file
772
gnu/usr.bin/rcs/ci/ci.1
Normal file
|
|
@ -0,0 +1,772 @@
|
|||
.de Id
|
||||
.ds Rv \\$3
|
||||
.ds Dt \\$4
|
||||
..
|
||||
.Id $Id: ci.1,v 5.9 1991/10/07 17:32:46 eggert Exp $
|
||||
.ds r \&\s-1RCS\s0
|
||||
.if n .ds - \%--
|
||||
.if t .ds - \(em
|
||||
.TH CI 1 \*(Dt GNU
|
||||
.SH NAME
|
||||
ci \- check in RCS revisions
|
||||
.SH SYNOPSIS
|
||||
.B ci
|
||||
.RI [ options ] " file " .\|.\|.
|
||||
.SH DESCRIPTION
|
||||
.B ci
|
||||
stores new revisions into \*r files.
|
||||
Each pathname matching an \*r suffix
|
||||
is taken to be an \*r file.
|
||||
All others
|
||||
are assumed to be working files containing new revisions.
|
||||
.B ci
|
||||
deposits the contents of each working file
|
||||
into the corresponding \*r file.
|
||||
If only a working file is given,
|
||||
.B ci
|
||||
tries to find the corresponding \*r file in an \*r subdirectory
|
||||
and then in the working file's directory.
|
||||
For more details, see
|
||||
.SM "FILE NAMING"
|
||||
below.
|
||||
.PP
|
||||
For
|
||||
.B ci
|
||||
to work, the caller's login must be on the access list,
|
||||
except if the access list is empty or the caller is the superuser or the
|
||||
owner of the file.
|
||||
To append a new revision to an existing branch, the tip revision on
|
||||
that branch must be locked by the caller. Otherwise, only a
|
||||
new branch can be created. This restriction is not enforced
|
||||
for the owner of the file if non-strict locking is used
|
||||
(see
|
||||
.BR rcs (1)).
|
||||
A lock held by someone else may be broken with the
|
||||
.B rcs
|
||||
command.
|
||||
.PP
|
||||
Unless the
|
||||
.B \-f
|
||||
option is given,
|
||||
.B ci
|
||||
checks whether the revision to be deposited differs from the preceding one.
|
||||
If not, instead of creating a new revision
|
||||
.B ci
|
||||
reverts to the preceding one.
|
||||
To revert, ordinary
|
||||
.B ci
|
||||
removes the working file and any lock;
|
||||
.B "ci\ \-l"
|
||||
keeps and
|
||||
.B "ci\ \-u"
|
||||
removes any lock, and then they both generate a new working file much as if
|
||||
.B "co\ \-l"
|
||||
or
|
||||
.B "co\ \-u"
|
||||
had been applied to the preceding revision.
|
||||
When reverting, any
|
||||
.B \-n
|
||||
and
|
||||
.B \-s
|
||||
options apply to the preceding revision.
|
||||
.PP
|
||||
For each revision deposited,
|
||||
.B ci
|
||||
prompts for a log message.
|
||||
The log message should summarize the change and must be terminated by
|
||||
end-of-file or by a line containing
|
||||
.BR \&. "\ by"
|
||||
itself.
|
||||
If several files are checked in
|
||||
.B ci
|
||||
asks whether to reuse the
|
||||
previous log message.
|
||||
If the standard input is not a terminal,
|
||||
.B ci
|
||||
suppresses the prompt
|
||||
and uses the same log message for all files.
|
||||
See also
|
||||
.BR \-m .
|
||||
.PP
|
||||
If the \*r file does not exist,
|
||||
.B ci
|
||||
creates it and
|
||||
deposits the contents of the working file as the initial revision
|
||||
(default number:
|
||||
.BR 1.1 ).
|
||||
The access list is initialized to empty.
|
||||
Instead of the log message,
|
||||
.B ci
|
||||
requests descriptive text (see
|
||||
.B \-t
|
||||
below).
|
||||
.PP
|
||||
The number
|
||||
.I rev
|
||||
of the deposited revision can be given by any of the options
|
||||
.BR \-f ,
|
||||
.BR \-I ,
|
||||
.BR \-k ,
|
||||
.BR \-l ,
|
||||
.BR \-M ,
|
||||
.BR \-q ,
|
||||
.BR \-r ,
|
||||
or
|
||||
.BR \-u .
|
||||
.I rev
|
||||
may be symbolic, numeric, or mixed.
|
||||
If
|
||||
.I rev
|
||||
is
|
||||
.BR $ ,
|
||||
.B ci
|
||||
determines the revision number from keyword values in the working file.
|
||||
.PP
|
||||
If
|
||||
.I rev
|
||||
is a revision number, it must be higher than the latest
|
||||
one on the branch to which
|
||||
.I rev
|
||||
belongs, or must start a new branch.
|
||||
.PP
|
||||
If
|
||||
.I rev
|
||||
is a branch rather than a revision number,
|
||||
the new revision is appended to that branch. The level number is obtained
|
||||
by incrementing the tip revision number of that branch.
|
||||
If
|
||||
.I rev
|
||||
indicates a non-existing branch,
|
||||
that branch is created with the initial revision numbered
|
||||
.IB rev .1\f1.\fP
|
||||
.br
|
||||
.ne 8
|
||||
.PP
|
||||
If
|
||||
.I rev
|
||||
is omitted,
|
||||
.B ci
|
||||
tries to derive the new revision number from
|
||||
the caller's last lock. If the caller has locked the tip revision of a branch,
|
||||
the new revision is appended to that branch.
|
||||
The new revision number is obtained
|
||||
by incrementing the tip revision number.
|
||||
If the caller locked a non-tip revision, a new branch is started at
|
||||
that revision by incrementing the highest branch number at that revision.
|
||||
The default initial branch and level numbers are
|
||||
.BR 1 .
|
||||
.PP
|
||||
If
|
||||
.I rev
|
||||
is omitted and the caller has no lock, but owns
|
||||
the file and locking
|
||||
is not set to
|
||||
.IR strict ,
|
||||
then the revision is appended to the
|
||||
default branch (normally the trunk; see the
|
||||
.B \-b
|
||||
option of
|
||||
.BR rcs (1)).
|
||||
.PP
|
||||
Exception: On the trunk, revisions can be appended to the end, but
|
||||
not inserted.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BR \-r [\f2rev\fP]
|
||||
checks in a revision, releases the corresponding lock, and
|
||||
removes the working file. This is the default.
|
||||
.RS
|
||||
.PP
|
||||
The
|
||||
.B \-r
|
||||
option has an unusual meaning in
|
||||
.BR ci .
|
||||
In other \*r commands,
|
||||
.B \-r
|
||||
merely specifies a revision number,
|
||||
but in
|
||||
.B ci
|
||||
it also releases a lock and removes the working file.
|
||||
See
|
||||
.B \-u
|
||||
for a tricky example.
|
||||
.RE
|
||||
.TP
|
||||
.BR \-l [\f2rev\fP]
|
||||
works like
|
||||
.BR \-r ,
|
||||
except it performs an additional
|
||||
.B "co\ \-l"
|
||||
for the
|
||||
deposited revision. Thus, the deposited revision is immediately
|
||||
checked out again and locked.
|
||||
This is useful for saving a revision although one wants to continue
|
||||
editing it after the checkin.
|
||||
.TP
|
||||
.BR \-u [\f2rev\fP]
|
||||
works like
|
||||
.BR \-l ,
|
||||
except that the deposited revision is not locked.
|
||||
This lets one read the working file
|
||||
immediately after checkin.
|
||||
.RS
|
||||
.PP
|
||||
The
|
||||
.BR \-l ,
|
||||
.BR \-r ,
|
||||
and
|
||||
.B \-u
|
||||
options are mutually exclusive and silently override each other.
|
||||
For example,
|
||||
.B "ci\ \-u\ \-r"
|
||||
is equivalent to
|
||||
.B "ci\ \-r"
|
||||
because
|
||||
.B \-r
|
||||
overrides
|
||||
.BR \-u .
|
||||
.RE
|
||||
.TP
|
||||
.BR \-f [\f2rev\fP]
|
||||
forces a deposit; the new revision is deposited even it is not different
|
||||
from the preceding one.
|
||||
.TP
|
||||
.BR \-k [\f2rev\fP]
|
||||
searches the working file for keyword values to determine its revision number,
|
||||
creation date, state, and author (see
|
||||
.BR co (1)),
|
||||
and assigns these
|
||||
values to the deposited revision, rather than computing them locally.
|
||||
It also generates a default login message noting the login of the caller
|
||||
and the actual checkin date.
|
||||
This option is useful for software distribution. A revision that is sent to
|
||||
several sites should be checked in with the
|
||||
.B \-k
|
||||
option at these sites to
|
||||
preserve the original number, date, author, and state.
|
||||
The extracted keyword values and the default log message may be overridden
|
||||
with the options
|
||||
.BR \-d ,
|
||||
.BR \-m ,
|
||||
.BR \-s ,
|
||||
.BR \-w ,
|
||||
and any option that carries a revision number.
|
||||
.TP
|
||||
.BR \-q [\f2rev\fP]
|
||||
quiet mode; diagnostic output is not printed.
|
||||
A revision that is not different from the preceding one is not deposited,
|
||||
unless
|
||||
.B \-f
|
||||
is given.
|
||||
.TP
|
||||
.BR \-I [\f2rev\fP]
|
||||
interactive mode;
|
||||
the user is prompted and questioned
|
||||
even if the standard input is not a terminal.
|
||||
.TP
|
||||
.BR \-d "[\f2date\fP]"
|
||||
uses
|
||||
.I date
|
||||
for the checkin date and time.
|
||||
The
|
||||
.I date
|
||||
is specified in free format as explained in
|
||||
.BR co (1).
|
||||
This is useful for lying about the checkin date, and for
|
||||
.B \-k
|
||||
if no date is available.
|
||||
If
|
||||
.I date
|
||||
is empty, the working file's time of last modification is used.
|
||||
.TP
|
||||
.BR \-M [\f2rev\fP]
|
||||
Set the modification time on any new working file
|
||||
to be the date of the retrieved revision.
|
||||
For example,
|
||||
.BI "ci\ \-d\ \-M\ \-u" "\ f"
|
||||
does not alter
|
||||
.IR f 's
|
||||
modification time, even if
|
||||
.IR f 's
|
||||
contents change due to keyword substitution.
|
||||
Use this option with care; it can confuse
|
||||
.BR make (1).
|
||||
.TP
|
||||
.BI \-m "msg"
|
||||
uses the string
|
||||
.I msg
|
||||
as the log message for all revisions checked in.
|
||||
.TP
|
||||
.BI \-n "name"
|
||||
assigns the symbolic name
|
||||
.I name
|
||||
to the number of the checked-in revision.
|
||||
.B ci
|
||||
prints an error message if
|
||||
.I name
|
||||
is already assigned to another
|
||||
number.
|
||||
.TP
|
||||
.BI \-N "name"
|
||||
same as
|
||||
.BR \-n ,
|
||||
except that it overrides a previous assignment of
|
||||
.IR name .
|
||||
.TP
|
||||
.BI \-s "state"
|
||||
sets the state of the checked-in revision to the identifier
|
||||
.IR state .
|
||||
The default state is
|
||||
.BR Exp .
|
||||
.TP
|
||||
.BI \-t file
|
||||
writes descriptive text from the contents of the named
|
||||
.I file
|
||||
into the \*r file,
|
||||
deleting the existing text.
|
||||
The
|
||||
.I file
|
||||
may not begin with
|
||||
.BR \- .
|
||||
.TP
|
||||
.BI \-t\- string
|
||||
Write descriptive text from the
|
||||
.I string
|
||||
into the \*r file, deleting the existing text.
|
||||
.RS
|
||||
.PP
|
||||
The
|
||||
.B \-t
|
||||
option, in both its forms, has effect only during an initial checkin;
|
||||
it is silently ignored otherwise.
|
||||
.PP
|
||||
During the initial checkin, if
|
||||
.B \-t
|
||||
is not given,
|
||||
.B ci
|
||||
obtains the text from standard input,
|
||||
terminated by end-of-file or by a line containing
|
||||
.BR \&. "\ by"
|
||||
itself.
|
||||
The user is prompted for the text if interaction is possible; see
|
||||
.BR \-I .
|
||||
.PP
|
||||
For backward compatibility with older versions of \*r, a bare
|
||||
.B \-t
|
||||
option is ignored.
|
||||
.RE
|
||||
.TP
|
||||
.BI \-w "login"
|
||||
uses
|
||||
.I login
|
||||
for the author field of the deposited revision.
|
||||
Useful for lying about the author, and for
|
||||
.B \-k
|
||||
if no author is available.
|
||||
.TP
|
||||
.BI \-V n
|
||||
Emulate \*r version
|
||||
.IR n .
|
||||
See
|
||||
.BR co (1)
|
||||
for details.
|
||||
.TP
|
||||
.BI \-x "suffixes"
|
||||
specifies the suffixes for \*r files.
|
||||
A nonempty suffix matches any pathname ending in the suffix.
|
||||
An empty suffix matches any pathname of the form
|
||||
.BI RCS/ file
|
||||
or
|
||||
.IB path /RCS/ file.
|
||||
The
|
||||
.B \-x
|
||||
option can specify a list of suffixes
|
||||
separated by
|
||||
.BR / .
|
||||
For example,
|
||||
.B \-x,v/
|
||||
specifies two suffixes:
|
||||
.B ,v
|
||||
and the empty suffix.
|
||||
If two or more suffixes are specified,
|
||||
they are tried in order when looking for an \*r file;
|
||||
the first one that works is used for that file.
|
||||
If no \*r file is found but an \*r file can be created,
|
||||
the suffixes are tried in order
|
||||
to determine the new \*r file's name.
|
||||
The default for
|
||||
.IR suffixes
|
||||
is installation-dependent; normally it is
|
||||
.B ,v/
|
||||
for hosts like Unix that permit commas in file names,
|
||||
and is empty (i.e. just the empty suffix) for other hosts.
|
||||
.SH "FILE NAMING"
|
||||
Pairs of \*r files and working files may be specified in three ways
|
||||
(see also the
|
||||
example section).
|
||||
.PP
|
||||
1) Both the \*r file and the working file are given. The \*r pathname is of
|
||||
the form
|
||||
.IB path1 / workfileX
|
||||
and the working pathname is of the form
|
||||
.IB path2 / workfile
|
||||
where
|
||||
.IB path1 /
|
||||
and
|
||||
.IB path2 /
|
||||
are (possibly different or empty) paths,
|
||||
.I workfile
|
||||
is a filename, and
|
||||
.I X
|
||||
is an \*r suffix.
|
||||
If
|
||||
.I X
|
||||
is empty,
|
||||
.IB path1 /
|
||||
must be
|
||||
.B RCS/
|
||||
or must end in
|
||||
.BR /RCS/ .
|
||||
.PP
|
||||
2) Only the \*r file is given. Then the working file is created in the current
|
||||
directory and its name is derived from the name of the \*r file
|
||||
by removing
|
||||
.IB path1 /
|
||||
and the suffix
|
||||
.IR X .
|
||||
.PP
|
||||
3) Only the working file is given.
|
||||
Then
|
||||
.B ci
|
||||
considers each \*r suffix
|
||||
.I X
|
||||
in turn, looking for an \*r file of the form
|
||||
.IB path2 /RCS/ workfileX
|
||||
or (if the former is not found and
|
||||
.I X
|
||||
is nonempty)
|
||||
.IB path2 / workfileX.
|
||||
.PP
|
||||
If the \*r file is specified without a path in 1) and 2),
|
||||
.B ci
|
||||
looks for the \*r file first in the directory
|
||||
.B ./RCS
|
||||
and then in the current
|
||||
directory.
|
||||
.PP
|
||||
.B ci
|
||||
reports an error if an attempt to open an \*r file fails for an unusual reason,
|
||||
even if the \*r file's pathname is just one of several possibilities.
|
||||
For example, to suppress use of \*r commands in a directory
|
||||
.IR d ,
|
||||
create a regular file named
|
||||
.IB d /RCS
|
||||
so that casual attempts to use \*r commands in
|
||||
.I d
|
||||
fail because
|
||||
.IB d /RCS
|
||||
is not a directory.
|
||||
.SH EXAMPLES
|
||||
Suppose
|
||||
.B ,v
|
||||
is an \*r suffix and the current directory contains a subdirectory
|
||||
.B RCS
|
||||
with an \*r file
|
||||
.BR io.c,v .
|
||||
Then each of the following commands check in a copy of
|
||||
.B io.c
|
||||
into
|
||||
.B RCS/io.c,v
|
||||
as the latest revision, removing
|
||||
.BR io.c .
|
||||
.LP
|
||||
.RS
|
||||
.nf
|
||||
.ft 3
|
||||
ci io.c; ci RCS/io.c,v; ci io.c,v;
|
||||
ci io.c RCS/io.c,v; ci io.c io.c,v;
|
||||
ci RCS/io.c,v io.c; ci io.c,v io.c;
|
||||
.ft
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
Suppose instead that the empty suffix
|
||||
is an \*r suffix and the current directory contains a subdirectory
|
||||
.B RCS
|
||||
with an \*r file
|
||||
.BR io.c .
|
||||
The each of the following commands checks in a new revision.
|
||||
.LP
|
||||
.RS
|
||||
.nf
|
||||
.ft 3
|
||||
ci io.c; ci RCS/io.c;
|
||||
ci io.c RCS/io.c;
|
||||
ci RCS/io.c io.c;
|
||||
.ft
|
||||
.fi
|
||||
.RE
|
||||
.SH "FILE MODES"
|
||||
An \*r file created by
|
||||
.B ci
|
||||
inherits the read and execute permissions
|
||||
from the working file. If the \*r file exists already,
|
||||
.B ci
|
||||
preserves its read and execute permissions.
|
||||
.B ci
|
||||
always turns off all write permissions of \*r files.
|
||||
.SH FILES
|
||||
Several temporary files may be created in the directory containing
|
||||
the working file, and also in the temporary directory (see
|
||||
.B \s-1TMPDIR\s0
|
||||
under
|
||||
.BR \s-1ENVIRONMENT\s0 ).
|
||||
A semaphore file or files are created in the directory containing the \*r file.
|
||||
With a nonempty suffix, the semaphore names begin with
|
||||
the first character of the suffix; therefore, do not specify an suffix
|
||||
whose first character could be that of a working filename.
|
||||
With an empty suffix, the semaphore names end with
|
||||
.B _
|
||||
so working filenames should not end in
|
||||
.BR _ .
|
||||
.PP
|
||||
.B ci
|
||||
never changes an \*r or working file.
|
||||
Normally,
|
||||
.B ci
|
||||
unlinks the file and creates a new one;
|
||||
but instead of breaking a chain of one or more symbolic links to an \*r file,
|
||||
it unlinks the destination file instead.
|
||||
Therefore,
|
||||
.B ci
|
||||
breaks any hard or symbolic links to any working file it changes;
|
||||
and hard links to \*r files are ineffective,
|
||||
but symbolic links to \*r files are preserved.
|
||||
.PP
|
||||
The effective user must be able to
|
||||
search and write the directory containing the \*r file.
|
||||
Normally, the real user must be able to
|
||||
read the \*r and working files
|
||||
and to search and write the directory containing the working file;
|
||||
however, some older hosts
|
||||
cannot easily switch between real and effective users,
|
||||
so on these hosts the effective user is used for all accesses.
|
||||
The effective user is the same as the real user
|
||||
unless your copies of
|
||||
.B ci
|
||||
and
|
||||
.B co
|
||||
have setuid privileges.
|
||||
As described in the next section,
|
||||
these privileges yield extra security if
|
||||
the effective user owns all \*r files and directories,
|
||||
and if only the effective user can write \*r directories.
|
||||
.PP
|
||||
Users can control access to \*r files by setting the permissions
|
||||
of the directory containing the files; only users with write access
|
||||
to the directory can use \*r commands to change its \*r files.
|
||||
For example, in hosts that allow a user to belong to several groups,
|
||||
one can make a group's \*r directories writable to that group only.
|
||||
This approach suffices for informal projects,
|
||||
but it means that any group member can arbitrarily change the group's \*r files,
|
||||
and can even remove them entirely.
|
||||
Hence more formal projects sometimes distinguish between an \*r administrator,
|
||||
who can change the \*r files at will, and other project members,
|
||||
who can check in new revisions but cannot otherwise change the \*r files.
|
||||
.SH "SETUID USE"
|
||||
To prevent anybody but their \*r administrator from deleting revisions,
|
||||
a set of users can employ setuid privileges as follows.
|
||||
.nr n \w'\(bu '+1n-1/1n
|
||||
.IP \(bu \nn
|
||||
Check that the host supports \*r setuid use.
|
||||
Consult a trustworthy expert if there are any doubts.
|
||||
It is best if the
|
||||
.B seteuid()
|
||||
system call works as described in Posix 1003.1a Draft 5,
|
||||
because \*r can switch back and forth easily
|
||||
between real and effective users, even if the real user is
|
||||
.BR root .
|
||||
If not, the second best is if the
|
||||
.B setuid()
|
||||
system call supports saved setuid
|
||||
(the {\s-1_POSIX_SAVED_IDS\s0} behavior of Posix 1003.1-1990);
|
||||
this fails only if the real user is
|
||||
.BR root .
|
||||
If \*r detects any failure in setuid, it quits immediately.
|
||||
.IP \(bu \nn
|
||||
Choose a user
|
||||
.I A
|
||||
to serve as \*r administrator for the set of users.
|
||||
Only
|
||||
.I A
|
||||
will be able to invoke the
|
||||
.B rcs
|
||||
command on the users' \*r files.
|
||||
.I A
|
||||
should not be
|
||||
.B root
|
||||
or any other user with special powers.
|
||||
Mutually suspicious sets of users should use different administrators.
|
||||
.IP \(bu \nn
|
||||
Choose a path name
|
||||
.I B
|
||||
that will be a directory of files to be executed by the users.
|
||||
.IP \(bu \nn
|
||||
Have
|
||||
.I A
|
||||
set up
|
||||
.I B
|
||||
to contain copies of
|
||||
.B ci
|
||||
and
|
||||
.B co
|
||||
that are setuid to
|
||||
.I A
|
||||
by copying the commands from their standard installation directory
|
||||
.I D
|
||||
as follows:
|
||||
.LP
|
||||
.RS
|
||||
.nf
|
||||
.ne 3
|
||||
\f3mkdir\fP \f2B\fP
|
||||
\f3cp\fP \f2D\fP\^\f3/c[io]\fP \f2B\fP
|
||||
\f3chmod go\-w,u+s\fP \f2B\fP\f3/c[io]\fP
|
||||
.fi
|
||||
.RE
|
||||
.IP \(bu \nn
|
||||
Have each user prepend
|
||||
.I B
|
||||
to their path as follows:
|
||||
.LP
|
||||
.RS
|
||||
.nf
|
||||
.ne 2
|
||||
\f3PATH=\fP\f2B\fP\f3:$PATH; export PATH\fP # ordinary shell
|
||||
\f3set path=(\fP\f2B\fP \f3$path)\fP # C shell
|
||||
.fi
|
||||
.RE
|
||||
.IP \(bu \nn
|
||||
Have
|
||||
.I A
|
||||
create each \*r directory
|
||||
.I R
|
||||
with write access only to
|
||||
.I A
|
||||
as follows:
|
||||
.LP
|
||||
.RS
|
||||
.nf
|
||||
.ne 2
|
||||
\f3mkdir\fP \f2R\fP
|
||||
\f3chmod go\-w\fP \f2R\fP
|
||||
.fi
|
||||
.RE
|
||||
.IP \(bu \nn
|
||||
If you want to let only certain users read the \*r files,
|
||||
put the users into a group
|
||||
.IR G ,
|
||||
and have
|
||||
.I A
|
||||
further protect the \*r directory as follows:
|
||||
.LP
|
||||
.RS
|
||||
.nf
|
||||
.ne 2
|
||||
\f3chgrp\fP \f2G R\fP
|
||||
\f3chmod g\-w,o\-rwx\fP \f2R\fP
|
||||
.fi
|
||||
.RE
|
||||
.IP \(bu \nn
|
||||
Have
|
||||
.I A
|
||||
copy old \*r files (if any) into
|
||||
.IR R ,
|
||||
to ensure that
|
||||
.I A
|
||||
owns them.
|
||||
.IP \(bu \nn
|
||||
An \*r file's access list limits who can check in and lock revisions.
|
||||
The default access list is empty,
|
||||
which grants checkin access to anyone who can read the \*r file.
|
||||
If you want limit checkin access,
|
||||
have
|
||||
.I A
|
||||
invoke
|
||||
.B "rcs\ \-a"
|
||||
on the file; see
|
||||
.BR rcs (1).
|
||||
In particular,
|
||||
.BI "rcs\ \-e\ \-a" A
|
||||
limits access to just
|
||||
.IR A .
|
||||
.IP \(bu \nn
|
||||
Have
|
||||
.I A
|
||||
initialize any new \*r files with
|
||||
.B "rcs\ \-i"
|
||||
before initial checkin, adding the
|
||||
.B \-a
|
||||
option if you want to limit checkin access.
|
||||
.IP \(bu \nn
|
||||
Give setuid privileges only to
|
||||
.BR ci ,
|
||||
.BR co ,
|
||||
and
|
||||
.BR rcsclean ;
|
||||
do not give them to
|
||||
.B rcs
|
||||
or to any other command.
|
||||
.IP \(bu \nn
|
||||
Do not use other setuid commands to invoke \*r commands;
|
||||
setuid is trickier than you think!
|
||||
.SH ENVIRONMENT
|
||||
.TP
|
||||
.B \s-1RCSINIT\s0
|
||||
options prepended to the argument list, separated by spaces.
|
||||
A backslash escapes spaces within an option.
|
||||
The
|
||||
.B \s-1RCSINIT\s0
|
||||
options are prepended to the argument lists of most \*r commands.
|
||||
Useful
|
||||
.B \s-1RCSINIT\s0
|
||||
options include
|
||||
.BR \-q ,
|
||||
.BR \-V ,
|
||||
and
|
||||
.BR \-x .
|
||||
.TP
|
||||
.B \s-1TMPDIR\s0
|
||||
Name of the temporary directory.
|
||||
If not set, the environment variables
|
||||
.B \s-1TMP\s0
|
||||
and
|
||||
.B \s-1TEMP\s0
|
||||
are inspected instead and the first value found is taken;
|
||||
if none of them are set,
|
||||
a host-dependent default is used, typically
|
||||
.BR /tmp .
|
||||
.SH DIAGNOSTICS
|
||||
For each revision,
|
||||
.B ci
|
||||
prints the \*r file, the working file, and the number
|
||||
of both the deposited and the preceding revision.
|
||||
The exit status is zero if and only if all operations were successful.
|
||||
.SH IDENTIFICATION
|
||||
Author: Walter F. Tichy.
|
||||
.br
|
||||
Revision Number: \*(Rv; Release Date: \*(Dt.
|
||||
.br
|
||||
Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
|
||||
.br
|
||||
Copyright \(co 1990, 1991 by Paul Eggert.
|
||||
.SH "SEE ALSO"
|
||||
co(1), ident(1), make(1), rcs(1), rcsclean(1), rcsdiff(1),
|
||||
rcsintro(1), rcsmerge(1), rlog(1), rcsfile(5)
|
||||
.br
|
||||
Walter F. Tichy,
|
||||
\*r\*-A System for Version Control,
|
||||
.I "Software\*-Practice & Experience"
|
||||
.BR 15 ,
|
||||
7 (July 1985), 637-654.
|
||||
.br
|
||||
1165
gnu/usr.bin/rcs/ci/ci.c
Normal file
1165
gnu/usr.bin/rcs/ci/ci.c
Normal file
File diff suppressed because it is too large
Load diff
7
gnu/usr.bin/rcs/co/Makefile
Normal file
7
gnu/usr.bin/rcs/co/Makefile
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
PROG= co
|
||||
|
||||
SRCS= co.c
|
||||
LDADD= -L${.CURDIR}/../lib/obj -lrcs
|
||||
CFLAGS+= -I${.CURDIR}/../lib
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
569
gnu/usr.bin/rcs/co/co.1
Normal file
569
gnu/usr.bin/rcs/co/co.1
Normal file
|
|
@ -0,0 +1,569 @@
|
|||
.de Id
|
||||
.ds Rv \\$3
|
||||
.ds Dt \\$4
|
||||
..
|
||||
.Id $Id: co.1,v 5.7 1991/08/19 03:13:55 eggert Exp $
|
||||
.ds g \&\s-1UTC\s0
|
||||
.ds r \&\s-1RCS\s0
|
||||
.if n .ds - \%--
|
||||
.if t .ds - \(em
|
||||
.TH CO 1 \*(Dt GNU
|
||||
.SH NAME
|
||||
co \- check out RCS revisions
|
||||
.SH SYNOPSIS
|
||||
.B co
|
||||
.RI [ options ] " file " .\|.\|.
|
||||
.SH DESCRIPTION
|
||||
.B co
|
||||
retrieves a revision from each \*r file and stores it into
|
||||
the corresponding working file.
|
||||
.PP
|
||||
Pathnames matching an \*r suffix denote \*r files;
|
||||
all others denote working files.
|
||||
Names are paired as explained in
|
||||
.BR ci (1).
|
||||
.PP
|
||||
Revisions of an \*r file may be checked out locked or unlocked. Locking a
|
||||
revision prevents overlapping updates. A revision checked out for reading or
|
||||
processing (e.g., compiling) need not be locked. A revision checked out
|
||||
for editing and later checkin must normally be locked. Checkout with locking
|
||||
fails if the revision to be checked out is currently locked by another user.
|
||||
(A lock may be broken with
|
||||
.BR rcs "(1).)\ \&"
|
||||
Checkout with locking also requires the caller to be on the access list of
|
||||
the \*r file, unless he is the owner of the
|
||||
file or the superuser, or the access list is empty.
|
||||
Checkout without locking is not subject to accesslist restrictions, and is
|
||||
not affected by the presence of locks.
|
||||
.PP
|
||||
A revision is selected by options for revision or branch number,
|
||||
checkin date/time, author, or state.
|
||||
When the selection options
|
||||
are applied in combination,
|
||||
.B co
|
||||
retrieves the latest revision
|
||||
that satisfies all of them.
|
||||
If none of the selection options
|
||||
is specified,
|
||||
.B co
|
||||
retrieves the latest revision
|
||||
on the default branch (normally the trunk, see the
|
||||
.B \-b
|
||||
option of
|
||||
.BR rcs (1)).
|
||||
A revision or branch number may be attached
|
||||
to any of the options
|
||||
.BR \-f ,
|
||||
.BR \-I ,
|
||||
.BR \-l ,
|
||||
.BR \-M ,
|
||||
.BR \-p ,
|
||||
.BR \-q ,
|
||||
.BR \-r ,
|
||||
or
|
||||
.BR \-u .
|
||||
The options
|
||||
.B \-d
|
||||
(date),
|
||||
.B \-s
|
||||
(state), and
|
||||
.B \-w
|
||||
(author)
|
||||
retrieve from a single branch, the
|
||||
.I selected
|
||||
branch,
|
||||
which is either specified by one of
|
||||
.BR \-f,
|
||||
\&.\|.\|.,
|
||||
.BR \-u ,
|
||||
or the default branch.
|
||||
.PP
|
||||
A
|
||||
.B co
|
||||
command applied to an \*r
|
||||
file with no revisions creates a zero-length working file.
|
||||
.B co
|
||||
always performs keyword substitution (see below).
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BR \-r [\f2rev\fP]
|
||||
retrieves the latest revision whose number is less than or equal to
|
||||
.I rev.
|
||||
If
|
||||
.I rev
|
||||
indicates a branch rather than a revision,
|
||||
the latest revision on that branch is retrieved.
|
||||
If
|
||||
.I rev
|
||||
is omitted, the latest revision on the default branch
|
||||
(see the
|
||||
.B \-b
|
||||
option of
|
||||
.BR rcs (1))
|
||||
is retrieved.
|
||||
If
|
||||
.I rev
|
||||
is
|
||||
.BR $ ,
|
||||
.B co
|
||||
determines the revision number from keyword values in the working file.
|
||||
Otherwise, a revision is composed of one or more numeric or symbolic fields
|
||||
separated by periods. The numeric equivalent of a symbolic field
|
||||
is specified with the
|
||||
.B \-n
|
||||
option of the commands
|
||||
.BR ci (1)
|
||||
and
|
||||
.BR rcs (1).
|
||||
.TP
|
||||
.BR \-l [\f2rev\fP]
|
||||
same as
|
||||
.BR \-r ,
|
||||
except that it also locks the retrieved revision for
|
||||
the caller.
|
||||
.TP
|
||||
.BR \-u [\f2rev\fP]
|
||||
same as
|
||||
.BR \-r ,
|
||||
except that it unlocks the retrieved revision if it was
|
||||
locked by the caller. If
|
||||
.I rev
|
||||
is omitted,
|
||||
.B \-u
|
||||
retrieves the revision locked by the caller, if there is one; otherwise,
|
||||
it retrieves the latest revision on the default branch.
|
||||
.TP
|
||||
.BR \-f [\f2rev\fP]
|
||||
forces the overwriting of the working file;
|
||||
useful in connection with
|
||||
.BR \-q .
|
||||
See also
|
||||
.SM "FILE MODES"
|
||||
below.
|
||||
.TP
|
||||
.B \-kkv
|
||||
Generate keyword strings using the default form, e.g.\&
|
||||
.B "$\&Revision: \*(Rv $"
|
||||
for the
|
||||
.B Revision
|
||||
keyword.
|
||||
A locker's name is inserted in the value of the
|
||||
.BR Header ,
|
||||
.BR Id ,
|
||||
and
|
||||
.B Locker
|
||||
keyword strings
|
||||
only as a file is being locked,
|
||||
i.e. by
|
||||
.B "ci\ \-l"
|
||||
and
|
||||
.BR "co\ \-l".
|
||||
This is the default.
|
||||
.TP
|
||||
.B \-kkvl
|
||||
Like
|
||||
.BR \-kkv ,
|
||||
except that a locker's name is always inserted
|
||||
if the given revision is currently locked.
|
||||
.TP
|
||||
.BR \-kk
|
||||
Generate only keyword names in keyword strings; omit their values.
|
||||
See
|
||||
.SM "KEYWORD SUBSTITUTION"
|
||||
below.
|
||||
For example, for the
|
||||
.B Revision
|
||||
keyword, generate the string
|
||||
.B $\&Revision$
|
||||
instead of
|
||||
.BR "$\&Revision: \*(Rv $".
|
||||
This option is useful to ignore differences due to keyword substitution
|
||||
when comparing different revisions of a file.
|
||||
.TP
|
||||
.BR \-ko
|
||||
Generate the old keyword string,
|
||||
present in the working file just before it was checked in.
|
||||
For example, for the
|
||||
.B Revision
|
||||
keyword, generate the string
|
||||
.B "$\&Revision: 1.1 $"
|
||||
instead of
|
||||
.B "$\&Revision: \*(Rv $"
|
||||
if that is how the string appeared when the file was checked in.
|
||||
This can be useful for binary file formats
|
||||
that cannot tolerate any changes to substrings
|
||||
that happen to take the form of keyword strings.
|
||||
.TP
|
||||
.BR \-kv
|
||||
Generate only keyword values for keyword strings.
|
||||
For example, for the
|
||||
.B Revision
|
||||
keyword, generate the string
|
||||
.B \*(Rv
|
||||
instead of
|
||||
.BR "$\&Revision: \*(Rv $".
|
||||
This can help generate files in programming languages where it is hard to
|
||||
strip keyword delimiters like
|
||||
.B "$\&Revision:\ $"
|
||||
from a string.
|
||||
However, further keyword substitution cannot be performed once the
|
||||
keyword names are removed, so this option should be used with care.
|
||||
Because of this danger of losing keywords,
|
||||
this option cannot be combined with
|
||||
.BR \-l ,
|
||||
and the owner write permission of the working file is turned off;
|
||||
to edit the file later, check it out again without
|
||||
.BR \-kv .
|
||||
.TP
|
||||
.BR \-p [\f2rev\fP]
|
||||
prints the retrieved revision on the standard output rather than storing it
|
||||
in the working file.
|
||||
This option is useful when
|
||||
.B co
|
||||
is part of a pipe.
|
||||
.TP
|
||||
.BR \-q [\f2rev\fP]
|
||||
quiet mode; diagnostics are not printed.
|
||||
.TP
|
||||
.BR \-I [\f2rev\fP]
|
||||
interactive mode;
|
||||
the user is prompted and questioned
|
||||
even if the standard input is not a terminal.
|
||||
.TP
|
||||
.BI \-d date
|
||||
retrieves the latest revision on the selected branch whose checkin date/time is
|
||||
less than or equal to
|
||||
.I date.
|
||||
The date and time may be given in free format.
|
||||
The time zone
|
||||
.B LT
|
||||
stands for local time;
|
||||
other common time zone names are understood.
|
||||
For example, the following
|
||||
.IR date s
|
||||
are equivalent
|
||||
if local time is January 11, 1990, 8pm Pacific Standard Time,
|
||||
eight hours west of Coordinated Universal Time (\*g):
|
||||
.RS
|
||||
.LP
|
||||
.RS
|
||||
.nf
|
||||
.ta \w'\f3Thu, 11 Jan 1990 20:00:00 \-0800\fP 'u
|
||||
.ne 9
|
||||
\f38:00 pm lt\fP
|
||||
\f34:00 AM, Jan. 12, 1990\fP note: default is \*g
|
||||
\f31990/01/12 04:00:00\fP \*r date format
|
||||
\f3Thu Jan 11 20:00:00 1990 LT\fP output of \f3ctime\fP(3) + \f3LT\fP
|
||||
\f3Thu Jan 11 20:00:00 PST 1990\fP output of \f3date\fP(1)
|
||||
\f3Fri Jan 12 04:00:00 GMT 1990\fP
|
||||
\f3Thu, 11 Jan 1990 20:00:00 \-0800\fP
|
||||
\f3Fri-JST, 1990, 1pm Jan 12\fP
|
||||
\f312-January-1990, 04:00-WET\fP
|
||||
.ta 4n +4n +4n +4n
|
||||
.fi
|
||||
.RE
|
||||
.LP
|
||||
Most fields in the date and time may be defaulted.
|
||||
The default time zone is \*g.
|
||||
The other defaults are determined in the order year, month, day,
|
||||
hour, minute, and second (most to least significant). At least one of these
|
||||
fields must be provided. For omitted fields that are of higher significance
|
||||
than the highest provided field, the time zone's current values are assumed.
|
||||
For all other omitted fields,
|
||||
the lowest possible values are assumed.
|
||||
For example, the date
|
||||
.B "20, 10:30"
|
||||
defaults to
|
||||
10:30:00 \*g of the 20th of the \*g time zone's current month and year.
|
||||
The date/time must be quoted if it contains spaces.
|
||||
.RE
|
||||
.TP
|
||||
.BR \-M [\f2rev\fP]
|
||||
Set the modification time on the new working file
|
||||
to be the date of the retrieved revision.
|
||||
Use this option with care; it can confuse
|
||||
.BR make (1).
|
||||
.TP
|
||||
.BI \-s state
|
||||
retrieves the latest revision on the selected branch whose state is set to
|
||||
.I state.
|
||||
.TP
|
||||
.BR \-w [\f2login\fP]
|
||||
retrieves the latest revision on the selected branch which was checked in
|
||||
by the user with login name
|
||||
.I login.
|
||||
If the argument
|
||||
.I login
|
||||
is
|
||||
omitted, the caller's login is assumed.
|
||||
.TP
|
||||
.BI \-j joinlist
|
||||
generates a new revision which is the join of the revisions on
|
||||
.I joinlist.
|
||||
This option is largely obsoleted by
|
||||
.BR rcsmerge (1)
|
||||
but is retained for backwards compatibility.
|
||||
.RS
|
||||
.PP
|
||||
The
|
||||
.I joinlist
|
||||
is a comma-separated list of pairs of the form
|
||||
.IB rev2 : rev3,
|
||||
where
|
||||
.I rev2
|
||||
and
|
||||
.I rev3
|
||||
are (symbolic or numeric)
|
||||
revision numbers.
|
||||
For the initial such pair,
|
||||
.I rev1
|
||||
denotes the revision selected
|
||||
by the above options
|
||||
.BR \-f,
|
||||
\&.\|.\|.,
|
||||
.BR \-w .
|
||||
For all other pairs,
|
||||
.I rev1
|
||||
denotes the revision generated by the previous pair.
|
||||
(Thus, the output
|
||||
of one join becomes the input to the next.)
|
||||
.PP
|
||||
For each pair,
|
||||
.B co
|
||||
joins revisions
|
||||
.I rev1
|
||||
and
|
||||
.I rev3
|
||||
with respect to
|
||||
.I rev2.
|
||||
This means that all changes that transform
|
||||
.I rev2
|
||||
into
|
||||
.I rev1
|
||||
are applied to a copy of
|
||||
.I rev3.
|
||||
This is particularly useful if
|
||||
.I rev1
|
||||
and
|
||||
.I rev3
|
||||
are the ends of two branches that have
|
||||
.I rev2
|
||||
as a common ancestor. If
|
||||
.IR rev1 < rev2 < rev3
|
||||
on the same branch,
|
||||
joining generates a new revision which is like
|
||||
.I rev3,
|
||||
but with all changes that lead from
|
||||
.I rev1
|
||||
to
|
||||
.I rev2
|
||||
undone.
|
||||
If changes from
|
||||
.I rev2
|
||||
to
|
||||
.I rev1
|
||||
overlap with changes from
|
||||
.I rev2
|
||||
to
|
||||
.I rev3,
|
||||
.B co
|
||||
reports overlaps as described in
|
||||
.BR merge (1).
|
||||
.PP
|
||||
For the initial pair,
|
||||
.I rev2
|
||||
may be omitted. The default is the common
|
||||
ancestor.
|
||||
If any of the arguments indicate branches, the latest revisions
|
||||
on those branches are assumed.
|
||||
The options
|
||||
.B \-l
|
||||
and
|
||||
.B \-u
|
||||
lock or unlock
|
||||
.I rev1.
|
||||
.RE
|
||||
.TP
|
||||
.BI \-V n
|
||||
Emulate \*r version
|
||||
.I n,
|
||||
where
|
||||
.I n
|
||||
may be
|
||||
.BR 3 ,
|
||||
.BR 4 ,
|
||||
or
|
||||
.BR 5 .
|
||||
This may be useful when interchanging \*r files with others who are
|
||||
running older versions of \*r.
|
||||
To see which version of \*r your correspondents are running, have them invoke
|
||||
.B rlog
|
||||
on an \*r file;
|
||||
if none of the first few lines of output contain the string
|
||||
.B branch:
|
||||
it is version 3;
|
||||
if the dates' years have just two digits, it is version 4;
|
||||
otherwise, it is version 5.
|
||||
An \*r file generated while emulating version 3 will lose its default branch.
|
||||
An \*r revision generated while emulating version 4 or earlier will have
|
||||
a timestamp that is off by up to 13 hours.
|
||||
A revision extracted while emulating version 4 or earlier will contain
|
||||
dates of the form
|
||||
.IB yy / mm / dd
|
||||
instead of
|
||||
.IB yyyy / mm / dd
|
||||
and may also contain different white space in the substitution for
|
||||
.BR $\&Log$ .
|
||||
.TP
|
||||
.BI \-x "suffixes"
|
||||
Use
|
||||
.I suffixes
|
||||
to characterize \*r files.
|
||||
See
|
||||
.BR ci (1)
|
||||
for details.
|
||||
.SH "KEYWORD SUBSTITUTION"
|
||||
Strings of the form
|
||||
.BI $ keyword $
|
||||
and
|
||||
.BI $ keyword : .\|.\|. $
|
||||
embedded in
|
||||
the text are replaced
|
||||
with strings of the form
|
||||
.BI $ keyword : value $
|
||||
where
|
||||
.I keyword
|
||||
and
|
||||
.I value
|
||||
are pairs listed below.
|
||||
Keywords may be embedded in literal strings
|
||||
or comments to identify a revision.
|
||||
.PP
|
||||
Initially, the user enters strings of the form
|
||||
.BI $ keyword $ .
|
||||
On checkout,
|
||||
.B co
|
||||
replaces these strings with strings of the form
|
||||
.BI $ keyword : value $ .
|
||||
If a revision containing strings of the latter form
|
||||
is checked back in, the value fields will be replaced during the next
|
||||
checkout.
|
||||
Thus, the keyword values are automatically updated on checkout.
|
||||
This automatic substitution can be modified by the
|
||||
.B \-k
|
||||
options.
|
||||
.PP
|
||||
Keywords and their corresponding values:
|
||||
.TP
|
||||
.B $\&Author$
|
||||
The login name of the user who checked in the revision.
|
||||
.TP
|
||||
.B $\&Date$
|
||||
The date and time (\*g) the revision was checked in.
|
||||
.TP
|
||||
.B $\&Header$
|
||||
A standard header containing the full pathname of the \*r file, the
|
||||
revision number, the date (\*g), the author, the state,
|
||||
and the locker (if locked).
|
||||
.TP
|
||||
.B $\&Id$
|
||||
Same as
|
||||
.BR $\&Header$ ,
|
||||
except that the \*r filename is without a path.
|
||||
.TP
|
||||
.B $\&Locker$
|
||||
The login name of the user who locked the revision (empty if not locked).
|
||||
.TP
|
||||
.B $\&Log$
|
||||
The log message supplied during checkin, preceded by a header
|
||||
containing the \*r filename, the revision number, the author, and the date
|
||||
(\*g).
|
||||
Existing log messages are
|
||||
.I not
|
||||
replaced.
|
||||
Instead, the new log message is inserted after
|
||||
.BR $\&Log: .\|.\|. $ .
|
||||
This is useful for
|
||||
accumulating a complete change log in a source file.
|
||||
.TP
|
||||
.B $\&RCSfile$
|
||||
The name of the \*r file without a path.
|
||||
.TP
|
||||
.B $\&Revision$
|
||||
The revision number assigned to the revision.
|
||||
.TP
|
||||
.B $\&Source$
|
||||
The full pathname of the \*r file.
|
||||
.TP
|
||||
.B $\&State$
|
||||
The state assigned to the revision with the
|
||||
.B \-s
|
||||
option of
|
||||
.BR rcs (1)
|
||||
or
|
||||
.BR ci (1).
|
||||
.SH "FILE MODES"
|
||||
The working file inherits the read and execute permissions from the \*r
|
||||
file. In addition, the owner write permission is turned on, unless
|
||||
.B \-kv
|
||||
is set or the file
|
||||
is checked out unlocked and locking is set to strict (see
|
||||
.BR rcs (1)).
|
||||
.PP
|
||||
If a file with the name of the working file exists already and has write
|
||||
permission,
|
||||
.B co
|
||||
aborts the checkout,
|
||||
asking beforehand if possible.
|
||||
If the existing working file is
|
||||
not writable or
|
||||
.B \-f
|
||||
is given, the working file is deleted without asking.
|
||||
.SH FILES
|
||||
.B co
|
||||
accesses files much as
|
||||
.BR ci (1)
|
||||
does, except that it does not need to read the working file.
|
||||
.SH ENVIRONMENT
|
||||
.TP
|
||||
.B \s-1RCSINIT\s0
|
||||
options prepended to the argument list, separated by spaces.
|
||||
See
|
||||
.BR ci (1)
|
||||
for details.
|
||||
.SH DIAGNOSTICS
|
||||
The \*r pathname, the working pathname,
|
||||
and the revision number retrieved are
|
||||
written to the diagnostic output.
|
||||
The exit status is zero if and only if all operations were successful.
|
||||
.SH IDENTIFICATION
|
||||
Author: Walter F. Tichy.
|
||||
.br
|
||||
Revision Number: \*(Rv; Release Date: \*(Dt.
|
||||
.br
|
||||
Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
|
||||
.br
|
||||
Copyright \(co 1990, 1991 by Paul Eggert.
|
||||
.SH "SEE ALSO"
|
||||
ci(1), ctime(3), date(1), ident(1), make(1),
|
||||
rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1),
|
||||
rcsfile(5)
|
||||
.br
|
||||
Walter F. Tichy,
|
||||
\*r\*-A System for Version Control,
|
||||
.I "Software\*-Practice & Experience"
|
||||
.BR 15 ,
|
||||
7 (July 1985), 637-654.
|
||||
.SH LIMITS
|
||||
Links to the \*r and working files are not preserved.
|
||||
.PP
|
||||
There is no way to selectively suppress the expansion of keywords, except
|
||||
by writing them differently. In nroff and troff, this is done by embedding the
|
||||
null-character
|
||||
.B \e&
|
||||
into the keyword.
|
||||
.SH BUGS
|
||||
The
|
||||
.B \-d
|
||||
option sometimes gets confused, and accepts no date before 1970.
|
||||
.br
|
||||
769
gnu/usr.bin/rcs/co/co.c
Normal file
769
gnu/usr.bin/rcs/co/co.c
Normal file
|
|
@ -0,0 +1,769 @@
|
|||
/* Copyright (C) 1982, 1988, 1989 Walter Tichy
|
||||
Copyright 1990, 1991 by 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, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Report problems and direct all questions to:
|
||||
|
||||
rcs-bugs@cs.purdue.edu
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* RCS checkout operation
|
||||
*/
|
||||
/*****************************************************************************
|
||||
* check out revisions from RCS files
|
||||
*****************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
/* $Log: co.c,v $
|
||||
* Revision 5.9 1991/10/07 17:32:46 eggert
|
||||
* ci -u src/RCS/co.c,v src/co.c <<\.
|
||||
* -k affects just working file, not RCS file.
|
||||
*
|
||||
* Revision 5.8 1991/08/19 03:13:55 eggert
|
||||
* Warn before removing somebody else's file.
|
||||
* Add -M. Fix co -j bugs. Tune.
|
||||
*
|
||||
* Revision 5.7 1991/04/21 11:58:15 eggert
|
||||
* Ensure that working file is newer than RCS file after co -[lu].
|
||||
* Add -x, RCSINIT, MS-DOS support.
|
||||
*
|
||||
* Revision 5.6 1990/12/04 05:18:38 eggert
|
||||
* Don't checkaccesslist() unless necessary.
|
||||
* Use -I for prompts and -q for diagnostics.
|
||||
*
|
||||
* Revision 5.5 1990/11/01 05:03:26 eggert
|
||||
* Fix -j. Add -I.
|
||||
*
|
||||
* Revision 5.4 1990/10/04 06:30:11 eggert
|
||||
* Accumulate exit status across files.
|
||||
*
|
||||
* Revision 5.3 1990/09/11 02:41:09 eggert
|
||||
* co -kv yields a readonly working file.
|
||||
*
|
||||
* Revision 5.2 1990/09/04 08:02:13 eggert
|
||||
* Standardize yes-or-no procedure.
|
||||
*
|
||||
* Revision 5.0 1990/08/22 08:10:02 eggert
|
||||
* Permit multiple locks by same user. Add setuid support.
|
||||
* Remove compile-time limits; use malloc instead.
|
||||
* Permit dates past 1999/12/31. Switch to GMT.
|
||||
* Make lock and temp files faster and safer.
|
||||
* Ansify and Posixate. Add -k, -V. Remove snooping. Tune.
|
||||
*
|
||||
* Revision 4.7 89/05/01 15:11:41 narten
|
||||
* changed copyright header to reflect current distribution rules
|
||||
*
|
||||
* Revision 4.6 88/08/09 19:12:15 eggert
|
||||
* Fix "co -d" core dump; rawdate wasn't always initialized.
|
||||
* Use execv(), not system(); fix putchar('\0') and diagnose() botches; remove lint
|
||||
*
|
||||
* Revision 4.5 87/12/18 11:35:40 narten
|
||||
* lint cleanups (from Guy Harris)
|
||||
*
|
||||
* Revision 4.4 87/10/18 10:20:53 narten
|
||||
* Updating version numbers changes relative to 1.1, are actually
|
||||
* relative to 4.2
|
||||
*
|
||||
* Revision 1.3 87/09/24 13:58:30 narten
|
||||
* Sources now pass through lint (if you ignore printf/sprintf/fprintf
|
||||
* warnings)
|
||||
*
|
||||
* Revision 1.2 87/03/27 14:21:38 jenkins
|
||||
* Port to suns
|
||||
*
|
||||
* Revision 4.2 83/12/05 13:39:48 wft
|
||||
* made rewriteflag external.
|
||||
*
|
||||
* Revision 4.1 83/05/10 16:52:55 wft
|
||||
* Added option -u and -f.
|
||||
* Added handling of default branch.
|
||||
* Replaced getpwuid() with getcaller().
|
||||
* Removed calls to stat(); now done by pairfilenames().
|
||||
* Changed and renamed rmoldfile() to rmworkfile().
|
||||
* Replaced catchints() calls with restoreints(), unlink()--link() with rename();
|
||||
*
|
||||
* Revision 3.7 83/02/15 15:27:07 wft
|
||||
* Added call to fastcopy() to copy remainder of RCS file.
|
||||
*
|
||||
* Revision 3.6 83/01/15 14:37:50 wft
|
||||
* Added ignoring of interrupts while RCS file is renamed; this avoids
|
||||
* deletion of RCS files during the unlink/link window.
|
||||
*
|
||||
* Revision 3.5 82/12/08 21:40:11 wft
|
||||
* changed processing of -d to use DATEFORM; removed actual from
|
||||
* call to preparejoin; re-fixed printing of done at the end.
|
||||
*
|
||||
* Revision 3.4 82/12/04 18:40:00 wft
|
||||
* Replaced getdelta() with gettree(), SNOOPDIR with SNOOPFILE.
|
||||
* Fixed printing of "done".
|
||||
*
|
||||
* Revision 3.3 82/11/28 22:23:11 wft
|
||||
* Replaced getlogin() with getpwuid(), flcose() with ffclose(),
|
||||
* %02d with %.2d, mode generation for working file with WORKMODE.
|
||||
* Fixed nil printing. Fixed -j combined with -l and -p, and exit
|
||||
* for non-existing revisions in preparejoin().
|
||||
*
|
||||
* Revision 3.2 82/10/18 20:47:21 wft
|
||||
* Mode of working file is now maintained even for co -l, but write permission
|
||||
* is removed.
|
||||
* The working file inherits its mode from the RCS file, plus write permission
|
||||
* for the owner. The write permission is not given if locking is strict and
|
||||
* co does not lock.
|
||||
* An existing working file without write permission is deleted automatically.
|
||||
* Otherwise, co asks (empty answer: abort co).
|
||||
* Call to getfullRCSname() added, check for write error added, call
|
||||
* for getlogin() fixed.
|
||||
*
|
||||
* Revision 3.1 82/10/13 16:01:30 wft
|
||||
* fixed type of variables receiving from getc() (char -> int).
|
||||
* removed unused variables.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
#include "rcsbase.h"
|
||||
|
||||
static char const *getancestor P((char const*,char const*));
|
||||
static int buildjoin P((char const*));
|
||||
static int preparejoin P((void));
|
||||
static int rmlock P((struct hshentry const*));
|
||||
static int rmworkfile P((void));
|
||||
static void cleanup P((void));
|
||||
|
||||
static char const quietarg[] = "-q";
|
||||
|
||||
static char const *expandarg, *join, *suffixarg, *versionarg;
|
||||
static char const *joinlist[joinlength]; /* revisions to be joined */
|
||||
static FILE *neworkptr;
|
||||
static int exitstatus;
|
||||
static int forceflag;
|
||||
static int lastjoin; /* index of last element in joinlist */
|
||||
static int lockflag; /* -1 -> unlock, 0 -> do nothing, 1 -> lock */
|
||||
static int mtimeflag;
|
||||
static struct hshentries *gendeltas; /* deltas to be generated */
|
||||
static struct hshentry *targetdelta; /* final delta to be generated */
|
||||
static struct stat workstat;
|
||||
|
||||
mainProg(coId, "co", "$Id: co.c,v 5.9 1991/10/07 17:32:46 eggert Exp $")
|
||||
{
|
||||
static char const cmdusage[] =
|
||||
"\nco usage: co -{flpqru}[rev] -ddate -jjoinlist -sstate -w[login] -Vn file ...";
|
||||
|
||||
char *a, **newargv;
|
||||
char const *author, *date, *rev, *state;
|
||||
char const *joinfilename, *newdate, *neworkfilename;
|
||||
int changelock; /* 1 if a lock has been changed, -1 if error */
|
||||
int expmode, r, tostdout, workstatstat;
|
||||
struct buf numericrev; /* expanded revision number */
|
||||
char finaldate[datesize];
|
||||
|
||||
setrid();
|
||||
author = date = rev = state = nil;
|
||||
bufautobegin(&numericrev);
|
||||
expmode = -1;
|
||||
suffixes = X_DEFAULT;
|
||||
tostdout = false;
|
||||
|
||||
argc = getRCSINIT(argc, argv, &newargv);
|
||||
argv = newargv;
|
||||
while (a = *++argv, 0<--argc && *a++=='-') {
|
||||
switch (*a++) {
|
||||
|
||||
case 'r':
|
||||
revno:
|
||||
if (*a) {
|
||||
if (rev) warn("redefinition of revision number");
|
||||
rev = a;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
forceflag=true;
|
||||
goto revno;
|
||||
|
||||
case 'l':
|
||||
if (lockflag < 0) {
|
||||
warn("-l overrides -u.");
|
||||
}
|
||||
lockflag = 1;
|
||||
goto revno;
|
||||
|
||||
case 'u':
|
||||
if (0 < lockflag) {
|
||||
warn("-l overrides -u.");
|
||||
}
|
||||
lockflag = -1;
|
||||
goto revno;
|
||||
|
||||
case 'p':
|
||||
tostdout = true;
|
||||
goto revno;
|
||||
|
||||
case 'I':
|
||||
interactiveflag = true;
|
||||
goto revno;
|
||||
|
||||
case 'q':
|
||||
quietflag=true;
|
||||
goto revno;
|
||||
|
||||
case 'd':
|
||||
if (date)
|
||||
redefined('d');
|
||||
str2date(a, finaldate);
|
||||
date=finaldate;
|
||||
break;
|
||||
|
||||
case 'j':
|
||||
if (*a) {
|
||||
if (join) redefined('j');
|
||||
join = a;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
mtimeflag = true;
|
||||
goto revno;
|
||||
|
||||
case 's':
|
||||
if (*a) {
|
||||
if (state) redefined('s');
|
||||
state = a;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
if (author) redefined('w');
|
||||
if (*a)
|
||||
author = a;
|
||||
else
|
||||
author = getcaller();
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
suffixarg = *argv;
|
||||
suffixes = a;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
versionarg = *argv;
|
||||
setRCSversion(versionarg);
|
||||
break;
|
||||
|
||||
case 'k': /* set keyword expand mode */
|
||||
expandarg = *argv;
|
||||
if (0 <= expmode) redefined('k');
|
||||
if (0 <= (expmode = str2expmode(a)))
|
||||
break;
|
||||
/* fall into */
|
||||
default:
|
||||
faterror("unknown option: %s%s", *argv, cmdusage);
|
||||
|
||||
};
|
||||
} /* end of option processing */
|
||||
|
||||
if (argc<1) faterror("no input file%s", cmdusage);
|
||||
if (tostdout)
|
||||
# if text_equals_binary_stdio || text_work_stdio
|
||||
workstdout = stdout;
|
||||
# else
|
||||
if (!(workstdout = fdopen(STDOUT_FILENO, FOPEN_W_WORK)))
|
||||
efaterror("stdout");
|
||||
# endif
|
||||
|
||||
/* now handle all filenames */
|
||||
do {
|
||||
ffree();
|
||||
|
||||
if (pairfilenames(argc, argv, lockflag?rcswriteopen:rcsreadopen, true, false) <= 0)
|
||||
continue;
|
||||
|
||||
/* now RCSfilename contains the name of the RCS file, and finptr
|
||||
* points at it. workfilename contains the name of the working file.
|
||||
* Also, RCSstat has been set.
|
||||
*/
|
||||
diagnose("%s --> %s\n", RCSfilename,tostdout?"stdout":workfilename);
|
||||
|
||||
workstatstat = -1;
|
||||
if (tostdout) {
|
||||
neworkfilename = 0;
|
||||
neworkptr = workstdout;
|
||||
} else {
|
||||
workstatstat = stat(workfilename, &workstat);
|
||||
neworkfilename = makedirtemp(workfilename, 1);
|
||||
if (!(neworkptr = fopen(neworkfilename, FOPEN_W_WORK))) {
|
||||
if (errno == EACCES)
|
||||
error("%s: parent directory isn't writable",
|
||||
workfilename
|
||||
);
|
||||
else
|
||||
eerror(neworkfilename);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
gettree(); /* reads in the delta tree */
|
||||
|
||||
if (Head==nil) {
|
||||
/* no revisions; create empty file */
|
||||
diagnose("no revisions present; generating empty revision 0.0\n");
|
||||
Ozclose(&fcopy);
|
||||
if (workstatstat == 0)
|
||||
if (!rmworkfile()) continue;
|
||||
changelock = 0;
|
||||
newdate = 0;
|
||||
/* Can't reserve a delta, so don't call addlock */
|
||||
} else {
|
||||
if (rev!=nil) {
|
||||
/* expand symbolic revision number */
|
||||
if (!expandsym(rev, &numericrev))
|
||||
continue;
|
||||
} else
|
||||
switch (lockflag<0 ? findlock(false,&targetdelta) : 0) {
|
||||
default:
|
||||
continue;
|
||||
case 0:
|
||||
bufscpy(&numericrev, Dbranch?Dbranch:"");
|
||||
break;
|
||||
case 1:
|
||||
bufscpy(&numericrev, targetdelta->num);
|
||||
break;
|
||||
}
|
||||
/* get numbers of deltas to be generated */
|
||||
if (!(targetdelta=genrevs(numericrev.string,date,author,state,&gendeltas)))
|
||||
continue;
|
||||
/* check reservations */
|
||||
changelock =
|
||||
lockflag < 0 ?
|
||||
rmlock(targetdelta)
|
||||
: lockflag == 0 ?
|
||||
0
|
||||
:
|
||||
addlock(targetdelta);
|
||||
|
||||
if (
|
||||
changelock < 0 ||
|
||||
changelock && !checkaccesslist() ||
|
||||
!dorewrite(lockflag, changelock)
|
||||
)
|
||||
continue;
|
||||
|
||||
if (0 <= expmode)
|
||||
Expand = expmode;
|
||||
if (0 < lockflag && Expand == VAL_EXPAND) {
|
||||
error("cannot combine -kv and -l");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (join && !preparejoin()) continue;
|
||||
|
||||
diagnose("revision %s%s\n",targetdelta->num,
|
||||
0<lockflag ? " (locked)" :
|
||||
lockflag<0 ? " (unlocked)" : "");
|
||||
|
||||
/* Prepare to remove old working file if necessary. */
|
||||
if (workstatstat == 0)
|
||||
if (!rmworkfile()) continue;
|
||||
|
||||
/* skip description */
|
||||
getdesc(false); /* don't echo*/
|
||||
|
||||
locker_expansion = 0 < lockflag;
|
||||
joinfilename = buildrevision(
|
||||
gendeltas, targetdelta,
|
||||
join&&tostdout ? (FILE*)0 : neworkptr,
|
||||
Expand!=OLD_EXPAND
|
||||
);
|
||||
# if !large_memory
|
||||
if (fcopy == neworkptr)
|
||||
fcopy = 0; /* Don't close it twice. */
|
||||
# endif
|
||||
if_advise_access(changelock && gendeltas->first!=targetdelta,
|
||||
finptr, MADV_SEQUENTIAL
|
||||
);
|
||||
|
||||
if (!donerewrite(changelock))
|
||||
continue;
|
||||
|
||||
newdate = targetdelta->date;
|
||||
if (join) {
|
||||
newdate = 0;
|
||||
if (!joinfilename) {
|
||||
aflush(neworkptr);
|
||||
joinfilename = neworkfilename;
|
||||
}
|
||||
if (!buildjoin(joinfilename))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!tostdout) {
|
||||
r = 0;
|
||||
if (mtimeflag && newdate) {
|
||||
if (!join)
|
||||
aflush(neworkptr);
|
||||
r = setfiledate(neworkfilename, newdate);
|
||||
}
|
||||
if (r == 0) {
|
||||
ignoreints();
|
||||
r = chnamemod(&neworkptr, neworkfilename, workfilename,
|
||||
WORKMODE(RCSstat.st_mode,
|
||||
!(Expand==VAL_EXPAND || lockflag<=0&&StrictLocks)
|
||||
)
|
||||
);
|
||||
keepdirtemp(neworkfilename);
|
||||
restoreints();
|
||||
}
|
||||
if (r != 0) {
|
||||
eerror(workfilename);
|
||||
error("see %s", neworkfilename);
|
||||
continue;
|
||||
}
|
||||
diagnose("done\n");
|
||||
}
|
||||
} while (cleanup(),
|
||||
++argv, --argc >=1);
|
||||
|
||||
tempunlink();
|
||||
Ofclose(workstdout);
|
||||
exitmain(exitstatus);
|
||||
|
||||
} /* end of main (co) */
|
||||
|
||||
static void
|
||||
cleanup()
|
||||
{
|
||||
if (nerror) exitstatus = EXIT_FAILURE;
|
||||
Izclose(&finptr);
|
||||
Ozclose(&frewrite);
|
||||
# if !large_memory
|
||||
if (fcopy!=workstdout) Ozclose(&fcopy);
|
||||
# endif
|
||||
if (neworkptr!=workstdout) Ozclose(&neworkptr);
|
||||
dirtempunlink();
|
||||
}
|
||||
|
||||
#if lint
|
||||
# define exiterr coExit
|
||||
#endif
|
||||
exiting void
|
||||
exiterr()
|
||||
{
|
||||
dirtempunlink();
|
||||
tempunlink();
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
* The following routines are auxiliary routines
|
||||
*****************************************************************/
|
||||
|
||||
static int
|
||||
rmworkfile()
|
||||
/* Function: prepares to remove workfilename, if it exists, and if
|
||||
* it is read-only.
|
||||
* Otherwise (file writable):
|
||||
* if !quietmode asks the user whether to really delete it (default: fail);
|
||||
* otherwise failure.
|
||||
* Returns true if permission is gotten.
|
||||
*/
|
||||
{
|
||||
if (workstat.st_mode&(S_IWUSR|S_IWGRP|S_IWOTH) && !forceflag) {
|
||||
/* File is writable */
|
||||
if (!yesorno(false, "writable %s exists%s; remove it? [ny](n): ",
|
||||
workfilename,
|
||||
myself(workstat.st_uid) ? "" : ", and you do not own it"
|
||||
)) {
|
||||
error(!quietflag && ttystdin()
|
||||
? "checkout aborted"
|
||||
: "writable %s exists; checkout aborted", workfilename);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/* Actual unlink is done later by caller. */
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
rmlock(delta)
|
||||
struct hshentry const *delta;
|
||||
/* Function: removes the lock held by caller on delta.
|
||||
* Returns -1 if someone else holds the lock,
|
||||
* 0 if there is no lock on delta,
|
||||
* and 1 if a lock was found and removed.
|
||||
*/
|
||||
{ register struct lock * next, * trail;
|
||||
char const *num;
|
||||
struct lock dummy;
|
||||
int whomatch, nummatch;
|
||||
|
||||
num=delta->num;
|
||||
dummy.nextlock=next=Locks;
|
||||
trail = &dummy;
|
||||
while (next!=nil) {
|
||||
whomatch = strcmp(getcaller(), next->login);
|
||||
nummatch=strcmp(num,next->delta->num);
|
||||
if ((whomatch==0) && (nummatch==0)) break;
|
||||
/*found a lock on delta by caller*/
|
||||
if ((whomatch!=0)&&(nummatch==0)) {
|
||||
error("revision %s locked by %s; use co -r or rcs -u",num,next->login);
|
||||
return -1;
|
||||
}
|
||||
trail=next;
|
||||
next=next->nextlock;
|
||||
}
|
||||
if (next!=nil) {
|
||||
/*found one; delete it */
|
||||
trail->nextlock=next->nextlock;
|
||||
Locks=dummy.nextlock;
|
||||
next->delta->lockedby=nil; /* reset locked-by */
|
||||
return 1; /*success*/
|
||||
} else return 0; /*no lock on delta*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
* The rest of the routines are for handling joins
|
||||
*****************************************************************/
|
||||
|
||||
|
||||
static char const *
|
||||
addjoin(joinrev)
|
||||
char *joinrev;
|
||||
/* Add joinrev's number to joinlist, yielding address of char past joinrev,
|
||||
* or nil if no such revision exists.
|
||||
*/
|
||||
{
|
||||
register char *j;
|
||||
register struct hshentry const *d;
|
||||
char terminator;
|
||||
struct buf numrev;
|
||||
struct hshentries *joindeltas;
|
||||
|
||||
j = joinrev;
|
||||
for (;;) {
|
||||
switch (*j++) {
|
||||
default:
|
||||
continue;
|
||||
case 0:
|
||||
case ' ': case '\t': case '\n':
|
||||
case ':': case ',': case ';':
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
terminator = *--j;
|
||||
*j = 0;
|
||||
bufautobegin(&numrev);
|
||||
d = 0;
|
||||
if (expandsym(joinrev, &numrev))
|
||||
d = genrevs(numrev.string,(char*)nil,(char*)nil,(char*)nil,&joindeltas);
|
||||
bufautoend(&numrev);
|
||||
*j = terminator;
|
||||
if (d) {
|
||||
joinlist[++lastjoin] = d->num;
|
||||
return j;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
static int
|
||||
preparejoin()
|
||||
/* Function: Parses a join list pointed to by join and places pointers to the
|
||||
* revision numbers into joinlist.
|
||||
*/
|
||||
{
|
||||
register char const *j;
|
||||
|
||||
j=join;
|
||||
lastjoin= -1;
|
||||
for (;;) {
|
||||
while ((*j==' ')||(*j=='\t')||(*j==',')) j++;
|
||||
if (*j=='\0') break;
|
||||
if (lastjoin>=joinlength-2) {
|
||||
error("too many joins");
|
||||
return(false);
|
||||
}
|
||||
if (!(j = addjoin(j))) return false;
|
||||
while ((*j==' ') || (*j=='\t')) j++;
|
||||
if (*j == ':') {
|
||||
j++;
|
||||
while((*j==' ') || (*j=='\t')) j++;
|
||||
if (*j!='\0') {
|
||||
if (!(j = addjoin(j))) return false;
|
||||
} else {
|
||||
error("join pair incomplete");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (lastjoin==0) { /* first pair */
|
||||
/* common ancestor missing */
|
||||
joinlist[1]=joinlist[0];
|
||||
lastjoin=1;
|
||||
/*derive common ancestor*/
|
||||
if (!(joinlist[0] = getancestor(targetdelta->num,joinlist[1])))
|
||||
return false;
|
||||
} else {
|
||||
error("join pair incomplete");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lastjoin<1) {
|
||||
error("empty join");
|
||||
return false;
|
||||
} else return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static char const *
|
||||
getancestor(r1, r2)
|
||||
char const *r1, *r2;
|
||||
/* Yield the common ancestor of r1 and r2 if successful, nil otherwise.
|
||||
* Work reliably only if r1 and r2 are not branch numbers.
|
||||
*/
|
||||
{
|
||||
static struct buf t1, t2;
|
||||
|
||||
unsigned l1, l2, l3;
|
||||
char const *r;
|
||||
|
||||
l1 = countnumflds(r1);
|
||||
l2 = countnumflds(r2);
|
||||
if ((2<l1 || 2<l2) && cmpnum(r1,r2)!=0) {
|
||||
/* not on main trunk or identical */
|
||||
l3 = 0;
|
||||
while (cmpnumfld(r1, r2, l3+1)==0 && cmpnumfld(r1, r2, l3+2)==0)
|
||||
l3 += 2;
|
||||
/* This will terminate since r1 and r2 are not the same; see above. */
|
||||
if (l3==0) {
|
||||
/* no common prefix; common ancestor on main trunk */
|
||||
VOID partialno(&t1, r1, l1>2 ? (unsigned)2 : l1);
|
||||
VOID partialno(&t2, r2, l2>2 ? (unsigned)2 : l2);
|
||||
r = cmpnum(t1.string,t2.string)<0 ? t1.string : t2.string;
|
||||
if (cmpnum(r,r1)!=0 && cmpnum(r,r2)!=0)
|
||||
return r;
|
||||
} else if (cmpnumfld(r1, r2, l3+1)!=0)
|
||||
return partialno(&t1,r1,l3);
|
||||
}
|
||||
error("common ancestor of %s and %s undefined", r1, r2);
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
buildjoin(initialfile)
|
||||
char const *initialfile;
|
||||
/* Function: merge pairs of elements in joinlist into initialfile
|
||||
* If workstdout is set, copy result to stdout.
|
||||
* All unlinking of initialfile, rev2, and rev3 should be done by tempunlink().
|
||||
*/
|
||||
{
|
||||
struct buf commarg;
|
||||
struct buf subs;
|
||||
char const *rev2, *rev3;
|
||||
int i;
|
||||
char const *cov[10], *mergev[12];
|
||||
char const **p;
|
||||
|
||||
bufautobegin(&commarg);
|
||||
bufautobegin(&subs);
|
||||
rev2 = maketemp(0);
|
||||
rev3 = maketemp(3); /* buildrevision() may use 1 and 2 */
|
||||
|
||||
cov[0] = nil;
|
||||
/* cov[1] setup below */
|
||||
cov[2] = CO;
|
||||
/* cov[3] setup below */
|
||||
p = &cov[4];
|
||||
if (expandarg) *p++ = expandarg;
|
||||
if (suffixarg) *p++ = suffixarg;
|
||||
if (versionarg) *p++ = versionarg;
|
||||
*p++ = quietarg;
|
||||
*p++ = RCSfilename;
|
||||
*p = nil;
|
||||
|
||||
mergev[0] = nil;
|
||||
mergev[1] = nil;
|
||||
mergev[2] = MERGE;
|
||||
mergev[3] = mergev[5] = "-L";
|
||||
/* rest of mergev setup below */
|
||||
|
||||
i=0;
|
||||
while (i<lastjoin) {
|
||||
/*prepare marker for merge*/
|
||||
if (i==0)
|
||||
bufscpy(&subs, targetdelta->num);
|
||||
else {
|
||||
bufscat(&subs, ",");
|
||||
bufscat(&subs, joinlist[i-2]);
|
||||
bufscat(&subs, ":");
|
||||
bufscat(&subs, joinlist[i-1]);
|
||||
}
|
||||
diagnose("revision %s\n",joinlist[i]);
|
||||
bufscpy(&commarg, "-p");
|
||||
bufscat(&commarg, joinlist[i]);
|
||||
cov[1] = rev2;
|
||||
cov[3] = commarg.string;
|
||||
if (runv(cov))
|
||||
goto badmerge;
|
||||
diagnose("revision %s\n",joinlist[i+1]);
|
||||
bufscpy(&commarg, "-p");
|
||||
bufscat(&commarg, joinlist[i+1]);
|
||||
cov[1] = rev3;
|
||||
cov[3] = commarg.string;
|
||||
if (runv(cov))
|
||||
goto badmerge;
|
||||
diagnose("merging...\n");
|
||||
mergev[4] = subs.string;
|
||||
mergev[6] = joinlist[i+1];
|
||||
p = &mergev[7];
|
||||
if (quietflag) *p++ = quietarg;
|
||||
if (lastjoin<=i+2 && workstdout) *p++ = "-p";
|
||||
*p++ = initialfile;
|
||||
*p++ = rev2;
|
||||
*p++ = rev3;
|
||||
*p = nil;
|
||||
switch (runv(mergev)) {
|
||||
case DIFF_FAILURE: case DIFF_SUCCESS:
|
||||
break;
|
||||
default:
|
||||
goto badmerge;
|
||||
}
|
||||
i=i+2;
|
||||
}
|
||||
bufautoend(&commarg);
|
||||
bufautoend(&subs);
|
||||
return true;
|
||||
|
||||
badmerge:
|
||||
nerror++;
|
||||
bufautoend(&commarg);
|
||||
bufautoend(&subs);
|
||||
return false;
|
||||
}
|
||||
1524
gnu/usr.bin/rcs/doc/rcs.ms
Normal file
1524
gnu/usr.bin/rcs/doc/rcs.ms
Normal file
File diff suppressed because it is too large
Load diff
95
gnu/usr.bin/rcs/doc/rcs_func.ms
Normal file
95
gnu/usr.bin/rcs/doc/rcs_func.ms
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
.SH
|
||||
Functions of RCS (Revision Control System)
|
||||
.PP
|
||||
RCS manages software libraries. It greatly increases programmer productivity
|
||||
by providing the following functions.
|
||||
.IP 1.
|
||||
RCS stores and retrieves multiple revisions of program and other text.
|
||||
Thus, one can maintain one or more releases while developing the next
|
||||
release, with a minimum of space overhead. Changes no longer destroy the
|
||||
original -- previous revisions remain accessible.
|
||||
.RS
|
||||
.IP a.
|
||||
Maintains each module as a tree of revisions.
|
||||
.IP b.
|
||||
Project libraries can
|
||||
be organized centrally, decentralized, or any way you like.
|
||||
.IP c.
|
||||
RCS works for any type of text: programs, documentation, memos, papers,
|
||||
graphics, VLSI layouts, form letters, etc.
|
||||
.RE
|
||||
.IP 2.
|
||||
RCS maintains a complete history of changes.
|
||||
Thus, one can find out what happened to a module easily
|
||||
and quickly, without having to compare source listings or
|
||||
having to track down colleagues.
|
||||
.RS
|
||||
.IP a.
|
||||
RCS performs automatic record keeping.
|
||||
.IP b.
|
||||
RCS logs all changes automatically.
|
||||
.IP c.
|
||||
RCS guarantees project continuity.
|
||||
.RE
|
||||
.IP 3.
|
||||
RCS manages multiple lines of development.
|
||||
.IP 4.
|
||||
RCS can merge multiple lines of development.
|
||||
Thus, when several parallel lines of development must be consolidated
|
||||
into one line, the merging of changes is automatic.
|
||||
.IP 5.
|
||||
RCS flags coding conflicts.
|
||||
If two or more lines of development modify the same section of code,
|
||||
RCS can alert programmers about overlapping changes.
|
||||
.IP 6.
|
||||
RCS resolves access conflicts.
|
||||
When two or more programmers wish to modify the same revision,
|
||||
RCS alerts the programmers and makes sure that one modification won't wipe
|
||||
out the other one.
|
||||
.IP 7.
|
||||
RCS provides high-level retrieval functions.
|
||||
Revisions can be retrieved according to ranges of revision numbers,
|
||||
symbolic names, dates, authors, and states.
|
||||
.IP 8.
|
||||
RCS provides release and configuration control.
|
||||
Revisions can be marked as released, stable, experimental, etc.
|
||||
Configurations of modules can be described simply and directly.
|
||||
.IP 9.
|
||||
RCS performs automatic identification of modules with name, revision
|
||||
number, creation time, author, etc.
|
||||
Thus, it is always possible to determine which revisions of which
|
||||
modules make up a given configuration.
|
||||
.IP 10.
|
||||
Provides high-level management visibility.
|
||||
Thus, it is easy to track the status of a software project.
|
||||
.RS
|
||||
.IP a.
|
||||
RCS provides a complete change history.
|
||||
.IP b.
|
||||
RCS records who did what when to which revision of which module.
|
||||
.RE
|
||||
.IP 11.
|
||||
RCS is fully compatible with existing software development tools.
|
||||
RCS is unobtrusive -- its interface to the file system is such that
|
||||
all your existing software tools can be used as before.
|
||||
.IP 12.
|
||||
RCS' basic user interface is extremely simple. The novice need to learn
|
||||
only two commands. Its more sophisticated features have been
|
||||
tuned towards advanced software development environments and the
|
||||
experienced software professional.
|
||||
.IP 13.
|
||||
RCS simplifies software distribution if customers
|
||||
maintain sources with RCS also. This technique assures proper
|
||||
identification of versions and configurations, and tracking of customer
|
||||
modifications. Customer modifications can be merged into distributed
|
||||
versions locally or by the development group.
|
||||
.IP 14.
|
||||
RCS needs little extra space for the revisions (only the differences).
|
||||
If intermediate revisions are deleted, the corresponding
|
||||
differences are compressed into the shortest possible form.
|
||||
.IP 15.
|
||||
RCS is implemented with reverse deltas. This means that
|
||||
the latest revision, which is the one that is accessed most often,
|
||||
is stored intact. All others are regenerated from the latest one
|
||||
by applying reverse deltas (backward differences). This
|
||||
results in fast access time for the revision needed most often.
|
||||
7
gnu/usr.bin/rcs/ident/Makefile
Normal file
7
gnu/usr.bin/rcs/ident/Makefile
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
PROG= ident
|
||||
|
||||
SRCS= ident.c
|
||||
LDADD= -L${.CURDIR}/../lib/obj -lrcs
|
||||
CFLAGS+= -I${.CURDIR}/../lib
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
76
gnu/usr.bin/rcs/ident/ident.1
Normal file
76
gnu/usr.bin/rcs/ident/ident.1
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
.de Id
|
||||
.ds Rv \\$3
|
||||
.ds Dt \\$4
|
||||
.ds iD \\$3 \\$4 \\$5 \\$6 \\$7
|
||||
..
|
||||
.Id $Id: ident.1,v 5.0 1990/08/22 09:09:36 eggert Exp $
|
||||
.ds r \s-1RCS\s0
|
||||
.if n .ds - \%--
|
||||
.if t .ds - \(em
|
||||
.TH IDENT 1 \*(Dt GNU
|
||||
.SH NAME
|
||||
ident \- identify files
|
||||
.SH SYNOPSIS
|
||||
.B ident
|
||||
[
|
||||
.B \-q
|
||||
] [
|
||||
.I file
|
||||
\&.\|.\|. ]
|
||||
.SH DESCRIPTION
|
||||
.B ident
|
||||
searches for all occurrences of the pattern
|
||||
.BI $ keyword : .\|.\|. $
|
||||
in the named files or, if no file name appears, the standard input.
|
||||
.PP
|
||||
These patterns are normally inserted automatically by the \*r command
|
||||
.BR co (1),
|
||||
but can also be inserted manually.
|
||||
The option
|
||||
.B \-q
|
||||
suppresses
|
||||
the warning given if there are no patterns in a file.
|
||||
.PP
|
||||
.B ident
|
||||
works on text files as well as object files and dumps.
|
||||
For example, if the C program in
|
||||
.B f.c
|
||||
contains
|
||||
.IP
|
||||
\f3char rcsid[] = \&"$\&Id: f.c,v \*(iD $\&";\fP
|
||||
.LP
|
||||
and
|
||||
.B f.c
|
||||
is compiled into
|
||||
.BR f.o ,
|
||||
then the command
|
||||
.IP
|
||||
.B "ident f.c f.o"
|
||||
.LP
|
||||
will output
|
||||
.nf
|
||||
.IP
|
||||
.ft 3
|
||||
f.c:
|
||||
$\&Id: f.c,v \*(iD $
|
||||
f.o:
|
||||
$\&Id: f.c,v \*(iD $
|
||||
.ft
|
||||
.fi
|
||||
.SH IDENTIFICATION
|
||||
Author: Walter F. Tichy.
|
||||
.br
|
||||
Revision Number: \*(Rv; Release Date: \*(Dt.
|
||||
.br
|
||||
Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
|
||||
.br
|
||||
Copyright \(co 1990 by Paul Eggert.
|
||||
.SH "SEE ALSO"
|
||||
ci(1), co(1), rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1),
|
||||
rcsfile(5)
|
||||
.br
|
||||
Walter F. Tichy,
|
||||
\*r\*-A System for Version Control,
|
||||
.I "Software\*-Practice & Experience"
|
||||
.BR 15 ,
|
||||
7 (July 1985), 637-654.
|
||||
214
gnu/usr.bin/rcs/ident/ident.c
Normal file
214
gnu/usr.bin/rcs/ident/ident.c
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
/* Copyright (C) 1982, 1988, 1989 Walter Tichy
|
||||
Copyright 1990, 1991 by 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, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Report problems and direct all questions to:
|
||||
|
||||
rcs-bugs@cs.purdue.edu
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* RCS identification operation
|
||||
*/
|
||||
|
||||
/* $Log: ident.c,v $
|
||||
* Revision 5.3 1991/09/10 22:15:46 eggert
|
||||
* Open files with FOPEN_R, not FOPEN_R_WORK,
|
||||
* because they might be executables, not working files.
|
||||
*
|
||||
* Revision 5.2 1991/08/19 03:13:55 eggert
|
||||
* Report read errors immediately.
|
||||
*
|
||||
* Revision 5.1 1991/02/25 07:12:37 eggert
|
||||
* Don't report empty keywords. Check for I/O errors.
|
||||
*
|
||||
* Revision 5.0 1990/08/22 08:12:37 eggert
|
||||
* Don't limit output to known keywords.
|
||||
* Remove arbitrary limits and lint. Ansify and Posixate.
|
||||
*
|
||||
* Revision 4.5 89/05/01 15:11:54 narten
|
||||
* changed copyright header to reflect current distribution rules
|
||||
*
|
||||
* Revision 4.4 87/10/23 17:09:57 narten
|
||||
* added exit(0) so exit return code would be non random
|
||||
*
|
||||
* Revision 4.3 87/10/18 10:23:55 narten
|
||||
* Updating version numbers. Changes relative to 1.1 are actually relative
|
||||
* to 4.1
|
||||
*
|
||||
* Revision 1.3 87/07/09 09:20:52 trinkle
|
||||
* Added check to make sure there is at least one arg before comparing argv[1]
|
||||
* with "-q". This necessary on machines that don't allow dereferncing null
|
||||
* pointers (i.e. Suns).
|
||||
*
|
||||
* Revision 1.2 87/03/27 14:21:47 jenkins
|
||||
* Port to suns
|
||||
*
|
||||
* Revision 4.1 83/05/10 16:31:02 wft
|
||||
* Added option -q and input from reading stdin.
|
||||
* Marker matching is now done with trymatch() (independent of keywords).
|
||||
*
|
||||
* Revision 3.4 83/02/18 17:37:49 wft
|
||||
* removed printing of new line after last file.
|
||||
*
|
||||
* Revision 3.3 82/12/04 12:48:55 wft
|
||||
* Added LOCKER.
|
||||
*
|
||||
* Revision 3.2 82/11/28 18:24:17 wft
|
||||
* removed Suffix; added ungetc to avoid skipping over trailing KDELIM.
|
||||
*
|
||||
* Revision 3.1 82/10/13 15:58:51 wft
|
||||
* fixed type of variables receiving from getc() (char-->int).
|
||||
*/
|
||||
|
||||
#include "rcsbase.h"
|
||||
|
||||
static int match P((FILE*));
|
||||
static void scanfile P((FILE*,char const*,int));
|
||||
|
||||
mainProg(identId, "ident", "$Id: ident.c,v 5.3 1991/09/10 22:15:46 eggert Exp $")
|
||||
/* Ident searches the named files for all occurrences
|
||||
* of the pattern $keyword:...$, where the keywords are
|
||||
* Author, Date, Header, Id, Log, RCSfile, Revision, Source, and State.
|
||||
*/
|
||||
|
||||
{
|
||||
FILE *fp;
|
||||
int quiet;
|
||||
int status = EXIT_SUCCESS;
|
||||
|
||||
if ((quiet = argc > 1 && strcmp("-q",argv[1])==0)) {
|
||||
argc--; argv++;
|
||||
}
|
||||
|
||||
if (argc<2)
|
||||
scanfile(stdin, (char*)0, quiet);
|
||||
|
||||
while ( --argc > 0 ) {
|
||||
if (!(fp = fopen(*++argv, FOPEN_R))) {
|
||||
VOID fprintf(stderr, "%s error: can't open %s\n", cmdid, *argv);
|
||||
status = EXIT_FAILURE;
|
||||
} else {
|
||||
scanfile(fp, *argv, quiet);
|
||||
if (argc>1) VOID putchar('\n');
|
||||
}
|
||||
}
|
||||
if (ferror(stdout) || fclose(stdout)!=0) {
|
||||
VOID fprintf(stderr, "%s error: write error\n", cmdid);
|
||||
status = EXIT_FAILURE;
|
||||
}
|
||||
exitmain(status);
|
||||
}
|
||||
|
||||
#if lint
|
||||
exiting void identExit() { _exit(EXIT_FAILURE); }
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
scanfile(file, name, quiet)
|
||||
register FILE *file;
|
||||
char const *name;
|
||||
int quiet;
|
||||
/* Function: scan an open file with descriptor file for keywords.
|
||||
* Return false if there's a read error.
|
||||
*/
|
||||
{
|
||||
register int c;
|
||||
|
||||
if (name)
|
||||
VOID printf("%s:\n", name);
|
||||
else
|
||||
name = "input";
|
||||
c = 0;
|
||||
for (;;) {
|
||||
if (c < 0) {
|
||||
if (feof(file))
|
||||
break;
|
||||
if (ferror(file))
|
||||
goto read_error;
|
||||
}
|
||||
if (c == KDELIM) {
|
||||
if ((c = match(file)))
|
||||
continue;
|
||||
quiet = true;
|
||||
}
|
||||
c = getc(file);
|
||||
}
|
||||
if (!quiet)
|
||||
VOID fprintf(stderr, "%s warning: no id keywords in %s\n", cmdid, name);
|
||||
if (fclose(file) == 0)
|
||||
return;
|
||||
|
||||
read_error:
|
||||
VOID fprintf(stderr, "%s error: %s: read error\n", cmdid, name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
match(fp) /* group substring between two KDELIM's; then do pattern match */
|
||||
register FILE *fp;
|
||||
{
|
||||
char line[BUFSIZ];
|
||||
register int c;
|
||||
register char * tp;
|
||||
|
||||
tp = line;
|
||||
while ((c = getc(fp)) != VDELIM) {
|
||||
if (c < 0)
|
||||
return c;
|
||||
switch (ctab[c]) {
|
||||
case LETTER: case Letter:
|
||||
*tp++ = c;
|
||||
if (tp < line+sizeof(line)-4)
|
||||
break;
|
||||
/* fall into */
|
||||
default:
|
||||
return c ? c : '\n'/* anything but 0 or KDELIM or EOF */;
|
||||
}
|
||||
}
|
||||
if (tp == line)
|
||||
return c;
|
||||
*tp++ = c;
|
||||
if ((c = getc(fp)) != ' ')
|
||||
return c ? c : '\n';
|
||||
*tp++ = c;
|
||||
while( (c = getc(fp)) != KDELIM ) {
|
||||
if (c < 0 && feof(fp) | ferror(fp))
|
||||
return c;
|
||||
switch (ctab[c]) {
|
||||
default:
|
||||
*tp++ = c;
|
||||
if (tp < line+sizeof(line)-2)
|
||||
break;
|
||||
/* fall into */
|
||||
case NEWLN: case UNKN:
|
||||
return c ? c : '\n';
|
||||
}
|
||||
}
|
||||
if (tp[-1] != ' ')
|
||||
return c;
|
||||
*tp++ = c; /*append trailing KDELIM*/
|
||||
*tp = '\0';
|
||||
VOID fprintf(stdout, " %c%s\n", KDELIM, line);
|
||||
return 0;
|
||||
}
|
||||
5
gnu/usr.bin/rcs/lib/Makefile
Normal file
5
gnu/usr.bin/rcs/lib/Makefile
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
LIB= rcs
|
||||
SRCS= maketime.c partime.c rcsedit.c rcsfcmp.c rcsfnms.c rcsgen.c rcskeep.c \
|
||||
rcskeys.c rcslex.c rcsmap.c rcsrev.c rcssyn.c rcsutil.c merger.c
|
||||
|
||||
.include <bsd.lib.mk>
|
||||
495
gnu/usr.bin/rcs/lib/conf.h
Normal file
495
gnu/usr.bin/rcs/lib/conf.h
Normal file
|
|
@ -0,0 +1,495 @@
|
|||
/* RCS compile-time configuration */
|
||||
|
||||
/* $Id: conf.sh,v 5.14 1991/11/20 18:21:10 eggert Exp $ */
|
||||
|
||||
/*
|
||||
* This file is generated automatically.
|
||||
* If you edit it by hand your changes may be lost.
|
||||
* Instead, please try to fix conf.sh,
|
||||
* and send your fixes to rcs-bugs@cs.purdue.edu.
|
||||
*/
|
||||
|
||||
#define exitmain(n) return n /* how to exit from main() */
|
||||
/* #define _POSIX_SOURCE */ /* Define this if Posix + strict Standard C. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
/* Comment out #include lines below that do not work. */
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <utime.h>
|
||||
/* #include <vfork.h> */
|
||||
|
||||
/* Define the following symbols to be 1 or 0. */
|
||||
#define has_sys_dir_h 1 /* Does #include <sys/dir.h> work? */
|
||||
#define has_sys_param_h 1 /* Does #include <sys/param.h> work? */
|
||||
#define has_readlink 1 /* Does readlink() work? */
|
||||
|
||||
/* #undef NAME_MAX */ /* Uncomment this if NAME_MAX is broken. */
|
||||
|
||||
#if !defined(NAME_MAX) && !defined(_POSIX_NAME_MAX)
|
||||
# if has_sys_dir_h
|
||||
# include <sys/dir.h>
|
||||
# endif
|
||||
# ifndef NAME_MAX
|
||||
# ifndef MAXNAMLEN
|
||||
# define MAXNAMLEN 14
|
||||
# endif
|
||||
# define NAME_MAX MAXNAMLEN
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(PATH_MAX) && !defined(_POSIX_PATH_MAX)
|
||||
# if has_sys_param_h
|
||||
# include <sys/param.h>
|
||||
# define included_sys_param_h 1
|
||||
# endif
|
||||
# ifndef PATH_MAX
|
||||
# ifndef MAXPATHLEN
|
||||
# define MAXPATHLEN 1024
|
||||
# endif
|
||||
# define PATH_MAX (MAXPATHLEN-1)
|
||||
# endif
|
||||
#endif
|
||||
#if has_readlink && !defined(MAXSYMLINKS)
|
||||
# if has_sys_param_h && !included_sys_param_h
|
||||
# include <sys/param.h>
|
||||
# endif
|
||||
# ifndef MAXSYMLINKS
|
||||
# define MAXSYMLINKS 20 /* BSD; not standard yet */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Comment out the keyword definitions below if the keywords work. */
|
||||
/* #define const */
|
||||
/* #define volatile */
|
||||
|
||||
/* Comment out the typedefs below if the types are already declared. */
|
||||
/* Fix any uncommented typedefs that are wrong. */
|
||||
/* typedef int mode_t; */
|
||||
/* typedef int pid_t; */
|
||||
typedef int sig_atomic_t;
|
||||
/* typedef unsigned size_t; */
|
||||
/* typedef int ssize_t; */
|
||||
/* typedef long time_t; */
|
||||
/* typedef int uid_t; */
|
||||
|
||||
/* Define the following symbols to be 1 or 0. */
|
||||
#define has_prototypes 1 /* Do function prototypes work? */
|
||||
#define has_stdarg 1 /* Does <stdarg.h> work? */
|
||||
#define has_varargs 0 /* Does <varargs.h> work? */
|
||||
#define va_start_args 2 /* How many args does va_start() take? */
|
||||
#if has_prototypes
|
||||
# define P(params) params
|
||||
#else
|
||||
# define P(params) ()
|
||||
#endif
|
||||
#if has_stdarg
|
||||
# include <stdarg.h>
|
||||
#else
|
||||
# if has_varargs
|
||||
# include <varargs.h>
|
||||
# else
|
||||
typedef char *va_list;
|
||||
# define va_dcl int va_alist;
|
||||
# define va_start(ap) ((ap) = (va_list)&va_alist)
|
||||
# define va_arg(ap,t) (((t*) ((ap)+=sizeof(t))) [-1])
|
||||
# define va_end(ap)
|
||||
# endif
|
||||
#endif
|
||||
#if va_start_args == 2
|
||||
# define vararg_start va_start
|
||||
#else
|
||||
# define vararg_start(ap,p) va_start(ap)
|
||||
#endif
|
||||
|
||||
#define text_equals_binary_stdio 1 /* Does stdio treat text like binary? */
|
||||
#define text_work_stdio 0 /* Text i/o for working file, binary for RCS file? */
|
||||
#if text_equals_binary_stdio
|
||||
/* Text and binary i/o behave the same, or binary i/o does not work. */
|
||||
# define FOPEN_R "r"
|
||||
# define FOPEN_W "w"
|
||||
# define FOPEN_WPLUS "w+"
|
||||
#else
|
||||
/* Text and binary i/o behave differently. */
|
||||
/* This is incompatible with Posix and Unix. */
|
||||
# define FOPEN_R "rb"
|
||||
# define FOPEN_W "wb"
|
||||
# define FOPEN_WPLUS "w+b"
|
||||
#endif
|
||||
#if text_work_stdio
|
||||
# define FOPEN_R_WORK "r"
|
||||
# define FOPEN_W_WORK "w"
|
||||
# define FOPEN_WPLUS_WORK "w+"
|
||||
#else
|
||||
# define FOPEN_R_WORK FOPEN_R
|
||||
# define FOPEN_W_WORK FOPEN_W
|
||||
# define FOPEN_WPLUS_WORK FOPEN_WPLUS
|
||||
#endif
|
||||
|
||||
/* Define or comment out the following symbols as needed. */
|
||||
#define bad_fopen_wplus 0 /* Does fopen(f,FOPEN_WPLUS) fail to truncate f? */
|
||||
#define getlogin_is_secure 0 /* Is getlogin() secure? Usually it's not. */
|
||||
#define has_dirent 1 /* Do opendir(), readdir(), closedir() work? */
|
||||
#define has_fchmod 0 /* Does fchmod() work? */
|
||||
#define has_fputs 0 /* Does fputs() work? */
|
||||
#define has_ftruncate 1 /* Does ftruncate() work? */
|
||||
#define has_getuid 1 /* Does getuid() work? */
|
||||
#define has_getpwuid 1 /* Does getpwuid() work? */
|
||||
#define has_link 1 /* Does link() work? */
|
||||
#define has_memcmp 1 /* Does memcmp() work? */
|
||||
#define has_memcpy 1 /* Does memcpy() work? */
|
||||
#define has_memmove 1 /* Does memmove() work? */
|
||||
#define has_madvise 0 /* Does madvise() work? */
|
||||
#define has_mmap 0 /* Does mmap() work on regular files? */
|
||||
#define has_rename 1 /* Does rename() work? */
|
||||
#define bad_a_rename 0 /* Does rename(A,B) fail if A is unwritable? */
|
||||
#define bad_b_rename 0 /* Does rename(A,B) fail if B is unwritable? */
|
||||
#define VOID (void) /* 'VOID e;' discards the value of an expression 'e'. */
|
||||
#define has_seteuid 0 /* Does seteuid() work? See README. */
|
||||
#define has_setuid 1 /* Does setuid() exist? */
|
||||
#define has_signal 1 /* Does signal() work? */
|
||||
#define signal_args P((int)) /* arguments of signal handlers */
|
||||
#define signal_type void /* type returned by signal handlers */
|
||||
#define sig_zaps_handler 0 /* Must a signal handler reinvoke signal()? */
|
||||
#define has_sigaction 1 /* Does struct sigaction work? */
|
||||
/* #define has_sigblock ? */ /* Does sigblock() work? */
|
||||
/* #define sigmask(s) (1 << ((s)-1)) */ /* Yield mask for signal number. */
|
||||
#define has_sys_siglist 0 /* Does sys_siglist[] work? */
|
||||
typedef ssize_t fread_type; /* type returned by fread() and fwrite() */
|
||||
typedef size_t freadarg_type; /* type of their size arguments */
|
||||
typedef void *malloc_type; /* type returned by malloc() */
|
||||
#define has_getcwd 1 /* Does getcwd() work? */
|
||||
/* #define has_getwd ? */ /* Does getwd() work? */
|
||||
#define has_mktemp 1 /* Does mktemp() work? */
|
||||
#define has_NFS 1 /* Might NFS be used? */
|
||||
/* #define strchr index */ /* Use old-fashioned name for strchr()? */
|
||||
/* #define strrchr rindex */ /* Use old-fashioned name for strrchr()? */
|
||||
#define bad_unlink 0 /* Does unlink() fail on unwritable files? */
|
||||
#define has_vfork 0 /* Does vfork() work? */
|
||||
#define has_fork 1 /* Does fork() work? */
|
||||
#define has_spawn 0 /* Does spawn*() work? */
|
||||
#define has_wait 1 /* Does wait() work? */
|
||||
#define has_waitpid 0 /* Does waitpid() work? */
|
||||
#define RCS_SHELL "/bin/sh" /* shell to run RCS subprograms */
|
||||
#define has_vfprintf 1 /* Does vfprintf() work? */
|
||||
/* #define has__doprintf ? */ /* Does _doprintf() work? */
|
||||
/* #define has__doprnt ? */ /* Does _doprnt() work? */
|
||||
/* #undef EXIT_FAILURE */ /* Uncomment this if EXIT_FAILURE is broken. */
|
||||
#define large_memory 0 /* Can main memory hold entire RCS files? */
|
||||
/* #undef ULONG_MAX */ /* Uncomment this if ULONG_MAX is broken (e.g. < 0). */
|
||||
/* struct utimbuf { time_t actime, modtime; }; */ /* Uncomment this if needed. */
|
||||
#define CO "/usr/bin/co" /* name of 'co' program */
|
||||
#define COMPAT2 0 /* Are version 2 files supported? */
|
||||
#define DATEFORM "%.2d.%.2d.%.2d.%.2d.%.2d.%.2d" /* e.g. 01.01.01.01.01.01 */
|
||||
#define DIFF "/usr/bin/diff" /* name of 'diff' program */
|
||||
#define DIFF3 "/usr/bin/diff3" /* name of 'diff3' program */
|
||||
#define DIFF3_BIN 1 /* Is diff3 user-visible (not the /usr/lib auxiliary)? */
|
||||
#define DIFF_FLAGS , "-an" /* Make diff output suitable for RCS. */
|
||||
#define DIFF_L 1 /* Does diff -L work? */
|
||||
#define DIFF_SUCCESS 0 /* DIFF status if no differences are found */
|
||||
#define DIFF_FAILURE 1 /* DIFF status if differences are found */
|
||||
#define DIFF_TROUBLE 2 /* DIFF status if trouble */
|
||||
#define ED "/bin/ed" /* name of 'ed' program (used only if !DIFF3_BIN) */
|
||||
#define MERGE "/usr/bin/merge" /* name of 'merge' program */
|
||||
#define TMPDIR "/tmp" /* default directory for temporary files */
|
||||
#define SLASH '/' /* principal pathname separator */
|
||||
#define SLASHes '/' /* `case SLASHes:' labels all pathname separators */
|
||||
#define isSLASH(c) ((c) == SLASH) /* Is arg a pathname separator? */
|
||||
#define ROOTPATH(p) isSLASH((p)[0]) /* Is p an absolute pathname? */
|
||||
#define X_DEFAULT ",v/" /* default value for -x option */
|
||||
#define DIFF_ABSOLUTE 1 /* Is ROOTPATH(DIFF) true? */
|
||||
#define ALL_ABSOLUTE 1 /* Are all subprograms absolute pathnames? */
|
||||
#define SENDMAIL "/usr/bin/mail" /* how to send mail */
|
||||
#define TZ_must_be_set 0 /* Must TZ be set for gmtime() to work? */
|
||||
|
||||
|
||||
|
||||
/* Adjust the following declarations as needed. */
|
||||
|
||||
|
||||
#if __GNUC__ && !__STRICT_ANSI__
|
||||
# define exiting volatile /* GCC extension: function cannot return */
|
||||
#else
|
||||
# define exiting
|
||||
#endif
|
||||
|
||||
#if has_ftruncate
|
||||
int ftruncate P((int,off_t));
|
||||
#endif
|
||||
|
||||
/* <sys/mman.h> */
|
||||
#if has_madvise
|
||||
int madvise P((caddr_t,size_t,int));
|
||||
#endif
|
||||
#if has_mmap
|
||||
caddr_t mmap P((caddr_t,size_t,int,int,int,off_t));
|
||||
int munmap P((caddr_t,size_t));
|
||||
#endif
|
||||
|
||||
|
||||
/* Posix (ISO/IEC 9945-1: 1990 / IEEE Std 1003.1-1990) */
|
||||
/* These definitions are for the benefit of non-Posix hosts, and */
|
||||
/* Posix hosts that have Standard C compilers but traditional include files. */
|
||||
/* Unfortunately, mixed-up hosts are all too common. */
|
||||
|
||||
/* <fcntl.h> */
|
||||
#ifdef F_DUPFD
|
||||
int fcntl P((int,int,...));
|
||||
#else
|
||||
int dup2 P((int,int));
|
||||
#endif
|
||||
#ifndef O_BINARY /* some non-Posix hosts need O_BINARY */
|
||||
# define O_BINARY 0 /* no effect on Posix */
|
||||
#endif
|
||||
#ifdef O_CREAT
|
||||
# define open_can_creat 1
|
||||
#else
|
||||
# define open_can_creat 0
|
||||
# define O_RDONLY 0
|
||||
# define O_WRONLY 1
|
||||
# define O_RDWR 2
|
||||
# define O_CREAT 01000
|
||||
# define O_TRUNC 02000
|
||||
int creat P((char const*,mode_t));
|
||||
#endif
|
||||
#ifndef O_EXCL
|
||||
# define O_EXCL 0
|
||||
#endif
|
||||
|
||||
/* <pwd.h> */
|
||||
#if has_getpwuid
|
||||
struct passwd *getpwuid P((uid_t));
|
||||
#endif
|
||||
|
||||
/* <signal.h> */
|
||||
#if has_sigaction
|
||||
int sigaction P((int,struct sigaction const*,struct sigaction*));
|
||||
int sigaddset P((sigset_t*,int));
|
||||
int sigemptyset P((sigset_t*));
|
||||
#else
|
||||
#if has_sigblock
|
||||
/* BSD */
|
||||
int sigblock P((int));
|
||||
int sigmask P((int));
|
||||
int sigsetmask P((int));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* <stdio.h> */
|
||||
FILE *fdopen P((int,char const*));
|
||||
int fileno P((FILE*));
|
||||
|
||||
/* <sys/stat.h> */
|
||||
int chmod P((char const*,mode_t));
|
||||
int fstat P((int,struct stat*));
|
||||
int stat P((char const*,struct stat*));
|
||||
mode_t umask P((mode_t));
|
||||
#if has_fchmod
|
||||
int fchmod P((int,mode_t));
|
||||
#endif
|
||||
#ifndef S_IRUSR
|
||||
# ifdef S_IREAD
|
||||
# define S_IRUSR S_IREAD
|
||||
# else
|
||||
# define S_IRUSR 0400
|
||||
# endif
|
||||
# ifdef S_IWRITE
|
||||
# define S_IWUSR S_IWRITE
|
||||
# else
|
||||
# define S_IWUSR (S_IRUSR/2)
|
||||
# endif
|
||||
#endif
|
||||
#ifndef S_IRGRP
|
||||
# if has_getuid
|
||||
# define S_IRGRP (S_IRUSR / 0010)
|
||||
# define S_IWGRP (S_IWUSR / 0010)
|
||||
# define S_IROTH (S_IRUSR / 0100)
|
||||
# define S_IWOTH (S_IWUSR / 0100)
|
||||
# else
|
||||
/* single user OS -- not Posix or Unix */
|
||||
# define S_IRGRP 0
|
||||
# define S_IWGRP 0
|
||||
# define S_IROTH 0
|
||||
# define S_IWOTH 0
|
||||
# endif
|
||||
#endif
|
||||
#ifndef S_ISREG
|
||||
# define S_ISREG(n) (((n) & S_IFMT) == S_IFREG)
|
||||
#endif
|
||||
|
||||
/* <sys/wait.h> */
|
||||
#if has_wait
|
||||
pid_t wait P((int*));
|
||||
#endif
|
||||
#ifndef WEXITSTATUS
|
||||
# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
|
||||
# undef WIFEXITED /* Avoid 4.3BSD incompatibility with Posix. */
|
||||
#endif
|
||||
#ifndef WIFEXITED
|
||||
# define WIFEXITED(stat_val) (!((stat_val) & 255))
|
||||
#endif
|
||||
|
||||
/* <unistd.h> */
|
||||
char *getlogin P((void));
|
||||
int close P((int));
|
||||
int isatty P((int));
|
||||
int link P((char const*,char const*));
|
||||
int open P((char const*,int,...));
|
||||
int unlink P((char const*));
|
||||
int _filbuf P((FILE*)); /* keeps lint quiet in traditional C */
|
||||
int _flsbuf P((int,FILE*)); /* keeps lint quiet in traditional C */
|
||||
long pathconf P((char const*,int));
|
||||
ssize_t write P((int,void const*,size_t));
|
||||
#ifndef STDIN_FILENO
|
||||
# define STDIN_FILENO 0
|
||||
# define STDOUT_FILENO 1
|
||||
# define STDERR_FILENO 2
|
||||
#endif
|
||||
#if has_fork
|
||||
# if !has_vfork
|
||||
# undef vfork
|
||||
# define vfork fork
|
||||
# endif
|
||||
pid_t vfork P((void)); /* vfork is nonstandard but faster */
|
||||
#endif
|
||||
#if has_getcwd || !has_getwd
|
||||
char *getcwd P((char*,size_t));
|
||||
#else
|
||||
char *getwd P((char*));
|
||||
#endif
|
||||
#if has_getuid
|
||||
uid_t getuid P((void));
|
||||
#endif
|
||||
#if has_readlink
|
||||
/* ssize_t readlink P((char const*,char*,size_t)); *//* BSD; not standard yet */
|
||||
#endif
|
||||
#if has_setuid
|
||||
# if !has_seteuid
|
||||
# undef seteuid
|
||||
# define seteuid setuid
|
||||
# endif
|
||||
int seteuid P((uid_t));
|
||||
uid_t geteuid P((void));
|
||||
#endif
|
||||
#if has_spawn
|
||||
int spawnv P((int,char const*,char*const*));
|
||||
# if ALL_ABSOLUTE
|
||||
# define spawn_RCS spawnv
|
||||
# else
|
||||
# define spawn_RCS spawnvp
|
||||
int spawnvp P((int,char const*,char*const*));
|
||||
# endif
|
||||
#else
|
||||
int execv P((char const*,char*const*));
|
||||
# if ALL_ABSOLUTE
|
||||
# define exec_RCS execv
|
||||
# else
|
||||
# define exec_RCS execvp
|
||||
int execvp P((char const*,char*const*));
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* utime.h */
|
||||
int utime P((char const*,struct utimbuf const*));
|
||||
|
||||
|
||||
/* Standard C library */
|
||||
/* These definitions are for the benefit of hosts that have */
|
||||
/* traditional C include files, possibly with Standard C compilers. */
|
||||
/* Unfortunately, mixed-up hosts are all too common. */
|
||||
|
||||
/* <errno.h> */
|
||||
extern int errno;
|
||||
|
||||
/* <limits.h> */
|
||||
#ifndef ULONG_MAX
|
||||
/* This does not work in #ifs, but it's good enough for us. */
|
||||
# define ULONG_MAX ((unsigned long)-1)
|
||||
#endif
|
||||
|
||||
/* <signal.h> */
|
||||
#if has_signal
|
||||
signal_type (*signal P((int,signal_type(*)signal_args)))signal_args;
|
||||
#endif
|
||||
|
||||
/* <stdio.h> */
|
||||
FILE *fopen P((char const*,char const*));
|
||||
fread_type fread P((void*,freadarg_type,freadarg_type,FILE*));
|
||||
fread_type fwrite P((void const*,freadarg_type,freadarg_type,FILE*));
|
||||
int fclose P((FILE*));
|
||||
int feof P((FILE*));
|
||||
int ferror P((FILE*));
|
||||
int fflush P((FILE*));
|
||||
int fprintf P((FILE*,char const*,...));
|
||||
int fputs P((char const*,FILE*));
|
||||
int fseek P((FILE*,long,int));
|
||||
int printf P((char const*,...));
|
||||
int rename P((char const*,char const*));
|
||||
int sprintf P((char*,char const*,...));
|
||||
/* long ftell P((FILE*)); */
|
||||
void clearerr P((FILE*));
|
||||
void perror P((char const*));
|
||||
#ifndef L_tmpnam
|
||||
# define L_tmpnam 32 /* power of 2 > sizeof("/usr/tmp/xxxxxxxxxxxxxxx") */
|
||||
#endif
|
||||
#ifndef SEEK_SET
|
||||
# define SEEK_SET 0
|
||||
#endif
|
||||
#if has_mktemp
|
||||
char *mktemp P((char*)); /* traditional */
|
||||
#else
|
||||
char *tmpnam P((char*));
|
||||
#endif
|
||||
#if has_vfprintf
|
||||
int vfprintf P((FILE*,char const*,va_list));
|
||||
#else
|
||||
#if has__doprintf
|
||||
void _doprintf P((FILE*,char const*,va_list)); /* Minix */
|
||||
#else
|
||||
void _doprnt P((char const*,va_list,FILE*)); /* BSD */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* <stdlib.h> */
|
||||
char *getenv P((char const*));
|
||||
exiting void _exit P((int));
|
||||
exiting void exit P((int));
|
||||
malloc_type malloc P((size_t));
|
||||
malloc_type realloc P((malloc_type,size_t));
|
||||
void free P((malloc_type));
|
||||
#ifndef EXIT_FAILURE
|
||||
# define EXIT_FAILURE 1
|
||||
#endif
|
||||
#ifndef EXIT_SUCCESS
|
||||
# define EXIT_SUCCESS 0
|
||||
#endif
|
||||
#if !has_fork && !has_spawn
|
||||
int system P((char const*));
|
||||
#endif
|
||||
|
||||
/* <string.h> */
|
||||
char *strcpy P((char*,char const*));
|
||||
char *strchr P((char const*,int));
|
||||
char *strrchr P((char const*,int));
|
||||
int memcmp P((void const*,void const*,size_t));
|
||||
int strcmp P((char const*,char const*));
|
||||
size_t strlen P((char const*));
|
||||
void *memcpy P((void*,void const*,size_t));
|
||||
#if has_memmove
|
||||
void *memmove P((void*,void const*,size_t));
|
||||
#endif
|
||||
|
||||
/* <time.h> */
|
||||
time_t time P((time_t*));
|
||||
344
gnu/usr.bin/rcs/lib/maketime.c
Normal file
344
gnu/usr.bin/rcs/lib/maketime.c
Normal file
|
|
@ -0,0 +1,344 @@
|
|||
#
|
||||
/*
|
||||
* MAKETIME derive 32-bit time value from TM structure.
|
||||
*
|
||||
* Usage:
|
||||
* int zone; Minutes west of GMT, or
|
||||
* 48*60 for localtime
|
||||
* time_t t;
|
||||
* struct tm *tp; Pointer to TM structure from <time.h>
|
||||
* t = maketime(tp,zone);
|
||||
*
|
||||
* Returns:
|
||||
* -1 if failure; parameter out of range or nonsensical.
|
||||
* else time-value.
|
||||
* Notes:
|
||||
* This code is quasi-public; it may be used freely in like software.
|
||||
* It is not to be sold, nor used in licensed software without
|
||||
* permission of the author.
|
||||
* For everyone's benefit, please report bugs and improvements!
|
||||
* Copyright 1981 by Ken Harrenstien, SRI International.
|
||||
* (ARPANET: KLH @ SRI)
|
||||
*/
|
||||
/* $Log: maketime.c,v $
|
||||
* Revision 5.3 1991/08/19 03:13:55 eggert
|
||||
* Add setfiledate, str2time, TZ_must_be_set.
|
||||
*
|
||||
* Revision 5.2 1990/11/01 05:03:30 eggert
|
||||
* Remove lint.
|
||||
*
|
||||
* Revision 5.1 1990/10/04 06:30:13 eggert
|
||||
* Calculate the GMT offset of 'xxx LT' as of xxx, not as of now.
|
||||
* Don't assume time_t is 32 bits. Fix bugs near epoch and near end of time.
|
||||
*
|
||||
* Revision 5.0 1990/08/22 08:12:38 eggert
|
||||
* Switch to GMT and fix the bugs exposed thereby.
|
||||
* Permit dates past 1999/12/31. Ansify and Posixate.
|
||||
*
|
||||
* Revision 1.8 88/11/08 13:54:53 narten
|
||||
* allow negative timezones (-24h <= x <= 24h)
|
||||
*
|
||||
* Revision 1.7 88/08/28 14:47:52 eggert
|
||||
* Allow cc -R. Remove unportable "#endif XXX"s.
|
||||
*
|
||||
* Revision 1.6 87/12/18 17:05:58 narten
|
||||
* include rcsparam.h
|
||||
*
|
||||
* Revision 1.5 87/12/18 11:35:51 narten
|
||||
* maketime.c: fixed USG code - you have tgo call "tzset" in order to have
|
||||
* "timezone" set. ("localtime" calls it, but it's probably better not to
|
||||
* count on "localtime" having been called.)
|
||||
*
|
||||
* Revision 1.4 87/10/18 10:26:57 narten
|
||||
* Updating version numbers. Changes relative to 1.0 are actually
|
||||
* relative to 1.2
|
||||
*
|
||||
* Revision 1.3 87/09/24 13:58:45 narten
|
||||
* Sources now pass through lint (if you ignore printf/sprintf/fprintf
|
||||
* warnings)
|
||||
*
|
||||
* Revision 1.2 87/03/27 14:21:48 jenkins
|
||||
* Port to suns
|
||||
*
|
||||
* Revision 1.2 83/12/05 10:12:56 wft
|
||||
* added cond. compilation for USG Unix; long timezone;
|
||||
*
|
||||
* Revision 1.1 82/05/06 11:38:00 wft
|
||||
* Initial revision
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "rcsbase.h"
|
||||
|
||||
libId(maketId, "$Id: maketime.c,v 5.3 1991/08/19 03:13:55 eggert Exp $")
|
||||
|
||||
static struct tm const *time2tm P((time_t));
|
||||
|
||||
#define given(v) (0 <= (v)) /* Negative values are unspecified. */
|
||||
|
||||
static int const daytb[] = {
|
||||
/* # days in year thus far, indexed by month (0-12!!) */
|
||||
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
|
||||
};
|
||||
|
||||
static time_t
|
||||
maketime(atm,zone)
|
||||
struct tm const *atm;
|
||||
int zone;
|
||||
{
|
||||
register struct tm const *tp;
|
||||
register int i;
|
||||
int year, yday, mon, day, hour, min, sec, leap, localzone;
|
||||
int attempts;
|
||||
time_t t, tres;
|
||||
|
||||
attempts = 2;
|
||||
localzone = zone==48*60;
|
||||
tres = -1;
|
||||
year = mon = day = 0; /* Keep lint happy. */
|
||||
|
||||
do {
|
||||
|
||||
if (localzone || !given(atm->tm_year)) {
|
||||
if (tres == -1)
|
||||
if ((tres = time((time_t*)0)) == -1)
|
||||
return -1;
|
||||
tp = time2tm(tres);
|
||||
/* Get breakdowns of default time, adjusting to zone. */
|
||||
year = tp->tm_year; /* Use to set up defaults */
|
||||
yday = tp->tm_yday;
|
||||
mon = tp->tm_mon;
|
||||
day = tp->tm_mday;
|
||||
hour = tp->tm_hour;
|
||||
min = tp->tm_min;
|
||||
if (localzone) {
|
||||
tp = localtime(&tres);
|
||||
zone =
|
||||
min - tp->tm_min + 60*(
|
||||
hour - tp->tm_hour + 24*(
|
||||
/* If years differ, it's by one day. */
|
||||
year - tp->tm_year
|
||||
? year - tp->tm_year
|
||||
: yday - tp->tm_yday));
|
||||
}
|
||||
/* Adjust the default day, month and year according to zone. */
|
||||
if ((min -= zone) < 0) {
|
||||
if (hour-(59-min)/60 < 0 && --day <= 0) {
|
||||
if (--mon < 0) {
|
||||
--year;
|
||||
mon = 11;
|
||||
}
|
||||
day = daytb[mon+1] - daytb[mon] + (mon==1&&!(year&3));
|
||||
}
|
||||
} else
|
||||
if (
|
||||
24 <= hour+min/60 &&
|
||||
daytb[mon+1] - daytb[mon] + (mon==1&&!(year&3)) < ++day
|
||||
) {
|
||||
if (11 < ++mon) {
|
||||
++year;
|
||||
mon = 0;
|
||||
}
|
||||
day = 1;
|
||||
}
|
||||
}
|
||||
if (zone < -24*60 || 24*60 < zone)
|
||||
return -1;
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("first YMD: %d %d %d\n",year,mon,day);
|
||||
#endif
|
||||
tp = atm;
|
||||
|
||||
/* First must find date, using specified year, month, day.
|
||||
* If one of these is unspecified, it defaults either to the
|
||||
* current date (if no more global spec was given) or to the
|
||||
* zero-value for that spec (i.e. a more global spec was seen).
|
||||
* Reject times that do not fit in time_t,
|
||||
* without assuming that time_t is 32 bits or is signed.
|
||||
*/
|
||||
if (given(tp->tm_year))
|
||||
{
|
||||
year = tp->tm_year;
|
||||
mon = 0; /* Since year was given, default */
|
||||
day = 1; /* for remaining specs is zero */
|
||||
}
|
||||
if (year < 69) /* 1969/12/31 OK in some timezones. */
|
||||
return -1; /* ERR: year out of range */
|
||||
leap = !(year&3) && (year%100 || !((year+300)%400));
|
||||
year -= 70; /* UNIX time starts at 1970 */
|
||||
|
||||
/*
|
||||
* Find day of year.
|
||||
*/
|
||||
{
|
||||
if (given(tp->tm_mon))
|
||||
{ mon = tp->tm_mon; /* Month was specified */
|
||||
day = 1; /* so set remaining default */
|
||||
}
|
||||
if (11 < (unsigned)mon)
|
||||
return -1; /* ERR: bad month */
|
||||
if (given(tp->tm_mday)) day = tp->tm_mday;
|
||||
if(day < 1
|
||||
|| (((daytb[mon+1]-daytb[mon]) < day)
|
||||
&& (day!=29 || mon!=1 || !leap) ))
|
||||
return -1; /* ERR: bad day */
|
||||
yday = daytb[mon] /* Add # of days in months so far */
|
||||
+ ((leap /* Leap year, and past Feb? If */
|
||||
&& mon>1)? 1:0) /* so, add leap day for this year */
|
||||
+ day-1; /* And finally add # days this mon */
|
||||
|
||||
}
|
||||
if (leap+365 <= (unsigned)yday)
|
||||
return -1; /* ERR: bad YDAY */
|
||||
|
||||
if (year < 0) {
|
||||
if (yday != 364)
|
||||
return -1; /* ERR: too early */
|
||||
t = -1;
|
||||
} else {
|
||||
tres = year*365; /* Get # days of years so far */
|
||||
if (tres/365 != year)
|
||||
return -1; /* ERR: overflow */
|
||||
t = tres
|
||||
+ ((year+1)>>2) /* plus # of leap days since 1970 */
|
||||
+ yday; /* and finally add # days this year */
|
||||
if (t+4 < tres)
|
||||
return -1; /* ERR: overflow */
|
||||
}
|
||||
tres = t;
|
||||
|
||||
if (given(i = tp->tm_wday)) /* Check WDAY if present */
|
||||
if (i != (tres+4)%7) /* 1970/01/01 was Thu = 4 */
|
||||
return -1; /* ERR: bad WDAY */
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("YMD: %d %d %d, T=%ld\n",year,mon,day,tres);
|
||||
#endif
|
||||
/*
|
||||
* Now determine time. If not given, default to zeros
|
||||
* (since time is always the least global spec)
|
||||
*/
|
||||
tres *= 86400L; /* Get # seconds (24*60*60) */
|
||||
if (tres/86400L != t)
|
||||
return -1; /* ERR: overflow */
|
||||
hour = min = sec = 0;
|
||||
if (given(tp->tm_hour)) hour = tp->tm_hour;
|
||||
if (given(tp->tm_min )) min = tp->tm_min;
|
||||
if (given(tp->tm_sec )) sec = tp->tm_sec;
|
||||
if (60 <= (unsigned)min || 60 < (unsigned)sec)
|
||||
return -1; /* ERR: MS out of range */
|
||||
if (24 <= (unsigned)hour)
|
||||
if(hour != 24 || (min+sec) !=0) /* Allow 24:00 */
|
||||
return -1; /* ERR: H out of range */
|
||||
|
||||
t = tres;
|
||||
tres += sec + 60L*(zone + min + 60*hour);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("HMS: %d %d %d T=%ld\n",hour,min,sec,tres);
|
||||
#endif
|
||||
|
||||
if (!localzone) /* check for overflow */
|
||||
return (year<0 ? (tres<0||86400L<=tres) : tres<t) ? -1 : tres;
|
||||
|
||||
/* Check results; LT may have had a different GMT offset back then. */
|
||||
tp = localtime(&tres);
|
||||
if (given(atm->tm_sec) && atm->tm_sec != tp->tm_sec)
|
||||
return -1; /* If seconds don't match, we're in trouble. */
|
||||
if (!(
|
||||
given(atm->tm_min) && atm->tm_min != tp->tm_min ||
|
||||
given(atm->tm_hour) && atm->tm_hour != tp->tm_hour ||
|
||||
given(atm->tm_mday) && atm->tm_mday != tp->tm_mday ||
|
||||
given(atm->tm_mon) && atm->tm_mon != tp->tm_mon ||
|
||||
given(atm->tm_year) && atm->tm_year != tp->tm_year
|
||||
))
|
||||
return tres; /* Everything matches. */
|
||||
|
||||
} while (--attempts);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert Unix time to struct tm format.
|
||||
* Use Coordinated Universal Time (UTC) if version 5 or newer;
|
||||
* use local time otherwise.
|
||||
*/
|
||||
static struct tm const *
|
||||
time2tm(unixtime)
|
||||
time_t unixtime;
|
||||
{
|
||||
struct tm const *tm;
|
||||
# if TZ_must_be_set
|
||||
static char const *TZ;
|
||||
if (!TZ && !(TZ = getenv("TZ")))
|
||||
faterror("TZ is not set");
|
||||
# endif
|
||||
if (!(tm = (RCSversion<VERSION(5) ? localtime : gmtime)(&unixtime)))
|
||||
faterror("UTC is not available; perhaps TZ is not set?");
|
||||
return tm;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert Unix time to RCS format.
|
||||
* For compatibility with older versions of RCS,
|
||||
* dates before AD 2000 are stored without the leading "19".
|
||||
*/
|
||||
void
|
||||
time2date(unixtime,date)
|
||||
time_t unixtime;
|
||||
char date[datesize];
|
||||
{
|
||||
register struct tm const *tm = time2tm(unixtime);
|
||||
VOID sprintf(date, DATEFORM,
|
||||
tm->tm_year + (tm->tm_year<100 ? 0 : 1900),
|
||||
tm->tm_mon+1, tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static time_t
|
||||
str2time(source)
|
||||
char const *source;
|
||||
/* Parse a free-format date in SOURCE, yielding a Unix format time. */
|
||||
{
|
||||
int zone;
|
||||
time_t unixtime;
|
||||
struct tm parseddate;
|
||||
|
||||
if (!partime(source, &parseddate, &zone))
|
||||
faterror("can't parse date/time: %s", source);
|
||||
if ((unixtime = maketime(&parseddate, zone)) == -1)
|
||||
faterror("bad date/time: %s", source);
|
||||
return unixtime;
|
||||
}
|
||||
|
||||
void
|
||||
str2date(source, target)
|
||||
char const *source;
|
||||
char target[datesize];
|
||||
/* Parse a free-format date in SOURCE, convert it
|
||||
* into RCS internal format, and store the result into TARGET.
|
||||
*/
|
||||
{
|
||||
time2date(str2time(source), target);
|
||||
}
|
||||
|
||||
int
|
||||
setfiledate(file, date)
|
||||
char const *file, date[datesize];
|
||||
/* Set the access and modification time of FILE to DATE. */
|
||||
{
|
||||
static struct utimbuf times; /* static so unused fields are zero */
|
||||
char datebuf[datesize];
|
||||
|
||||
if (!date)
|
||||
return 0;
|
||||
times.actime = times.modtime = str2time(date2str(date, datebuf));
|
||||
return utime(file, ×);
|
||||
}
|
||||
139
gnu/usr.bin/rcs/lib/merger.c
Normal file
139
gnu/usr.bin/rcs/lib/merger.c
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/* merger - three-way file merge internals */
|
||||
|
||||
/* Copyright 1991 by 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, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Report problems and direct all questions to:
|
||||
|
||||
rcs-bugs@cs.purdue.edu
|
||||
|
||||
*/
|
||||
|
||||
#include "rcsbase.h"
|
||||
|
||||
libId(mergerId, "$Id: merger.c,v 1.3 1991/08/20 23:05:00 eggert Exp $")
|
||||
|
||||
static char const *
|
||||
normalize_arg(s, b)
|
||||
char const *s;
|
||||
char **b;
|
||||
/*
|
||||
* If S looks like an option, prepend ./ to it. Yield the result.
|
||||
* Set *B to the address of any storage that was allocated..
|
||||
*/
|
||||
{
|
||||
char *t;
|
||||
switch (*s) {
|
||||
case '-': case '+':
|
||||
*b = t = testalloc(strlen(s) + 3);
|
||||
VOID sprintf(t, ".%c%s", SLASH, s);
|
||||
return t;
|
||||
default:
|
||||
*b = 0;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
merge(tostdout, label, argv)
|
||||
int tostdout;
|
||||
char const *const label[2];
|
||||
char const *const argv[3];
|
||||
/*
|
||||
* Do `merge [-p] -L l0 -L l1 a0 a1 a2',
|
||||
* where TOSTDOUT specifies whether -p is present,
|
||||
* LABEL gives l0 and l1, and ARGV gives a0, a1, and a2.
|
||||
* Yield DIFF_SUCCESS or DIFF_FAILURE.
|
||||
*/
|
||||
{
|
||||
register int i;
|
||||
FILE *f;
|
||||
RILE *rt;
|
||||
char const *a[3], *t;
|
||||
char *b[3];
|
||||
int s;
|
||||
#if !DIFF3_BIN
|
||||
char const *d[2];
|
||||
#endif
|
||||
|
||||
for (i=3; 0<=--i; )
|
||||
a[i] = normalize_arg(argv[i], &b[i]);
|
||||
|
||||
#if DIFF3_BIN
|
||||
t = 0;
|
||||
if (!tostdout)
|
||||
t = maketemp(0);
|
||||
s = run(
|
||||
(char*)0, t,
|
||||
DIFF3, "-am", "-L", label[0], "-L", label[1],
|
||||
a[0], a[1], a[2], (char*)0
|
||||
);
|
||||
switch (s) {
|
||||
case DIFF_SUCCESS:
|
||||
break;
|
||||
case DIFF_FAILURE:
|
||||
if (!quietflag)
|
||||
warn("overlaps during merge");
|
||||
break;
|
||||
default:
|
||||
exiterr();
|
||||
}
|
||||
if (t) {
|
||||
if (!(f = fopen(argv[0], FOPEN_W)))
|
||||
efaterror(argv[0]);
|
||||
if (!(rt = Iopen(t, FOPEN_R, (struct stat*)0)))
|
||||
efaterror(t);
|
||||
fastcopy(rt, f);
|
||||
Ifclose(rt);
|
||||
Ofclose(f);
|
||||
}
|
||||
#else
|
||||
for (i=0; i<2; i++)
|
||||
switch (run(
|
||||
(char*)0, d[i]=maketemp(i),
|
||||
DIFF, a[i], a[2], (char*)0
|
||||
)) {
|
||||
case DIFF_FAILURE: case DIFF_SUCCESS: break;
|
||||
default: exiterr();
|
||||
}
|
||||
t = maketemp(2);
|
||||
s = run(
|
||||
(char*)0, t,
|
||||
DIFF3, "-E", d[0], d[1], a[0], a[1], a[2],
|
||||
label[0], label[1], (char*)0
|
||||
);
|
||||
if (s != DIFF_SUCCESS) {
|
||||
s = DIFF_FAILURE;
|
||||
if (!quietflag)
|
||||
warn("overlaps or other problems during merge");
|
||||
}
|
||||
if (!(f = fopen(t, "a")))
|
||||
efaterror(t);
|
||||
aputs(tostdout ? "1,$p\n" : "w\n", f);
|
||||
Ofclose(f);
|
||||
if (run(t, (char*)0, ED, "-", a[0], (char*)0))
|
||||
exiterr();
|
||||
#endif
|
||||
|
||||
tempunlink();
|
||||
for (i=3; 0<=--i; )
|
||||
if (b[i])
|
||||
tfree(b[i]);
|
||||
return s;
|
||||
}
|
||||
639
gnu/usr.bin/rcs/lib/partime.c
Normal file
639
gnu/usr.bin/rcs/lib/partime.c
Normal file
|
|
@ -0,0 +1,639 @@
|
|||
/*
|
||||
* PARTIME parse date/time string into a TM structure
|
||||
*
|
||||
* Returns:
|
||||
* 0 if parsing failed
|
||||
* else time values in specified TM structure and zone (unspecified values
|
||||
* set to TMNULL)
|
||||
* Notes:
|
||||
* This code is quasi-public; it may be used freely in like software.
|
||||
* It is not to be sold, nor used in licensed software without
|
||||
* permission of the author.
|
||||
* For everyone's benefit, please report bugs and improvements!
|
||||
* Copyright 1980 by Ken Harrenstien, SRI International.
|
||||
* (ARPANET: KLH @ SRI)
|
||||
*/
|
||||
|
||||
/* Hacknotes:
|
||||
* If parsing changed so that no backup needed, could perhaps modify
|
||||
* to use a FILE input stream. Need terminator, though.
|
||||
* Perhaps should return 0 on success, else a non-zero error val?
|
||||
*/
|
||||
|
||||
/* $Log: partime.c,v $
|
||||
* Revision 5.6 1991/08/19 03:13:55 eggert
|
||||
* Update timezones.
|
||||
*
|
||||
* Revision 5.5 1991/04/21 11:58:18 eggert
|
||||
* Don't put , just before } in initializer.
|
||||
*
|
||||
* Revision 5.4 1990/10/04 06:30:15 eggert
|
||||
* Remove date vs time heuristics that fail between 2000 and 2400.
|
||||
* Check for overflow when lexing an integer.
|
||||
* Parse 'Jan 10 LT' as 'Jan 10, LT', not 'Jan, 10 LT'.
|
||||
*
|
||||
* Revision 5.3 1990/09/24 18:56:31 eggert
|
||||
* Update timezones.
|
||||
*
|
||||
* Revision 5.2 1990/09/04 08:02:16 eggert
|
||||
* Don't parse two-digit years, because it won't work after 1999/12/31.
|
||||
* Don't permit 'Aug Aug'.
|
||||
*
|
||||
* Revision 5.1 1990/08/29 07:13:49 eggert
|
||||
* Be able to parse our own date format. Don't assume year<10000.
|
||||
*
|
||||
* Revision 5.0 1990/08/22 08:12:40 eggert
|
||||
* Switch to GMT and fix the bugs exposed thereby. Update timezones.
|
||||
* Ansify and Posixate. Fix peekahead and int-size bugs.
|
||||
*
|
||||
* Revision 1.4 89/05/01 14:48:46 narten
|
||||
* fixed #ifdef DEBUG construct
|
||||
*
|
||||
* Revision 1.3 88/08/28 14:53:40 eggert
|
||||
* Remove unportable "#endif XXX"s.
|
||||
*
|
||||
* Revision 1.2 87/03/27 14:21:53 jenkins
|
||||
* Port to suns
|
||||
*
|
||||
* Revision 1.1 82/05/06 11:38:26 wft
|
||||
* Initial revision
|
||||
*
|
||||
*/
|
||||
|
||||
#include "rcsbase.h"
|
||||
|
||||
libId(partId, "$Id: partime.c,v 5.6 1991/08/19 03:13:55 eggert Exp $")
|
||||
|
||||
#define given(v) (0 <= (v))
|
||||
#define TMNULL (-1) /* Items not given are given this value */
|
||||
#define TZ_OFFSET (24*60) /* TMNULL < zone_offset - TZ_OFFSET */
|
||||
|
||||
struct tmwent {
|
||||
char const *went;
|
||||
short wval;
|
||||
char wflgs;
|
||||
char wtype;
|
||||
};
|
||||
/* wflgs */
|
||||
#define TWTIME 02 /* Word is a time value (absence implies date) */
|
||||
#define TWDST 04 /* Word is a DST-type timezone */
|
||||
/* wtype */
|
||||
#define TM_MON 1 /* month name */
|
||||
#define TM_WDAY 2 /* weekday name */
|
||||
#define TM_ZON 3 /* time zone name */
|
||||
#define TM_LT 4 /* local time */
|
||||
#define TM_DST 5 /* daylight savings time */
|
||||
#define TM_12 6 /* AM, PM, NOON, or MIDNIGHT */
|
||||
/* wval (for wtype==TM_12) */
|
||||
#define T12_AM 1
|
||||
#define T12_PM 2
|
||||
#define T12_NOON 12
|
||||
#define T12_MIDNIGHT 0
|
||||
|
||||
static struct tmwent const tmwords [] = {
|
||||
{"january", 0, 0, TM_MON},
|
||||
{"february", 1, 0, TM_MON},
|
||||
{"march", 2, 0, TM_MON},
|
||||
{"april", 3, 0, TM_MON},
|
||||
{"may", 4, 0, TM_MON},
|
||||
{"june", 5, 0, TM_MON},
|
||||
{"july", 6, 0, TM_MON},
|
||||
{"august", 7, 0, TM_MON},
|
||||
{"september", 8, 0, TM_MON},
|
||||
{"october", 9, 0, TM_MON},
|
||||
{"november", 10, 0, TM_MON},
|
||||
{"december", 11, 0, TM_MON},
|
||||
|
||||
{"sunday", 0, 0, TM_WDAY},
|
||||
{"monday", 1, 0, TM_WDAY},
|
||||
{"tuesday", 2, 0, TM_WDAY},
|
||||
{"wednesday", 3, 0, TM_WDAY},
|
||||
{"thursday", 4, 0, TM_WDAY},
|
||||
{"friday", 5, 0, TM_WDAY},
|
||||
{"saturday", 6, 0, TM_WDAY},
|
||||
|
||||
{"gmt", 0*60, TWTIME, TM_ZON}, /* Greenwich */
|
||||
{"utc", 0*60, TWTIME, TM_ZON},
|
||||
{"ut", 0*60, TWTIME, TM_ZON},
|
||||
{"cut", 0*60, TWTIME, TM_ZON},
|
||||
|
||||
{"nzst", -12*60, TWTIME, TM_ZON}, /* New Zealand */
|
||||
{"jst", -9*60, TWTIME, TM_ZON}, /* Japan */
|
||||
{"kst", -9*60, TWTIME, TM_ZON}, /* Korea */
|
||||
{"ist", -5*60-30, TWTIME, TM_ZON},/* India */
|
||||
{"eet", -2*60, TWTIME, TM_ZON}, /* Eastern Europe */
|
||||
{"cet", -1*60, TWTIME, TM_ZON}, /* Central Europe */
|
||||
{"met", -1*60, TWTIME, TM_ZON}, /* Middle Europe */
|
||||
{"wet", 0*60, TWTIME, TM_ZON}, /* Western Europe */
|
||||
{"nst", 3*60+30, TWTIME, TM_ZON},/* Newfoundland */
|
||||
{"ast", 4*60, TWTIME, TM_ZON}, /* Atlantic */
|
||||
{"est", 5*60, TWTIME, TM_ZON}, /* Eastern */
|
||||
{"cst", 6*60, TWTIME, TM_ZON}, /* Central */
|
||||
{"mst", 7*60, TWTIME, TM_ZON}, /* Mountain */
|
||||
{"pst", 8*60, TWTIME, TM_ZON}, /* Pacific */
|
||||
{"akst", 9*60, TWTIME, TM_ZON}, /* Alaska */
|
||||
{"hast", 10*60, TWTIME, TM_ZON}, /* Hawaii-Aleutian */
|
||||
{"hst", 10*60, TWTIME, TM_ZON}, /* Hawaii */
|
||||
{"sst", 11*60, TWTIME, TM_ZON}, /* Samoa */
|
||||
|
||||
{"nzdt", -12*60, TWTIME+TWDST, TM_ZON}, /* New Zealand */
|
||||
{"kdt", -9*60, TWTIME+TWDST, TM_ZON}, /* Korea */
|
||||
{"bst", 0*60, TWTIME+TWDST, TM_ZON}, /* Britain */
|
||||
{"ndt", 3*60+30, TWTIME+TWDST, TM_ZON}, /* Newfoundland */
|
||||
{"adt", 4*60, TWTIME+TWDST, TM_ZON}, /* Atlantic */
|
||||
{"edt", 5*60, TWTIME+TWDST, TM_ZON}, /* Eastern */
|
||||
{"cdt", 6*60, TWTIME+TWDST, TM_ZON}, /* Central */
|
||||
{"mdt", 7*60, TWTIME+TWDST, TM_ZON}, /* Mountain */
|
||||
{"pdt", 8*60, TWTIME+TWDST, TM_ZON}, /* Pacific */
|
||||
{"akdt", 9*60, TWTIME+TWDST, TM_ZON}, /* Alaska */
|
||||
{"hadt", 10*60, TWTIME+TWDST, TM_ZON}, /* Hawaii-Aleutian */
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* The following names are duplicates or are not well attested.
|
||||
* A standard is needed.
|
||||
*/
|
||||
{"east", -10*60, TWTIME, TM_ZON}, /* Eastern Australia */
|
||||
{"cast", -9*60-30, TWTIME, TM_ZON},/* Central Australia */
|
||||
{"cst", -8*60, TWTIME, TM_ZON}, /* China */
|
||||
{"hkt", -8*60, TWTIME, TM_ZON}, /* Hong Kong */
|
||||
{"sst", -8*60, TWTIME, TM_ZON}, /* Singapore */
|
||||
{"wast", -8*60, TWTIME, TM_ZON}, /* Western Australia */
|
||||
{"?", -6*60-30, TWTIME, TM_ZON},/* Burma */
|
||||
{"?", -4*60-30, TWTIME, TM_ZON},/* Afghanistan */
|
||||
{"it", -3*60-30, TWTIME, TM_ZON},/* Iran */
|
||||
{"ist", -2*60, TWTIME, TM_ZON}, /* Israel */
|
||||
{"mez", -1*60, TWTIME, TM_ZON}, /* Mittel-Europaeische Zeit */
|
||||
{"ast", 1*60, TWTIME, TM_ZON}, /* Azores */
|
||||
{"fst", 2*60, TWTIME, TM_ZON}, /* Fernando de Noronha */
|
||||
{"bst", 3*60, TWTIME, TM_ZON}, /* Brazil */
|
||||
{"wst", 4*60, TWTIME, TM_ZON}, /* Western Brazil */
|
||||
{"ast", 5*60, TWTIME, TM_ZON}, /* Acre Brazil */
|
||||
{"?", 9*60+30, TWTIME, TM_ZON},/* Marquesas */
|
||||
{"?", 12*60, TWTIME, TM_ZON}, /* Kwajalein */
|
||||
|
||||
{"eadt", -10*60, TWTIME+TWDST, TM_ZON}, /* Eastern Australia */
|
||||
{"cadt", -9*60-30, TWTIME+TWDST, TM_ZON}, /* Central Australia */
|
||||
{"cdt", -8*60, TWTIME+TWDST, TM_ZON}, /* China */
|
||||
{"wadt", -8*60, TWTIME+TWDST, TM_ZON}, /* Western Australia */
|
||||
{"idt", -2*60, TWTIME+TWDST, TM_ZON}, /* Israel */
|
||||
{"eest", -2*60, TWTIME+TWDST, TM_ZON}, /* Eastern Europe */
|
||||
{"cest", -1*60, TWTIME+TWDST, TM_ZON}, /* Central Europe */
|
||||
{"mest", -1*60, TWTIME+TWDST, TM_ZON}, /* Middle Europe */
|
||||
{"mesz", -1*60, TWTIME+TWDST, TM_ZON}, /* Mittel-Europaeische Sommerzeit */
|
||||
{"west", 0*60, TWTIME+TWDST, TM_ZON}, /* Western Europe */
|
||||
{"adt", 1*60, TWTIME+TWDST, TM_ZON}, /* Azores */
|
||||
{"fdt", 2*60, TWTIME+TWDST, TM_ZON}, /* Fernando de Noronha */
|
||||
{"edt", 3*60, TWTIME+TWDST, TM_ZON}, /* Eastern Brazil */
|
||||
{"wdt", 4*60, TWTIME+TWDST, TM_ZON}, /* Western Brazil */
|
||||
{"adt", 5*60, TWTIME+TWDST, TM_ZON}, /* Acre Brazil */
|
||||
#endif
|
||||
|
||||
{"lt", 0, TWTIME, TM_LT}, /* local time */
|
||||
{"dst", 1*60, TWTIME, TM_DST}, /* daylight savings time */
|
||||
{"ddst", 2*60, TWTIME, TM_DST}, /* double dst */
|
||||
|
||||
{"am", T12_AM, TWTIME, TM_12},
|
||||
{"pm", T12_PM, TWTIME, TM_12},
|
||||
{"noon", T12_NOON, TWTIME, TM_12},
|
||||
{"midnight", T12_MIDNIGHT, TWTIME, TM_12},
|
||||
|
||||
{0, 0, 0, 0} /* Zero entry to terminate searches */
|
||||
};
|
||||
|
||||
struct token {
|
||||
char const *tcp;/* pointer to string */
|
||||
int tcnt; /* # chars */
|
||||
char tbrk; /* "break" char */
|
||||
char tbrkl; /* last break char */
|
||||
char tflg; /* 0 = alpha, 1 = numeric */
|
||||
union { /* Resulting value; */
|
||||
int tnum;/* either a #, or */
|
||||
struct tmwent const *ttmw;/* a ptr to a tmwent. */
|
||||
} tval;
|
||||
};
|
||||
|
||||
static struct tmwent const*ptmatchstr P((char const*,int,struct tmwent const*));
|
||||
static int pt12hack P((struct tm *,int));
|
||||
static int ptitoken P((struct token *));
|
||||
static int ptstash P((int *,int));
|
||||
static int pttoken P((struct token *));
|
||||
|
||||
static int
|
||||
goodzone(t, offset, am)
|
||||
register struct token const *t;
|
||||
int offset;
|
||||
int *am;
|
||||
{
|
||||
register int m;
|
||||
if (
|
||||
t->tflg &&
|
||||
t->tcnt == 4+offset &&
|
||||
(m = t->tval.tnum) <= 2400 &&
|
||||
isdigit(t->tcp[offset]) &&
|
||||
(m%=100) < 60
|
||||
) {
|
||||
m += t->tval.tnum/100 * 60;
|
||||
if (t->tcp[offset-1]=='+')
|
||||
m = -m;
|
||||
*am = m;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
partime(astr, atm, zone)
|
||||
char const *astr;
|
||||
register struct tm *atm;
|
||||
int *zone;
|
||||
{
|
||||
register int i;
|
||||
struct token btoken, atoken;
|
||||
int zone_offset; /* minutes west of GMT, plus TZ_OFFSET */
|
||||
register char const *cp;
|
||||
register char ch;
|
||||
int ord, midnoon;
|
||||
int *atmfield, dst, m;
|
||||
int got1 = 0;
|
||||
|
||||
atm->tm_sec = TMNULL;
|
||||
atm->tm_min = TMNULL;
|
||||
atm->tm_hour = TMNULL;
|
||||
atm->tm_mday = TMNULL;
|
||||
atm->tm_mon = TMNULL;
|
||||
atm->tm_year = TMNULL;
|
||||
atm->tm_wday = TMNULL;
|
||||
atm->tm_yday = TMNULL;
|
||||
midnoon = TMNULL; /* and our own temp stuff */
|
||||
zone_offset = TMNULL;
|
||||
dst = TMNULL;
|
||||
btoken.tcnt = btoken.tbrk = 0;
|
||||
btoken.tcp = astr;
|
||||
|
||||
for (;; got1=1) {
|
||||
if (!ptitoken(&btoken)) /* Get a token */
|
||||
{ if(btoken.tval.tnum) return(0); /* Read error? */
|
||||
if (given(midnoon)) /* EOF, wrap up */
|
||||
if (!pt12hack(atm, midnoon))
|
||||
return 0;
|
||||
if (!given(atm->tm_min))
|
||||
atm->tm_min = 0;
|
||||
*zone =
|
||||
(given(zone_offset) ? zone_offset-TZ_OFFSET : 0)
|
||||
- (given(dst) ? dst : 0);
|
||||
return got1;
|
||||
}
|
||||
if(btoken.tflg == 0) /* Alpha? */
|
||||
{ i = btoken.tval.ttmw->wval;
|
||||
switch (btoken.tval.ttmw->wtype) {
|
||||
default:
|
||||
return 0;
|
||||
case TM_MON:
|
||||
atmfield = &atm->tm_mon;
|
||||
break;
|
||||
case TM_WDAY:
|
||||
atmfield = &atm->tm_wday;
|
||||
break;
|
||||
case TM_DST:
|
||||
atmfield = &dst;
|
||||
break;
|
||||
case TM_LT:
|
||||
if (ptstash(&dst, 0))
|
||||
return 0;
|
||||
i = 48*60; /* local time magic number -- see maketime() */
|
||||
/* fall into */
|
||||
case TM_ZON:
|
||||
i += TZ_OFFSET;
|
||||
if (btoken.tval.ttmw->wflgs & TWDST)
|
||||
if (ptstash(&dst, 60))
|
||||
return 0;
|
||||
/* Peek ahead for offset immediately afterwards. */
|
||||
if (
|
||||
(btoken.tbrk=='-' || btoken.tbrk=='+') &&
|
||||
(atoken=btoken, ++atoken.tcnt, ptitoken(&atoken)) &&
|
||||
goodzone(&atoken, 0, &m)
|
||||
) {
|
||||
i += m;
|
||||
btoken = atoken;
|
||||
}
|
||||
atmfield = &zone_offset;
|
||||
break;
|
||||
case TM_12:
|
||||
atmfield = &midnoon;
|
||||
}
|
||||
if (ptstash(atmfield, i))
|
||||
return(0); /* ERR: val already set */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Token is number. Lots of hairy heuristics. */
|
||||
if (!isdigit(*btoken.tcp)) {
|
||||
if (!goodzone(&btoken, 1, &m))
|
||||
return 0;
|
||||
zone_offset = TZ_OFFSET + m;
|
||||
continue;
|
||||
}
|
||||
|
||||
i = btoken.tval.tnum; /* Value now known to be valid; get it. */
|
||||
if (btoken.tcnt == 3) /* 3 digits = HMM */
|
||||
{
|
||||
hhmm4: if (ptstash(&atm->tm_min, i%100))
|
||||
return(0); /* ERR: min conflict */
|
||||
i /= 100;
|
||||
hh2: if (ptstash(&atm->tm_hour, i))
|
||||
return(0); /* ERR: hour conflict */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (4 < btoken.tcnt)
|
||||
goto year4; /* far in the future */
|
||||
if(btoken.tcnt == 4) /* 4 digits = YEAR or HHMM */
|
||||
{ if (given(atm->tm_year)) goto hhmm4; /* Already got yr? */
|
||||
if (given(atm->tm_hour)) goto year4; /* Already got hr? */
|
||||
if(btoken.tbrk == ':') /* HHMM:SS ? */
|
||||
if ( ptstash(&atm->tm_hour, i/100)
|
||||
|| ptstash(&atm->tm_min, i%100))
|
||||
return(0); /* ERR: hr/min clash */
|
||||
else goto coltm2; /* Go handle SS */
|
||||
if(btoken.tbrk != ',' && btoken.tbrk != '/'
|
||||
&& (atoken=btoken, ptitoken(&atoken)) /* Peek */
|
||||
&& ( atoken.tflg
|
||||
? !isdigit(*atoken.tcp)
|
||||
: atoken.tval.ttmw->wflgs & TWTIME)) /* HHMM-ZON */
|
||||
goto hhmm4;
|
||||
goto year4; /* Give up, assume year. */
|
||||
}
|
||||
|
||||
/* From this point on, assume tcnt == 1 or 2 */
|
||||
/* 2 digits = MM, DD, or HH (MM and SS caught at coltime) */
|
||||
if(btoken.tbrk == ':') /* HH:MM[:SS] */
|
||||
goto coltime; /* must be part of time. */
|
||||
if (31 < i)
|
||||
return 0;
|
||||
|
||||
/* Check for numerical-format date */
|
||||
for (cp = "/-."; ch = *cp++;)
|
||||
{ ord = (ch == '.' ? 0 : 1); /* n/m = D/M or M/D */
|
||||
if(btoken.tbrk == ch) /* "NN-" */
|
||||
{ if(btoken.tbrkl != ch)
|
||||
{
|
||||
atoken = btoken;
|
||||
atoken.tcnt++;
|
||||
if (ptitoken(&atoken)
|
||||
&& atoken.tflg == 0
|
||||
&& atoken.tval.ttmw->wtype == TM_MON)
|
||||
goto dd2;
|
||||
if(ord)goto mm2; else goto dd2; /* "NN-" */
|
||||
} /* "-NN-" */
|
||||
if (!given(atm->tm_mday)
|
||||
&& given(atm->tm_year)) /* If "YYYY-NN-" */
|
||||
goto mm2; /* then always MM */
|
||||
if(ord)goto dd2; else goto mm2;
|
||||
}
|
||||
if(btoken.tbrkl == ch /* "-NN" */
|
||||
&& given(ord ? atm->tm_mon : atm->tm_mday))
|
||||
if (!given(ord ? atm->tm_mday : atm->tm_mon)) /* MM/DD */
|
||||
if(ord)goto dd2; else goto mm2;
|
||||
}
|
||||
|
||||
/* Now reduced to choice between HH and DD */
|
||||
if (given(atm->tm_hour)) goto dd2; /* Have hour? Assume day. */
|
||||
if (given(atm->tm_mday)) goto hh2; /* Have day? Assume hour. */
|
||||
if (given(atm->tm_mon)) goto dd2; /* Have month? Assume day. */
|
||||
if(i > 24) goto dd2; /* Impossible HH means DD */
|
||||
atoken = btoken;
|
||||
if (!ptitoken(&atoken)) /* Read ahead! */
|
||||
if(atoken.tval.tnum) return(0); /* ERR: bad token */
|
||||
else goto dd2; /* EOF, assume day. */
|
||||
if ( atoken.tflg
|
||||
? !isdigit(*atoken.tcp)
|
||||
: atoken.tval.ttmw->wflgs & TWTIME)
|
||||
/* If next token is a time spec, assume hour */
|
||||
goto hh2; /* e.g. "3 PM", "11-EDT" */
|
||||
|
||||
dd2: if (ptstash(&atm->tm_mday, i)) /* Store day (1 based) */
|
||||
return(0);
|
||||
continue;
|
||||
|
||||
mm2: if (ptstash(&atm->tm_mon, i-1)) /* Store month (make zero based) */
|
||||
return(0);
|
||||
continue;
|
||||
|
||||
year4: if ((i-=1900) < 0 || ptstash(&atm->tm_year, i)) /* Store year-1900 */
|
||||
return(0); /* ERR: year conflict */
|
||||
continue;
|
||||
|
||||
/* Hack HH:MM[[:]SS] */
|
||||
coltime:
|
||||
if (ptstash(&atm->tm_hour, i)) return 0;
|
||||
if (!ptitoken(&btoken))
|
||||
return(!btoken.tval.tnum);
|
||||
if(!btoken.tflg) return(0); /* ERR: HH:<alpha> */
|
||||
if(btoken.tcnt == 4) /* MMSS */
|
||||
if (ptstash(&atm->tm_min, btoken.tval.tnum/100)
|
||||
|| ptstash(&atm->tm_sec, btoken.tval.tnum%100))
|
||||
return(0);
|
||||
else continue;
|
||||
if(btoken.tcnt != 2
|
||||
|| ptstash(&atm->tm_min, btoken.tval.tnum))
|
||||
return(0); /* ERR: MM bad */
|
||||
if (btoken.tbrk != ':') continue; /* Seconds follow? */
|
||||
coltm2: if (!ptitoken(&btoken))
|
||||
return(!btoken.tval.tnum);
|
||||
if(!btoken.tflg || btoken.tcnt != 2 /* Verify SS */
|
||||
|| ptstash(&atm->tm_sec, btoken.tval.tnum))
|
||||
return(0); /* ERR: SS bad */
|
||||
}
|
||||
}
|
||||
|
||||
/* Store date/time value, return 0 if successful.
|
||||
* Fail if entry is already set.
|
||||
*/
|
||||
static int
|
||||
ptstash(adr,val)
|
||||
int *adr;
|
||||
int val;
|
||||
{ register int *a;
|
||||
if (given(*(a=adr)))
|
||||
return 1;
|
||||
*a = val;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* This subroutine is invoked for AM, PM, NOON and MIDNIGHT when wrapping up
|
||||
* just prior to returning from partime.
|
||||
*/
|
||||
static int
|
||||
pt12hack(tm, aval)
|
||||
register struct tm *tm;
|
||||
register int aval;
|
||||
{ register int h = tm->tm_hour;
|
||||
switch (aval) {
|
||||
case T12_AM:
|
||||
case T12_PM:
|
||||
if (h > 12)
|
||||
return 0;
|
||||
if (h == 12)
|
||||
tm->tm_hour = 0;
|
||||
if (aval == T12_PM)
|
||||
tm->tm_hour += 12;
|
||||
break;
|
||||
default:
|
||||
if (0 < tm->tm_min || 0 < tm->tm_sec)
|
||||
return 0;
|
||||
if (!given(h) || h==12)
|
||||
tm->tm_hour = aval;
|
||||
else if (aval==T12_MIDNIGHT && (h==0 || h==24))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Get a token and identify it to some degree.
|
||||
* Returns 0 on failure; token.tval will be 0 for normal EOF, otherwise
|
||||
* hit error of some sort
|
||||
*/
|
||||
|
||||
static int
|
||||
ptitoken(tkp)
|
||||
register struct token *tkp;
|
||||
{
|
||||
register char const *cp;
|
||||
register int i, j, k;
|
||||
|
||||
if (!pttoken(tkp))
|
||||
#ifdef DEBUG
|
||||
{
|
||||
VOID printf("EOF\n");
|
||||
return(0);
|
||||
}
|
||||
#else
|
||||
return(0);
|
||||
#endif
|
||||
cp = tkp->tcp;
|
||||
|
||||
#ifdef DEBUG
|
||||
VOID printf("Token: \"%.*s\" ", tkp->tcnt, cp);
|
||||
#endif
|
||||
|
||||
if (tkp->tflg) {
|
||||
i = tkp->tcnt;
|
||||
if (*cp == '+' || *cp == '-') {
|
||||
cp++;
|
||||
i--;
|
||||
}
|
||||
while (0 <= --i) {
|
||||
j = tkp->tval.tnum*10;
|
||||
k = j + (*cp++ - '0');
|
||||
if (j/10 != tkp->tval.tnum || k < j) {
|
||||
/* arithmetic overflow */
|
||||
tkp->tval.tnum = 1;
|
||||
return 0;
|
||||
}
|
||||
tkp->tval.tnum = k;
|
||||
}
|
||||
} else if (!(tkp->tval.ttmw = ptmatchstr(cp, tkp->tcnt, tmwords)))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
VOID printf("Not found!\n");
|
||||
#endif
|
||||
tkp->tval.tnum = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if(tkp->tflg)
|
||||
VOID printf("Val: %d.\n",tkp->tval.tnum);
|
||||
else VOID printf("Found: \"%s\", val: %d, type %d\n",
|
||||
tkp->tval.ttmw->went,tkp->tval.ttmw->wval,tkp->tval.ttmw->wtype);
|
||||
#endif
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* Read token from input string into token structure */
|
||||
static int
|
||||
pttoken(tkp)
|
||||
register struct token *tkp;
|
||||
{
|
||||
register char const *cp;
|
||||
register int c;
|
||||
char const *astr;
|
||||
|
||||
tkp->tcp = astr = cp = tkp->tcp + tkp->tcnt;
|
||||
tkp->tbrkl = tkp->tbrk; /* Set "last break" */
|
||||
tkp->tcnt = tkp->tbrk = tkp->tflg = 0;
|
||||
tkp->tval.tnum = 0;
|
||||
|
||||
while(c = *cp++)
|
||||
{ switch(c)
|
||||
{ case ' ': case '\t': /* Flush all whitespace */
|
||||
case '\r': case '\n':
|
||||
case '\v': case '\f':
|
||||
if (!tkp->tcnt) { /* If no token yet */
|
||||
tkp->tcp = cp; /* ignore the brk */
|
||||
continue; /* and go on. */
|
||||
}
|
||||
/* fall into */
|
||||
case '(': case ')': /* Perhaps any non-alphanum */
|
||||
case '-': case ',': /* shd qualify as break? */
|
||||
case '+':
|
||||
case '/': case ':': case '.': /* Break chars */
|
||||
if(tkp->tcnt == 0) /* If no token yet */
|
||||
{ tkp->tcp = cp; /* ignore the brk */
|
||||
tkp->tbrkl = c;
|
||||
continue; /* and go on. */
|
||||
}
|
||||
tkp->tbrk = c;
|
||||
return(tkp->tcnt);
|
||||
}
|
||||
if (!tkp->tcnt++) { /* If first char of token, */
|
||||
if (isdigit(c)) {
|
||||
tkp->tflg = 1;
|
||||
if (astr<cp-2 && (cp[-2]=='-'||cp[-2]=='+')) {
|
||||
/* timezone is break+sign+digit */
|
||||
tkp->tcp--;
|
||||
tkp->tcnt++;
|
||||
}
|
||||
}
|
||||
} else if ((isdigit(c)!=0) != tkp->tflg) { /* else check type */
|
||||
tkp->tbrk = c;
|
||||
return --tkp->tcnt; /* Wrong type, back up */
|
||||
}
|
||||
}
|
||||
return(tkp->tcnt); /* When hit EOF */
|
||||
}
|
||||
|
||||
|
||||
static struct tmwent const *
|
||||
ptmatchstr(astr,cnt,astruc)
|
||||
char const *astr;
|
||||
int cnt;
|
||||
struct tmwent const *astruc;
|
||||
{
|
||||
register char const *cp, *mp;
|
||||
register int c;
|
||||
struct tmwent const *lastptr;
|
||||
int i;
|
||||
|
||||
lastptr = 0;
|
||||
for(;mp = astruc->went; astruc += 1)
|
||||
{ cp = astr;
|
||||
for(i = cnt; i > 0; i--)
|
||||
{
|
||||
switch (*cp++ - (c = *mp++))
|
||||
{ case 0: continue; /* Exact match */
|
||||
case 'A'-'a':
|
||||
if (ctab[c] == Letter)
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(i==0)
|
||||
if (!*mp) return astruc; /* Exact match */
|
||||
else if(lastptr) return(0); /* Ambiguous */
|
||||
else lastptr = astruc; /* 1st ambig */
|
||||
}
|
||||
return lastptr;
|
||||
}
|
||||
677
gnu/usr.bin/rcs/lib/rcsbase.h
Normal file
677
gnu/usr.bin/rcs/lib/rcsbase.h
Normal file
|
|
@ -0,0 +1,677 @@
|
|||
|
||||
/*
|
||||
* RCS common definitions and data structures
|
||||
*/
|
||||
#define RCSBASE "$Id: rcsbase.h,v 5.11 1991/10/07 17:32:46 eggert Exp $"
|
||||
|
||||
/* Copyright (C) 1982, 1988, 1989 Walter Tichy
|
||||
Copyright 1990, 1991 by 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, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Report problems and direct all questions to:
|
||||
|
||||
rcs-bugs@cs.purdue.edu
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* INSTRUCTIONS:
|
||||
* =============
|
||||
* See the Makefile for how to define C preprocessor symbols.
|
||||
* If you need to change the comment leaders, update the table comtable[]
|
||||
* in rcsfnms.c. (This can wait until you know what a comment leader is.)
|
||||
*****************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
/* $Log: rcsbase.h,v $
|
||||
* Revision 5.11 1991/10/07 17:32:46 eggert
|
||||
* Support piece tables even if !has_mmap.
|
||||
*
|
||||
* Revision 5.10 1991/09/24 00:28:39 eggert
|
||||
* Remove unexported functions.
|
||||
*
|
||||
* Revision 5.9 1991/08/19 03:13:55 eggert
|
||||
* Add piece tables and other tuneups, and NFS workarounds.
|
||||
*
|
||||
* Revision 5.8 1991/04/21 11:58:20 eggert
|
||||
* Add -x, RCSINIT, MS-DOS support.
|
||||
*
|
||||
* Revision 5.7 1991/02/28 19:18:50 eggert
|
||||
* Try setuid() if seteuid() doesn't work.
|
||||
*
|
||||
* Revision 5.6 1991/02/26 17:48:37 eggert
|
||||
* Support new link behavior. Move ANSI C / Posix declarations into conf.sh.
|
||||
*
|
||||
* Revision 5.5 1990/12/04 05:18:43 eggert
|
||||
* Use -I for prompts and -q for diagnostics.
|
||||
*
|
||||
* Revision 5.4 1990/11/01 05:03:35 eggert
|
||||
* Don't assume that builtins are functions; they may be macros.
|
||||
* Permit arbitrary data in logs.
|
||||
*
|
||||
* Revision 5.3 1990/09/26 23:36:58 eggert
|
||||
* Port wait() to non-Posix ANSI C hosts.
|
||||
*
|
||||
* Revision 5.2 1990/09/04 08:02:20 eggert
|
||||
* Don't redefine NAME_MAX, PATH_MAX.
|
||||
* Improve incomplete line handling. Standardize yes-or-no procedure.
|
||||
*
|
||||
* Revision 5.1 1990/08/29 07:13:53 eggert
|
||||
* Add -kkvl. Fix type typos exposed by porting. Clean old log messages too.
|
||||
*
|
||||
* Revision 5.0 1990/08/22 08:12:44 eggert
|
||||
* Adjust ANSI C / Posix support. Add -k, -V, setuid. Don't call access().
|
||||
* Remove compile-time limits; use malloc instead.
|
||||
* Ansify and Posixate. Add support for ISO 8859.
|
||||
* Remove snoop and v2 support.
|
||||
*
|
||||
* Revision 4.9 89/05/01 15:17:14 narten
|
||||
* botched previous USG fix
|
||||
*
|
||||
* Revision 4.8 89/05/01 14:53:05 narten
|
||||
* changed #include <strings.h> -> string.h for USG systems.
|
||||
*
|
||||
* Revision 4.7 88/11/08 15:58:45 narten
|
||||
* removed defs for functions loaded from libraries
|
||||
*
|
||||
* Revision 4.6 88/08/09 19:12:36 eggert
|
||||
* Shrink stdio code size; remove lint; permit -Dhshsize=nn.
|
||||
*
|
||||
* Revision 4.5 87/12/18 17:06:41 narten
|
||||
* made removed BSD ifdef, now uses V4_2BSD
|
||||
*
|
||||
* Revision 4.4 87/10/18 10:29:49 narten
|
||||
* Updating version numbers
|
||||
* Changes relative to 1.1 are actually relative to 4.2
|
||||
*
|
||||
* Revision 1.3 87/09/24 14:02:25 narten
|
||||
* changes for lint
|
||||
*
|
||||
* Revision 1.2 87/03/27 14:22:02 jenkins
|
||||
* Port to suns
|
||||
*
|
||||
* Revision 4.2 83/12/20 16:04:20 wft
|
||||
* merged 3.6.1.1 and 4.1 (SMALLOG, logsize).
|
||||
* moved setting of STRICT_LOCKING to Makefile.
|
||||
* changed DOLLAR to UNKN (conflict with KDELIM).
|
||||
*
|
||||
* Revision 4.1 83/05/04 09:12:41 wft
|
||||
* Added markers Id and RCSfile.
|
||||
* Added Dbranch for default branches.
|
||||
*
|
||||
* Revision 3.6.1.1 83/12/02 21:56:22 wft
|
||||
* Increased logsize, added macro SMALLOG.
|
||||
*
|
||||
* Revision 3.6 83/01/15 16:43:28 wft
|
||||
* 4.2 prerelease
|
||||
*
|
||||
* Revision 3.6 83/01/15 16:43:28 wft
|
||||
* Replaced dbm.h with BYTESIZ, fixed definition of rindex().
|
||||
* Added variants of NCPFN and NCPPN for bsd 4.2, selected by defining V4_2BSD.
|
||||
* Added macro DELNUMFORM to have uniform format for printing delta text nodes.
|
||||
* Added macro DELETE to mark deleted deltas.
|
||||
*
|
||||
* Revision 3.5 82/12/10 12:16:56 wft
|
||||
* Added two forms of DATEFORM, one using %02d, the other %.2d.
|
||||
*
|
||||
* Revision 3.4 82/12/04 20:01:25 wft
|
||||
* added LOCKER, Locker, and USG (redefinition of rindex).
|
||||
*
|
||||
* Revision 3.3 82/12/03 12:22:04 wft
|
||||
* Added dbm.h, stdio.h, RCSBASE, RCSSEP, RCSSUF, WORKMODE, TMPFILE3,
|
||||
* PRINTDATE, PRINTTIME, map, and ctab; removed Suffix. Redefined keyvallength
|
||||
* using NCPPN. Changed putc() to abort on write error.
|
||||
*
|
||||
* Revision 3.2 82/10/18 15:03:52 wft
|
||||
* added macro STRICT_LOCKING, removed RCSUMASK.
|
||||
* renamed JOINFILE[1,2] to JOINFIL[1,2].
|
||||
*
|
||||
* Revision 3.1 82/10/11 19:41:17 wft
|
||||
* removed NBPW, NBPC, NCPW.
|
||||
* added typdef int void to aid compiling
|
||||
*/
|
||||
|
||||
|
||||
#include "conf.h"
|
||||
|
||||
|
||||
#define EXIT_TROUBLE DIFF_TROUBLE
|
||||
|
||||
#ifdef PATH_MAX
|
||||
# define SIZEABLE_PATH PATH_MAX /* size of a large path; not a hard limit */
|
||||
#else
|
||||
# define SIZEABLE_PATH _POSIX_PATH_MAX
|
||||
#endif
|
||||
|
||||
/* for traditional C hosts with unusual size arguments */
|
||||
#define Fread(p,s,n,f) fread(p, (freadarg_type)(s), (freadarg_type)(n), f)
|
||||
#define Fwrite(p,s,n,f) fwrite(p, (freadarg_type)(s), (freadarg_type)(n), f)
|
||||
|
||||
|
||||
/*
|
||||
* Parameters
|
||||
*/
|
||||
|
||||
/* backwards compatibility with old versions of RCS */
|
||||
#define VERSION_min 3 /* old output RCS format supported */
|
||||
#define VERSION_max 5 /* newest output RCS format supported */
|
||||
#ifndef VERSION_DEFAULT /* default RCS output format */
|
||||
# define VERSION_DEFAULT VERSION_max
|
||||
#endif
|
||||
#define VERSION(n) ((n) - VERSION_DEFAULT) /* internally, 0 is the default */
|
||||
|
||||
#ifndef STRICT_LOCKING
|
||||
#define STRICT_LOCKING 1
|
||||
#endif
|
||||
/* 0 sets the default locking to non-strict; */
|
||||
/* used in experimental environments. */
|
||||
/* 1 sets the default locking to strict; */
|
||||
/* used in production environments. */
|
||||
|
||||
#define yearlength 16 /* (good through AD 9,999,999,999,999,999) */
|
||||
#define datesize (yearlength+16) /* size of output of DATEFORM */
|
||||
#define joinlength 20 /* number of joined revisions permitted */
|
||||
#define RCSTMPPREFIX '_' /* prefix for temp files in working dir */
|
||||
#define KDELIM '$' /* delimiter for keywords */
|
||||
#define VDELIM ':' /* separates keywords from values */
|
||||
#define DEFAULTSTATE "Exp" /* default state of revisions */
|
||||
|
||||
|
||||
|
||||
#define true 1
|
||||
#define false 0
|
||||
#define nil 0
|
||||
|
||||
|
||||
/*
|
||||
* RILE - readonly file
|
||||
* declarecache; - declares local cache for RILE variable(s)
|
||||
* setupcache - sets up the local RILE cache, but does not initialize it
|
||||
* cache, uncache - caches and uncaches the local RILE;
|
||||
* (uncache,cache) is needed around functions that advance the RILE pointer
|
||||
* Igeteof(f,c,s) - get a char c from f, executing statement s at EOF
|
||||
* cachegeteof(c,s) - Igeteof applied to the local RILE
|
||||
* Iget(f,c) - like Igeteof, except EOF is an error
|
||||
* cacheget(c) - Iget applied to the local RILE
|
||||
* Ifileno, Irewind, Iseek, Itell - analogs to stdio routines
|
||||
*/
|
||||
|
||||
#if large_memory
|
||||
typedef unsigned char const *Iptr_type;
|
||||
typedef struct {
|
||||
Iptr_type ptr, lim;
|
||||
unsigned char *base; /* for lint, not Iptr_type even if has_mmap */
|
||||
# if has_mmap
|
||||
# define Ifileno(f) ((f)->fd)
|
||||
int fd;
|
||||
# else
|
||||
# define Ifileno(f) fileno((f)->stream)
|
||||
FILE *stream;
|
||||
unsigned char *readlim;
|
||||
# endif
|
||||
} RILE;
|
||||
# if has_mmap
|
||||
# define declarecache register Iptr_type ptr, lim
|
||||
# define setupcache(f) (lim = (f)->lim)
|
||||
# define Igeteof(f,c,s) if ((f)->ptr==(f)->lim) s else (c)= *(f)->ptr++
|
||||
# define cachegeteof(c,s) if (ptr==lim) s else (c)= *ptr++
|
||||
# else
|
||||
# define declarecache register Iptr_type ptr; register RILE *rRILE
|
||||
# define setupcache(f) (rRILE = (f))
|
||||
# define Igeteof(f,c,s) if ((f)->ptr==(f)->readlim && !Igetmore(f)) s else (c)= *(f)->ptr++
|
||||
# define cachegeteof(c,s) if (ptr==rRILE->readlim && !Igetmore(rRILE)) s else (c)= *ptr++
|
||||
# endif
|
||||
# define uncache(f) ((f)->ptr = ptr)
|
||||
# define cache(f) (ptr = (f)->ptr)
|
||||
# define Iget(f,c) Igeteof(f,c,Ieof();)
|
||||
# define cacheget(c) cachegeteof(c,Ieof();)
|
||||
# define Itell(f) ((f)->ptr)
|
||||
# define Iseek(f,p) ((f)->ptr = (p))
|
||||
# define Irewind(f) Iseek(f, (f)->base)
|
||||
# define cachetell() ptr
|
||||
#else
|
||||
# define RILE FILE
|
||||
# define declarecache register FILE *ptr
|
||||
# define setupcache(f) (ptr = (f))
|
||||
# define uncache(f)
|
||||
# define cache(f)
|
||||
# define Igeteof(f,c,s) if(((c)=getc(f))<0){testIerror(f);if(feof(f))s}else
|
||||
# define cachegeteof(c,s) Igeteof(ptr,c,s)
|
||||
# define Iget(f,c) if (((c)=getc(f))<0) testIeof(f); else
|
||||
# define cacheget(c) Iget(ptr,c)
|
||||
# define Ifileno(f) fileno(f)
|
||||
#endif
|
||||
|
||||
/* Print a char, but abort on write error. */
|
||||
#define aputc(c,o) if (putc(c,o)<0) testOerror(o); else
|
||||
|
||||
/* Get a character from an RCS file, perhaps copying to a new RCS file. */
|
||||
#define GETCeof(o,c,s) { cachegeteof(c,s); if (o) aputc(c,o); }
|
||||
#define GETC(o,c) { cacheget(c); if (o) aputc(c,o); }
|
||||
|
||||
|
||||
#define WORKMODE(RCSmode, writable) ((RCSmode)&~(S_IWUSR|S_IWGRP|S_IWOTH) | ((writable)?S_IWUSR:0))
|
||||
/* computes mode of working file: same as RCSmode, but write permission */
|
||||
/* determined by writable */
|
||||
|
||||
|
||||
/* character classes and token codes */
|
||||
enum tokens {
|
||||
/* classes */ DELIM, DIGIT, IDCHAR, NEWLN, LETTER, Letter,
|
||||
PERIOD, SBEGIN, SPACE, UNKN,
|
||||
/* tokens */ COLON, ID, NUM, SEMI, STRING
|
||||
};
|
||||
|
||||
#define SDELIM '@' /* the actual character is needed for string handling*/
|
||||
/* SDELIM must be consistent with ctab[], so that ctab[SDELIM]==SBEGIN.
|
||||
* there should be no overlap among SDELIM, KDELIM, and VDELIM
|
||||
*/
|
||||
|
||||
#define isdigit(c) ((unsigned)((c)-'0') <= 9) /* faster than ctab[c]==DIGIT */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/***************************************
|
||||
* Data structures for the symbol table
|
||||
***************************************/
|
||||
|
||||
/* Buffer of arbitrary data */
|
||||
struct buf {
|
||||
char *string;
|
||||
size_t size;
|
||||
};
|
||||
struct cbuf {
|
||||
char const *string;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
/* Hash table entry */
|
||||
struct hshentry {
|
||||
char const * num; /* pointer to revision number (ASCIZ) */
|
||||
char const * date; /* pointer to date of checkin */
|
||||
char const * author; /* login of person checking in */
|
||||
char const * lockedby; /* who locks the revision */
|
||||
char const * state; /* state of revision (Exp by default) */
|
||||
struct cbuf log; /* log message requested at checkin */
|
||||
struct branchhead * branches; /* list of first revisions on branches*/
|
||||
struct cbuf ig; /* ignored phrases of revision */
|
||||
struct hshentry * next; /* next revision on same branch */
|
||||
struct hshentry * nexthsh; /* next revision with same hash value */
|
||||
unsigned long insertlns;/* lines inserted (computed by rlog) */
|
||||
unsigned long deletelns;/* lines deleted (computed by rlog) */
|
||||
char selector; /* true if selected, false if deleted */
|
||||
};
|
||||
|
||||
/* list of hash entries */
|
||||
struct hshentries {
|
||||
struct hshentries *rest;
|
||||
struct hshentry *first;
|
||||
};
|
||||
|
||||
/* list element for branch lists */
|
||||
struct branchhead {
|
||||
struct hshentry * hsh;
|
||||
struct branchhead * nextbranch;
|
||||
};
|
||||
|
||||
/* accesslist element */
|
||||
struct access {
|
||||
char const * login;
|
||||
struct access * nextaccess;
|
||||
};
|
||||
|
||||
/* list element for locks */
|
||||
struct lock {
|
||||
char const * login;
|
||||
struct hshentry * delta;
|
||||
struct lock * nextlock;
|
||||
};
|
||||
|
||||
/* list element for symbolic names */
|
||||
struct assoc {
|
||||
char const * symbol;
|
||||
char const * num;
|
||||
struct assoc * nextassoc;
|
||||
};
|
||||
|
||||
|
||||
#define mainArgs (argc,argv) int argc; char **argv;
|
||||
|
||||
#if lint
|
||||
# define libId(name,rcsid)
|
||||
# define mainProg(name,cmd,rcsid) int name mainArgs
|
||||
#else
|
||||
# define libId(name,rcsid) char const name[] = rcsid;
|
||||
# define mainProg(name,cmd,rcsid) char const copyright[] = "Copyright 1982,1988,1989 by Walter F. Tichy\nPurdue CS\nCopyright 1990,1991 by Paul Eggert", rcsbaseId[] = RCSBASE, cmdid[] = cmd; libId(name,rcsid) int main mainArgs
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Markers for keyword expansion (used in co and ident)
|
||||
* Every byte must have class LETTER or Letter.
|
||||
*/
|
||||
#define AUTHOR "Author"
|
||||
#define DATE "Date"
|
||||
#define HEADER "Header"
|
||||
#define IDH "Id"
|
||||
#define LOCKER "Locker"
|
||||
#define LOG "Log"
|
||||
#define RCSFILE "RCSfile"
|
||||
#define REVISION "Revision"
|
||||
#define SOURCE "Source"
|
||||
#define STATE "State"
|
||||
#define keylength 8 /* max length of any of the above keywords */
|
||||
|
||||
enum markers { Nomatch, Author, Date, Header, Id,
|
||||
Locker, Log, RCSfile, Revision, Source, State };
|
||||
/* This must be in the same order as rcskeys.c's Keyword[] array. */
|
||||
|
||||
#define DELNUMFORM "\n\n%s\n%s\n"
|
||||
/* used by putdtext and scanlogtext */
|
||||
|
||||
#define EMPTYLOG "*** empty log message ***" /* used by ci and rlog */
|
||||
|
||||
/* main program */
|
||||
extern char const cmdid[];
|
||||
exiting void exiterr P((void));
|
||||
|
||||
/* maketime */
|
||||
int setfiledate P((char const*,char const[datesize]));
|
||||
void str2date P((char const*,char[datesize]));
|
||||
void time2date P((time_t,char[datesize]));
|
||||
|
||||
/* merge */
|
||||
int merge P((int,char const*const[2],char const*const[3]));
|
||||
|
||||
/* partime */
|
||||
int partime P((char const*,struct tm*,int*));
|
||||
|
||||
/* rcsedit */
|
||||
#define ciklogsize 23 /* sizeof("checked in with -k by ") */
|
||||
extern FILE *fcopy;
|
||||
extern char const *resultfile;
|
||||
extern char const ciklog[ciklogsize];
|
||||
extern int locker_expansion;
|
||||
extern struct buf dirtfname[];
|
||||
#define newRCSfilename (dirtfname[0].string)
|
||||
RILE *rcswriteopen P((struct buf*,struct stat*,int));
|
||||
char const *makedirtemp P((char const*,int));
|
||||
char const *getcaller P((void));
|
||||
int addlock P((struct hshentry*));
|
||||
int addsymbol P((char const*,char const*,int));
|
||||
int checkaccesslist P((void));
|
||||
int chnamemod P((FILE**,char const*,char const*,mode_t));
|
||||
int donerewrite P((int));
|
||||
int dorewrite P((int,int));
|
||||
int expandline P((RILE*,FILE*,struct hshentry const*,int,FILE*));
|
||||
int findlock P((int,struct hshentry**));
|
||||
void aflush P((FILE*));
|
||||
void copystring P((void));
|
||||
void dirtempunlink P((void));
|
||||
void enterstring P((void));
|
||||
void finishedit P((struct hshentry const*,FILE*,int));
|
||||
void keepdirtemp P((char const*));
|
||||
void openfcopy P((FILE*));
|
||||
void snapshotedit P((FILE*));
|
||||
void xpandstring P((struct hshentry const*));
|
||||
#if has_NFS || bad_unlink
|
||||
int un_link P((char const*));
|
||||
#else
|
||||
# define un_link(s) unlink(s)
|
||||
#endif
|
||||
#if large_memory
|
||||
void edit_string P((void));
|
||||
# define editstring(delta) edit_string()
|
||||
#else
|
||||
void editstring P((struct hshentry const*));
|
||||
#endif
|
||||
|
||||
/* rcsfcmp */
|
||||
int rcsfcmp P((RILE*,struct stat const*,char const*,struct hshentry const*));
|
||||
|
||||
/* rcsfnms */
|
||||
#define bufautobegin(b) ((void) ((b)->string = 0, (b)->size = 0))
|
||||
extern FILE *workstdout;
|
||||
extern char *workfilename;
|
||||
extern char const *RCSfilename;
|
||||
extern char const *suffixes;
|
||||
extern struct stat RCSstat;
|
||||
RILE *rcsreadopen P((struct buf*,struct stat*,int));
|
||||
char *bufenlarge P((struct buf*,char const**));
|
||||
char const *basename P((char const*));
|
||||
char const *getfullRCSname P((void));
|
||||
char const *maketemp P((int));
|
||||
char const *rcssuffix P((char const*));
|
||||
int pairfilenames P((int,char**,RILE*(*)P((struct buf*,struct stat*,int)),int,int));
|
||||
size_t dirlen P((char const*));
|
||||
struct cbuf bufremember P((struct buf*,size_t));
|
||||
void bufalloc P((struct buf*,size_t));
|
||||
void bufautoend P((struct buf*));
|
||||
void bufrealloc P((struct buf*,size_t));
|
||||
void bufscat P((struct buf*,char const*));
|
||||
void bufscpy P((struct buf*,char const*));
|
||||
void tempunlink P((void));
|
||||
|
||||
/* rcsgen */
|
||||
extern int interactiveflag;
|
||||
extern struct buf curlogbuf;
|
||||
char const *buildrevision P((struct hshentries const*,struct hshentry*,FILE*,int));
|
||||
int getcstdin P((void));
|
||||
int ttystdin P((void));
|
||||
int yesorno P((int,char const*,...));
|
||||
struct cbuf cleanlogmsg P((char*,size_t));
|
||||
struct cbuf getsstdin P((char const*,char const*,char const*,struct buf*));
|
||||
void putdesc P((int,char*));
|
||||
|
||||
/* rcskeep */
|
||||
extern int prevkeys;
|
||||
extern struct buf prevauthor, prevdate, prevrev, prevstate;
|
||||
int getoldkeys P((RILE*));
|
||||
|
||||
/* rcskeys */
|
||||
extern char const *const Keyword[];
|
||||
enum markers trymatch P((char const*));
|
||||
|
||||
/* rcslex */
|
||||
extern FILE *foutptr;
|
||||
extern FILE *frewrite;
|
||||
extern RILE *finptr;
|
||||
extern char const *NextString;
|
||||
extern enum tokens nexttok;
|
||||
extern int hshenter;
|
||||
extern int nerror;
|
||||
extern int nextc;
|
||||
extern int quietflag;
|
||||
extern unsigned long rcsline;
|
||||
char const *getid P((void));
|
||||
exiting void efaterror P((char const*));
|
||||
exiting void enfaterror P((int,char const*));
|
||||
exiting void faterror P((char const*,...));
|
||||
exiting void fatserror P((char const*,...));
|
||||
exiting void Ieof P((void));
|
||||
exiting void Ierror P((void));
|
||||
exiting void Oerror P((void));
|
||||
char *checkid P((char*,int));
|
||||
int eoflex P((void));
|
||||
int getkeyopt P((char const*));
|
||||
int getlex P((enum tokens));
|
||||
struct cbuf getphrases P((char const*));
|
||||
struct cbuf savestring P((struct buf*));
|
||||
struct hshentry *getnum P((void));
|
||||
void Ifclose P((RILE*));
|
||||
void Izclose P((RILE**));
|
||||
void Lexinit P((void));
|
||||
void Ofclose P((FILE*));
|
||||
void Ozclose P((FILE**));
|
||||
void afputc P((int,FILE*));
|
||||
void aprintf P((FILE*,char const*,...));
|
||||
void aputs P((char const*,FILE*));
|
||||
void checksid P((char*));
|
||||
void diagnose P((char const*,...));
|
||||
void eerror P((char const*));
|
||||
void eflush P((void));
|
||||
void enerror P((int,char const*));
|
||||
void error P((char const*,...));
|
||||
void fvfprintf P((FILE*,char const*,va_list));
|
||||
void getkey P((char const*));
|
||||
void getkeystring P((char const*));
|
||||
void nextlex P((void));
|
||||
void oflush P((void));
|
||||
void printstring P((void));
|
||||
void readstring P((void));
|
||||
void redefined P((int));
|
||||
void testIerror P((FILE*));
|
||||
void testOerror P((FILE*));
|
||||
void warn P((char const*,...));
|
||||
void warnignore P((void));
|
||||
#if has_madvise && has_mmap && large_memory
|
||||
void advise_access P((RILE*,int));
|
||||
# define if_advise_access(p,f,advice) if (p) advise_access(f,advice)
|
||||
#else
|
||||
# define advise_access(f,advice)
|
||||
# define if_advise_access(p,f,advice)
|
||||
#endif
|
||||
#if has_mmap && large_memory
|
||||
RILE *I_open P((char const*,struct stat*));
|
||||
# define Iopen(f,m,s) I_open(f,s)
|
||||
#else
|
||||
RILE *Iopen P((char const*,char const*,struct stat*));
|
||||
#endif
|
||||
#if !large_memory
|
||||
void testIeof P((FILE*));
|
||||
void Irewind P((RILE*));
|
||||
#endif
|
||||
|
||||
/* rcsmap */
|
||||
extern const enum tokens ctab[];
|
||||
|
||||
/* rcsrev */
|
||||
char *partialno P((struct buf*,char const*,unsigned));
|
||||
char const *tiprev P((void));
|
||||
int cmpnum P((char const*,char const*));
|
||||
int cmpnumfld P((char const*,char const*,unsigned));
|
||||
int compartial P((char const*,char const*,unsigned));
|
||||
int expandsym P((char const*,struct buf*));
|
||||
int fexpandsym P((char const*,struct buf*,RILE*));
|
||||
struct hshentry *genrevs P((char const*,char const*,char const*,char const*,struct hshentries**));
|
||||
unsigned countnumflds P((char const*));
|
||||
void getbranchno P((char const*,struct buf*));
|
||||
|
||||
/* rcssyn */
|
||||
/* These expand modes must agree with Expand_names[] in rcssyn.c. */
|
||||
#define KEYVAL_EXPAND 0 /* -kkv `$Keyword: value $' */
|
||||
#define KEYVALLOCK_EXPAND 1 /* -kkvl `$Keyword: value locker $' */
|
||||
#define KEY_EXPAND 2 /* -kk `$Keyword$' */
|
||||
#define VAL_EXPAND 3 /* -kv `value' */
|
||||
#define OLD_EXPAND 4 /* -ko use old string, omitting expansion */
|
||||
struct diffcmd {
|
||||
unsigned long
|
||||
line1, /* number of first line */
|
||||
nlines, /* number of lines affected */
|
||||
adprev, /* previous 'a' line1+1 or 'd' line1 */
|
||||
dafter; /* sum of previous 'd' line1 and previous 'd' nlines */
|
||||
};
|
||||
extern char const * Dbranch;
|
||||
extern struct access * AccessList;
|
||||
extern struct assoc * Symbols;
|
||||
extern struct cbuf Comment;
|
||||
extern struct lock * Locks;
|
||||
extern struct hshentry * Head;
|
||||
extern int Expand;
|
||||
extern int StrictLocks;
|
||||
extern unsigned TotalDeltas;
|
||||
extern char const *const expand_names[];
|
||||
extern char const Kdesc[];
|
||||
extern char const Klog[];
|
||||
extern char const Ktext[];
|
||||
int getdiffcmd P((RILE*,int,FILE*,struct diffcmd*));
|
||||
int putdftext P((char const*,struct cbuf,RILE*,FILE*,int));
|
||||
int putdtext P((char const*,struct cbuf,char const*,FILE*,int));
|
||||
int str2expmode P((char const*));
|
||||
void getadmin P((void));
|
||||
void getdesc P((int));
|
||||
void gettree P((void));
|
||||
void ignorephrase P((void));
|
||||
void initdiffcmd P((struct diffcmd*));
|
||||
void putadmin P((FILE*));
|
||||
void putstring P((FILE*,int,struct cbuf,int));
|
||||
void puttree P((struct hshentry const*,FILE*));
|
||||
|
||||
/* rcsutil */
|
||||
extern int RCSversion;
|
||||
char *cgetenv P((char const*));
|
||||
char *fstr_save P((char const*));
|
||||
char *str_save P((char const*));
|
||||
char const *date2str P((char const[datesize],char[datesize]));
|
||||
char const *getusername P((int));
|
||||
int getRCSINIT P((int,char**,char***));
|
||||
int run P((char const*,char const*,...));
|
||||
int runv P((char const**));
|
||||
malloc_type fremember P((malloc_type));
|
||||
malloc_type ftestalloc P((size_t));
|
||||
malloc_type testalloc P((size_t));
|
||||
malloc_type testrealloc P((malloc_type,size_t));
|
||||
#define ftalloc(T) ftnalloc(T,1)
|
||||
#define talloc(T) tnalloc(T,1)
|
||||
#if lint
|
||||
extern malloc_type lintalloc;
|
||||
# define ftnalloc(T,n) (lintalloc = ftestalloc(sizeof(T)*(n)), (T*)0)
|
||||
# define tnalloc(T,n) (lintalloc = testalloc(sizeof(T)*(n)), (T*)0)
|
||||
# define trealloc(T,p,n) (lintalloc = testrealloc((malloc_type)0, sizeof(T)*(n)), p)
|
||||
# define tfree(p)
|
||||
#else
|
||||
# define ftnalloc(T,n) ((T*) ftestalloc(sizeof(T)*(n)))
|
||||
# define tnalloc(T,n) ((T*) testalloc(sizeof(T)*(n)))
|
||||
# define trealloc(T,p,n) ((T*) testrealloc((malloc_type)(p), sizeof(T)*(n)))
|
||||
# define tfree(p) free((malloc_type)(p))
|
||||
#endif
|
||||
void awrite P((char const*,size_t,FILE*));
|
||||
void fastcopy P((RILE*,FILE*));
|
||||
void ffree P((void));
|
||||
void ffree1 P((char const*));
|
||||
void setRCSversion P((char const*));
|
||||
#if has_signal
|
||||
void catchints P((void));
|
||||
void ignoreints P((void));
|
||||
void restoreints P((void));
|
||||
#else
|
||||
# define catchints()
|
||||
# define ignoreints()
|
||||
# define restoreints()
|
||||
#endif
|
||||
#if has_getuid
|
||||
uid_t ruid P((void));
|
||||
# define myself(u) ((u) == ruid())
|
||||
#else
|
||||
# define myself(u) true
|
||||
#endif
|
||||
#if has_setuid
|
||||
uid_t euid P((void));
|
||||
void nosetid P((void));
|
||||
void seteid P((void));
|
||||
void setrid P((void));
|
||||
#else
|
||||
# define nosetid()
|
||||
# define seteid()
|
||||
# define setrid()
|
||||
#endif
|
||||
1656
gnu/usr.bin/rcs/lib/rcsedit.c
Normal file
1656
gnu/usr.bin/rcs/lib/rcsedit.c
Normal file
File diff suppressed because it is too large
Load diff
321
gnu/usr.bin/rcs/lib/rcsfcmp.c
Normal file
321
gnu/usr.bin/rcs/lib/rcsfcmp.c
Normal file
|
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
* RCS file comparison
|
||||
*/
|
||||
/*****************************************************************************
|
||||
* rcsfcmp()
|
||||
* Testprogram: define FCMPTEST
|
||||
*****************************************************************************
|
||||
*/
|
||||
|
||||
/* Copyright (C) 1982, 1988, 1989 Walter Tichy
|
||||
Copyright 1990, 1991 by 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, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Report problems and direct all questions to:
|
||||
|
||||
rcs-bugs@cs.purdue.edu
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* $Log: rcsfcmp.c,v $
|
||||
* Revision 5.9 1991/10/07 17:32:46 eggert
|
||||
* Count log lines correctly.
|
||||
*
|
||||
* Revision 5.8 1991/08/19 03:13:55 eggert
|
||||
* Tune.
|
||||
*
|
||||
* Revision 5.7 1991/04/21 11:58:22 eggert
|
||||
* Fix errno bug. Add MS-DOS support.
|
||||
*
|
||||
* Revision 5.6 1991/02/28 19:18:47 eggert
|
||||
* Open work file at most once.
|
||||
*
|
||||
* Revision 5.5 1990/11/27 09:26:05 eggert
|
||||
* Fix comment leader bug.
|
||||
*
|
||||
* Revision 5.4 1990/11/01 05:03:42 eggert
|
||||
* Permit arbitrary data in logs and comment leaders.
|
||||
*
|
||||
* Revision 5.3 1990/09/11 02:41:15 eggert
|
||||
* Don't ignore differences inside keyword strings if -ko is set.
|
||||
*
|
||||
* Revision 5.1 1990/08/29 07:13:58 eggert
|
||||
* Clean old log messages too.
|
||||
*
|
||||
* Revision 5.0 1990/08/22 08:12:49 eggert
|
||||
* Don't append "checked in with -k by " log to logs,
|
||||
* so that checking in a program with -k doesn't change it.
|
||||
* Ansify and Posixate. Remove lint.
|
||||
*
|
||||
* Revision 4.5 89/05/01 15:12:42 narten
|
||||
* changed copyright header to reflect current distribution rules
|
||||
*
|
||||
* Revision 4.4 88/08/09 19:12:50 eggert
|
||||
* Shrink stdio code size.
|
||||
*
|
||||
* Revision 4.3 87/12/18 11:40:02 narten
|
||||
* lint cleanups (Guy Harris)
|
||||
*
|
||||
* Revision 4.2 87/10/18 10:33:06 narten
|
||||
* updting version number. Changes relative to 1.1 actually relative to
|
||||
* 4.1
|
||||
*
|
||||
* Revision 1.2 87/03/27 14:22:19 jenkins
|
||||
* Port to suns
|
||||
*
|
||||
* Revision 4.1 83/05/10 16:24:04 wft
|
||||
* Marker matching now uses trymatch(). Marker pattern is now
|
||||
* checked precisely.
|
||||
*
|
||||
* Revision 3.1 82/12/04 13:21:40 wft
|
||||
* Initial revision.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
#define FCMPTEST
|
||||
*/
|
||||
/* Testprogram; prints out whether two files are identical,
|
||||
* except for keywords
|
||||
*/
|
||||
|
||||
#include "rcsbase.h"
|
||||
|
||||
libId(fcmpId, "$Id: rcsfcmp.c,v 5.9 1991/10/07 17:32:46 eggert Exp $")
|
||||
|
||||
static int
|
||||
discardkeyval(c, f)
|
||||
register int c;
|
||||
register RILE *f;
|
||||
{
|
||||
for (;;)
|
||||
switch (c) {
|
||||
case KDELIM:
|
||||
case '\n':
|
||||
return c;
|
||||
default:
|
||||
Igeteof(f, c, return EOF;);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
rcsfcmp(xfp, xstatp, ufname, delta)
|
||||
register RILE *xfp;
|
||||
struct stat const *xstatp;
|
||||
char const *ufname;
|
||||
struct hshentry const *delta;
|
||||
/* Compare the files xfp and ufname. Return zero
|
||||
* if xfp has the same contents as ufname and neither has keywords,
|
||||
* otherwise -1 if they are the same ignoring keyword values,
|
||||
* and 1 if they differ even ignoring
|
||||
* keyword values. For the LOG-keyword, rcsfcmp skips the log message
|
||||
* given by the parameter delta in xfp. Thus, rcsfcmp returns nonpositive
|
||||
* if xfp contains the same as ufname, with the keywords expanded.
|
||||
* Implementation: character-by-character comparison until $ is found.
|
||||
* If a $ is found, read in the marker keywords; if they are real keywords
|
||||
* and identical, read in keyword value. If value is terminated properly,
|
||||
* disregard it and optionally skip log message; otherwise, compare value.
|
||||
*/
|
||||
{
|
||||
register int xc, uc;
|
||||
char xkeyword[keylength+2];
|
||||
int eqkeyvals;
|
||||
register RILE *ufp;
|
||||
register int xeof, ueof;
|
||||
register char * tp;
|
||||
register char const *sp;
|
||||
int result;
|
||||
enum markers match1;
|
||||
struct stat ustat;
|
||||
|
||||
if (!(ufp = Iopen(ufname, FOPEN_R_WORK, &ustat))) {
|
||||
efaterror(ufname);
|
||||
}
|
||||
xeof = ueof = false;
|
||||
if (Expand==OLD_EXPAND) {
|
||||
if (!(result = xstatp->st_size!=ustat.st_size)) {
|
||||
# if has_mmap && large_memory
|
||||
result = !!memcmp(xfp->base,ufp->base,(size_t)xstatp->st_size);
|
||||
# else
|
||||
for (;;) {
|
||||
/* get the next characters */
|
||||
Igeteof(xfp, xc, xeof=true;);
|
||||
Igeteof(ufp, uc, ueof=true;);
|
||||
if (xeof | ueof)
|
||||
goto eof;
|
||||
if (xc != uc)
|
||||
goto return1;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
} else {
|
||||
xc = 0;
|
||||
uc = 0; /* Keep lint happy. */
|
||||
result = 0;
|
||||
|
||||
for (;;) {
|
||||
if (xc != KDELIM) {
|
||||
/* get the next characters */
|
||||
Igeteof(xfp, xc, xeof=true;);
|
||||
Igeteof(ufp, uc, ueof=true;);
|
||||
if (xeof | ueof)
|
||||
goto eof;
|
||||
} else {
|
||||
/* try to get both keywords */
|
||||
tp = xkeyword;
|
||||
for (;;) {
|
||||
Igeteof(xfp, xc, xeof=true;);
|
||||
Igeteof(ufp, uc, ueof=true;);
|
||||
if (xeof | ueof)
|
||||
goto eof;
|
||||
if (xc != uc)
|
||||
break;
|
||||
switch (xc) {
|
||||
default:
|
||||
if (xkeyword+keylength <= tp)
|
||||
break;
|
||||
*tp++ = xc;
|
||||
continue;
|
||||
case '\n': case KDELIM: case VDELIM:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (
|
||||
(xc==KDELIM || xc==VDELIM) && (uc==KDELIM || uc==VDELIM) &&
|
||||
(*tp = xc, (match1 = trymatch(xkeyword)) != Nomatch)
|
||||
) {
|
||||
#ifdef FCMPTEST
|
||||
VOID printf("found common keyword %s\n",xkeyword);
|
||||
#endif
|
||||
result = -1;
|
||||
for (;;) {
|
||||
if (xc != uc) {
|
||||
xc = discardkeyval(xc, xfp);
|
||||
uc = discardkeyval(uc, ufp);
|
||||
if ((xeof = xc==EOF) | (ueof = uc==EOF))
|
||||
goto eof;
|
||||
eqkeyvals = false;
|
||||
break;
|
||||
}
|
||||
switch (xc) {
|
||||
default:
|
||||
Igeteof(xfp, xc, xeof=true;);
|
||||
Igeteof(ufp, uc, ueof=true;);
|
||||
if (xeof | ueof)
|
||||
goto eof;
|
||||
continue;
|
||||
|
||||
case '\n': case KDELIM:
|
||||
eqkeyvals = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (xc != uc)
|
||||
goto return1;
|
||||
if (xc==KDELIM) {
|
||||
/* Skip closing KDELIM. */
|
||||
Igeteof(xfp, xc, xeof=true;);
|
||||
Igeteof(ufp, uc, ueof=true;);
|
||||
if (xeof | ueof)
|
||||
goto eof;
|
||||
/* if the keyword is LOG, also skip the log message in xfp*/
|
||||
if (match1==Log) {
|
||||
/* first, compute the number of line feeds in log msg */
|
||||
unsigned lncnt;
|
||||
size_t ls, ccnt;
|
||||
sp = delta->log.string;
|
||||
ls = delta->log.size;
|
||||
if (ls<sizeof(ciklog)-1 || memcmp(sp,ciklog,sizeof(ciklog)-1)) {
|
||||
/* This log message was inserted. */
|
||||
lncnt = 3;
|
||||
while (ls--) if (*sp++=='\n') lncnt++;
|
||||
for (;;) {
|
||||
if (xc=='\n')
|
||||
if(--lncnt==0) break;
|
||||
Igeteof(xfp, xc, goto returnresult;);
|
||||
}
|
||||
/* skip last comment leader */
|
||||
/* Can't just skip another line here, because there may be */
|
||||
/* additional characters on the line (after the Log....$) */
|
||||
for (ccnt=Comment.size; ccnt--; ) {
|
||||
Igeteof(xfp, xc, goto returnresult;);
|
||||
if(xc=='\n') break;
|
||||
/*
|
||||
* Read to the end of the comment leader or '\n',
|
||||
* whatever comes first. Some editors strip
|
||||
* trailing white space from a leader like " * ".
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* both end in the same character, but not a KDELIM */
|
||||
/* must compare string values.*/
|
||||
#ifdef FCMPTEST
|
||||
VOID printf("non-terminated keywords %s, potentially different values\n",xkeyword);
|
||||
#endif
|
||||
if (!eqkeyvals)
|
||||
goto return1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (xc != uc)
|
||||
goto return1;
|
||||
}
|
||||
}
|
||||
|
||||
eof:
|
||||
if (xeof==ueof)
|
||||
goto returnresult;
|
||||
return1:
|
||||
result = 1;
|
||||
returnresult:
|
||||
Ifclose(ufp);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef FCMPTEST
|
||||
|
||||
char const cmdid[] = "rcsfcmp";
|
||||
|
||||
main(argc, argv)
|
||||
int argc; char *argv[];
|
||||
/* first argument: comment leader; 2nd: log message, 3rd: expanded file,
|
||||
* 4th: unexpanded file
|
||||
*/
|
||||
{ struct hshentry delta;
|
||||
|
||||
Comment.string = argv[1];
|
||||
Comment.size = strlen(argv[1]);
|
||||
delta.log.string = argv[2];
|
||||
delta.log.size = strlen(argv[2]);
|
||||
if (rcsfcmp(Iopen(argv[3], FOPEN_R_WORK, (struct stat*)0), argv[4], &delta))
|
||||
VOID printf("files are the same\n");
|
||||
else VOID printf("files are different\n");
|
||||
}
|
||||
#endif
|
||||
1088
gnu/usr.bin/rcs/lib/rcsfnms.c
Normal file
1088
gnu/usr.bin/rcs/lib/rcsfnms.c
Normal file
File diff suppressed because it is too large
Load diff
432
gnu/usr.bin/rcs/lib/rcsgen.c
Normal file
432
gnu/usr.bin/rcs/lib/rcsgen.c
Normal file
|
|
@ -0,0 +1,432 @@
|
|||
/*
|
||||
* RCS revision generation
|
||||
*/
|
||||
|
||||
/* Copyright (C) 1982, 1988, 1989 Walter Tichy
|
||||
Copyright 1990, 1991 by 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, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Report problems and direct all questions to:
|
||||
|
||||
rcs-bugs@cs.purdue.edu
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* $Log: rcsgen.c,v $
|
||||
* Revision 5.10 1991/10/07 17:32:46 eggert
|
||||
* Fix log bugs, e.g. ci -t/dev/null when has_mmap.
|
||||
*
|
||||
* Revision 5.9 1991/09/10 22:15:46 eggert
|
||||
* Fix test for redirected stdin.
|
||||
*
|
||||
* Revision 5.8 1991/08/19 03:13:55 eggert
|
||||
* Add piece tables. Tune.
|
||||
*
|
||||
* Revision 5.7 1991/04/21 11:58:24 eggert
|
||||
* Add MS-DOS support.
|
||||
*
|
||||
* Revision 5.6 1990/12/27 19:54:26 eggert
|
||||
* Fix bug: rcs -t inserted \n, making RCS file grow.
|
||||
*
|
||||
* Revision 5.5 1990/12/04 05:18:45 eggert
|
||||
* Use -I for prompts and -q for diagnostics.
|
||||
*
|
||||
* Revision 5.4 1990/11/01 05:03:47 eggert
|
||||
* Add -I and new -t behavior. Permit arbitrary data in logs.
|
||||
*
|
||||
* Revision 5.3 1990/09/21 06:12:43 hammer
|
||||
* made putdesc() treat stdin the same whether or not it was from a terminal
|
||||
* by making it recognize that a single '.' was then end of the
|
||||
* description always
|
||||
*
|
||||
* Revision 5.2 1990/09/04 08:02:25 eggert
|
||||
* Fix `co -p1.1 -ko' bug. Standardize yes-or-no procedure.
|
||||
*
|
||||
* Revision 5.1 1990/08/29 07:14:01 eggert
|
||||
* Clean old log messages too.
|
||||
*
|
||||
* Revision 5.0 1990/08/22 08:12:52 eggert
|
||||
* Remove compile-time limits; use malloc instead.
|
||||
* Ansify and Posixate.
|
||||
*
|
||||
* Revision 4.7 89/05/01 15:12:49 narten
|
||||
* changed copyright header to reflect current distribution rules
|
||||
*
|
||||
* Revision 4.6 88/08/28 14:59:10 eggert
|
||||
* Shrink stdio code size; allow cc -R; remove lint; isatty() -> ttystdin()
|
||||
*
|
||||
* Revision 4.5 87/12/18 11:43:25 narten
|
||||
* additional lint cleanups, and a bug fix from the 4.3BSD version that
|
||||
* keeps "ci" from sticking a '\377' into the description if you run it
|
||||
* with a zero-length file as the description. (Guy Harris)
|
||||
*
|
||||
* Revision 4.4 87/10/18 10:35:10 narten
|
||||
* Updating version numbers. Changes relative to 1.1 actually relative to
|
||||
* 4.2
|
||||
*
|
||||
* Revision 1.3 87/09/24 13:59:51 narten
|
||||
* Sources now pass through lint (if you ignore printf/sprintf/fprintf
|
||||
* warnings)
|
||||
*
|
||||
* Revision 1.2 87/03/27 14:22:27 jenkins
|
||||
* Port to suns
|
||||
*
|
||||
* Revision 4.2 83/12/02 23:01:39 wft
|
||||
* merged 4.1 and 3.3.1.1 (clearerr(stdin)).
|
||||
*
|
||||
* Revision 4.1 83/05/10 16:03:33 wft
|
||||
* Changed putamin() to abort if trying to reread redirected stdin.
|
||||
* Fixed getdesc() to output a prompt on initial newline.
|
||||
*
|
||||
* Revision 3.3.1.1 83/10/19 04:21:51 lepreau
|
||||
* Added clearerr(stdin) for re-reading description from stdin.
|
||||
*
|
||||
* Revision 3.3 82/11/28 21:36:49 wft
|
||||
* 4.2 prerelease
|
||||
*
|
||||
* Revision 3.3 82/11/28 21:36:49 wft
|
||||
* Replaced ferror() followed by fclose() with ffclose().
|
||||
* Putdesc() now suppresses the prompts if stdin
|
||||
* is not a terminal. A pointer to the current log message is now
|
||||
* inserted into the corresponding delta, rather than leaving it in a
|
||||
* global variable.
|
||||
*
|
||||
* Revision 3.2 82/10/18 21:11:26 wft
|
||||
* I added checks for write errors during editing, and improved
|
||||
* the prompt on putdesc().
|
||||
*
|
||||
* Revision 3.1 82/10/13 15:55:09 wft
|
||||
* corrected type of variables assigned to by getc (char --> int)
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
#include "rcsbase.h"
|
||||
|
||||
libId(genId, "$Id: rcsgen.c,v 5.10 1991/10/07 17:32:46 eggert Exp $")
|
||||
|
||||
int interactiveflag; /* Should we act as if stdin is a tty? */
|
||||
struct buf curlogbuf; /* buffer for current log message */
|
||||
|
||||
enum stringwork { enter, copy, edit, expand, edit_expand };
|
||||
static void scandeltatext P((struct hshentry*,enum stringwork,int));
|
||||
|
||||
|
||||
|
||||
|
||||
char const *
|
||||
buildrevision(deltas, target, outfile, expandflag)
|
||||
struct hshentries const *deltas;
|
||||
struct hshentry *target;
|
||||
FILE *outfile;
|
||||
int expandflag;
|
||||
/* Function: Generates the revision given by target
|
||||
* by retrieving all deltas given by parameter deltas and combining them.
|
||||
* If outfile is set, the revision is output to it,
|
||||
* otherwise written into a temporary file.
|
||||
* Temporary files are allocated by maketemp().
|
||||
* if expandflag is set, keyword expansion is performed.
|
||||
* Return nil if outfile is set, the name of the temporary file otherwise.
|
||||
*
|
||||
* Algorithm: Copy initial revision unchanged. Then edit all revisions but
|
||||
* the last one into it, alternating input and output files (resultfile and
|
||||
* editfile). The last revision is then edited in, performing simultaneous
|
||||
* keyword substitution (this saves one extra pass).
|
||||
* All this simplifies if only one revision needs to be generated,
|
||||
* or no keyword expansion is necessary, or if output goes to stdout.
|
||||
*/
|
||||
{
|
||||
if (deltas->first == target) {
|
||||
/* only latest revision to generate */
|
||||
openfcopy(outfile);
|
||||
scandeltatext(target, expandflag?expand:copy, true);
|
||||
if (outfile)
|
||||
return 0;
|
||||
else {
|
||||
Ozclose(&fcopy);
|
||||
return(resultfile);
|
||||
}
|
||||
} else {
|
||||
/* several revisions to generate */
|
||||
/* Get initial revision without keyword expansion. */
|
||||
scandeltatext(deltas->first, enter, false);
|
||||
while ((deltas=deltas->rest)->rest) {
|
||||
/* do all deltas except last one */
|
||||
scandeltatext(deltas->first, edit, false);
|
||||
}
|
||||
if (expandflag || outfile) {
|
||||
/* first, get to beginning of file*/
|
||||
finishedit((struct hshentry *)nil, outfile, false);
|
||||
}
|
||||
scandeltatext(deltas->first, expandflag?edit_expand:edit, true);
|
||||
finishedit(
|
||||
expandflag ? deltas->first : (struct hshentry*)nil,
|
||||
outfile, true
|
||||
);
|
||||
if (outfile)
|
||||
return 0;
|
||||
Ozclose(&fcopy);
|
||||
return resultfile;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
scandeltatext(delta, func, needlog)
|
||||
struct hshentry * delta;
|
||||
enum stringwork func;
|
||||
int needlog;
|
||||
/* Function: Scans delta text nodes up to and including the one given
|
||||
* by delta. For the one given by delta, the log message is saved into
|
||||
* delta->log if needlog is set; func specifies how to handle the text.
|
||||
* Assumes the initial lexeme must be read in first.
|
||||
* Does not advance nexttok after it is finished.
|
||||
*/
|
||||
{
|
||||
struct hshentry const *nextdelta;
|
||||
struct cbuf cb;
|
||||
|
||||
for (;;) {
|
||||
if (eoflex())
|
||||
fatserror("can't find delta for revision %s", delta->num);
|
||||
nextlex();
|
||||
if (!(nextdelta=getnum())) {
|
||||
fatserror("delta number corrupted");
|
||||
}
|
||||
getkeystring(Klog);
|
||||
if (needlog && delta==nextdelta) {
|
||||
cb = savestring(&curlogbuf);
|
||||
delta->log = cleanlogmsg(curlogbuf.string, cb.size);
|
||||
} else {readstring();
|
||||
}
|
||||
nextlex();
|
||||
while (nexttok==ID && strcmp(NextString,Ktext)!=0)
|
||||
ignorephrase();
|
||||
getkeystring(Ktext);
|
||||
|
||||
if (delta==nextdelta)
|
||||
break;
|
||||
readstring(); /* skip over it */
|
||||
|
||||
}
|
||||
switch (func) {
|
||||
case enter: enterstring(); break;
|
||||
case copy: copystring(); break;
|
||||
case expand: xpandstring(delta); break;
|
||||
case edit: editstring((struct hshentry *)nil); break;
|
||||
case edit_expand: editstring(delta); break;
|
||||
}
|
||||
}
|
||||
|
||||
struct cbuf
|
||||
cleanlogmsg(m, s)
|
||||
char *m;
|
||||
size_t s;
|
||||
{
|
||||
register char *t = m;
|
||||
register char const *f = t;
|
||||
struct cbuf r;
|
||||
while (s) {
|
||||
--s;
|
||||
if ((*t++ = *f++) == '\n')
|
||||
while (m < --t)
|
||||
if (t[-1]!=' ' && t[-1]!='\t') {
|
||||
*t++ = '\n';
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (m < t && (t[-1]==' ' || t[-1]=='\t' || t[-1]=='\n'))
|
||||
--t;
|
||||
r.string = m;
|
||||
r.size = t - m;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
int ttystdin()
|
||||
{
|
||||
static int initialized;
|
||||
if (!initialized) {
|
||||
if (!interactiveflag)
|
||||
interactiveflag = isatty(STDIN_FILENO);
|
||||
initialized = true;
|
||||
}
|
||||
return interactiveflag;
|
||||
}
|
||||
|
||||
int
|
||||
getcstdin()
|
||||
{
|
||||
register FILE *in;
|
||||
register int c;
|
||||
|
||||
in = stdin;
|
||||
if (feof(in) && ttystdin())
|
||||
clearerr(in);
|
||||
c = getc(in);
|
||||
if (c < 0) {
|
||||
testIerror(in);
|
||||
if (feof(in) && ttystdin())
|
||||
afputc('\n',stderr);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
#if has_prototypes
|
||||
int
|
||||
yesorno(int default_answer, char const *question, ...)
|
||||
#else
|
||||
/*VARARGS2*/ int
|
||||
yesorno(default_answer, question, va_alist)
|
||||
int default_answer; char const *question; va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list args;
|
||||
register int c, r;
|
||||
if (!quietflag && ttystdin()) {
|
||||
oflush();
|
||||
vararg_start(args, question);
|
||||
fvfprintf(stderr, question, args);
|
||||
va_end(args);
|
||||
eflush();
|
||||
r = c = getcstdin();
|
||||
while (c!='\n' && !feof(stdin))
|
||||
c = getcstdin();
|
||||
if (r=='y' || r=='Y')
|
||||
return true;
|
||||
if (r=='n' || r=='N')
|
||||
return false;
|
||||
}
|
||||
return default_answer;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
putdesc(textflag, textfile)
|
||||
int textflag;
|
||||
char *textfile;
|
||||
/* Function: puts the descriptive text into file frewrite.
|
||||
* if finptr && !textflag, the text is copied from the old description.
|
||||
* Otherwise, if the textfile!=nil, the text is read from that
|
||||
* file, or from stdin, if textfile==nil.
|
||||
* A textfile with a leading '-' is treated as a string, not a file name.
|
||||
* If finptr, the old descriptive text is discarded.
|
||||
* Always clears foutptr.
|
||||
*/
|
||||
{
|
||||
static struct buf desc;
|
||||
static struct cbuf desclean;
|
||||
|
||||
register FILE *txt;
|
||||
register int c;
|
||||
register FILE * frew;
|
||||
register char *p;
|
||||
register size_t s;
|
||||
char const *plim;
|
||||
|
||||
frew = frewrite;
|
||||
if (finptr && !textflag) {
|
||||
/* copy old description */
|
||||
aprintf(frew, "\n\n%s%c", Kdesc, nextc);
|
||||
foutptr = frewrite;
|
||||
getdesc(false);
|
||||
foutptr = 0;
|
||||
} else {
|
||||
foutptr = 0;
|
||||
/* get new description */
|
||||
if (finptr) {
|
||||
/*skip old description*/
|
||||
getdesc(false);
|
||||
}
|
||||
aprintf(frew,"\n\n%s\n%c",Kdesc,SDELIM);
|
||||
if (!textfile)
|
||||
desclean = getsstdin(
|
||||
"t-", "description",
|
||||
"NOTE: This is NOT the log message!\n", &desc
|
||||
);
|
||||
else if (!desclean.string) {
|
||||
if (*textfile == '-') {
|
||||
p = textfile + 1;
|
||||
s = strlen(p);
|
||||
} else {
|
||||
if (!(txt = fopen(textfile, "r")))
|
||||
efaterror(textfile);
|
||||
bufalloc(&desc, 1);
|
||||
p = desc.string;
|
||||
plim = p + desc.size;
|
||||
for (;;) {
|
||||
if ((c=getc(txt)) < 0) {
|
||||
testIerror(txt);
|
||||
if (feof(txt))
|
||||
break;
|
||||
}
|
||||
if (plim <= p)
|
||||
p = bufenlarge(&desc, &plim);
|
||||
*p++ = c;
|
||||
}
|
||||
if (fclose(txt) != 0)
|
||||
Ierror();
|
||||
s = p - desc.string;
|
||||
p = desc.string;
|
||||
}
|
||||
desclean = cleanlogmsg(p, s);
|
||||
}
|
||||
putstring(frew, false, desclean, true);
|
||||
aputc('\n', frew);
|
||||
}
|
||||
}
|
||||
|
||||
struct cbuf
|
||||
getsstdin(option, name, note, buf)
|
||||
char const *option, *name, *note;
|
||||
struct buf *buf;
|
||||
{
|
||||
register int c;
|
||||
register char *p;
|
||||
register size_t i;
|
||||
register int tty = ttystdin();
|
||||
|
||||
if (tty)
|
||||
aprintf(stderr,
|
||||
"enter %s, terminated with single '.' or end of file:\n%s>> ",
|
||||
name, note
|
||||
);
|
||||
else if (feof(stdin))
|
||||
faterror("can't reread redirected stdin for %s; use -%s<%s>",
|
||||
name, option, name
|
||||
);
|
||||
|
||||
for (
|
||||
i = 0, p = 0;
|
||||
c = getcstdin(), !feof(stdin);
|
||||
bufrealloc(buf, i+1), p = buf->string, p[i++] = c
|
||||
)
|
||||
if (c == '\n')
|
||||
if (i && p[i-1]=='.' && (i==1 || p[i-2]=='\n')) {
|
||||
/* Remove trailing '.'. */
|
||||
--i;
|
||||
break;
|
||||
} else if (tty)
|
||||
aputs(">> ", stderr);
|
||||
return cleanlogmsg(p, i);
|
||||
}
|
||||
422
gnu/usr.bin/rcs/lib/rcskeep.c
Normal file
422
gnu/usr.bin/rcs/lib/rcskeep.c
Normal file
|
|
@ -0,0 +1,422 @@
|
|||
/*
|
||||
* RCS keyword extraction
|
||||
*/
|
||||
/*****************************************************************************
|
||||
* main routine: getoldkeys()
|
||||
* Testprogram: define KEEPTEST
|
||||
*****************************************************************************
|
||||
*/
|
||||
|
||||
/* Copyright (C) 1982, 1988, 1989 Walter Tichy
|
||||
Copyright 1990, 1991 by 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, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Report problems and direct all questions to:
|
||||
|
||||
rcs-bugs@cs.purdue.edu
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* $Log: rcskeep.c,v $
|
||||
* Revision 5.4 1991/08/19 03:13:55 eggert
|
||||
* Tune.
|
||||
*
|
||||
* Revision 5.3 1991/04/21 11:58:25 eggert
|
||||
* Shorten names to keep them distinct on shortname hosts.
|
||||
*
|
||||
* Revision 5.2 1990/10/04 06:30:20 eggert
|
||||
* Parse time zone offsets; future RCS versions may output them.
|
||||
*
|
||||
* Revision 5.1 1990/09/20 02:38:56 eggert
|
||||
* ci -k now checks dates more thoroughly.
|
||||
*
|
||||
* Revision 5.0 1990/08/22 08:12:53 eggert
|
||||
* Retrieve old log message if there is one.
|
||||
* Don't require final newline.
|
||||
* Remove compile-time limits; use malloc instead. Tune.
|
||||
* Permit dates past 1999/12/31. Ansify and Posixate.
|
||||
*
|
||||
* Revision 4.6 89/05/01 15:12:56 narten
|
||||
* changed copyright header to reflect current distribution rules
|
||||
*
|
||||
* Revision 4.5 88/08/09 19:13:03 eggert
|
||||
* Remove lint and speed up by making FILE *fp local, not global.
|
||||
*
|
||||
* Revision 4.4 87/12/18 11:44:21 narten
|
||||
* more lint cleanups (Guy Harris)
|
||||
*
|
||||
* Revision 4.3 87/10/18 10:35:50 narten
|
||||
* Updating version numbers. Changes relative to 1.1 actually relative
|
||||
* to 4.1
|
||||
*
|
||||
* Revision 1.3 87/09/24 14:00:00 narten
|
||||
* Sources now pass through lint (if you ignore printf/sprintf/fprintf
|
||||
* warnings)
|
||||
*
|
||||
* Revision 1.2 87/03/27 14:22:29 jenkins
|
||||
* Port to suns
|
||||
*
|
||||
* Revision 4.1 83/05/10 16:26:44 wft
|
||||
* Added new markers Id and RCSfile; extraction added.
|
||||
* Marker matching with trymatch().
|
||||
*
|
||||
* Revision 3.2 82/12/24 12:08:26 wft
|
||||
* added missing #endif.
|
||||
*
|
||||
* Revision 3.1 82/12/04 13:22:41 wft
|
||||
* Initial revision.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
#define KEEPTEST
|
||||
*/
|
||||
/* Testprogram; prints out the keyword values found. */
|
||||
|
||||
#include "rcsbase.h"
|
||||
|
||||
libId(keepId, "$Id: rcskeep.c,v 5.4 1991/08/19 03:13:55 eggert Exp $")
|
||||
|
||||
static int checknum P((char const*,int));
|
||||
static int getval P((RILE*,struct buf*,int));
|
||||
static int get0val P((int,RILE*,struct buf*,int));
|
||||
static int keepdate P((RILE*));
|
||||
static int keepid P((int,RILE*,struct buf*));
|
||||
static int keeprev P((RILE*));
|
||||
|
||||
int prevkeys;
|
||||
struct buf prevauthor, prevdate, prevrev, prevstate;
|
||||
|
||||
int
|
||||
getoldkeys(fp)
|
||||
register RILE *fp;
|
||||
/* Function: Tries to read keyword values for author, date,
|
||||
* revision number, and state out of the file fp.
|
||||
* If FNAME is nonnull, it is opened and closed instead of using FP.
|
||||
* The results are placed into
|
||||
* prevauthor, prevdate, prevrev, prevstate.
|
||||
* Aborts immediately if it finds an error and returns false.
|
||||
* If it returns true, it doesn't mean that any of the
|
||||
* values were found; instead, check to see whether the corresponding arrays
|
||||
* contain the empty string.
|
||||
*/
|
||||
{
|
||||
register int c;
|
||||
char keyword[keylength+1];
|
||||
register char * tp;
|
||||
int needs_closing;
|
||||
|
||||
if (prevkeys)
|
||||
return true;
|
||||
|
||||
needs_closing = false;
|
||||
if (!fp) {
|
||||
if (!(fp = Iopen(workfilename, FOPEN_R_WORK, (struct stat*)0))) {
|
||||
eerror(workfilename);
|
||||
return false;
|
||||
}
|
||||
needs_closing = true;
|
||||
}
|
||||
|
||||
/* initialize to empty */
|
||||
bufscpy(&prevauthor, "");
|
||||
bufscpy(&prevdate, "");
|
||||
bufscpy(&prevrev, "");
|
||||
bufscpy(&prevstate, "");
|
||||
|
||||
c = '\0'; /* anything but KDELIM */
|
||||
for (;;) {
|
||||
if ( c==KDELIM) {
|
||||
do {
|
||||
/* try to get keyword */
|
||||
tp = keyword;
|
||||
for (;;) {
|
||||
Igeteof(fp, c, goto ok;);
|
||||
switch (c) {
|
||||
default:
|
||||
if (keyword+keylength <= tp)
|
||||
break;
|
||||
*tp++ = c;
|
||||
continue;
|
||||
|
||||
case '\n': case KDELIM: case VDELIM:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while (c==KDELIM);
|
||||
if (c!=VDELIM) continue;
|
||||
*tp = c;
|
||||
Igeteof(fp, c, break;);
|
||||
switch (c) {
|
||||
case ' ': case '\t': break;
|
||||
default: continue;
|
||||
}
|
||||
|
||||
switch (trymatch(keyword)) {
|
||||
case Author:
|
||||
if (!keepid(0, fp, &prevauthor))
|
||||
return false;
|
||||
c = 0;
|
||||
break;
|
||||
case Date:
|
||||
if (!(c = keepdate(fp)))
|
||||
return false;
|
||||
break;
|
||||
case Header:
|
||||
case Id:
|
||||
if (!(
|
||||
getval(fp, (struct buf*)nil, false) &&
|
||||
keeprev(fp) &&
|
||||
(c = keepdate(fp)) &&
|
||||
keepid(c, fp, &prevauthor) &&
|
||||
keepid(0, fp, &prevstate)
|
||||
))
|
||||
return false;
|
||||
/* Skip either ``who'' (new form) or ``Locker: who'' (old). */
|
||||
if (getval(fp, (struct buf*)nil, true) &&
|
||||
getval(fp, (struct buf*)nil, true))
|
||||
c = 0;
|
||||
else if (nerror)
|
||||
return false;
|
||||
else
|
||||
c = KDELIM;
|
||||
break;
|
||||
case Locker:
|
||||
case Log:
|
||||
case RCSfile:
|
||||
case Source:
|
||||
if (!getval(fp, (struct buf*)nil, false))
|
||||
return false;
|
||||
c = 0;
|
||||
break;
|
||||
case Revision:
|
||||
if (!keeprev(fp))
|
||||
return false;
|
||||
c = 0;
|
||||
break;
|
||||
case State:
|
||||
if (!keepid(0, fp, &prevstate))
|
||||
return false;
|
||||
c = 0;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
if (!c)
|
||||
Igeteof(fp, c, c=0;);
|
||||
if (c != KDELIM) {
|
||||
error("closing %c missing on keyword", KDELIM);
|
||||
return false;
|
||||
}
|
||||
if (*prevauthor.string && *prevdate.string && *prevrev.string && *prevstate.string) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Igeteof(fp, c, break;);
|
||||
}
|
||||
|
||||
ok:
|
||||
if (needs_closing)
|
||||
Ifclose(fp);
|
||||
else
|
||||
Irewind(fp);
|
||||
prevkeys = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
badly_terminated()
|
||||
{
|
||||
error("badly terminated keyword value");
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
getval(fp, target, optional)
|
||||
register RILE *fp;
|
||||
struct buf *target;
|
||||
int optional;
|
||||
/* Reads a keyword value from FP into TARGET.
|
||||
* Returns true if one is found, false otherwise.
|
||||
* Does not modify target if it is nil.
|
||||
* Do not report an error if OPTIONAL is set and KDELIM is found instead.
|
||||
*/
|
||||
{
|
||||
int c;
|
||||
Igeteof(fp, c, return badly_terminated(););
|
||||
return get0val(c, fp, target, optional);
|
||||
}
|
||||
|
||||
static int
|
||||
get0val(c, fp, target, optional)
|
||||
register int c;
|
||||
register RILE *fp;
|
||||
struct buf *target;
|
||||
int optional;
|
||||
/* Reads a keyword value from C+FP into TARGET, perhaps OPTIONALly.
|
||||
* Same as getval, except C is the lookahead character.
|
||||
*/
|
||||
{ register char * tp;
|
||||
char const *tlim;
|
||||
register int got1;
|
||||
|
||||
if (target) {
|
||||
bufalloc(target, 1);
|
||||
tp = target->string;
|
||||
tlim = tp + target->size;
|
||||
} else
|
||||
tlim = tp = 0;
|
||||
got1 = false;
|
||||
for (;;) {
|
||||
switch (c) {
|
||||
default:
|
||||
got1 = true;
|
||||
if (tp) {
|
||||
*tp++ = c;
|
||||
if (tlim <= tp)
|
||||
tp = bufenlarge(target, &tlim);
|
||||
}
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
if (tp) {
|
||||
*tp = 0;
|
||||
# ifdef KEEPTEST
|
||||
VOID printf("getval: %s\n", target);
|
||||
# endif
|
||||
}
|
||||
if (!got1)
|
||||
error("too much white space in keyword value");
|
||||
return got1;
|
||||
|
||||
case KDELIM:
|
||||
if (!got1 && optional)
|
||||
return false;
|
||||
/* fall into */
|
||||
case '\n':
|
||||
case 0:
|
||||
return badly_terminated();
|
||||
}
|
||||
Igeteof(fp, c, return badly_terminated(););
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
keepdate(fp)
|
||||
RILE *fp;
|
||||
/* Function: reads a date prevdate; checks format
|
||||
* Return 0 on error, lookahead character otherwise.
|
||||
*/
|
||||
{
|
||||
struct buf prevday, prevtime, prevzone;
|
||||
register char const *p;
|
||||
register int c;
|
||||
|
||||
c = 0;
|
||||
bufautobegin(&prevday);
|
||||
if (getval(fp,&prevday,false)) {
|
||||
bufautobegin(&prevtime);
|
||||
if (getval(fp,&prevtime,false)) {
|
||||
bufautobegin(&prevzone);
|
||||
bufscpy(&prevzone, "");
|
||||
Igeteof(fp, c, c=0;);
|
||||
if (c=='-' || c=='+')
|
||||
if (!get0val(c,fp,&prevzone,false))
|
||||
c = 0;
|
||||
else
|
||||
Igeteof(fp, c, c=0;);
|
||||
if (c) {
|
||||
p = prevday.string;
|
||||
bufalloc(&prevdate, strlen(p) + strlen(prevtime.string) + strlen(prevzone.string) + 5);
|
||||
VOID sprintf(prevdate.string, "%s%s %s %s",
|
||||
/* Parse dates put out by old versions of RCS. */
|
||||
isdigit(p[0]) && isdigit(p[1]) && p[2]=='/' ? "19" : "",
|
||||
p, prevtime.string, prevzone.string
|
||||
);
|
||||
}
|
||||
bufautoend(&prevzone);
|
||||
}
|
||||
bufautoend(&prevtime);
|
||||
}
|
||||
bufautoend(&prevday);
|
||||
return c;
|
||||
}
|
||||
|
||||
static int
|
||||
keepid(c, fp, b)
|
||||
int c;
|
||||
RILE *fp;
|
||||
struct buf *b;
|
||||
/* Get previous identifier from C+FP into B. */
|
||||
{
|
||||
if (!c)
|
||||
Igeteof(fp, c, return false;);
|
||||
if (!get0val(c, fp, b, false))
|
||||
return false;
|
||||
checksid(b->string);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
keeprev(fp)
|
||||
RILE *fp;
|
||||
/* Get previous revision from FP into prevrev. */
|
||||
{
|
||||
return getval(fp,&prevrev,false) && checknum(prevrev.string,-1);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
checknum(sp,fields)
|
||||
register char const *sp;
|
||||
int fields;
|
||||
{ register int dotcount;
|
||||
dotcount=0;
|
||||
while(*sp) {
|
||||
if (*sp=='.') dotcount++;
|
||||
else if (!isdigit(*sp)) return false;
|
||||
sp++;
|
||||
}
|
||||
return fields<0 ? dotcount&1 : dotcount==fields;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef KEEPTEST
|
||||
|
||||
char const cmdid[] ="keeptest";
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc; char *argv[];
|
||||
{
|
||||
while (*(++argv)) {
|
||||
workfilename = *argv;
|
||||
getoldkeys((RILE*)0);
|
||||
VOID printf("%s: revision: %s, date: %s, author: %s, state: %s\n",
|
||||
*argv, prevrev.string, prevdate.string, prevauthor.string, prevstate.string);
|
||||
}
|
||||
exitmain(EXIT_SUCCESS);
|
||||
}
|
||||
#endif
|
||||
102
gnu/usr.bin/rcs/lib/rcskeys.c
Normal file
102
gnu/usr.bin/rcs/lib/rcskeys.c
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* RCS keyword table and match operation
|
||||
*/
|
||||
|
||||
/* Copyright (C) 1982, 1988, 1989 Walter Tichy
|
||||
Copyright 1990, 1991 by 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, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Report problems and direct all questions to:
|
||||
|
||||
rcs-bugs@cs.purdue.edu
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* $Log: rcskeys.c,v $
|
||||
* Revision 5.2 1991/08/19 03:13:55 eggert
|
||||
* Say `T const' instead of `const T'; it's less confusing for pointer types.
|
||||
* (This change was made in other source files too.)
|
||||
*
|
||||
* Revision 5.1 1991/04/21 11:58:25 eggert
|
||||
* Don't put , just before } in initializer.
|
||||
*
|
||||
* Revision 5.0 1990/08/22 08:12:54 eggert
|
||||
* Add -k. Ansify and Posixate.
|
||||
*
|
||||
* Revision 4.3 89/05/01 15:13:02 narten
|
||||
* changed copyright header to reflect current distribution rules
|
||||
*
|
||||
* Revision 4.2 87/10/18 10:36:33 narten
|
||||
* Updating version numbers. Changes relative to 1.1 actuallyt
|
||||
* relative to 4.1
|
||||
*
|
||||
* Revision 1.2 87/09/24 14:00:10 narten
|
||||
* Sources now pass through lint (if you ignore printf/sprintf/fprintf
|
||||
* warnings)
|
||||
*
|
||||
* Revision 4.1 83/05/04 10:06:53 wft
|
||||
* Initial revision.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "rcsbase.h"
|
||||
|
||||
libId(keysId, "$Id: rcskeys.c,v 5.2 1991/08/19 03:13:55 eggert Exp $")
|
||||
|
||||
|
||||
char const *const Keyword[] = {
|
||||
/* This must be in the same order as rcsbase.h's enum markers type. */
|
||||
nil,
|
||||
AUTHOR, DATE, HEADER, IDH,
|
||||
LOCKER, LOG, RCSFILE, REVISION, SOURCE, STATE
|
||||
};
|
||||
|
||||
|
||||
|
||||
enum markers
|
||||
trymatch(string)
|
||||
char const *string;
|
||||
/* function: Checks whether string starts with a keyword followed
|
||||
* by a KDELIM or a VDELIM.
|
||||
* If successful, returns the appropriate marker, otherwise Nomatch.
|
||||
*/
|
||||
{
|
||||
register int j;
|
||||
register char const *p, *s;
|
||||
for (j = sizeof(Keyword)/sizeof(*Keyword); (--j); ) {
|
||||
/* try next keyword */
|
||||
p = Keyword[j];
|
||||
s = string;
|
||||
while (*p++ == *s++) {
|
||||
if (!*p)
|
||||
switch (*s) {
|
||||
case KDELIM:
|
||||
case VDELIM:
|
||||
return (enum markers)j;
|
||||
default:
|
||||
return Nomatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(Nomatch);
|
||||
}
|
||||
|
||||
1241
gnu/usr.bin/rcs/lib/rcslex.c
Normal file
1241
gnu/usr.bin/rcs/lib/rcslex.c
Normal file
File diff suppressed because it is too large
Load diff
68
gnu/usr.bin/rcs/lib/rcsmap.c
Normal file
68
gnu/usr.bin/rcs/lib/rcsmap.c
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/* RCS map of character types */
|
||||
|
||||
/* Copyright (C) 1982, 1988, 1989 Walter Tichy
|
||||
Copyright 1990, 1991 by 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, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Report problems and direct all questions to:
|
||||
|
||||
rcs-bugs@cs.purdue.edu
|
||||
|
||||
*/
|
||||
|
||||
#include "rcsbase.h"
|
||||
|
||||
libId(mapId, "$Id: rcsmap.c,v 5.2 1991/08/19 03:13:55 eggert Exp $")
|
||||
|
||||
/* map of character types */
|
||||
/* ISO 8859/1 (Latin-1) */
|
||||
enum tokens const ctab[] = {
|
||||
UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN,
|
||||
SPACE, SPACE, NEWLN, SPACE, SPACE, SPACE, UNKN, UNKN,
|
||||
UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN,
|
||||
UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN,
|
||||
SPACE, IDCHAR, IDCHAR, IDCHAR, DELIM, IDCHAR, IDCHAR, IDCHAR,
|
||||
IDCHAR, IDCHAR, IDCHAR, IDCHAR, DELIM, IDCHAR, PERIOD, IDCHAR,
|
||||
DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT,
|
||||
DIGIT, DIGIT, COLON, SEMI, IDCHAR, IDCHAR, IDCHAR, IDCHAR,
|
||||
SBEGIN, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
|
||||
LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
|
||||
LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
|
||||
LETTER, LETTER, LETTER, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR,
|
||||
IDCHAR, Letter, Letter, Letter, Letter, Letter, Letter, Letter,
|
||||
Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter,
|
||||
Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter,
|
||||
Letter, Letter, Letter, IDCHAR, IDCHAR, IDCHAR, IDCHAR, UNKN,
|
||||
UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN,
|
||||
UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN,
|
||||
UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN,
|
||||
UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN,
|
||||
IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR,
|
||||
IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR,
|
||||
IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR,
|
||||
IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR,
|
||||
LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
|
||||
LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
|
||||
LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, IDCHAR,
|
||||
LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, Letter,
|
||||
Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter,
|
||||
Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter,
|
||||
Letter, Letter, Letter, Letter, Letter, Letter, Letter, IDCHAR,
|
||||
Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter
|
||||
};
|
||||
790
gnu/usr.bin/rcs/lib/rcsrev.c
Normal file
790
gnu/usr.bin/rcs/lib/rcsrev.c
Normal file
|
|
@ -0,0 +1,790 @@
|
|||
/*
|
||||
* RCS revision number handling
|
||||
*/
|
||||
|
||||
/* Copyright (C) 1982, 1988, 1989 Walter Tichy
|
||||
Copyright 1990, 1991 by 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, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Report problems and direct all questions to:
|
||||
|
||||
rcs-bugs@cs.purdue.edu
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* $Log: rcsrev.c,v $
|
||||
* Revision 5.3 1991/08/19 03:13:55 eggert
|
||||
* Add `-r$', `-rB.'. Remove botches like `<now>' from messages. Tune.
|
||||
*
|
||||
* Revision 5.2 1991/04/21 11:58:28 eggert
|
||||
* Add tiprev().
|
||||
*
|
||||
* Revision 5.1 1991/02/25 07:12:43 eggert
|
||||
* Avoid overflow when comparing revision numbers.
|
||||
*
|
||||
* Revision 5.0 1990/08/22 08:13:43 eggert
|
||||
* Remove compile-time limits; use malloc instead.
|
||||
* Ansify and Posixate. Tune.
|
||||
* Remove possibility of an internal error. Remove lint.
|
||||
*
|
||||
* Revision 4.5 89/05/01 15:13:22 narten
|
||||
* changed copyright header to reflect current distribution rules
|
||||
*
|
||||
* Revision 4.4 87/12/18 11:45:22 narten
|
||||
* more lint cleanups. Also, the NOTREACHED comment is no longer necessary,
|
||||
* since there's now a return value there with a value. (Guy Harris)
|
||||
*
|
||||
* Revision 4.3 87/10/18 10:38:42 narten
|
||||
* Updating version numbers. Changes relative to version 1.1 actually
|
||||
* relative to 4.1
|
||||
*
|
||||
* Revision 1.3 87/09/24 14:00:37 narten
|
||||
* Sources now pass through lint (if you ignore printf/sprintf/fprintf
|
||||
* warnings)
|
||||
*
|
||||
* Revision 1.2 87/03/27 14:22:37 jenkins
|
||||
* Port to suns
|
||||
*
|
||||
* Revision 4.1 83/03/25 21:10:45 wft
|
||||
* Only changed $Header to $Id.
|
||||
*
|
||||
* Revision 3.4 82/12/04 13:24:08 wft
|
||||
* Replaced getdelta() with gettree().
|
||||
*
|
||||
* Revision 3.3 82/11/28 21:33:15 wft
|
||||
* fixed compartial() and compnum() for nil-parameters; fixed nils
|
||||
* in error messages. Testprogram output shortenend.
|
||||
*
|
||||
* Revision 3.2 82/10/18 21:19:47 wft
|
||||
* renamed compnum->cmpnum, compnumfld->cmpnumfld,
|
||||
* numericrevno->numricrevno.
|
||||
*
|
||||
* Revision 3.1 82/10/11 19:46:09 wft
|
||||
* changed expandsym() to check for source==nil; returns zero length string
|
||||
* in that case.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
#define REVTEST
|
||||
*/
|
||||
/* version REVTEST is for testing the routines that generate a sequence
|
||||
* of delta numbers needed to regenerate a given delta.
|
||||
*/
|
||||
|
||||
#include "rcsbase.h"
|
||||
|
||||
libId(revId, "$Id: rcsrev.c,v 5.3 1991/08/19 03:13:55 eggert Exp $")
|
||||
|
||||
static char const *branchtip P((char const*));
|
||||
static struct hshentry *genbranch P((struct hshentry const*,char const*,unsigned,char const*,char const*,char const*,struct hshentries**));
|
||||
|
||||
|
||||
|
||||
unsigned
|
||||
countnumflds(s)
|
||||
char const *s;
|
||||
/* Given a pointer s to a dotted number (date or revision number),
|
||||
* countnumflds returns the number of digitfields in s.
|
||||
*/
|
||||
{
|
||||
register char const *sp;
|
||||
register unsigned count;
|
||||
if ((sp=s)==nil) return(0);
|
||||
if (*sp == '\0') return(0);
|
||||
count = 1;
|
||||
do {
|
||||
if (*sp++ == '.') count++;
|
||||
} while (*sp);
|
||||
return(count);
|
||||
}
|
||||
|
||||
void
|
||||
getbranchno(revno,branchno)
|
||||
char const *revno;
|
||||
struct buf *branchno;
|
||||
/* Given a non-nil revision number revno, getbranchno copies the number of the branch
|
||||
* on which revno is into branchno. If revno itself is a branch number,
|
||||
* it is copied unchanged.
|
||||
*/
|
||||
{
|
||||
register unsigned numflds;
|
||||
register char *tp;
|
||||
|
||||
bufscpy(branchno, revno);
|
||||
numflds=countnumflds(revno);
|
||||
if (!(numflds & 1)) {
|
||||
tp = branchno->string;
|
||||
while (--numflds)
|
||||
while (*tp++ != '.')
|
||||
;
|
||||
*(tp-1)='\0';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int cmpnum(num1, num2)
|
||||
char const *num1, *num2;
|
||||
/* compares the two dotted numbers num1 and num2 lexicographically
|
||||
* by field. Individual fields are compared numerically.
|
||||
* returns <0, 0, >0 if num1<num2, num1==num2, and num1>num2, resp.
|
||||
* omitted fields are assumed to be higher than the existing ones.
|
||||
*/
|
||||
{
|
||||
register char const *s1, *s2;
|
||||
register size_t d1, d2;
|
||||
register int r;
|
||||
|
||||
s1=num1==nil?"":num1;
|
||||
s2=num2==nil?"":num2;
|
||||
|
||||
for (;;) {
|
||||
/* Give precedence to shorter one. */
|
||||
if (!*s1)
|
||||
return (unsigned char)*s2;
|
||||
if (!*s2)
|
||||
return -1;
|
||||
|
||||
/* Strip leading zeros, then find number of digits. */
|
||||
while (*s1=='0') ++s1; for (d1=0; isdigit(s1[d1]); d1++) ;
|
||||
while (*s2=='0') ++s2; for (d2=0; isdigit(s2[d2]); d2++) ;
|
||||
|
||||
/* Do not convert to integer; it might overflow! */
|
||||
if (d1 != d2)
|
||||
return d1<d2 ? -1 : 1;
|
||||
if ((r = memcmp(s1, s2, d1)))
|
||||
return r;
|
||||
s1 += d1;
|
||||
s2 += d1;
|
||||
|
||||
/* skip '.' */
|
||||
if (*s1) s1++;
|
||||
if (*s2) s2++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int cmpnumfld(num1, num2, fld)
|
||||
char const *num1, *num2;
|
||||
unsigned fld;
|
||||
/* Compare the two dotted numbers at field fld.
|
||||
* num1 and num2 must have at least fld fields.
|
||||
* fld must be positive.
|
||||
*/
|
||||
{
|
||||
register char const *s1, *s2;
|
||||
register size_t d1, d2;
|
||||
|
||||
s1 = num1;
|
||||
s2 = num2;
|
||||
/* skip fld-1 fields */
|
||||
while (--fld) {
|
||||
while (*s1++ != '.')
|
||||
;
|
||||
while (*s2++ != '.')
|
||||
;
|
||||
}
|
||||
/* Now s1 and s2 point to the beginning of the respective fields */
|
||||
while (*s1=='0') ++s1; for (d1=0; isdigit(s1[d1]); d1++) ;
|
||||
while (*s2=='0') ++s2; for (d2=0; isdigit(s2[d2]); d2++) ;
|
||||
|
||||
return d1<d2 ? -1 : d1==d2 ? memcmp(s1,s2,d1) : 1;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cantfindbranch(revno, date, author, state)
|
||||
char const *revno, date[datesize], *author, *state;
|
||||
{
|
||||
char datebuf[datesize];
|
||||
|
||||
error("No revision on branch %s has%s%s%s%s%s%s.",
|
||||
revno,
|
||||
date ? " a date before " : "",
|
||||
date ? date2str(date,datebuf) : "",
|
||||
author ? " and author "+(date?0:4) : "",
|
||||
author ? author : "",
|
||||
state ? " and state "+(date||author?0:4) : "",
|
||||
state ? state : ""
|
||||
);
|
||||
}
|
||||
|
||||
static void
|
||||
absent(revno, field)
|
||||
char const *revno;
|
||||
unsigned field;
|
||||
{
|
||||
struct buf t;
|
||||
bufautobegin(&t);
|
||||
error("%s %s absent", field&1?"revision":"branch",
|
||||
partialno(&t,revno,field)
|
||||
);
|
||||
bufautoend(&t);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
compartial(num1, num2, length)
|
||||
char const *num1, *num2;
|
||||
unsigned length;
|
||||
|
||||
/* compare the first "length" fields of two dot numbers;
|
||||
the omitted field is considered to be larger than any number */
|
||||
/* restriction: at least one number has length or more fields */
|
||||
|
||||
{
|
||||
register char const *s1, *s2;
|
||||
register size_t d1, d2;
|
||||
register int r;
|
||||
|
||||
s1 = num1; s2 = num2;
|
||||
if (!s1) return 1;
|
||||
if (!s2) return -1;
|
||||
|
||||
for (;;) {
|
||||
if (!*s1) return 1;
|
||||
if (!*s2) return -1;
|
||||
|
||||
while (*s1=='0') ++s1; for (d1=0; isdigit(s1[d1]); d1++) ;
|
||||
while (*s2=='0') ++s2; for (d2=0; isdigit(s2[d2]); d2++) ;
|
||||
|
||||
if (d1 != d2)
|
||||
return d1<d2 ? -1 : 1;
|
||||
if ((r = memcmp(s1, s2, d1)))
|
||||
return r;
|
||||
s1 += d1;
|
||||
s2 += d1;
|
||||
|
||||
if (*s1 == '.') s1++;
|
||||
if (*s2 == '.') s2++;
|
||||
|
||||
if ( --length == 0 ) return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char * partialno(rev1,rev2,length)
|
||||
struct buf *rev1;
|
||||
char const *rev2;
|
||||
register unsigned length;
|
||||
/* Function: Copies length fields of revision number rev2 into rev1.
|
||||
* Return rev1's string.
|
||||
*/
|
||||
{
|
||||
register char *r1;
|
||||
|
||||
bufscpy(rev1, rev2);
|
||||
r1 = rev1->string;
|
||||
while (length) {
|
||||
while (*r1!='.' && *r1)
|
||||
++r1;
|
||||
++r1;
|
||||
length--;
|
||||
}
|
||||
/* eliminate last '.'*/
|
||||
*(r1-1)='\0';
|
||||
return rev1->string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static void
|
||||
store1(store, next)
|
||||
struct hshentries ***store;
|
||||
struct hshentry *next;
|
||||
/*
|
||||
* Allocate a new list node that addresses NEXT.
|
||||
* Append it to the list that **STORE is the end pointer of.
|
||||
*/
|
||||
{
|
||||
register struct hshentries *p;
|
||||
|
||||
p = ftalloc(struct hshentries);
|
||||
p->first = next;
|
||||
**store = p;
|
||||
*store = &p->rest;
|
||||
}
|
||||
|
||||
struct hshentry * genrevs(revno,date,author,state,store)
|
||||
char const *revno, *date, *author, *state;
|
||||
struct hshentries **store;
|
||||
/* Function: finds the deltas needed for reconstructing the
|
||||
* revision given by revno, date, author, and state, and stores pointers
|
||||
* to these deltas into a list whose starting address is given by store.
|
||||
* The last delta (target delta) is returned.
|
||||
* If the proper delta could not be found, nil is returned.
|
||||
*/
|
||||
{
|
||||
unsigned length;
|
||||
register struct hshentry * next;
|
||||
int result;
|
||||
char const *branchnum;
|
||||
struct buf t;
|
||||
char datebuf[datesize];
|
||||
|
||||
bufautobegin(&t);
|
||||
|
||||
if (!(next = Head)) {
|
||||
error("RCS file empty");
|
||||
goto norev;
|
||||
}
|
||||
|
||||
length = countnumflds(revno);
|
||||
|
||||
if (length >= 1) {
|
||||
/* at least one field; find branch exactly */
|
||||
while ((result=cmpnumfld(revno,next->num,1)) < 0) {
|
||||
store1(&store, next);
|
||||
next = next->next;
|
||||
if (!next) {
|
||||
error("branch number %s too low", partialno(&t,revno,1));
|
||||
goto norev;
|
||||
}
|
||||
}
|
||||
|
||||
if (result>0) {
|
||||
absent(revno, 1);
|
||||
goto norev;
|
||||
}
|
||||
}
|
||||
if (length<=1){
|
||||
/* pick latest one on given branch */
|
||||
branchnum = next->num; /* works even for empty revno*/
|
||||
while ((next!=nil) &&
|
||||
(cmpnumfld(branchnum,next->num,1)==0) &&
|
||||
!(
|
||||
(date==nil?1:(cmpnum(date,next->date)>=0)) &&
|
||||
(author==nil?1:(strcmp(author,next->author)==0)) &&
|
||||
(state ==nil?1:(strcmp(state, next->state) ==0))
|
||||
)
|
||||
)
|
||||
{
|
||||
store1(&store, next);
|
||||
next=next->next;
|
||||
}
|
||||
if ((next==nil) ||
|
||||
(cmpnumfld(branchnum,next->num,1)!=0))/*overshot*/ {
|
||||
cantfindbranch(
|
||||
length ? revno : partialno(&t,branchnum,1),
|
||||
date, author, state
|
||||
);
|
||||
goto norev;
|
||||
} else {
|
||||
store1(&store, next);
|
||||
}
|
||||
*store = nil;
|
||||
return next;
|
||||
}
|
||||
|
||||
/* length >=2 */
|
||||
/* find revision; may go low if length==2*/
|
||||
while ((result=cmpnumfld(revno,next->num,2)) < 0 &&
|
||||
(cmpnumfld(revno,next->num,1)==0) ) {
|
||||
store1(&store, next);
|
||||
next = next->next;
|
||||
if (!next)
|
||||
break;
|
||||
}
|
||||
|
||||
if ((next==nil) || (cmpnumfld(revno,next->num,1)!=0)) {
|
||||
error("revision number %s too low", partialno(&t,revno,2));
|
||||
goto norev;
|
||||
}
|
||||
if ((length>2) && (result!=0)) {
|
||||
absent(revno, 2);
|
||||
goto norev;
|
||||
}
|
||||
|
||||
/* print last one */
|
||||
store1(&store, next);
|
||||
|
||||
if (length>2)
|
||||
return genbranch(next,revno,length,date,author,state,store);
|
||||
else { /* length == 2*/
|
||||
if ((date!=nil) && (cmpnum(date,next->date)<0)){
|
||||
error("Revision %s has date %s.",
|
||||
next->num,
|
||||
date2str(next->date, datebuf)
|
||||
);
|
||||
return nil;
|
||||
}
|
||||
if ((author!=nil)&&(strcmp(author,next->author)!=0)) {
|
||||
error("Revision %s has author %s.",next->num,next->author);
|
||||
return nil;
|
||||
}
|
||||
if ((state!=nil)&&(strcmp(state,next->state)!=0)) {
|
||||
error("Revision %s has state %s.",next->num,
|
||||
next->state==nil?"<empty>":next->state);
|
||||
return nil;
|
||||
}
|
||||
*store=nil;
|
||||
return next;
|
||||
}
|
||||
|
||||
norev:
|
||||
bufautoend(&t);
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static struct hshentry *
|
||||
genbranch(bpoint, revno, length, date, author, state, store)
|
||||
struct hshentry const *bpoint;
|
||||
char const *revno;
|
||||
unsigned length;
|
||||
char const *date, *author, *state;
|
||||
struct hshentries **store;
|
||||
/* Function: given a branchpoint, a revision number, date, author, and state,
|
||||
* genbranch finds the deltas necessary to reconstruct the given revision
|
||||
* from the branch point on.
|
||||
* Pointers to the found deltas are stored in a list beginning with store.
|
||||
* revno must be on a side branch.
|
||||
* return nil on error
|
||||
*/
|
||||
{
|
||||
unsigned field;
|
||||
register struct hshentry * next, * trail;
|
||||
register struct branchhead const *bhead;
|
||||
int result;
|
||||
struct buf t;
|
||||
char datebuf[datesize];
|
||||
|
||||
field = 3;
|
||||
bhead = bpoint->branches;
|
||||
|
||||
do {
|
||||
if (!bhead) {
|
||||
bufautobegin(&t);
|
||||
error("no side branches present for %s", partialno(&t,revno,field-1));
|
||||
bufautoend(&t);
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*find branch head*/
|
||||
/*branches are arranged in increasing order*/
|
||||
while (0 < (result=cmpnumfld(revno,bhead->hsh->num,field))) {
|
||||
bhead = bhead->nextbranch;
|
||||
if (!bhead) {
|
||||
bufautobegin(&t);
|
||||
error("branch number %s too high",partialno(&t,revno,field));
|
||||
bufautoend(&t);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
if (result<0) {
|
||||
absent(revno, field);
|
||||
return nil;
|
||||
}
|
||||
|
||||
next = bhead->hsh;
|
||||
if (length==field) {
|
||||
/* pick latest one on that branch */
|
||||
trail=nil;
|
||||
do { if ((date==nil?1:(cmpnum(date,next->date)>=0)) &&
|
||||
(author==nil?1:(strcmp(author,next->author)==0)) &&
|
||||
(state ==nil?1:(strcmp(state, next->state) ==0))
|
||||
) trail = next;
|
||||
next=next->next;
|
||||
} while (next!=nil);
|
||||
|
||||
if (trail==nil) {
|
||||
cantfindbranch(revno, date, author, state);
|
||||
return nil;
|
||||
} else { /* print up to last one suitable */
|
||||
next = bhead->hsh;
|
||||
while (next!=trail) {
|
||||
store1(&store, next);
|
||||
next=next->next;
|
||||
}
|
||||
store1(&store, next);
|
||||
}
|
||||
*store = nil;
|
||||
return next;
|
||||
}
|
||||
|
||||
/* length > field */
|
||||
/* find revision */
|
||||
/* check low */
|
||||
if (cmpnumfld(revno,next->num,field+1)<0) {
|
||||
bufautobegin(&t);
|
||||
error("revision number %s too low", partialno(&t,revno,field+1));
|
||||
bufautoend(&t);
|
||||
return(nil);
|
||||
}
|
||||
do {
|
||||
store1(&store, next);
|
||||
trail = next;
|
||||
next = next->next;
|
||||
} while ((next!=nil) &&
|
||||
(cmpnumfld(revno,next->num,field+1) >=0));
|
||||
|
||||
if ((length>field+1) && /*need exact hit */
|
||||
(cmpnumfld(revno,trail->num,field+1) !=0)){
|
||||
absent(revno, field+1);
|
||||
return(nil);
|
||||
}
|
||||
if (length == field+1) {
|
||||
if ((date!=nil) && (cmpnum(date,trail->date)<0)){
|
||||
error("Revision %s has date %s.",
|
||||
trail->num,
|
||||
date2str(trail->date, datebuf)
|
||||
);
|
||||
return nil;
|
||||
}
|
||||
if ((author!=nil)&&(strcmp(author,trail->author)!=0)) {
|
||||
error("Revision %s has author %s.",trail->num,trail->author);
|
||||
return nil;
|
||||
}
|
||||
if ((state!=nil)&&(strcmp(state,trail->state)!=0)) {
|
||||
error("Revision %s has state %s.",trail->num,
|
||||
trail->state==nil?"<empty>":trail->state);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
bhead = trail->branches;
|
||||
|
||||
} while ((field+=2) <= length);
|
||||
* store = nil;
|
||||
return trail;
|
||||
}
|
||||
|
||||
|
||||
static char const *
|
||||
lookupsym(id)
|
||||
char const *id;
|
||||
/* Function: looks up id in the list of symbolic names starting
|
||||
* with pointer SYMBOLS, and returns a pointer to the corresponding
|
||||
* revision number. Returns nil if not present.
|
||||
*/
|
||||
{
|
||||
register struct assoc const *next;
|
||||
next = Symbols;
|
||||
while (next!=nil) {
|
||||
if (strcmp(id, next->symbol)==0)
|
||||
return next->num;
|
||||
else next=next->nextassoc;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
int expandsym(source, target)
|
||||
char const *source;
|
||||
struct buf *target;
|
||||
/* Function: Source points to a revision number. Expandsym copies
|
||||
* the number to target, but replaces all symbolic fields in the
|
||||
* source number with their numeric values.
|
||||
* Expand a branch followed by `.' to the latest revision on that branch.
|
||||
* Ignore `.' after a revision. Remove leading zeros.
|
||||
* returns false on error;
|
||||
*/
|
||||
{
|
||||
return fexpandsym(source, target, (RILE*)0);
|
||||
}
|
||||
|
||||
int
|
||||
fexpandsym(source, target, fp)
|
||||
char const *source;
|
||||
struct buf *target;
|
||||
RILE *fp;
|
||||
/* Same as expandsym, except if FP is nonzero, it is used to expand KDELIM. */
|
||||
{
|
||||
register char const *sp, *bp;
|
||||
register char *tp;
|
||||
char const *tlim;
|
||||
register enum tokens d;
|
||||
unsigned dots;
|
||||
|
||||
sp = source;
|
||||
bufalloc(target, 1);
|
||||
tp = target->string;
|
||||
if (!sp || !*sp) { /*accept nil pointer as a legal value*/
|
||||
*tp='\0';
|
||||
return true;
|
||||
}
|
||||
if (sp[0] == KDELIM && !sp[1]) {
|
||||
if (!getoldkeys(fp))
|
||||
return false;
|
||||
if (!*prevrev.string) {
|
||||
error("working file lacks revision number");
|
||||
return false;
|
||||
}
|
||||
bufscpy(target, prevrev.string);
|
||||
return true;
|
||||
}
|
||||
tlim = tp + target->size;
|
||||
dots = 0;
|
||||
|
||||
for (;;) {
|
||||
switch (ctab[(unsigned char)*sp]) {
|
||||
case DIGIT:
|
||||
while (*sp=='0' && isdigit(sp[1]))
|
||||
/* skip leading zeroes */
|
||||
sp++;
|
||||
do {
|
||||
if (tlim <= tp)
|
||||
tp = bufenlarge(target, &tlim);
|
||||
} while (isdigit(*tp++ = *sp++));
|
||||
--sp;
|
||||
tp[-1] = '\0';
|
||||
break;
|
||||
|
||||
case LETTER:
|
||||
case Letter:
|
||||
{
|
||||
register char *p = tp;
|
||||
register size_t s = tp - target->string;
|
||||
do {
|
||||
if (tlim <= p)
|
||||
p = bufenlarge(target, &tlim);
|
||||
*p++ = *sp++;
|
||||
} while ((d=ctab[(unsigned char)*sp])==LETTER ||
|
||||
d==Letter || d==DIGIT ||
|
||||
(d==IDCHAR));
|
||||
if (tlim <= p)
|
||||
p = bufenlarge(target, &tlim);
|
||||
*p = 0;
|
||||
tp = target->string + s;
|
||||
}
|
||||
bp = lookupsym(tp);
|
||||
if (bp==nil) {
|
||||
error("Symbolic number %s is undefined.", tp);
|
||||
return false;
|
||||
}
|
||||
do {
|
||||
if (tlim <= tp)
|
||||
tp = bufenlarge(target, &tlim);
|
||||
} while ((*tp++ = *bp++));
|
||||
break;
|
||||
|
||||
default:
|
||||
goto improper;
|
||||
}
|
||||
switch (*sp++) {
|
||||
case '\0': return true;
|
||||
case '.': break;
|
||||
default: goto improper;
|
||||
}
|
||||
if (!*sp) {
|
||||
if (dots & 1)
|
||||
goto improper;
|
||||
if (!(bp = branchtip(target->string)))
|
||||
return false;
|
||||
bufscpy(target, bp);
|
||||
return true;
|
||||
}
|
||||
++dots;
|
||||
tp[-1] = '.';
|
||||
}
|
||||
|
||||
improper:
|
||||
error("improper revision number: %s", source);
|
||||
return false;
|
||||
}
|
||||
|
||||
static char const *
|
||||
branchtip(branch)
|
||||
char const *branch;
|
||||
{
|
||||
struct hshentry *h;
|
||||
struct hshentries *hs;
|
||||
|
||||
h = genrevs(branch, (char*)0, (char*)0, (char*)0, &hs);
|
||||
return h ? h->num : (char const*)0;
|
||||
}
|
||||
|
||||
char const *
|
||||
tiprev()
|
||||
{
|
||||
return Dbranch ? branchtip(Dbranch) : Head ? Head->num : (char const*)0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef REVTEST
|
||||
|
||||
char const cmdid[] = "revtest";
|
||||
|
||||
int
|
||||
main(argc,argv)
|
||||
int argc; char * argv[];
|
||||
{
|
||||
static struct buf numricrevno;
|
||||
char symrevno[100]; /* used for input of revision numbers */
|
||||
char author[20];
|
||||
char state[20];
|
||||
char date[20];
|
||||
struct hshentries *gendeltas;
|
||||
struct hshentry * target;
|
||||
int i;
|
||||
|
||||
if (argc<2) {
|
||||
aputs("No input file\n",stderr);
|
||||
exitmain(EXIT_FAILURE);
|
||||
}
|
||||
if (!(finptr=Iopen(argv[1], FOPEN_R, (struct stat*)0))) {
|
||||
faterror("can't open input file %s", argv[1]);
|
||||
}
|
||||
Lexinit();
|
||||
getadmin();
|
||||
|
||||
gettree();
|
||||
|
||||
getdesc(false);
|
||||
|
||||
do {
|
||||
/* all output goes to stderr, to have diagnostics and */
|
||||
/* errors in sequence. */
|
||||
aputs("\nEnter revision number or <return> or '.': ",stderr);
|
||||
if (!gets(symrevno)) break;
|
||||
if (*symrevno == '.') break;
|
||||
aprintf(stderr,"%s;\n",symrevno);
|
||||
expandsym(symrevno,&numricrevno);
|
||||
aprintf(stderr,"expanded number: %s; ",numricrevno.string);
|
||||
aprintf(stderr,"Date: ");
|
||||
gets(date); aprintf(stderr,"%s; ",date);
|
||||
aprintf(stderr,"Author: ");
|
||||
gets(author); aprintf(stderr,"%s; ",author);
|
||||
aprintf(stderr,"State: ");
|
||||
gets(state); aprintf(stderr, "%s;\n", state);
|
||||
target = genrevs(numricrevno.string, *date?date:(char *)nil, *author?author:(char *)nil,
|
||||
*state?state:(char*)nil, &gendeltas);
|
||||
if (target!=nil) {
|
||||
while (gendeltas) {
|
||||
aprintf(stderr,"%s\n",gendeltas->first->num);
|
||||
gendeltas = gendeltas->next;
|
||||
}
|
||||
}
|
||||
} while (true);
|
||||
aprintf(stderr,"done\n");
|
||||
exitmain(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
exiting void exiterr() { _exit(EXIT_FAILURE); }
|
||||
|
||||
#endif
|
||||
857
gnu/usr.bin/rcs/lib/rcssyn.c
Normal file
857
gnu/usr.bin/rcs/lib/rcssyn.c
Normal file
|
|
@ -0,0 +1,857 @@
|
|||
/*
|
||||
* RCS file input
|
||||
*/
|
||||
/*********************************************************************************
|
||||
* Syntax Analysis.
|
||||
* Keyword table
|
||||
* Testprogram: define SYNTEST
|
||||
* Compatibility with Release 2: define COMPAT2=1
|
||||
*********************************************************************************
|
||||
*/
|
||||
|
||||
/* Copyright (C) 1982, 1988, 1989 Walter Tichy
|
||||
Copyright 1990, 1991 by 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, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Report problems and direct all questions to:
|
||||
|
||||
rcs-bugs@cs.purdue.edu
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* $Log: rcssyn.c,v $
|
||||
* Revision 5.8 1991/08/19 03:13:55 eggert
|
||||
* Tune.
|
||||
*
|
||||
* Revision 5.7 1991/04/21 11:58:29 eggert
|
||||
* Disambiguate names on shortname hosts.
|
||||
* Fix errno bug. Add MS-DOS support.
|
||||
*
|
||||
* Revision 5.6 1991/02/28 19:18:51 eggert
|
||||
* Fix null termination bug in reporting keyword expansion.
|
||||
*
|
||||
* Revision 5.5 1991/02/25 07:12:44 eggert
|
||||
* Check diff output more carefully; avoid overflow.
|
||||
*
|
||||
* Revision 5.4 1990/11/01 05:28:48 eggert
|
||||
* When ignoring unknown phrases, copy them to the output RCS file.
|
||||
* Permit arbitrary data in logs and comment leaders.
|
||||
* Don't check for nontext on initial checkin.
|
||||
*
|
||||
* Revision 5.3 1990/09/20 07:58:32 eggert
|
||||
* Remove the test for non-text bytes; it caused more pain than it cured.
|
||||
*
|
||||
* Revision 5.2 1990/09/04 08:02:30 eggert
|
||||
* Parse RCS files with no revisions.
|
||||
* Don't strip leading white space from diff commands. Count RCS lines better.
|
||||
*
|
||||
* Revision 5.1 1990/08/29 07:14:06 eggert
|
||||
* Add -kkvl. Clean old log messages too.
|
||||
*
|
||||
* Revision 5.0 1990/08/22 08:13:44 eggert
|
||||
* Try to parse future RCS formats without barfing.
|
||||
* Add -k. Don't require final newline.
|
||||
* Remove compile-time limits; use malloc instead.
|
||||
* Don't output branch keyword if there's no default branch,
|
||||
* because RCS version 3 doesn't understand it.
|
||||
* Tune. Remove lint.
|
||||
* Add support for ISO 8859. Ansify and Posixate.
|
||||
* Check that a newly checked-in file is acceptable as input to 'diff'.
|
||||
* Check diff's output.
|
||||
*
|
||||
* Revision 4.6 89/05/01 15:13:32 narten
|
||||
* changed copyright header to reflect current distribution rules
|
||||
*
|
||||
* Revision 4.5 88/08/09 19:13:21 eggert
|
||||
* Allow cc -R; remove lint.
|
||||
*
|
||||
* Revision 4.4 87/12/18 11:46:16 narten
|
||||
* more lint cleanups (Guy Harris)
|
||||
*
|
||||
* Revision 4.3 87/10/18 10:39:36 narten
|
||||
* Updating version numbers. Changes relative to 1.1 actually relative to
|
||||
* 4.1
|
||||
*
|
||||
* Revision 1.3 87/09/24 14:00:49 narten
|
||||
* Sources now pass through lint (if you ignore printf/sprintf/fprintf
|
||||
* warnings)
|
||||
*
|
||||
* Revision 1.2 87/03/27 14:22:40 jenkins
|
||||
* Port to suns
|
||||
*
|
||||
* Revision 4.1 83/03/28 11:38:49 wft
|
||||
* Added parsing and printing of default branch.
|
||||
*
|
||||
* Revision 3.6 83/01/15 17:46:50 wft
|
||||
* Changed readdelta() to initialize selector and log-pointer.
|
||||
* Changed puttree to check for selector==DELETE; putdtext() uses DELNUMFORM.
|
||||
*
|
||||
* Revision 3.5 82/12/08 21:58:58 wft
|
||||
* renamed Commentleader to Commleader.
|
||||
*
|
||||
* Revision 3.4 82/12/04 13:24:40 wft
|
||||
* Added routine gettree(), which updates keeplock after reading the
|
||||
* delta tree.
|
||||
*
|
||||
* Revision 3.3 82/11/28 21:30:11 wft
|
||||
* Reading and printing of Suffix removed; version COMPAT2 skips the
|
||||
* Suffix for files of release 2 format. Fixed problems with printing nil.
|
||||
*
|
||||
* Revision 3.2 82/10/18 21:18:25 wft
|
||||
* renamed putdeltatext to putdtext.
|
||||
*
|
||||
* Revision 3.1 82/10/11 19:45:11 wft
|
||||
* made sure getc() returns into an integer.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* version COMPAT2 reads files of the format of release 2 and 3, but
|
||||
* generates files of release 3 format. Need not be defined if no
|
||||
* old RCS files generated with release 2 exist.
|
||||
*/
|
||||
/* version SYNTEST inputs a RCS file and then prints out its internal
|
||||
* data structures.
|
||||
*/
|
||||
|
||||
#include "rcsbase.h"
|
||||
|
||||
libId(synId, "$Id: rcssyn.c,v 5.8 1991/08/19 03:13:55 eggert Exp $")
|
||||
|
||||
/* forward */
|
||||
static char const *getkeyval P((char const*,enum tokens,int));
|
||||
static int strn2expmode P((char const*,size_t));
|
||||
|
||||
/* keyword table */
|
||||
|
||||
char const
|
||||
Kdesc[] = "desc",
|
||||
Klog[] = "log",
|
||||
Ktext[] = "text";
|
||||
|
||||
static char const
|
||||
Kaccess[] = "access",
|
||||
Kauthor[] = "author",
|
||||
Kbranch[] = "branch",
|
||||
K_branches[]= "branches",
|
||||
Kcomment[] = "comment",
|
||||
Kdate[] = "date",
|
||||
Kexpand[] = "expand",
|
||||
Khead[] = "head",
|
||||
Klocks[] = "locks",
|
||||
Knext[] = "next",
|
||||
Kstate[] = "state",
|
||||
Kstrict[] = "strict",
|
||||
#if COMPAT2
|
||||
Ksuffix[] = "suffix",
|
||||
#endif
|
||||
Ksymbols[] = "symbols";
|
||||
|
||||
static struct buf Commleader;
|
||||
static struct cbuf Ignored;
|
||||
struct cbuf Comment;
|
||||
struct access * AccessList;
|
||||
struct assoc * Symbols;
|
||||
struct lock * Locks;
|
||||
int Expand;
|
||||
int StrictLocks;
|
||||
struct hshentry * Head;
|
||||
char const * Dbranch;
|
||||
unsigned TotalDeltas;
|
||||
|
||||
|
||||
static void
|
||||
getsemi(key)
|
||||
char const *key;
|
||||
/* Get a semicolon to finish off a phrase started by KEY. */
|
||||
{
|
||||
if (!getlex(SEMI))
|
||||
fatserror("missing ';' after '%s'", key);
|
||||
}
|
||||
|
||||
static struct hshentry *
|
||||
getdnum()
|
||||
/* Get a delta number. */
|
||||
{
|
||||
register struct hshentry *delta = getnum();
|
||||
if (delta && countnumflds(delta->num)&1)
|
||||
fatserror("%s isn't a delta number", delta->num);
|
||||
return delta;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
getadmin()
|
||||
/* Read an <admin> and initialize the appropriate global variables. */
|
||||
{
|
||||
register char const *id;
|
||||
struct access * newaccess;
|
||||
struct assoc * newassoc;
|
||||
struct lock * newlock;
|
||||
struct hshentry * delta;
|
||||
struct access **LastAccess;
|
||||
struct assoc **LastSymbol;
|
||||
struct lock **LastLock;
|
||||
struct buf b;
|
||||
struct cbuf cb;
|
||||
|
||||
TotalDeltas=0;
|
||||
|
||||
getkey(Khead);
|
||||
Head = getdnum();
|
||||
getsemi(Khead);
|
||||
|
||||
Dbranch = nil;
|
||||
if (getkeyopt(Kbranch)) {
|
||||
if ((delta = getnum()))
|
||||
Dbranch = delta->num;
|
||||
getsemi(Kbranch);
|
||||
}
|
||||
|
||||
|
||||
#if COMPAT2
|
||||
/* read suffix. Only in release 2 format */
|
||||
if (getkeyopt(Ksuffix)) {
|
||||
if (nexttok==STRING) {
|
||||
readstring(); nextlex(); /* Throw away the suffix. */
|
||||
} else if (nexttok==ID) {
|
||||
nextlex();
|
||||
}
|
||||
getsemi(Ksuffix);
|
||||
}
|
||||
#endif
|
||||
|
||||
getkey(Kaccess);
|
||||
LastAccess = &AccessList;
|
||||
while (id=getid()) {
|
||||
newaccess = ftalloc(struct access);
|
||||
newaccess->login = id;
|
||||
*LastAccess = newaccess;
|
||||
LastAccess = &newaccess->nextaccess;
|
||||
}
|
||||
*LastAccess = nil;
|
||||
getsemi(Kaccess);
|
||||
|
||||
getkey(Ksymbols);
|
||||
LastSymbol = &Symbols;
|
||||
while (id = getid()) {
|
||||
if (!getlex(COLON))
|
||||
fatserror("missing ':' in symbolic name definition");
|
||||
if (!(delta=getnum())) {
|
||||
fatserror("missing number in symbolic name definition");
|
||||
} else { /*add new pair to association list*/
|
||||
newassoc = ftalloc(struct assoc);
|
||||
newassoc->symbol=id;
|
||||
newassoc->num = delta->num;
|
||||
*LastSymbol = newassoc;
|
||||
LastSymbol = &newassoc->nextassoc;
|
||||
}
|
||||
}
|
||||
*LastSymbol = nil;
|
||||
getsemi(Ksymbols);
|
||||
|
||||
getkey(Klocks);
|
||||
LastLock = &Locks;
|
||||
while (id = getid()) {
|
||||
if (!getlex(COLON))
|
||||
fatserror("missing ':' in lock");
|
||||
if (!(delta=getdnum())) {
|
||||
fatserror("missing number in lock");
|
||||
} else { /*add new pair to lock list*/
|
||||
newlock = ftalloc(struct lock);
|
||||
newlock->login=id;
|
||||
newlock->delta=delta;
|
||||
*LastLock = newlock;
|
||||
LastLock = &newlock->nextlock;
|
||||
}
|
||||
}
|
||||
*LastLock = nil;
|
||||
getsemi(Klocks);
|
||||
|
||||
if ((StrictLocks = getkeyopt(Kstrict)))
|
||||
getsemi(Kstrict);
|
||||
|
||||
Comment.size = 0;
|
||||
if (getkeyopt(Kcomment)) {
|
||||
if (nexttok==STRING) {
|
||||
Comment = savestring(&Commleader);
|
||||
nextlex();
|
||||
}
|
||||
getsemi(Kcomment);
|
||||
}
|
||||
|
||||
Expand = KEYVAL_EXPAND;
|
||||
if (getkeyopt(Kexpand)) {
|
||||
if (nexttok==STRING) {
|
||||
bufautobegin(&b);
|
||||
cb = savestring(&b);
|
||||
if ((Expand = strn2expmode(cb.string,cb.size)) < 0)
|
||||
fatserror("unknown expand mode %.*s",
|
||||
(int)cb.size, cb.string
|
||||
);
|
||||
bufautoend(&b);
|
||||
nextlex();
|
||||
}
|
||||
getsemi(Kexpand);
|
||||
}
|
||||
Ignored = getphrases(Kdesc);
|
||||
}
|
||||
|
||||
char const *const expand_names[] = {
|
||||
/* These must agree with *_EXPAND in rcsbase.h. */
|
||||
"kv","kvl","k","v","o",
|
||||
0
|
||||
};
|
||||
|
||||
int
|
||||
str2expmode(s)
|
||||
char const *s;
|
||||
/* Yield expand mode corresponding to S, or -1 if bad. */
|
||||
{
|
||||
return strn2expmode(s, strlen(s));
|
||||
}
|
||||
|
||||
static int
|
||||
strn2expmode(s, n)
|
||||
char const *s;
|
||||
size_t n;
|
||||
{
|
||||
char const *const *p;
|
||||
|
||||
for (p = expand_names; *p; ++p)
|
||||
if (memcmp(*p,s,n) == 0 && !(*p)[n])
|
||||
return p - expand_names;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ignorephrase()
|
||||
/* Ignore a phrase introduced by a later version of RCS. */
|
||||
{
|
||||
warnignore();
|
||||
hshenter=false;
|
||||
for (;;) {
|
||||
switch (nexttok) {
|
||||
case SEMI: hshenter=true; nextlex(); return;
|
||||
case ID:
|
||||
case NUM: ffree1(NextString); break;
|
||||
case STRING: readstring(); break;
|
||||
default: break;
|
||||
}
|
||||
nextlex();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
getdelta()
|
||||
/* Function: reads a delta block.
|
||||
* returns false if the current block does not start with a number.
|
||||
*/
|
||||
{
|
||||
register struct hshentry * Delta, * num;
|
||||
struct branchhead **LastBranch, *NewBranch;
|
||||
|
||||
if (!(Delta = getdnum()))
|
||||
return false;
|
||||
|
||||
hshenter = false; /*Don't enter dates into hashtable*/
|
||||
Delta->date = getkeyval(Kdate, NUM, false);
|
||||
hshenter=true; /*reset hshenter for revision numbers.*/
|
||||
|
||||
Delta->author = getkeyval(Kauthor, ID, false);
|
||||
|
||||
Delta->state = getkeyval(Kstate, ID, true);
|
||||
|
||||
getkey(K_branches);
|
||||
LastBranch = &Delta->branches;
|
||||
while ((num = getdnum())) {
|
||||
NewBranch = ftalloc(struct branchhead);
|
||||
NewBranch->hsh = num;
|
||||
*LastBranch = NewBranch;
|
||||
LastBranch = &NewBranch->nextbranch;
|
||||
}
|
||||
*LastBranch = nil;
|
||||
getsemi(K_branches);
|
||||
|
||||
getkey(Knext);
|
||||
Delta->next = num = getdnum();
|
||||
getsemi(Knext);
|
||||
Delta->lockedby = nil;
|
||||
Delta->log.string = 0;
|
||||
Delta->selector = true;
|
||||
Delta->ig = getphrases(Kdesc);
|
||||
TotalDeltas++;
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gettree()
|
||||
/* Function: Reads in the delta tree with getdelta(), then
|
||||
* updates the lockedby fields.
|
||||
*/
|
||||
{
|
||||
struct lock const *currlock;
|
||||
|
||||
while (getdelta());
|
||||
currlock=Locks;
|
||||
while (currlock) {
|
||||
currlock->delta->lockedby = currlock->login;
|
||||
currlock = currlock->nextlock;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
getdesc(prdesc)
|
||||
int prdesc;
|
||||
/* Function: read in descriptive text
|
||||
* nexttok is not advanced afterwards.
|
||||
* If prdesc is set, the text is printed to stdout.
|
||||
*/
|
||||
{
|
||||
|
||||
getkeystring(Kdesc);
|
||||
if (prdesc)
|
||||
printstring(); /*echo string*/
|
||||
else readstring(); /*skip string*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static char const *
|
||||
getkeyval(keyword, token, optional)
|
||||
char const *keyword;
|
||||
enum tokens token;
|
||||
int optional;
|
||||
/* reads a pair of the form
|
||||
* <keyword> <token> ;
|
||||
* where token is one of <id> or <num>. optional indicates whether
|
||||
* <token> is optional. A pointer to
|
||||
* the actual character string of <id> or <num> is returned.
|
||||
*/
|
||||
{
|
||||
register char const *val = nil;
|
||||
|
||||
getkey(keyword);
|
||||
if (nexttok==token) {
|
||||
val = NextString;
|
||||
nextlex();
|
||||
} else {
|
||||
if (!optional)
|
||||
fatserror("missing %s", keyword);
|
||||
}
|
||||
getsemi(keyword);
|
||||
return(val);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
putadmin(fout)
|
||||
register FILE * fout;
|
||||
/* Function: Print the <admin> node read with getadmin() to file fout.
|
||||
* Assumption: Variables AccessList, Symbols, Locks, StrictLocks,
|
||||
* and Head have been set.
|
||||
*/
|
||||
{
|
||||
struct assoc const *curassoc;
|
||||
struct lock const *curlock;
|
||||
struct access const *curaccess;
|
||||
|
||||
aprintf(fout, "%s\t%s;\n", Khead, Head?Head->num:"");
|
||||
if (Dbranch && VERSION(4)<=RCSversion)
|
||||
aprintf(fout, "%s\t%s;\n", Kbranch, Dbranch);
|
||||
|
||||
aputs(Kaccess, fout);
|
||||
curaccess = AccessList;
|
||||
while (curaccess) {
|
||||
aprintf(fout, "\n\t%s", curaccess->login);
|
||||
curaccess = curaccess->nextaccess;
|
||||
}
|
||||
aprintf(fout, ";\n%s", Ksymbols);
|
||||
curassoc = Symbols;
|
||||
while (curassoc) {
|
||||
aprintf(fout, "\n\t%s:%s", curassoc->symbol, curassoc->num);
|
||||
curassoc = curassoc->nextassoc;
|
||||
}
|
||||
aprintf(fout, ";\n%s", Klocks);
|
||||
curlock = Locks;
|
||||
while (curlock) {
|
||||
aprintf(fout, "\n\t%s:%s", curlock->login, curlock->delta->num);
|
||||
curlock = curlock->nextlock;
|
||||
}
|
||||
if (StrictLocks) aprintf(fout, "; %s", Kstrict);
|
||||
aprintf(fout, ";\n");
|
||||
if (Comment.size) {
|
||||
aprintf(fout, "%s\t", Kcomment);
|
||||
putstring(fout, true, Comment, false);
|
||||
aprintf(fout, ";\n");
|
||||
}
|
||||
if (Expand != KEYVAL_EXPAND)
|
||||
aprintf(fout, "%s\t%c%s%c;\n",
|
||||
Kexpand, SDELIM, expand_names[Expand], SDELIM
|
||||
);
|
||||
awrite(Ignored.string, Ignored.size, fout);
|
||||
aputc('\n', fout);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static void
|
||||
putdelta(node,fout)
|
||||
register struct hshentry const *node;
|
||||
register FILE * fout;
|
||||
/* Function: prints a <delta> node to fout;
|
||||
*/
|
||||
{
|
||||
struct branchhead const *nextbranch;
|
||||
|
||||
if (node == nil) return;
|
||||
|
||||
aprintf(fout, "\n%s\n%s\t%s;\t%s %s;\t%s %s;\nbranches",
|
||||
node->num,
|
||||
Kdate, node->date,
|
||||
Kauthor, node->author,
|
||||
Kstate, node->state?node->state:""
|
||||
);
|
||||
nextbranch = node->branches;
|
||||
while (nextbranch) {
|
||||
aprintf(fout, "\n\t%s", nextbranch->hsh->num);
|
||||
nextbranch = nextbranch->nextbranch;
|
||||
}
|
||||
|
||||
aprintf(fout, ";\n%s\t%s;\n", Knext, node->next?node->next->num:"");
|
||||
awrite(node->ig.string, node->ig.size, fout);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
puttree(root,fout)
|
||||
struct hshentry const *root;
|
||||
register FILE * fout;
|
||||
/* Function: prints the delta tree in preorder to fout, starting with root.
|
||||
*/
|
||||
{
|
||||
struct branchhead const *nextbranch;
|
||||
|
||||
if (root==nil) return;
|
||||
|
||||
if (root->selector)
|
||||
putdelta(root,fout);
|
||||
|
||||
puttree(root->next,fout);
|
||||
|
||||
nextbranch = root->branches;
|
||||
while (nextbranch) {
|
||||
puttree(nextbranch->hsh,fout);
|
||||
nextbranch = nextbranch->nextbranch;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static exiting void
|
||||
unexpected_EOF()
|
||||
{
|
||||
faterror("unexpected EOF in diff output");
|
||||
}
|
||||
|
||||
int putdtext(num,log,srcfilename,fout,diffmt)
|
||||
char const *num, *srcfilename;
|
||||
struct cbuf log;
|
||||
FILE *fout;
|
||||
int diffmt;
|
||||
/* Function: write a deltatext-node to fout.
|
||||
* num points to the deltanumber, log to the logmessage, and
|
||||
* sourcefile contains the text. Doubles up all SDELIMs in both the
|
||||
* log and the text; Makes sure the log message ends in \n.
|
||||
* returns false on error.
|
||||
* If diffmt is true, also checks that text is valid diff -n output.
|
||||
*/
|
||||
{
|
||||
RILE *fin;
|
||||
int result;
|
||||
if (!(fin = Iopen(srcfilename, "r", (struct stat*)0))) {
|
||||
eerror(srcfilename);
|
||||
return false;
|
||||
}
|
||||
result = putdftext(num,log,fin,fout,diffmt);
|
||||
Ifclose(fin);
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
putstring(out, delim, s, log)
|
||||
register FILE *out;
|
||||
struct cbuf s;
|
||||
int delim, log;
|
||||
/*
|
||||
* Output to OUT one SDELIM if DELIM, then the string S with SDELIMs doubled.
|
||||
* If LOG is set then S is a log string; append a newline if S is nonempty.
|
||||
*/
|
||||
{
|
||||
register char const *sp;
|
||||
register size_t ss;
|
||||
|
||||
if (delim)
|
||||
aputc(SDELIM, out);
|
||||
sp = s.string;
|
||||
for (ss = s.size; ss; --ss) {
|
||||
if (*sp == SDELIM)
|
||||
aputc(SDELIM, out);
|
||||
aputc(*sp++, out);
|
||||
}
|
||||
if (s.size && log)
|
||||
aputc('\n', out);
|
||||
aputc(SDELIM, out);
|
||||
}
|
||||
|
||||
int
|
||||
putdftext(num,log,finfile,foutfile,diffmt)
|
||||
char const *num;
|
||||
struct cbuf log;
|
||||
RILE *finfile;
|
||||
FILE *foutfile;
|
||||
int diffmt;
|
||||
/* like putdtext(), except the source file is already open */
|
||||
{
|
||||
declarecache;
|
||||
register FILE *fout;
|
||||
register int c;
|
||||
register RILE *fin;
|
||||
int ed;
|
||||
struct diffcmd dc;
|
||||
|
||||
fout = foutfile;
|
||||
aprintf(fout,DELNUMFORM,num,Klog);
|
||||
/* put log */
|
||||
putstring(fout, true, log, true);
|
||||
/* put text */
|
||||
aprintf(fout, "\n%s\n%c", Ktext, SDELIM);
|
||||
fin = finfile;
|
||||
setupcache(fin);
|
||||
if (!diffmt) {
|
||||
/* Copy the file */
|
||||
cache(fin);
|
||||
for (;;) {
|
||||
cachegeteof(c, break;);
|
||||
if (c==SDELIM) aputc(SDELIM,fout); /*double up SDELIM*/
|
||||
aputc(c,fout);
|
||||
}
|
||||
} else {
|
||||
initdiffcmd(&dc);
|
||||
while (0 <= (ed = getdiffcmd(fin,false,fout,&dc)))
|
||||
if (ed) {
|
||||
cache(fin);
|
||||
while (dc.nlines--)
|
||||
do {
|
||||
cachegeteof(c, { if (!dc.nlines) goto OK_EOF; unexpected_EOF(); });
|
||||
if (c == SDELIM)
|
||||
aputc(SDELIM,fout);
|
||||
aputc(c,fout);
|
||||
} while (c != '\n');
|
||||
uncache(fin);
|
||||
}
|
||||
}
|
||||
OK_EOF:
|
||||
aprintf(fout, "%c\n", SDELIM);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
initdiffcmd(dc)
|
||||
register struct diffcmd *dc;
|
||||
/* Initialize *dc suitably for getdiffcmd(). */
|
||||
{
|
||||
dc->adprev = 0;
|
||||
dc->dafter = 0;
|
||||
}
|
||||
|
||||
static exiting void
|
||||
badDiffOutput(buf)
|
||||
char const *buf;
|
||||
{
|
||||
faterror("bad diff output line: %s", buf);
|
||||
}
|
||||
|
||||
static exiting void
|
||||
diffLineNumberTooLarge(buf)
|
||||
char const *buf;
|
||||
{
|
||||
faterror("diff line number too large: %s", buf);
|
||||
}
|
||||
|
||||
int
|
||||
getdiffcmd(finfile, delimiter, foutfile, dc)
|
||||
RILE *finfile;
|
||||
FILE *foutfile;
|
||||
int delimiter;
|
||||
struct diffcmd *dc;
|
||||
/* Get a editing command output by 'diff -n' from fin.
|
||||
* The input is delimited by SDELIM if delimiter is set, EOF otherwise.
|
||||
* Copy a clean version of the command to fout (if nonnull).
|
||||
* Yield 0 for 'd', 1 for 'a', and -1 for EOF.
|
||||
* Store the command's line number and length into dc->line1 and dc->nlines.
|
||||
* Keep dc->adprev and dc->dafter up to date.
|
||||
*/
|
||||
{
|
||||
register int c;
|
||||
declarecache;
|
||||
register FILE *fout;
|
||||
register char *p;
|
||||
register RILE *fin;
|
||||
unsigned long line1, nlines, t;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
fin = finfile;
|
||||
fout = foutfile;
|
||||
setupcache(fin); cache(fin);
|
||||
cachegeteof(c, { if (delimiter) unexpected_EOF(); return -1; } );
|
||||
if (delimiter) {
|
||||
if (c==SDELIM) {
|
||||
cacheget(c);
|
||||
if (c==SDELIM) {
|
||||
buf[0] = c;
|
||||
buf[1] = 0;
|
||||
badDiffOutput(buf);
|
||||
}
|
||||
uncache(fin);
|
||||
nextc = c;
|
||||
if (fout)
|
||||
aprintf(fout, "%c%c", SDELIM, c);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
p = buf;
|
||||
do {
|
||||
if (buf+BUFSIZ-2 <= p) {
|
||||
faterror("diff output command line too long");
|
||||
}
|
||||
*p++ = c;
|
||||
cachegeteof(c, unexpected_EOF();) ;
|
||||
} while (c != '\n');
|
||||
uncache(fin);
|
||||
if (delimiter)
|
||||
++rcsline;
|
||||
*p = '\0';
|
||||
for (p = buf+1; (c = *p++) == ' '; )
|
||||
;
|
||||
line1 = 0;
|
||||
while (isdigit(c)) {
|
||||
t = line1 * 10;
|
||||
if (
|
||||
ULONG_MAX/10 < line1 ||
|
||||
(line1 = t + (c - '0')) < t
|
||||
)
|
||||
diffLineNumberTooLarge(buf);
|
||||
c = *p++;
|
||||
}
|
||||
while (c == ' ')
|
||||
c = *p++;
|
||||
nlines = 0;
|
||||
while (isdigit(c)) {
|
||||
t = nlines * 10;
|
||||
if (
|
||||
ULONG_MAX/10 < nlines ||
|
||||
(nlines = t + (c - '0')) < t
|
||||
)
|
||||
diffLineNumberTooLarge(buf);
|
||||
c = *p++;
|
||||
}
|
||||
if (c || !nlines) {
|
||||
badDiffOutput(buf);
|
||||
}
|
||||
if (line1+nlines < line1)
|
||||
diffLineNumberTooLarge(buf);
|
||||
switch (buf[0]) {
|
||||
case 'a':
|
||||
if (line1 < dc->adprev) {
|
||||
faterror("backward insertion in diff output: %s", buf);
|
||||
}
|
||||
dc->adprev = line1 + 1;
|
||||
break;
|
||||
case 'd':
|
||||
if (line1 < dc->adprev || line1 < dc->dafter) {
|
||||
faterror("backward deletion in diff output: %s", buf);
|
||||
}
|
||||
dc->adprev = line1;
|
||||
dc->dafter = line1 + nlines;
|
||||
break;
|
||||
default:
|
||||
badDiffOutput(buf);
|
||||
}
|
||||
if (fout) {
|
||||
aprintf(fout, "%s\n", buf);
|
||||
}
|
||||
dc->line1 = line1;
|
||||
dc->nlines = nlines;
|
||||
return buf[0] == 'a';
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef SYNTEST
|
||||
|
||||
char const cmdid[] = "syntest";
|
||||
|
||||
int
|
||||
main(argc,argv)
|
||||
int argc; char * argv[];
|
||||
{
|
||||
|
||||
if (argc<2) {
|
||||
aputs("No input file\n",stderr);
|
||||
exitmain(EXIT_FAILURE);
|
||||
}
|
||||
if (!(finptr = Iopen(argv[1], FOPEN_R, (struct stat*)0))) {
|
||||
faterror("can't open input file %s", argv[1]);
|
||||
}
|
||||
Lexinit();
|
||||
getadmin();
|
||||
putadmin(stdout);
|
||||
|
||||
gettree();
|
||||
puttree(Head,stdout);
|
||||
|
||||
getdesc(true);
|
||||
|
||||
nextlex();
|
||||
|
||||
if (!eoflex()) {
|
||||
fatserror("expecting EOF");
|
||||
}
|
||||
exitmain(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
exiting void exiterr() { _exit(EXIT_FAILURE); }
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
994
gnu/usr.bin/rcs/lib/rcsutil.c
Normal file
994
gnu/usr.bin/rcs/lib/rcsutil.c
Normal file
|
|
@ -0,0 +1,994 @@
|
|||
/*
|
||||
* RCS utilities
|
||||
*/
|
||||
|
||||
/* Copyright (C) 1982, 1988, 1989 Walter Tichy
|
||||
Copyright 1990, 1991 by 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, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Report problems and direct all questions to:
|
||||
|
||||
rcs-bugs@cs.purdue.edu
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* $Log: rcsutil.c,v $
|
||||
* Revision 5.10 1991/10/07 17:32:46 eggert
|
||||
* Support piece tables even if !has_mmap.
|
||||
*
|
||||
* Revision 5.9 1991/08/19 03:13:55 eggert
|
||||
* Add spawn() support. Explicate assumptions about getting invoker's name.
|
||||
* Standardize user-visible dates. Tune.
|
||||
*
|
||||
* Revision 5.8 1991/04/21 11:58:30 eggert
|
||||
* Plug setuid security hole.
|
||||
*
|
||||
* Revision 5.6 1991/02/26 17:48:39 eggert
|
||||
* Fix setuid bug. Use fread, fwrite more portably.
|
||||
* Support waitpid. Don't assume -1 is acceptable to W* macros.
|
||||
* strsave -> str_save (DG/UX name clash)
|
||||
*
|
||||
* Revision 5.5 1990/12/04 05:18:49 eggert
|
||||
* Don't output a blank line after a signal diagnostic.
|
||||
* Use -I for prompts and -q for diagnostics.
|
||||
*
|
||||
* Revision 5.4 1990/11/01 05:03:53 eggert
|
||||
* Remove unneeded setid check. Add awrite(), fremember().
|
||||
*
|
||||
* Revision 5.3 1990/10/06 00:16:45 eggert
|
||||
* Don't fread F if feof(F).
|
||||
*
|
||||
* Revision 5.2 1990/09/04 08:02:31 eggert
|
||||
* Store fread()'s result in an fread_type object.
|
||||
*
|
||||
* Revision 5.1 1990/08/29 07:14:07 eggert
|
||||
* Declare getpwuid() more carefully.
|
||||
*
|
||||
* Revision 5.0 1990/08/22 08:13:46 eggert
|
||||
* Add setuid support. Permit multiple locks per user.
|
||||
* Remove compile-time limits; use malloc instead.
|
||||
* Switch to GMT. Permit dates past 1999/12/31.
|
||||
* Add -V. Remove snooping. Ansify and Posixate.
|
||||
* Tune. Some USG hosts define NSIG but not sys_siglist.
|
||||
* Don't run /bin/sh if it's hopeless.
|
||||
* Don't leave garbage behind if the output is an empty pipe.
|
||||
* Clean up after SIGXCPU or SIGXFSZ. Print name of signal that caused cleanup.
|
||||
*
|
||||
* Revision 4.6 89/05/01 15:13:40 narten
|
||||
* changed copyright header to reflect current distribution rules
|
||||
*
|
||||
* Revision 4.5 88/11/08 16:01:02 narten
|
||||
* corrected use of varargs routines
|
||||
*
|
||||
* Revision 4.4 88/08/09 19:13:24 eggert
|
||||
* Check for memory exhaustion.
|
||||
* Permit signal handlers to yield either 'void' or 'int'; fix oldSIGINT botch.
|
||||
* Use execv(), not system(); yield exit status like diff(1)'s.
|
||||
*
|
||||
* Revision 4.3 87/10/18 10:40:22 narten
|
||||
* Updating version numbers. Changes relative to 1.1 actually
|
||||
* relative to 4.1
|
||||
*
|
||||
* Revision 1.3 87/09/24 14:01:01 narten
|
||||
* Sources now pass through lint (if you ignore printf/sprintf/fprintf
|
||||
* warnings)
|
||||
*
|
||||
* Revision 1.2 87/03/27 14:22:43 jenkins
|
||||
* Port to suns
|
||||
*
|
||||
* Revision 4.1 83/05/10 15:53:13 wft
|
||||
* Added getcaller() and findlock().
|
||||
* Changed catchints() to check SIGINT for SIG_IGN before setting up the signal
|
||||
* (needed for background jobs in older shells). Added restoreints().
|
||||
* Removed printing of full RCS path from logcommand().
|
||||
*
|
||||
* Revision 3.8 83/02/15 15:41:49 wft
|
||||
* Added routine fastcopy() to copy remainder of a file in blocks.
|
||||
*
|
||||
* Revision 3.7 82/12/24 15:25:19 wft
|
||||
* added catchints(), ignoreints() for catching and ingnoring interrupts;
|
||||
* fixed catchsig().
|
||||
*
|
||||
* Revision 3.6 82/12/08 21:52:05 wft
|
||||
* Using DATEFORM to format dates.
|
||||
*
|
||||
* Revision 3.5 82/12/04 18:20:49 wft
|
||||
* Replaced SNOOPDIR with SNOOPFILE; changed addlock() to update
|
||||
* lockedby-field.
|
||||
*
|
||||
* Revision 3.4 82/12/03 17:17:43 wft
|
||||
* Added check to addlock() ensuring only one lock per person.
|
||||
* Addlock also returns a pointer to the lock created. Deleted fancydate().
|
||||
*
|
||||
* Revision 3.3 82/11/27 12:24:37 wft
|
||||
* moved rmsema(), trysema(), trydiraccess(), getfullRCSname() to rcsfnms.c.
|
||||
* Introduced macro SNOOP so that snoop can be placed in directory other than
|
||||
* TARGETDIR. Changed %02d to %.2d for compatibility reasons.
|
||||
*
|
||||
* Revision 3.2 82/10/18 21:15:11 wft
|
||||
* added function getfullRCSname().
|
||||
*
|
||||
* Revision 3.1 82/10/13 16:17:37 wft
|
||||
* Cleanup message is now suppressed in quiet mode.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
#include "rcsbase.h"
|
||||
|
||||
libId(utilId, "$Id: rcsutil.c,v 5.10 1991/10/07 17:32:46 eggert Exp $")
|
||||
|
||||
#if !has_memcmp
|
||||
int
|
||||
memcmp(s1, s2, n)
|
||||
void const *s1, *s2;
|
||||
size_t n;
|
||||
{
|
||||
register unsigned char const
|
||||
*p1 = (unsigned char const*)s1,
|
||||
*p2 = (unsigned char const*)s2;
|
||||
register size_t i = n;
|
||||
register int r = 0;
|
||||
while (i-- && !(r = (*p1++ - *p2++)))
|
||||
;
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !has_memcpy
|
||||
void *
|
||||
memcpy(s1, s2, n)
|
||||
void *s1;
|
||||
void const *s2;
|
||||
size_t n;
|
||||
{
|
||||
register char *p1 = (char*)s1;
|
||||
register char const *p2 = (char const*)s2;
|
||||
while (n--)
|
||||
*p1++ = *p2++;
|
||||
return s1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if lint
|
||||
malloc_type lintalloc;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* list of blocks allocated with ftestalloc()
|
||||
* These blocks can be freed by ffree when we're done with the current file.
|
||||
* We could put the free block inside struct alloclist, rather than a pointer
|
||||
* to the free block, but that would be less portable.
|
||||
*/
|
||||
struct alloclist {
|
||||
malloc_type alloc;
|
||||
struct alloclist *nextalloc;
|
||||
};
|
||||
static struct alloclist *alloced;
|
||||
|
||||
|
||||
static malloc_type
|
||||
okalloc(p)
|
||||
malloc_type p;
|
||||
{
|
||||
if (!p)
|
||||
faterror("out of memory");
|
||||
return p;
|
||||
}
|
||||
|
||||
malloc_type
|
||||
testalloc(size)
|
||||
size_t size;
|
||||
/* Allocate a block, testing that the allocation succeeded. */
|
||||
{
|
||||
return okalloc(malloc(size));
|
||||
}
|
||||
|
||||
malloc_type
|
||||
testrealloc(ptr, size)
|
||||
malloc_type ptr;
|
||||
size_t size;
|
||||
/* Reallocate a block, testing that the allocation succeeded. */
|
||||
{
|
||||
return okalloc(realloc(ptr, size));
|
||||
}
|
||||
|
||||
malloc_type
|
||||
fremember(ptr)
|
||||
malloc_type ptr;
|
||||
/* Remember PTR in 'alloced' so that it can be freed later. Yield PTR. */
|
||||
{
|
||||
register struct alloclist *q = talloc(struct alloclist);
|
||||
q->nextalloc = alloced;
|
||||
alloced = q;
|
||||
return q->alloc = ptr;
|
||||
}
|
||||
|
||||
malloc_type
|
||||
ftestalloc(size)
|
||||
size_t size;
|
||||
/* Allocate a block, putting it in 'alloced' so it can be freed later. */
|
||||
{
|
||||
return fremember(testalloc(size));
|
||||
}
|
||||
|
||||
void
|
||||
ffree()
|
||||
/* Free all blocks allocated with ftestalloc(). */
|
||||
{
|
||||
register struct alloclist *p, *q;
|
||||
for (p = alloced; p; p = q) {
|
||||
q = p->nextalloc;
|
||||
tfree(p->alloc);
|
||||
tfree(p);
|
||||
}
|
||||
alloced = nil;
|
||||
}
|
||||
|
||||
void
|
||||
ffree1(f)
|
||||
register char const *f;
|
||||
/* Free the block f, which was allocated by ftestalloc. */
|
||||
{
|
||||
register struct alloclist *p, **a = &alloced;
|
||||
|
||||
while ((p = *a)->alloc != f)
|
||||
a = &p->nextalloc;
|
||||
*a = p->nextalloc;
|
||||
tfree(p->alloc);
|
||||
tfree(p);
|
||||
}
|
||||
|
||||
char *
|
||||
str_save(s)
|
||||
char const *s;
|
||||
/* Save s in permanently allocated storage. */
|
||||
{
|
||||
return strcpy(tnalloc(char, strlen(s)+1), s);
|
||||
}
|
||||
|
||||
char *
|
||||
fstr_save(s)
|
||||
char const *s;
|
||||
/* Save s in storage that will be deallocated when we're done with this file. */
|
||||
{
|
||||
return strcpy(ftnalloc(char, strlen(s)+1), s);
|
||||
}
|
||||
|
||||
char *
|
||||
cgetenv(name)
|
||||
char const *name;
|
||||
/* Like getenv(), but yield a copy; getenv() can overwrite old results. */
|
||||
{
|
||||
register char *p;
|
||||
|
||||
return (p=getenv(name)) ? str_save(p) : p;
|
||||
}
|
||||
|
||||
char const *
|
||||
getusername(suspicious)
|
||||
int suspicious;
|
||||
/* Get the caller's login name. Trust only getwpuid if SUSPICIOUS. */
|
||||
{
|
||||
static char *name;
|
||||
|
||||
if (!name) {
|
||||
if (
|
||||
/* Prefer getenv() unless suspicious; it's much faster. */
|
||||
# if getlogin_is_secure
|
||||
(suspicious
|
||||
||
|
||||
!(name = cgetenv("LOGNAME"))
|
||||
&& !(name = cgetenv("USER")))
|
||||
&& !(name = getlogin())
|
||||
# else
|
||||
suspicious
|
||||
||
|
||||
!(name = cgetenv("LOGNAME"))
|
||||
&& !(name = cgetenv("USER"))
|
||||
&& !(name = getlogin())
|
||||
# endif
|
||||
) {
|
||||
#if has_getuid && has_getpwuid
|
||||
struct passwd const *pw = getpwuid(ruid());
|
||||
if (!pw)
|
||||
faterror("no password entry for userid %lu",
|
||||
(unsigned long)ruid()
|
||||
);
|
||||
name = pw->pw_name;
|
||||
#else
|
||||
#if has_setuid
|
||||
faterror("setuid not supported");
|
||||
#else
|
||||
faterror("Who are you? Please set LOGNAME.");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
checksid(name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#if has_signal
|
||||
|
||||
/*
|
||||
* Signal handling
|
||||
*
|
||||
* Standard C places too many restrictions on signal handlers.
|
||||
* We obey as many of them as we can.
|
||||
* Posix places fewer restrictions, and we are Posix-compatible here.
|
||||
*/
|
||||
|
||||
static sig_atomic_t volatile heldsignal, holdlevel;
|
||||
|
||||
static signal_type
|
||||
catchsig(s)
|
||||
int s;
|
||||
{
|
||||
char const *sname;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
#if sig_zaps_handler
|
||||
/* If a signal arrives before we reset the signal handler, we lose. */
|
||||
VOID signal(s, SIG_IGN);
|
||||
#endif
|
||||
if (holdlevel) {
|
||||
heldsignal = s;
|
||||
return;
|
||||
}
|
||||
ignoreints();
|
||||
setrid();
|
||||
if (!quietflag) {
|
||||
sname = nil;
|
||||
#if has_sys_siglist && defined(NSIG)
|
||||
if ((unsigned)s < NSIG) {
|
||||
# ifndef sys_siglist
|
||||
extern char const *sys_siglist[];
|
||||
# endif
|
||||
sname = sys_siglist[s];
|
||||
}
|
||||
#else
|
||||
switch (s) {
|
||||
#ifdef SIGHUP
|
||||
case SIGHUP: sname = "Hangup"; break;
|
||||
#endif
|
||||
#ifdef SIGINT
|
||||
case SIGINT: sname = "Interrupt"; break;
|
||||
#endif
|
||||
#ifdef SIGPIPE
|
||||
case SIGPIPE: sname = "Broken pipe"; break;
|
||||
#endif
|
||||
#ifdef SIGQUIT
|
||||
case SIGQUIT: sname = "Quit"; break;
|
||||
#endif
|
||||
#ifdef SIGTERM
|
||||
case SIGTERM: sname = "Terminated"; break;
|
||||
#endif
|
||||
#ifdef SIGXCPU
|
||||
case SIGXCPU: sname = "Cputime limit exceeded"; break;
|
||||
#endif
|
||||
#ifdef SIGXFSZ
|
||||
case SIGXFSZ: sname = "Filesize limit exceeded"; break;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
if (sname)
|
||||
VOID sprintf(buf, "\nRCS: %s. Cleaning up.\n", sname);
|
||||
else
|
||||
VOID sprintf(buf, "\nRCS: Signal %d. Cleaning up.\n", s);
|
||||
VOID write(STDERR_FILENO, buf, strlen(buf));
|
||||
}
|
||||
exiterr();
|
||||
}
|
||||
|
||||
void
|
||||
ignoreints()
|
||||
{
|
||||
++holdlevel;
|
||||
}
|
||||
|
||||
void
|
||||
restoreints()
|
||||
{
|
||||
if (!--holdlevel && heldsignal)
|
||||
VOID catchsig(heldsignal);
|
||||
}
|
||||
|
||||
|
||||
static int const sig[] = {
|
||||
#ifdef SIGHUP
|
||||
SIGHUP,
|
||||
#endif
|
||||
#ifdef SIGINT
|
||||
SIGINT,
|
||||
#endif
|
||||
#ifdef SIGPIPE
|
||||
SIGPIPE,
|
||||
#endif
|
||||
#ifdef SIGQUIT
|
||||
SIGQUIT,
|
||||
#endif
|
||||
#ifdef SIGTERM
|
||||
SIGTERM,
|
||||
#endif
|
||||
#ifdef SIGXCPU
|
||||
SIGXCPU,
|
||||
#endif
|
||||
#ifdef SIGXFSZ
|
||||
SIGXFSZ,
|
||||
#endif
|
||||
};
|
||||
#define SIGS (sizeof(sig)/sizeof(*sig))
|
||||
|
||||
|
||||
#if has_sigaction
|
||||
|
||||
static void
|
||||
check_sig(r)
|
||||
int r;
|
||||
{
|
||||
if (r != 0)
|
||||
efaterror("signal");
|
||||
}
|
||||
|
||||
static void
|
||||
setup_catchsig()
|
||||
{
|
||||
register int i;
|
||||
sigset_t blocked;
|
||||
struct sigaction act;
|
||||
|
||||
check_sig(sigemptyset(&blocked));
|
||||
for (i=SIGS; 0<=--i; )
|
||||
check_sig(sigaddset(&blocked, sig[i]));
|
||||
for (i=SIGS; 0<=--i; ) {
|
||||
check_sig(sigaction(sig[i], (struct sigaction*)nil, &act));
|
||||
if (act.sa_handler != SIG_IGN) {
|
||||
act.sa_handler = catchsig;
|
||||
act.sa_mask = blocked;
|
||||
check_sig(sigaction(sig[i], &act, (struct sigaction*)nil));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#if has_sigblock
|
||||
|
||||
static void
|
||||
setup_catchsig()
|
||||
{
|
||||
register int i;
|
||||
int mask;
|
||||
|
||||
mask = 0;
|
||||
for (i=SIGS; 0<=--i; )
|
||||
mask |= sigmask(sig[i]);
|
||||
mask = sigblock(mask);
|
||||
for (i=SIGS; 0<=--i; )
|
||||
if (
|
||||
signal(sig[i], catchsig) == SIG_IGN &&
|
||||
signal(sig[i], SIG_IGN) != catchsig
|
||||
)
|
||||
faterror("signal catcher failure");
|
||||
VOID sigsetmask(mask);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void
|
||||
setup_catchsig()
|
||||
{
|
||||
register i;
|
||||
|
||||
for (i=SIGS; 0<=--i; )
|
||||
if (
|
||||
signal(sig[i], SIG_IGN) != SIG_IGN &&
|
||||
signal(sig[i], catchsig) != SIG_IGN
|
||||
)
|
||||
faterror("signal catcher failure");
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void
|
||||
catchints()
|
||||
{
|
||||
static int catching_ints;
|
||||
if (!catching_ints) {
|
||||
catching_ints = true;
|
||||
setup_catchsig();
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* has_signal */
|
||||
|
||||
|
||||
void
|
||||
fastcopy(inf,outf)
|
||||
register RILE *inf;
|
||||
FILE *outf;
|
||||
/* Function: copies the remainder of file inf to outf.
|
||||
*/
|
||||
{
|
||||
#if large_memory
|
||||
# if has_mmap
|
||||
awrite((char const*)inf->ptr, (size_t)(inf->lim - inf->ptr), outf);
|
||||
inf->ptr = inf->lim;
|
||||
# else
|
||||
for (;;) {
|
||||
awrite((char const*)inf->ptr, (size_t)(inf->readlim - inf->ptr), outf);
|
||||
inf->ptr = inf->readlim;
|
||||
if (inf->ptr == inf->lim)
|
||||
break;
|
||||
VOID Igetmore(inf);
|
||||
}
|
||||
# endif
|
||||
#else
|
||||
char buf[BUFSIZ*8];
|
||||
register fread_type rcount;
|
||||
|
||||
/*now read the rest of the file in blocks*/
|
||||
while (!feof(inf)) {
|
||||
if (!(rcount = Fread(buf,sizeof(*buf),sizeof(buf),inf))) {
|
||||
testIerror(inf);
|
||||
return;
|
||||
}
|
||||
awrite(buf, (size_t)rcount, outf);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef SSIZE_MAX
|
||||
/* This does not work in #ifs, but it's good enough for us. */
|
||||
/* Underestimating SSIZE_MAX may slow us down, but it won't break us. */
|
||||
# define SSIZE_MAX ((unsigned)-1 >> 1)
|
||||
#endif
|
||||
|
||||
void
|
||||
awrite(buf, chars, f)
|
||||
char const *buf;
|
||||
size_t chars;
|
||||
FILE *f;
|
||||
{
|
||||
/* Posix 1003.1-1990 ssize_t hack */
|
||||
while (SSIZE_MAX < chars) {
|
||||
if (Fwrite(buf, sizeof(*buf), SSIZE_MAX, f) != SSIZE_MAX)
|
||||
Oerror();
|
||||
buf += SSIZE_MAX;
|
||||
chars -= SSIZE_MAX;
|
||||
}
|
||||
|
||||
if (Fwrite(buf, sizeof(*buf), chars, f) != chars)
|
||||
Oerror();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static int
|
||||
movefd(old, new)
|
||||
int old, new;
|
||||
{
|
||||
if (old < 0 || old == new)
|
||||
return old;
|
||||
# ifdef F_DUPFD
|
||||
new = fcntl(old, F_DUPFD, new);
|
||||
# else
|
||||
new = dup2(old, new);
|
||||
# endif
|
||||
return close(old)==0 ? new : -1;
|
||||
}
|
||||
|
||||
static int
|
||||
fdreopen(fd, file, flags)
|
||||
int fd;
|
||||
char const *file;
|
||||
int flags;
|
||||
{
|
||||
int newfd;
|
||||
VOID close(fd);
|
||||
newfd =
|
||||
#if !open_can_creat
|
||||
flags&O_CREAT ? creat(file, S_IRUSR|S_IWUSR) :
|
||||
#endif
|
||||
open(file, flags, S_IRUSR|S_IWUSR);
|
||||
return movefd(newfd, fd);
|
||||
}
|
||||
|
||||
#if !has_spawn
|
||||
static void
|
||||
tryopen(fd,file,flags)
|
||||
int fd, flags;
|
||||
char const *file;
|
||||
{
|
||||
if (file && fdreopen(fd,file,flags) != fd)
|
||||
efaterror(file);
|
||||
}
|
||||
#else
|
||||
static int
|
||||
tryopen(fd,file,flags)
|
||||
int fd, flags;
|
||||
char const *file;
|
||||
{
|
||||
int newfd = -1;
|
||||
if (file && ((newfd=dup(fd)) < 0 || fdreopen(fd,file,flags) != fd))
|
||||
efaterror(file);
|
||||
return newfd;
|
||||
}
|
||||
static void
|
||||
redirect(old, new)
|
||||
int old, new;
|
||||
{
|
||||
if (0 <= old && (close(new) != 0 || movefd(old,new) < 0))
|
||||
efaterror("spawn I/O redirection");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if !has_fork && !has_spawn
|
||||
static void
|
||||
bufargcat(b, c, s)
|
||||
register struct buf *b;
|
||||
int c;
|
||||
register char const *s;
|
||||
/* Append to B a copy of C, plus a quoted copy of S. */
|
||||
{
|
||||
register char *p;
|
||||
register char const *t;
|
||||
size_t bl, sl;
|
||||
|
||||
for (t=s, sl=0; *t; )
|
||||
sl += 3*(*t++=='\'') + 1;
|
||||
bl = strlen(b->string);
|
||||
bufrealloc(b, bl + sl + 4);
|
||||
p = b->string + bl;
|
||||
*p++ = c;
|
||||
*p++ = '\'';
|
||||
while (*s) {
|
||||
if (*s == '\'') {
|
||||
*p++ = '\'';
|
||||
*p++ = '\\';
|
||||
*p++ = '\'';
|
||||
}
|
||||
*p++ = *s++;
|
||||
}
|
||||
*p++ = '\'';
|
||||
*p = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Run a command specified by the strings in 'inoutargs'.
|
||||
* inoutargs[0], if nonnil, is the name of the input file.
|
||||
* inoutargs[1], if nonnil, is the name of the output file.
|
||||
* inoutargs[2..] form the command to be run.
|
||||
*/
|
||||
int
|
||||
runv(inoutargs)
|
||||
char const **inoutargs;
|
||||
{
|
||||
register char const **p;
|
||||
int wstatus;
|
||||
|
||||
oflush();
|
||||
eflush();
|
||||
{
|
||||
#if has_spawn
|
||||
int in, out;
|
||||
p = inoutargs;
|
||||
in = tryopen(STDIN_FILENO, *p++, O_BINARY|O_RDONLY);
|
||||
out = tryopen(STDOUT_FILENO, *p++, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY);
|
||||
wstatus = spawn_RCS(0, *p, (char*const*)p);
|
||||
if (wstatus == -1 && errno == ENOEXEC) {
|
||||
*--p = RCS_SHELL;
|
||||
wstatus = spawnv(0, *p, (char*const*)p);
|
||||
}
|
||||
redirect(in, STDIN_FILENO);
|
||||
redirect(out, STDOUT_FILENO);
|
||||
#else
|
||||
#if has_fork
|
||||
pid_t pid;
|
||||
# if !has_waitpid
|
||||
pid_t w;
|
||||
# endif
|
||||
if (!(pid = vfork())) {
|
||||
p = inoutargs;
|
||||
tryopen(STDIN_FILENO, *p++, O_BINARY|O_RDONLY);
|
||||
tryopen(STDOUT_FILENO, *p++, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY);
|
||||
VOID exec_RCS(*p, (char*const*)p);
|
||||
if (errno == ENOEXEC) {
|
||||
*--p = RCS_SHELL;
|
||||
VOID execv(*p, (char*const*)p);
|
||||
}
|
||||
VOID write(STDERR_FILENO, *p, strlen(*p));
|
||||
VOID write(STDERR_FILENO, ": not found\n", 12);
|
||||
_exit(EXIT_TROUBLE);
|
||||
}
|
||||
if (pid < 0)
|
||||
efaterror("fork");
|
||||
# if has_waitpid
|
||||
if (waitpid(pid, &wstatus, 0) < 0)
|
||||
efaterror("waitpid");
|
||||
# else
|
||||
do {
|
||||
if ((w = wait(&wstatus)) < 0)
|
||||
efaterror("wait");
|
||||
} while (w != pid);
|
||||
# endif
|
||||
#else
|
||||
static struct buf b;
|
||||
|
||||
/* Use system(). On many hosts system() discards signals. Yuck! */
|
||||
p = inoutargs+2;
|
||||
bufscpy(&b, *p);
|
||||
while (*++p)
|
||||
bufargcat(&b, ' ', *p);
|
||||
if (inoutargs[0])
|
||||
bufargcat(&b, '<', inoutargs[0]);
|
||||
if (inoutargs[1])
|
||||
bufargcat(&b, '>', inoutargs[1]);
|
||||
wstatus = system(b.string);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
if (!WIFEXITED(wstatus))
|
||||
faterror("%s failed", inoutargs[2]);
|
||||
return WEXITSTATUS(wstatus);
|
||||
}
|
||||
|
||||
#define CARGSMAX 20
|
||||
/*
|
||||
* Run a command.
|
||||
* The first two arguments are the input and output files (if nonnil);
|
||||
* the rest specify the command and its arguments.
|
||||
*/
|
||||
int
|
||||
#if has_prototypes
|
||||
run(char const *infile, char const *outfile, ...)
|
||||
#else
|
||||
/*VARARGS2*/
|
||||
run(infile, outfile, va_alist)
|
||||
char const *infile;
|
||||
char const *outfile;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list ap;
|
||||
char const *rgargs[CARGSMAX];
|
||||
register i = 0;
|
||||
rgargs[0] = infile;
|
||||
rgargs[1] = outfile;
|
||||
vararg_start(ap, outfile);
|
||||
for (i = 2; (rgargs[i++] = va_arg(ap, char const*)); )
|
||||
if (CARGSMAX <= i)
|
||||
faterror("too many command arguments");
|
||||
va_end(ap);
|
||||
return runv(rgargs);
|
||||
}
|
||||
|
||||
|
||||
char const *
|
||||
date2str(date, datebuf)
|
||||
char const date[datesize];
|
||||
char datebuf[datesize];
|
||||
/*
|
||||
* Format a user-readable form of the RCS format DATE into the buffer DATEBUF.
|
||||
* Yield DATEBUF.
|
||||
*/
|
||||
{
|
||||
register char const *p = date;
|
||||
|
||||
while (*p++ != '.')
|
||||
;
|
||||
VOID sprintf(datebuf,
|
||||
"19%.*s/%.2s/%.2s %.2s:%.2s:%s" +
|
||||
(date[2]=='.' && VERSION(5)<=RCSversion ? 0 : 2),
|
||||
(int)(p-date-1), date,
|
||||
p, p+3, p+6, p+9, p+12
|
||||
);
|
||||
return datebuf;
|
||||
}
|
||||
|
||||
|
||||
int RCSversion;
|
||||
|
||||
void
|
||||
setRCSversion(str)
|
||||
char const *str;
|
||||
{
|
||||
static int oldversion;
|
||||
|
||||
register char const *s = str + 2;
|
||||
int v = VERSION_DEFAULT;
|
||||
|
||||
if (oldversion)
|
||||
redefined('V');
|
||||
oldversion = true;
|
||||
|
||||
if (*s) {
|
||||
v = 0;
|
||||
while (isdigit(*s))
|
||||
v = 10*v + *s++ - '0';
|
||||
if (*s)
|
||||
faterror("%s isn't a number", str);
|
||||
if (v < VERSION_min || VERSION_max < v)
|
||||
faterror("%s out of range %d..%d", str, VERSION_min, VERSION_max);
|
||||
}
|
||||
|
||||
RCSversion = VERSION(v);
|
||||
}
|
||||
|
||||
int
|
||||
getRCSINIT(argc, argv, newargv)
|
||||
int argc;
|
||||
char **argv, ***newargv;
|
||||
{
|
||||
register char *p, *q, **pp;
|
||||
unsigned n;
|
||||
|
||||
if (!(q = cgetenv("RCSINIT")))
|
||||
*newargv = argv;
|
||||
else {
|
||||
n = argc + 2;
|
||||
/*
|
||||
* Count spaces in RCSINIT to allocate a new arg vector.
|
||||
* This is an upper bound, but it's OK even if too large.
|
||||
*/
|
||||
for (p = q; ; ) {
|
||||
switch (*p++) {
|
||||
default:
|
||||
continue;
|
||||
|
||||
case ' ':
|
||||
case '\b': case '\f': case '\n':
|
||||
case '\r': case '\t': case '\v':
|
||||
n++;
|
||||
continue;
|
||||
|
||||
case '\0':
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
*newargv = pp = tnalloc(char*, n);
|
||||
*pp++ = *argv++; /* copy program name */
|
||||
for (p = q; ; ) {
|
||||
for (;;) {
|
||||
switch (*q) {
|
||||
case '\0':
|
||||
goto copyrest;
|
||||
|
||||
case ' ':
|
||||
case '\b': case '\f': case '\n':
|
||||
case '\r': case '\t': case '\v':
|
||||
q++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
*pp++ = p;
|
||||
++argc;
|
||||
for (;;) {
|
||||
switch ((*p++ = *q++)) {
|
||||
case '\0':
|
||||
goto copyrest;
|
||||
|
||||
case '\\':
|
||||
if (!*q)
|
||||
goto copyrest;
|
||||
p[-1] = *q++;
|
||||
continue;
|
||||
|
||||
default:
|
||||
continue;
|
||||
|
||||
case ' ':
|
||||
case '\b': case '\f': case '\n':
|
||||
case '\r': case '\t': case '\v':
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
p[-1] = '\0';
|
||||
}
|
||||
copyrest:
|
||||
while ((*pp++ = *argv++))
|
||||
;
|
||||
}
|
||||
return argc;
|
||||
}
|
||||
|
||||
|
||||
#define cacheid(E) static uid_t i; static int s; if (!s){ s=1; i=(E); } return i
|
||||
|
||||
#if has_getuid
|
||||
uid_t ruid() { cacheid(getuid()); }
|
||||
#endif
|
||||
#if has_setuid
|
||||
uid_t euid() { cacheid(geteuid()); }
|
||||
#endif
|
||||
|
||||
|
||||
#if has_setuid
|
||||
|
||||
/*
|
||||
* Setuid execution really works only with Posix 1003.1a Draft 5 seteuid(),
|
||||
* because it lets us switch back and forth between arbitrary users.
|
||||
* If seteuid() doesn't work, we fall back on setuid(),
|
||||
* which works if saved setuid is supported,
|
||||
* unless the real or effective user is root.
|
||||
* This area is such a mess that we always check switches at runtime.
|
||||
*/
|
||||
|
||||
static void
|
||||
set_uid_to(u)
|
||||
uid_t u;
|
||||
/* Become user u. */
|
||||
{
|
||||
static int looping;
|
||||
|
||||
if (euid() == ruid())
|
||||
return;
|
||||
#if (has_fork||has_spawn) && DIFF_ABSOLUTE
|
||||
if (seteuid(u) != 0)
|
||||
efaterror("setuid");
|
||||
#endif
|
||||
if (geteuid() != u) {
|
||||
if (looping)
|
||||
return;
|
||||
looping = true;
|
||||
faterror("root setuid not supported" + (u?5:0));
|
||||
}
|
||||
}
|
||||
|
||||
static int stick_with_euid;
|
||||
|
||||
void
|
||||
/* Ignore all calls to seteid() and setrid(). */
|
||||
nosetid()
|
||||
{
|
||||
stick_with_euid = true;
|
||||
}
|
||||
|
||||
void
|
||||
seteid()
|
||||
/* Become effective user. */
|
||||
{
|
||||
if (!stick_with_euid)
|
||||
set_uid_to(euid());
|
||||
}
|
||||
|
||||
void
|
||||
setrid()
|
||||
/* Become real user. */
|
||||
{
|
||||
if (!stick_with_euid)
|
||||
set_uid_to(ruid());
|
||||
}
|
||||
#endif
|
||||
7
gnu/usr.bin/rcs/merge/Makefile
Normal file
7
gnu/usr.bin/rcs/merge/Makefile
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
PROG= merge
|
||||
|
||||
SRCS= merge.c
|
||||
LDADD= -L${.CURDIR}/../lib/obj -lrcs
|
||||
CFLAGS+= -I${.CURDIR}/../lib
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
102
gnu/usr.bin/rcs/merge/merge.1
Normal file
102
gnu/usr.bin/rcs/merge/merge.1
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
.de Id
|
||||
.ds Rv \\$3
|
||||
.ds Dt \\$4
|
||||
..
|
||||
.Id $Id: merge.1,v 5.3 1991/02/28 19:18:45 eggert Exp $
|
||||
.TH MERGE 1 \*(Dt GNU
|
||||
.SH NAME
|
||||
merge \- three-way file merge
|
||||
.SH SYNOPSIS
|
||||
.B merge
|
||||
[
|
||||
.B \-L
|
||||
.I label1
|
||||
[
|
||||
.B \-L
|
||||
.I label3
|
||||
] ] [
|
||||
.B \-p
|
||||
] [
|
||||
.B \-q
|
||||
]
|
||||
.I "file1 file2 file3"
|
||||
.SH DESCRIPTION
|
||||
.B merge
|
||||
incorporates all changes that lead from
|
||||
.I file2
|
||||
to
|
||||
.I file3
|
||||
into
|
||||
.IR file1 .
|
||||
The result goes to standard output if
|
||||
.B \-p
|
||||
is present, into
|
||||
.I file1
|
||||
otherwise.
|
||||
.B merge
|
||||
is useful for combining separate changes to an original. Suppose
|
||||
.I file2
|
||||
is the original, and both
|
||||
.I file1
|
||||
and
|
||||
.I file3
|
||||
are modifications of
|
||||
.IR file2 .
|
||||
Then
|
||||
.B merge
|
||||
combines both changes.
|
||||
.PP
|
||||
An overlap occurs if both
|
||||
.I file1
|
||||
and
|
||||
.I file3
|
||||
have changes in a common segment of lines.
|
||||
On a few older hosts where
|
||||
.B diff3
|
||||
does not support the
|
||||
.B \-E
|
||||
option,
|
||||
.B merge
|
||||
does not detect overlaps, and merely supplies the changed lines from
|
||||
.I file3.
|
||||
On most hosts, if overlaps occur,
|
||||
.B merge
|
||||
outputs a message (unless the
|
||||
.B \-q
|
||||
option is given),
|
||||
and includes both alternatives
|
||||
in the result. The alternatives are delimited as follows:
|
||||
.LP
|
||||
.RS
|
||||
.nf
|
||||
.BI <<<<<<< " file1"
|
||||
.I "lines in file1"
|
||||
.B "======="
|
||||
.I "lines in file3"
|
||||
.BI >>>>>>> " file3"
|
||||
.RE
|
||||
.fi
|
||||
.LP
|
||||
If there are overlaps, the user should edit the result and delete one of the
|
||||
alternatives.
|
||||
If the
|
||||
.BI \-L "\ label1"
|
||||
and
|
||||
.BI \-L "\ label3"
|
||||
options are given, the labels are output in place of the names
|
||||
.I file1
|
||||
and
|
||||
.I file3
|
||||
in overlap reports.
|
||||
.SH DIAGNOSTICS
|
||||
Exit status is 0 for no overlaps, 1 for some overlaps, 2 for trouble.
|
||||
.SH IDENTIFICATION
|
||||
Author: Walter F. Tichy.
|
||||
.br
|
||||
Revision Number: \*(Rv; Release Date: \*(Dt.
|
||||
.br
|
||||
Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
|
||||
.br
|
||||
Copyright \(co 1990, 1991 by Paul Eggert.
|
||||
.SH SEE ALSO
|
||||
diff3(1), diff(1), rcsmerge(1), co(1).
|
||||
97
gnu/usr.bin/rcs/merge/merge.c
Normal file
97
gnu/usr.bin/rcs/merge/merge.c
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/* merge - three-way file merge */
|
||||
|
||||
/* Copyright 1991 by 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, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Report problems and direct all questions to:
|
||||
|
||||
rcs-bugs@cs.purdue.edu
|
||||
|
||||
*/
|
||||
|
||||
#include "rcsbase.h"
|
||||
|
||||
|
||||
static char const usage[] =
|
||||
"\nmerge: usage: merge [-p] [-q] [-L label1 [-L label3]] file1 file2 file3\n";
|
||||
|
||||
static exiting void
|
||||
badoption(a)
|
||||
char const *a;
|
||||
{
|
||||
faterror("unknown option: %s%s", a-2, usage);
|
||||
}
|
||||
|
||||
|
||||
mainProg(mergeId, "merge", "$Id: merge.c,v 1.2 1991/08/19 03:13:55 eggert Exp $")
|
||||
{
|
||||
register char const *a;
|
||||
char const *label[2], *arg[3];
|
||||
int labels, tostdout;
|
||||
|
||||
labels = 0;
|
||||
tostdout = false;
|
||||
|
||||
while ((a = *++argv) && *a++ == '-') {
|
||||
switch (*a++) {
|
||||
case 'p': tostdout = true; break;
|
||||
case 'q': quietflag = true; break;
|
||||
case 'L':
|
||||
if (1<labels)
|
||||
faterror("too many -L options");
|
||||
if (!(label[labels++] = *++argv))
|
||||
faterror("-L needs following argument");
|
||||
--argc;
|
||||
break;
|
||||
default:
|
||||
badoption(a);
|
||||
}
|
||||
if (*a)
|
||||
badoption(a);
|
||||
--argc;
|
||||
}
|
||||
|
||||
if (argc != 4)
|
||||
faterror("%s arguments%s",
|
||||
argc<4 ? "not enough" : "too many", usage
|
||||
);
|
||||
|
||||
/* This copy keeps us `const'-clean. */
|
||||
arg[0] = argv[0];
|
||||
arg[1] = argv[1];
|
||||
arg[2] = argv[2];
|
||||
|
||||
switch (labels) {
|
||||
case 0: label[0] = arg[0]; /* fall into */
|
||||
case 1: label[1] = arg[2];
|
||||
}
|
||||
|
||||
exitmain(merge(tostdout, label, arg));
|
||||
}
|
||||
|
||||
|
||||
#if lint
|
||||
# define exiterr mergeExit
|
||||
#endif
|
||||
exiting void
|
||||
exiterr()
|
||||
{
|
||||
tempunlink();
|
||||
_exit(DIFF_TROUBLE);
|
||||
}
|
||||
10
gnu/usr.bin/rcs/rcs/Makefile
Normal file
10
gnu/usr.bin/rcs/rcs/Makefile
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
PROG= rcs
|
||||
|
||||
SRCS= rcs.c
|
||||
LDADD= -L${.CURDIR}/../lib/obj -lrcs
|
||||
CFLAGS+= -I${.CURDIR}/../lib
|
||||
|
||||
MAN1= rcs.0 rcsintro.0
|
||||
MAN5= rcsfile.0
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
397
gnu/usr.bin/rcs/rcs/rcs.1
Normal file
397
gnu/usr.bin/rcs/rcs/rcs.1
Normal file
|
|
@ -0,0 +1,397 @@
|
|||
.de Id
|
||||
.ds Rv \\$3
|
||||
.ds Dt \\$4
|
||||
..
|
||||
.Id $Id: rcs.1,v 5.6 1991/09/26 23:16:17 eggert Exp $
|
||||
.ds r \&\s-1RCS\s0
|
||||
.if n .ds - \%--
|
||||
.if t .ds - \(em
|
||||
.TH RCS 1 \*(Dt GNU
|
||||
.SH NAME
|
||||
rcs \- change RCS file attributes
|
||||
.SH SYNOPSIS
|
||||
.B rcs
|
||||
.RI [ " options " ] " file " .\|.\|.
|
||||
.SH DESCRIPTION
|
||||
.B rcs
|
||||
creates new \*r files or changes attributes of existing ones.
|
||||
An \*r file contains multiple revisions of text,
|
||||
an access list, a change log,
|
||||
descriptive text,
|
||||
and some control attributes.
|
||||
For
|
||||
.B rcs
|
||||
to work, the caller's login name must be on the access list,
|
||||
except if the access list is empty, the caller is the owner of the file
|
||||
or the superuser, or
|
||||
the
|
||||
.B \-i
|
||||
option is present.
|
||||
.PP
|
||||
Pathnames matching an \*r suffix denote \*r files;
|
||||
all others denote working files.
|
||||
Names are paired as explained in
|
||||
.BR ci (1).
|
||||
Revision numbers use the syntax described in
|
||||
.BR ci (1).
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-i
|
||||
Create and initialize a new \*r file, but do not deposit any revision.
|
||||
If the \*r file has no path prefix, try to place it
|
||||
first into the subdirectory
|
||||
.BR ./RCS ,
|
||||
and then into the current directory.
|
||||
If the \*r file
|
||||
already exists, print an error message.
|
||||
.TP
|
||||
.BI \-a "logins"
|
||||
Append the login names appearing in the comma-separated list
|
||||
.I logins
|
||||
to the access list of the \*r file.
|
||||
.TP
|
||||
.BI \-A "oldfile"
|
||||
Append the access list of
|
||||
.I oldfile
|
||||
to the access list of the \*r file.
|
||||
.TP
|
||||
.BR \-e [\f2logins\fP]
|
||||
Erase the login names appearing in the comma-separated list
|
||||
.I logins
|
||||
from the access list of the \*r file.
|
||||
If
|
||||
.I logins
|
||||
is omitted, erase the entire access list.
|
||||
.TP
|
||||
.BR \-b [\f2rev\fP]
|
||||
Set the default branch to
|
||||
.IR rev .
|
||||
If
|
||||
.I rev
|
||||
is omitted, the default
|
||||
branch is reset to the (dynamically) highest branch on the trunk.
|
||||
.TP
|
||||
.BI \-c string
|
||||
sets the comment leader to
|
||||
.IR string .
|
||||
The comment leader
|
||||
is printed before every log message line generated by the keyword
|
||||
.B $\&Log$
|
||||
during checkout (see
|
||||
.BR co (1)).
|
||||
This is useful for programming
|
||||
languages without multi-line comments.
|
||||
An initial
|
||||
.B ci ,
|
||||
or an
|
||||
.B "rcs\ \-i"
|
||||
without
|
||||
.BR \-c ,
|
||||
guesses the comment leader from the suffix of the working file.
|
||||
.TP
|
||||
.BI \-k subst
|
||||
Set the default keyword substitution to
|
||||
.IR subst .
|
||||
The effect of keyword substitution is described in
|
||||
.BR co (1).
|
||||
Giving an explicit
|
||||
.B \-k
|
||||
option to
|
||||
.BR co ,
|
||||
.BR rcsdiff ,
|
||||
and
|
||||
.B rcsmerge
|
||||
overrides this default.
|
||||
Beware
|
||||
.BR "rcs\ \-kv",
|
||||
because
|
||||
.B \-kv
|
||||
is incompatible with
|
||||
.BR "co\ \-l".
|
||||
Use
|
||||
.B "rcs\ \-kkv"
|
||||
to restore the normal default keyword substitution.
|
||||
.TP
|
||||
.BR \-l [\f2rev\fP]
|
||||
Lock the revision with number
|
||||
.IR rev .
|
||||
If a branch is given, lock the latest revision on that branch.
|
||||
If
|
||||
.I rev
|
||||
is omitted, lock the latest revision on the default branch.
|
||||
Locking prevents overlapping changes.
|
||||
A lock is removed with
|
||||
.B ci
|
||||
or
|
||||
.B "rcs\ \-u"
|
||||
(see below).
|
||||
.TP
|
||||
.BR \-u [\f2rev\fP]
|
||||
Unlock the revision with number
|
||||
.IR rev .
|
||||
If a branch is given, unlock the latest revision on that branch.
|
||||
If
|
||||
.I rev
|
||||
is omitted, remove the latest lock held by the caller.
|
||||
Normally, only the locker of a revision may unlock it.
|
||||
Somebody else unlocking a revision breaks the lock.
|
||||
This causes a mail message to be sent to the original locker.
|
||||
The message contains a commentary solicited from the breaker.
|
||||
The commentary is terminated by end-of-file or by a line containing
|
||||
.BR \&. "\ by"
|
||||
itself.
|
||||
.TP
|
||||
.B \-L
|
||||
Set locking to
|
||||
.IR strict .
|
||||
Strict locking means that the owner
|
||||
of an \*r file is not exempt from locking for checkin.
|
||||
This option should be used for files that are shared.
|
||||
.TP
|
||||
.B \-U
|
||||
Set locking to non-strict. Non-strict locking means that the owner of
|
||||
a file need not lock a revision for checkin.
|
||||
This option should
|
||||
.I not
|
||||
be used for files that are shared.
|
||||
Whether default locking is strict is determined by your system administrator,
|
||||
but it is normally strict.
|
||||
.TP
|
||||
\f3\-m\fP\f2rev\fP\f3:\fP\f2msg\fP
|
||||
Replace revision
|
||||
.IR rev 's
|
||||
log message with
|
||||
.IR msg .
|
||||
.TP
|
||||
\f3\-n\fP\f2name\fP[\f3:\fP[\f2rev\fP]]
|
||||
Associate the symbolic name
|
||||
.I name
|
||||
with the branch or
|
||||
revision
|
||||
.IR rev .
|
||||
Delete the symbolic name if both
|
||||
.B :
|
||||
and
|
||||
.I rev
|
||||
are omitted; otherwise, print an error message if
|
||||
.I name
|
||||
is already associated with
|
||||
another number.
|
||||
If
|
||||
.I rev
|
||||
is symbolic, it is expanded before association.
|
||||
A
|
||||
.I rev
|
||||
consisting of a branch number followed by a
|
||||
.B .\&
|
||||
stands for the current latest revision in the branch.
|
||||
A
|
||||
.B :
|
||||
with an empty
|
||||
.I rev
|
||||
stands for the current latest revision on the default branch,
|
||||
normally the trunk.
|
||||
For example,
|
||||
.BI "rcs\ \-n" name ":\ RCS/*"
|
||||
associates
|
||||
.I name
|
||||
with the current latest revision of all the named \*r files;
|
||||
this contrasts with
|
||||
.BI "rcs\ \-n" name ":$\ RCS/*"
|
||||
which associates
|
||||
.I name
|
||||
with the revision numbers extracted from keyword strings
|
||||
in the corresponding working files.
|
||||
.TP
|
||||
\f3\-N\fP\f2name\fP[\f3:\fP[\f2rev\fP]]
|
||||
Act like
|
||||
.BR \-n ,
|
||||
except override any previous assignment of
|
||||
.IR name .
|
||||
.TP
|
||||
.BI \-o range
|
||||
deletes (\*(lqoutdates\*(rq) the revisions given by
|
||||
.IR range .
|
||||
A range consisting of a single revision number means that revision.
|
||||
A range consisting of a branch number means the latest revision on that
|
||||
branch.
|
||||
A range of the form
|
||||
.IB rev1 : rev2
|
||||
means
|
||||
revisions
|
||||
.I rev1
|
||||
to
|
||||
.I rev2
|
||||
on the same branch,
|
||||
.BI : rev
|
||||
means from the beginning of the branch containing
|
||||
.I rev
|
||||
up to and including
|
||||
.IR rev ,
|
||||
and
|
||||
.IB rev :
|
||||
means
|
||||
from revision
|
||||
.I rev
|
||||
to the end of the branch containing
|
||||
.IR rev .
|
||||
None of the outdated revisions may have branches or locks.
|
||||
.TP
|
||||
.B \-q
|
||||
Run quietly; do not print diagnostics.
|
||||
.TP
|
||||
.B \-I
|
||||
Run interactively, even if the standard input is not a terminal.
|
||||
.TP
|
||||
.B \-s\f2state\fP\f1[\fP:\f2rev\fP\f1]\fP
|
||||
Set the state attribute of the revision
|
||||
.I rev
|
||||
to
|
||||
.I state .
|
||||
If
|
||||
.I rev
|
||||
is a branch number, assume the latest revision on that branch.
|
||||
If
|
||||
.I rev
|
||||
is omitted, assume the latest revision on the default branch.
|
||||
Any identifier is acceptable for
|
||||
.IR state .
|
||||
A useful set of states
|
||||
is
|
||||
.B Exp
|
||||
(for experimental),
|
||||
.B Stab
|
||||
(for stable), and
|
||||
.B Rel
|
||||
(for
|
||||
released).
|
||||
By default,
|
||||
.BR ci (1)
|
||||
sets the state of a revision to
|
||||
.BR Exp .
|
||||
.TP
|
||||
.BR \-t [\f2file\fP]
|
||||
Write descriptive text from the contents of the named
|
||||
.I file
|
||||
into the \*r file, deleting the existing text.
|
||||
The
|
||||
.IR file
|
||||
pathname may not begin with
|
||||
.BR \- .
|
||||
If
|
||||
.I file
|
||||
is omitted, obtain the text from standard input,
|
||||
terminated by end-of-file or by a line containing
|
||||
.BR \&. "\ by"
|
||||
itself.
|
||||
Prompt for the text if interaction is possible; see
|
||||
.BR \-I .
|
||||
With
|
||||
.BR \-i ,
|
||||
descriptive text is obtained
|
||||
even if
|
||||
.B \-t
|
||||
is not given.
|
||||
.TP
|
||||
.BI \-t\- string
|
||||
Write descriptive text from the
|
||||
.I string
|
||||
into the \*r file, deleting the existing text.
|
||||
.TP
|
||||
.BI \-V n
|
||||
Emulate \*r version
|
||||
.IR n .
|
||||
See
|
||||
.BR co (1)
|
||||
for details.
|
||||
.TP
|
||||
.BI \-x "suffixes"
|
||||
Use
|
||||
.I suffixes
|
||||
to characterize \*r files.
|
||||
See
|
||||
.BR ci (1)
|
||||
for details.
|
||||
.SH COMPATIBILITY
|
||||
The
|
||||
.BI \-b rev
|
||||
option generates an \*r file that cannot be parsed by \*r version 3 or earlier.
|
||||
.PP
|
||||
The
|
||||
.BI \-k subst
|
||||
options (except
|
||||
.BR \-kkv )
|
||||
generate an \*r file that cannot be parsed by \*r version 4 or earlier.
|
||||
.PP
|
||||
Use
|
||||
.BI "rcs \-V" n
|
||||
to make an \*r file acceptable to \*r version
|
||||
.I n
|
||||
by discarding information that would confuse version
|
||||
.IR n .
|
||||
.PP
|
||||
\*r version 5.5 and earlier does not support the
|
||||
.B \-x
|
||||
option, and requires a
|
||||
.B ,v
|
||||
suffix on an \*r pathname.
|
||||
.SH FILES
|
||||
.B rcs
|
||||
accesses files much as
|
||||
.BR ci (1)
|
||||
does,
|
||||
except that it uses the effective user for all accesses,
|
||||
it does not write the working file or its directory,
|
||||
and it does not even read the working file unless a revision number of
|
||||
.B $
|
||||
is specified.
|
||||
.SH ENVIRONMENT
|
||||
.TP
|
||||
.B \s-1RCSINIT\s0
|
||||
options prepended to the argument list, separated by spaces.
|
||||
See
|
||||
.BR ci (1)
|
||||
for details.
|
||||
.SH DIAGNOSTICS
|
||||
The \*r pathname and the revisions outdated are written to
|
||||
the diagnostic output.
|
||||
The exit status is zero if and only if all operations were successful.
|
||||
.SH IDENTIFICATION
|
||||
Author: Walter F. Tichy.
|
||||
.br
|
||||
Revision Number: \*(Rv; Release Date: \*(Dt.
|
||||
.br
|
||||
Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
|
||||
.br
|
||||
Copyright \(co 1990, 1991 by Paul Eggert.
|
||||
.SH "SEE ALSO"
|
||||
co(1), ci(1), ident(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1),
|
||||
rcsfile(5)
|
||||
.br
|
||||
Walter F. Tichy,
|
||||
\*r\*-A System for Version Control,
|
||||
.I "Software\*-Practice & Experience"
|
||||
.BR 15 ,
|
||||
7 (July 1985), 637-654.
|
||||
.SH BUGS
|
||||
The separator for revision ranges in the
|
||||
.B \-o
|
||||
option used to be
|
||||
.B \-
|
||||
instead of
|
||||
.BR : ,
|
||||
but this leads to confusion when symbolic names contain
|
||||
.BR \- .
|
||||
For backwards compatibility
|
||||
.B "rcs \-o"
|
||||
still supports the old
|
||||
.B \-
|
||||
separator, but it warns about this obsolete use.
|
||||
.PP
|
||||
Symbolic names need not refer to existing revisions or branches.
|
||||
For example, the
|
||||
.B \-o
|
||||
option does not remove symbolic names for the outdated revisions; you must use
|
||||
.B \-n
|
||||
to remove the names.
|
||||
.br
|
||||
1554
gnu/usr.bin/rcs/rcs/rcs.c
Normal file
1554
gnu/usr.bin/rcs/rcs/rcs.c
Normal file
File diff suppressed because it is too large
Load diff
224
gnu/usr.bin/rcs/rcs/rcsfile.5
Normal file
224
gnu/usr.bin/rcs/rcs/rcsfile.5
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
.de Id
|
||||
.ds Rv \\$3
|
||||
.ds Dt \\$4
|
||||
..
|
||||
.Id $Id: rcsfile.5,v 5.1 1991/08/19 03:13:55 eggert Exp $
|
||||
.ds r \s-1RCS\s0
|
||||
.if n .ds - \%--
|
||||
.if t .ds - \(em
|
||||
.TH RCSFILE 5 \*(Dt GNU
|
||||
.SH NAME
|
||||
rcsfile \- format of RCS file
|
||||
.SH DESCRIPTION
|
||||
An \*r file's
|
||||
contents are described by the grammar
|
||||
below.
|
||||
.PP
|
||||
The text is free format: space, backspace, tab, newline, vertical
|
||||
tab, form feed, and carriage return (collectively,
|
||||
.IR "white space")
|
||||
have no significance except in strings.
|
||||
However, an \*r file must end in a newline character.
|
||||
.PP
|
||||
Strings are enclosed by
|
||||
.BR @ .
|
||||
If a string contains a
|
||||
.BR @ ,
|
||||
it must be doubled;
|
||||
otherwise, strings may contain arbitrary binary data.
|
||||
.PP
|
||||
The meta syntax uses the following conventions: `|' (bar) separates
|
||||
alternatives; `{' and `}' enclose optional phrases; `{' and `}*' enclose
|
||||
phrases that may be repeated zero or more times;
|
||||
`{' and '}+' enclose phrases that must appear at least once and may be
|
||||
repeated;
|
||||
Terminal symbols are in
|
||||
.BR boldface ;
|
||||
nonterminal symbols are in
|
||||
.IR italics .
|
||||
.LP
|
||||
.nr x \w'\f3branches\fP'
|
||||
.nr y \w'{ \f3comment\fP'
|
||||
.if \nx<\ny .nr x \ny
|
||||
.nr y \w'\f3{ branch\fP'
|
||||
.if \nx<\ny .nr x \ny
|
||||
.ta \w'\f2deltatext\fP 'u +\w'::= 'u +\nxu+\w' 'u
|
||||
.fc ~
|
||||
.nf
|
||||
\f2rcstext\fP ::= \f2admin\fP {\f2delta\fP}* \f2desc\fP {\f2deltatext\fP}*
|
||||
.LP
|
||||
\f2admin\fP ::= \f3head\fP {\f2num\fP}\f3;\fP
|
||||
{ \f3branch\fP {\f2num\fP}\f3;\fP }
|
||||
\f3access\fP {\f2id\fP}*\f3;\fP
|
||||
\f3symbols\fP {\f2id\fP \f3:\fP \f2num\fP}*\f3;\fP
|
||||
\f3locks\fP {\f2id\fP \f3:\fP \f2num\fP}*\f3;\fP {\f3strict ;\fP}
|
||||
{ \f3comment\fP {\f2string\fP}\f3;\fP }
|
||||
{ \f3expand\fP {\f2string\fP}\f3;\fP }
|
||||
{ \f2newphrase\fP }*
|
||||
.LP
|
||||
\f2delta\fP ::= \f2num\fP
|
||||
\f3date\fP \f2num\fP\f3;\fP
|
||||
\f3author\fP \f2id\fP\f3;\fP
|
||||
\f3state\fP {\f2id\fP}\f3;\fP
|
||||
\f3branches\fP {\f2num\fP}*\f3;\fP
|
||||
\f3next\fP {\f2num\fP}\f3;\fP
|
||||
{ \f2newphrase\fP }*
|
||||
.LP
|
||||
\f2desc\fP ::= \f3desc\fP \f2string\fP
|
||||
.LP
|
||||
\f2deltatext\fP ::= \f2num\fP
|
||||
\f3log\fP \f2string\fP
|
||||
{ \f2newphrase\fP }*
|
||||
\f3text\fP \f2string\fP
|
||||
.LP
|
||||
\f2num\fP ::= {\f2digit\fP{\f3.\fP}}+
|
||||
.LP
|
||||
\f2digit\fP ::= \f30\fP | \f31\fP | .\|.\|. | \f39\fP
|
||||
.LP
|
||||
\f2id\fP ::= \f2letter\fP{\f2idchar\fP}*
|
||||
.LP
|
||||
\f2letter\fP ::= any letter
|
||||
.LP
|
||||
\f2idchar\fP ::= any visible graphic character except \f2special\fP
|
||||
.LP
|
||||
\f2special\fP ::= \f3$\fP | \f3,\fP | \f3.\fP | \f3:\fP | \f3;\fP | \f3@\fP
|
||||
.LP
|
||||
\f2string\fP ::= \f3@\fP{any character, with \f3@\fP doubled}*\f3@\fP
|
||||
.LP
|
||||
\f2newphrase\fP ::= \f2id\fP \f2word\fP* \f3;\fP
|
||||
.LP
|
||||
\f2word\fP ::= \f2id\fP | \f2num\fP | \f2string\fP | \f3:\fP
|
||||
.fi
|
||||
.PP
|
||||
Identifiers are case sensitive. Keywords are in lower case only.
|
||||
The sets of keywords and identifiers may overlap.
|
||||
In most environments RCS uses the ISO 8859/1 encoding:
|
||||
letters are octal codes 101\-132, 141\-172, 300\-326, 330\-366 and 370-377,
|
||||
visible graphic characters are codes 041\-176 and 240\-377,
|
||||
and white space characters are codes 010\-015 and 040.
|
||||
.PP
|
||||
The
|
||||
.I newphrase
|
||||
productions in the grammar are reserved for future extensions
|
||||
to the format of \*r files.
|
||||
No
|
||||
.I newphrase
|
||||
will begin with any keyword already in use.
|
||||
.PP
|
||||
The
|
||||
.I delta
|
||||
nodes form a tree. All nodes whose numbers
|
||||
consist of a single pair
|
||||
(e.g., 2.3, 2.1, 1.3, etc.)
|
||||
are on the trunk, and are linked through the
|
||||
.B next
|
||||
field in order of decreasing numbers.
|
||||
The
|
||||
.B head
|
||||
field in the
|
||||
.I admin
|
||||
node points to the head of that sequence (i.e., contains
|
||||
the highest pair).
|
||||
The
|
||||
.B branch
|
||||
node in the admin node indicates the default
|
||||
branch (or revision) for most \*r operations.
|
||||
If empty, the default
|
||||
branch is the highest branch on the trunk.
|
||||
.PP
|
||||
All
|
||||
.I delta
|
||||
nodes whose numbers consist of
|
||||
.RI 2 n
|
||||
fields
|
||||
.RI ( n >=2)
|
||||
(e.g., 3.1.1.1, 2.1.2.2, etc.)
|
||||
are linked as follows.
|
||||
All nodes whose first
|
||||
.RI 2 n \-1
|
||||
number fields are identical are linked through the
|
||||
.B next
|
||||
field in order of increasing numbers.
|
||||
For each such sequence,
|
||||
the
|
||||
.I delta
|
||||
node whose number is identical to the first
|
||||
.RI 2 n \-2
|
||||
number fields of the deltas on that sequence is called the branchpoint.
|
||||
The
|
||||
.B branches
|
||||
field of a node contains a list of the
|
||||
numbers of the first nodes of all sequences for which it is a branchpoint.
|
||||
This list is ordered in increasing numbers.
|
||||
.LP
|
||||
.nf
|
||||
.vs 12
|
||||
.ne 38
|
||||
Example:
|
||||
.if t .in +0.5i
|
||||
.cs 1 20
|
||||
.eo
|
||||
|
||||
Head
|
||||
|
|
||||
|
|
||||
v / \
|
||||
--------- / \
|
||||
/ \ / \ | | / \ / \
|
||||
/ \ / \ | 2.1 | / \ / \
|
||||
/ \ / \ | | / \ / \
|
||||
/1.2.1.3\ /1.3.1.1\ | | /1.2.2.2\ /1.2.2.1.1.1\
|
||||
--------- --------- --------- --------- -------------
|
||||
^ ^ | ^ ^
|
||||
| | | | |
|
||||
| | v | |
|
||||
/ \ | --------- / \ |
|
||||
/ \ | \ 1.3 / / \ |
|
||||
/ \ ---------\ / / \-----------
|
||||
/1.2.1.1\ \ / /1.2.2.1\
|
||||
--------- \ / ---------
|
||||
^ | ^
|
||||
| | |
|
||||
| v |
|
||||
| --------- |
|
||||
| \ 1.2 / |
|
||||
----------------------\ /---------
|
||||
\ /
|
||||
\ /
|
||||
|
|
||||
|
|
||||
v
|
||||
---------
|
||||
\ 1.1 /
|
||||
\ /
|
||||
\ /
|
||||
\ /
|
||||
|
||||
.ec
|
||||
.if t .in
|
||||
.cs 1
|
||||
.ce
|
||||
Fig. 1: A revision tree
|
||||
.vs
|
||||
.fi
|
||||
.PP
|
||||
.SH IDENTIFICATION
|
||||
.de VL
|
||||
\\$2
|
||||
..
|
||||
Author: Walter F. Tichy,
|
||||
Purdue University, West Lafayette, IN, 47907.
|
||||
.br
|
||||
Revision Number: \*(Rv; Release Date: \*(Dt.
|
||||
.br
|
||||
Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
|
||||
.br
|
||||
Copyright \(co 1990, 1991 by Paul Eggert.
|
||||
.SH SEE ALSO
|
||||
ci(1), co(1), ident(1), rcs(1), rcsdiff(1), rcsmerge(1), rlog(1),
|
||||
.br
|
||||
Walter F. Tichy,
|
||||
\*r\*-A System for Version Control,
|
||||
.I "Software\*-Practice & Experience"
|
||||
.BR 15 ,
|
||||
7 (July 1985), 637-654.
|
||||
292
gnu/usr.bin/rcs/rcs/rcsintro.1
Normal file
292
gnu/usr.bin/rcs/rcs/rcsintro.1
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
.de Id
|
||||
.ds Rv \\$3
|
||||
.ds Dt \\$4
|
||||
..
|
||||
.Id $Id: rcsintro.1,v 5.1 1991/04/21 12:00:46 eggert Exp $
|
||||
.ds r \&\s-1RCS\s0
|
||||
.if n .ds - \%--
|
||||
.if t .ds - \(em
|
||||
.am SS
|
||||
.LP
|
||||
..
|
||||
.TH RCSINTRO 1 \*(Dt GNU
|
||||
.SH NAME
|
||||
rcsintro \- introduction to RCS commands
|
||||
.SH DESCRIPTION
|
||||
The Revision Control System (\*r) manages multiple revisions of files.
|
||||
\*r automates the storing, retrieval, logging, identification, and merging
|
||||
of revisions. \*r is useful for text that is revised frequently, for example
|
||||
programs, documentation, graphics, papers, and form letters.
|
||||
.PP
|
||||
The basic user interface is extremely simple. The novice only needs
|
||||
to learn two commands:
|
||||
.BR ci (1)
|
||||
and
|
||||
.BR co (1).
|
||||
.BR ci ,
|
||||
short for \*(lqcheck in\*(rq, deposits the contents of a
|
||||
file into an archival file called an \*r file. An \*r file
|
||||
contains all revisions of a particular file.
|
||||
.BR co ,
|
||||
short for \*(lqcheck out\*(rq, retrieves revisions from an \*r file.
|
||||
.SS "Functions of \*r"
|
||||
.IP \(bu
|
||||
Store and retrieve multiple revisions of text. \*r saves all old
|
||||
revisions in a space efficient way.
|
||||
Changes no longer destroy the original, because the
|
||||
previous revisions remain accessible. Revisions can be retrieved according to
|
||||
ranges of revision numbers, symbolic names, dates, authors, and
|
||||
states.
|
||||
.IP \(bu
|
||||
Maintain a complete history of changes.
|
||||
\*r logs all changes automatically.
|
||||
Besides the text of each revision, \*r stores the author, the date and time of
|
||||
check-in, and a log message summarizing the change.
|
||||
The logging makes it easy to find out
|
||||
what happened to a module, without having to compare
|
||||
source listings or having to track down colleagues.
|
||||
.IP \(bu
|
||||
Resolve access conflicts. When two or more programmers wish to
|
||||
modify the same revision, \*r alerts the programmers and prevents one
|
||||
modification from corrupting the other.
|
||||
.IP \(bu
|
||||
Maintain a tree of revisions. \*r can maintain separate lines of development
|
||||
for each module. It stores a tree structure that represents the
|
||||
ancestral relationships among revisions.
|
||||
.IP \(bu
|
||||
Merge revisions and resolve conflicts.
|
||||
Two separate lines of development of a module can be coalesced by merging.
|
||||
If the revisions to be merged affect the same sections of code, \*r alerts the
|
||||
user about the overlapping changes.
|
||||
.IP \(bu
|
||||
Control releases and configurations.
|
||||
Revisions can be assigned symbolic names
|
||||
and marked as released, stable, experimental, etc.
|
||||
With these facilities, configurations of modules can be
|
||||
described simply and directly.
|
||||
.IP \(bu
|
||||
Automatically identify each revision with name, revision number,
|
||||
creation time, author, etc.
|
||||
The identification is like a stamp that can be embedded at an appropriate place
|
||||
in the text of a revision.
|
||||
The identification makes it simple to determine which
|
||||
revisions of which modules make up a given configuration.
|
||||
.IP \(bu
|
||||
Minimize secondary storage. \*r needs little extra space for
|
||||
the revisions (only the differences). If intermediate revisions are
|
||||
deleted, the corresponding deltas are compressed accordingly.
|
||||
.SS "Getting Started with \*r"
|
||||
Suppose you have a file
|
||||
.B f.c
|
||||
that you wish to put under control of \*r.
|
||||
If you have not already done so, make an \*r directory with the command
|
||||
.IP
|
||||
.B "mkdir RCS"
|
||||
.LP
|
||||
Then invoke the check-in command
|
||||
.IP
|
||||
.B "ci f.c"
|
||||
.LP
|
||||
This command creates an \*r file in the
|
||||
.B RCS
|
||||
directory,
|
||||
stores
|
||||
.B f.c
|
||||
into it as revision 1.1, and
|
||||
deletes
|
||||
.BR f.c .
|
||||
It also asks you for a description. The description
|
||||
should be a synopsis of the contents of the file. All later check-in
|
||||
commands will ask you for a log entry, which should summarize the
|
||||
changes that you made.
|
||||
.PP
|
||||
Files in the \*r directory are called \*r files;
|
||||
the others are called working files.
|
||||
To get back the working file
|
||||
.B f.c
|
||||
in the previous example, use the check-out
|
||||
command
|
||||
.IP
|
||||
.B "co f.c"
|
||||
.LP
|
||||
This command extracts the latest revision from the \*r file
|
||||
and writes
|
||||
it into
|
||||
.BR f.c .
|
||||
If you want to edit
|
||||
.BR f.c ,
|
||||
you must lock it as you check it out with the command
|
||||
.IP
|
||||
.B "co \-l f.c"
|
||||
.LP
|
||||
You can now edit
|
||||
.BR f.c .
|
||||
.PP
|
||||
Suppose after some editing you want to know what changes that you have made.
|
||||
The command
|
||||
.IP
|
||||
.B "rcsdiff f.c"
|
||||
.LP
|
||||
tells you the difference between the most recently checked-in version
|
||||
and the working file.
|
||||
You can check the file back in by invoking
|
||||
.IP
|
||||
.B "ci f.c"
|
||||
.LP
|
||||
This increments the revision number properly.
|
||||
.PP
|
||||
If
|
||||
.B ci
|
||||
complains with the message
|
||||
.IP
|
||||
.BI "ci error: no lock set by " "your name"
|
||||
.LP
|
||||
then you have tried to check in a file even though you did not
|
||||
lock it when you checked it out.
|
||||
Of course, it is too late now to do the check-out with locking, because
|
||||
another check-out would
|
||||
overwrite your modifications. Instead, invoke
|
||||
.IP
|
||||
.B "rcs \-l f.c"
|
||||
.LP
|
||||
This command will lock the latest revision for you, unless somebody
|
||||
else got ahead of you already. In this case, you'll have to negotiate with
|
||||
that person.
|
||||
.PP
|
||||
Locking assures that you, and only you, can check in the next update, and
|
||||
avoids nasty problems if several people work on the same file.
|
||||
Even if a revision is locked, it can still be checked out for
|
||||
reading, compiling, etc. All that locking
|
||||
prevents is a
|
||||
.I "check-in"
|
||||
by anybody but the locker.
|
||||
.PP
|
||||
If your \*r file is private, i.e., if you are the only person who is going
|
||||
to deposit revisions into it, strict locking is not needed and you
|
||||
can turn it off.
|
||||
If strict locking is turned off,
|
||||
the owner of the \*r file need not have a lock for check-in; all others
|
||||
still do. Turning strict locking off and on is done with the commands
|
||||
.IP
|
||||
.BR "rcs \-U f.c" " and " "rcs \-L f.c"
|
||||
.LP
|
||||
If you don't want to clutter your working directory with \*r files, create
|
||||
a subdirectory called
|
||||
.B RCS
|
||||
in your working directory, and move all your \*r
|
||||
files there. \*r commands will look first into that directory to find
|
||||
needed files. All the commands discussed above will still work, without any
|
||||
modification.
|
||||
(Actually, pairs of \*r and working files can be specified in three ways:
|
||||
(a) both are given, (b) only the working file is given, (c) only the
|
||||
\*r file is given. Both \*r and working files may have arbitrary path prefixes;
|
||||
\*r commands pair them up intelligently.)
|
||||
.PP
|
||||
To avoid the deletion of the working file during check-in (in case you want to
|
||||
continue editing or compiling), invoke
|
||||
.IP
|
||||
.BR "ci \-l f.c" " or " "ci \-u f.c"
|
||||
.LP
|
||||
These commands check in
|
||||
.B f.c
|
||||
as usual, but perform an implicit
|
||||
check-out. The first form also locks the checked in revision, the second one
|
||||
doesn't. Thus, these options save you one check-out operation.
|
||||
The first form is useful if you want to continue editing,
|
||||
the second one if you just want to read the file.
|
||||
Both update the identification markers in your working file (see below).
|
||||
.PP
|
||||
You can give
|
||||
.B ci
|
||||
the number you want assigned to a checked in
|
||||
revision. Assume all your revisions were numbered 1.1, 1.2, 1.3, etc.,
|
||||
and you would like to start release 2.
|
||||
The command
|
||||
.IP
|
||||
.BR "ci \-r2 f.c" " or " "ci \-r2.1 f.c"
|
||||
.LP
|
||||
assigns the number 2.1 to the new revision.
|
||||
From then on,
|
||||
.B ci
|
||||
will number the subsequent revisions
|
||||
with 2.2, 2.3, etc. The corresponding
|
||||
.B co
|
||||
commands
|
||||
.IP
|
||||
.BR "co \-r2 f.c" " and " "co \-r2.1 f.c"
|
||||
.PP
|
||||
retrieve the latest revision numbered
|
||||
.RI 2. x
|
||||
and the revision 2.1,
|
||||
respectively.
|
||||
.B co
|
||||
without a revision number selects
|
||||
the latest revision on the
|
||||
.IR trunk ,
|
||||
i.e. the highest
|
||||
revision with a number consisting of two fields. Numbers with more than two
|
||||
fields are needed for branches.
|
||||
For example, to start a branch at revision 1.3, invoke
|
||||
.IP
|
||||
.B "ci \-r1.3.1 f.c"
|
||||
.LP
|
||||
This command starts a branch numbered 1 at revision 1.3, and assigns
|
||||
the number 1.3.1.1 to the new revision. For more information about
|
||||
branches, see
|
||||
.BR rcsfile (5).
|
||||
.SS "Automatic Identification"
|
||||
\*r can put special strings for identification into your source and object
|
||||
code. To obtain such identification, place the marker
|
||||
.IP
|
||||
.B "$\&Id$"
|
||||
.LP
|
||||
into your text, for instance inside a comment.
|
||||
\*r will replace this marker with a string of the form
|
||||
.IP
|
||||
.BI $\&Id: " filename revision date time author state " $
|
||||
.LP
|
||||
With such a marker on the first page of each module, you can
|
||||
always see with which revision you are working.
|
||||
\*r keeps the markers up to date automatically.
|
||||
To propagate the markers into your object code, simply put
|
||||
them into literal character strings. In C, this is done as follows:
|
||||
.IP
|
||||
.ft 3
|
||||
static char rcsid[] = \&"$\&Id$\&";
|
||||
.ft
|
||||
.LP
|
||||
The command
|
||||
.B ident
|
||||
extracts such markers from any file, even object code
|
||||
and dumps.
|
||||
Thus,
|
||||
.B ident
|
||||
lets you find out
|
||||
which revisions of which modules were used in a given program.
|
||||
.PP
|
||||
You may also find it useful to put the marker
|
||||
.B $\&Log$
|
||||
into your text, inside a comment. This marker accumulates
|
||||
the log messages that are requested during check-in.
|
||||
Thus, you can maintain the complete history of your file directly inside it.
|
||||
There are several additional identification markers; see
|
||||
.BR co (1)
|
||||
for
|
||||
details.
|
||||
.SH IDENTIFICATION
|
||||
Author: Walter F. Tichy.
|
||||
.br
|
||||
Revision Number: \*(Rv; Release Date: \*(Dt.
|
||||
.br
|
||||
Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
|
||||
.br
|
||||
Copyright \(co 1990, 1991 by Paul Eggert.
|
||||
.SH "SEE ALSO"
|
||||
ci(1), co(1), ident(1), rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1)
|
||||
.br
|
||||
Walter F. Tichy,
|
||||
\*r\*-A System for Version Control,
|
||||
.I "Software\*-Practice & Experience"
|
||||
.BR 15 ,
|
||||
7 (July 1985), 637-654.
|
||||
.br
|
||||
7
gnu/usr.bin/rcs/rcsclean/Makefile
Normal file
7
gnu/usr.bin/rcs/rcsclean/Makefile
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
PROG= rcsclean
|
||||
|
||||
SRCS= rcsclean.c
|
||||
LDADD= -L${.CURDIR}/../lib/obj -lrcs
|
||||
CFLAGS+= -I${.CURDIR}/../lib
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
177
gnu/usr.bin/rcs/rcsclean/rcsclean.1
Normal file
177
gnu/usr.bin/rcs/rcsclean/rcsclean.1
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
.de Id
|
||||
.ds Rv \\$3
|
||||
.ds Dt \\$4
|
||||
..
|
||||
.Id $Id: rcsclean.1,v 1.8 1991/11/03 01:09:19 eggert Exp $
|
||||
.ds r \&\s-1RCS\s0
|
||||
.if n .ds - \%--
|
||||
.if t .ds - \(em
|
||||
.TH RCSCLEAN 1 \*(Dt GNU
|
||||
.SH NAME
|
||||
rcsclean \- clean up working files
|
||||
.SH SYNOPSIS
|
||||
.B rcsclean
|
||||
.RI [ options "] [ " file " .\|.\|. ]"
|
||||
.SH DESCRIPTION
|
||||
.B rcsclean
|
||||
removes working files that were checked out and never modified.
|
||||
For each
|
||||
.I file
|
||||
given,
|
||||
.B rcsclean
|
||||
compares the working file and a revision in the corresponding
|
||||
\*r file. If it finds a difference, it does nothing.
|
||||
Otherwise, it first unlocks the revision if the
|
||||
.B \-u
|
||||
option is given,
|
||||
and then removes the working file
|
||||
unless the working file is writable and the revision is locked.
|
||||
It logs its actions by outputting the corresponding
|
||||
.B "rcs \-u"
|
||||
and
|
||||
.B "rm \-f"
|
||||
commands on the standard output.
|
||||
.PP
|
||||
If no
|
||||
.I file
|
||||
is given, all working files in the current directory are cleaned.
|
||||
Pathnames matching an \*r suffix denote \*r files;
|
||||
all others denote working files.
|
||||
Names are paired as explained in
|
||||
.BR ci (1).
|
||||
.PP
|
||||
The number of the revision to which the working file is compared
|
||||
may be attached to any of the options
|
||||
.BR \-n ,
|
||||
.BR \-q ,
|
||||
.BR \-r ,
|
||||
or
|
||||
.BR \-u .
|
||||
If no revision number is specified, then if the
|
||||
.B \-u
|
||||
option is given and the caller has one revision locked,
|
||||
.B rcsclean
|
||||
uses that revision; otherwise
|
||||
.B rcsclean
|
||||
uses the latest revision on the default branch, normally the root.
|
||||
.PP
|
||||
.B rcsclean
|
||||
is useful for
|
||||
.B clean
|
||||
targets in Makefiles.
|
||||
See also
|
||||
.BR rcsdiff (1),
|
||||
which prints out the differences,
|
||||
and
|
||||
.BR ci (1),
|
||||
which
|
||||
normally asks whether to check in a file
|
||||
if it was not changed.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BI \-k subst
|
||||
Use
|
||||
.I subst
|
||||
style keyword substitution when retrieving the revision for comparison.
|
||||
See
|
||||
.BR co (1)
|
||||
for details.
|
||||
.TP
|
||||
.BR \-n [\f2rev\fP]
|
||||
Do not actually remove any files or unlock any revisions.
|
||||
Using this option will tell you what
|
||||
.B rcsclean
|
||||
would do without actually doing it.
|
||||
.TP
|
||||
.BR \-q [\f2rev\fP]
|
||||
Do not log the actions taken on standard output.
|
||||
.TP
|
||||
.BR \-r [\f2rev\fP]
|
||||
This option has no effect other than specifying the revision for comparison.
|
||||
.TP
|
||||
.BR \-u [\f2rev\fP]
|
||||
Unlock the revision if it is locked and no difference is found.
|
||||
.TP
|
||||
.BI \-V n
|
||||
Emulate \*r version
|
||||
.IR n .
|
||||
See
|
||||
.BR co (1)
|
||||
for details.
|
||||
.TP
|
||||
.BI \-x "suffixes"
|
||||
Use
|
||||
.I suffixes
|
||||
to characterize \*r files.
|
||||
See
|
||||
.BR ci (1)
|
||||
for details.
|
||||
.SH EXAMPLES
|
||||
.LP
|
||||
.RS
|
||||
.ft 3
|
||||
rcsclean *.c *.h
|
||||
.ft
|
||||
.RE
|
||||
.LP
|
||||
removes all working files ending in
|
||||
.B .c
|
||||
or
|
||||
.B .h
|
||||
that were not changed
|
||||
since their checkout.
|
||||
.LP
|
||||
.RS
|
||||
.ft 3
|
||||
rcsclean
|
||||
.ft
|
||||
.RE
|
||||
.LP
|
||||
removes all working files in the current directory
|
||||
that were not changed since their checkout.
|
||||
.SH FILES
|
||||
.B rcsclean
|
||||
accesses files much as
|
||||
.BR ci (1)
|
||||
does.
|
||||
.SH ENVIRONMENT
|
||||
.TP
|
||||
.B \s-1RCSINIT\s0
|
||||
options prepended to the argument list, separated by spaces.
|
||||
A backslash escapes spaces within an option.
|
||||
The
|
||||
.B \s-1RCSINIT\s0
|
||||
options are prepended to the argument lists of most \*r commands.
|
||||
Useful
|
||||
.B \s-1RCSINIT\s0
|
||||
options include
|
||||
.BR \-q ,
|
||||
.BR \-V ,
|
||||
and
|
||||
.BR \-x .
|
||||
.SH DIAGNOSTICS
|
||||
The exit status is zero if and only if all operations were successful.
|
||||
Missing working files and \*r files are silently ignored.
|
||||
.SH IDENTIFICATION
|
||||
Author: Walter F. Tichy.
|
||||
.br
|
||||
Revision Number: \*(Rv; Release Date: \*(Dt.
|
||||
.br
|
||||
Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
|
||||
.br
|
||||
Copyright \(co 1990, 1991 by Paul Eggert.
|
||||
.SH "SEE ALSO"
|
||||
ci(1), co(1), ident(1), rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1),
|
||||
rcsfile(5)
|
||||
.br
|
||||
Walter F. Tichy,
|
||||
\*r\*-A System for Version Control,
|
||||
.I "Software\*-Practice & Experience"
|
||||
.BR 15 ,
|
||||
7 (July 1985), 637-654.
|
||||
.SH BUGS
|
||||
At least one
|
||||
.I file
|
||||
must be given in older Unix versions that
|
||||
do not provide the needed directory scanning operations.
|
||||
.br
|
||||
297
gnu/usr.bin/rcs/rcsclean/rcsclean.c
Normal file
297
gnu/usr.bin/rcs/rcsclean/rcsclean.c
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
/* rcsclean - clean up working files */
|
||||
|
||||
/* Copyright 1991 by 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, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Report problems and direct all questions to:
|
||||
|
||||
rcs-bugs@cs.purdue.edu
|
||||
|
||||
*/
|
||||
|
||||
#include "rcsbase.h"
|
||||
|
||||
#if has_dirent
|
||||
static int get_directory P((char const*,char***));
|
||||
#endif
|
||||
|
||||
static int unlock P((struct hshentry *));
|
||||
static void cleanup P((void));
|
||||
|
||||
static RILE *workptr;
|
||||
static int exitstatus;
|
||||
|
||||
mainProg(rcscleanId, "rcsclean", "$Id: rcsclean.c,v 5.1 1991/11/03 01:11:44 eggert Exp $")
|
||||
{
|
||||
static char const usage[] =
|
||||
"\nrcsclean: usage: rcsclean [-ksubst] [-{nqru}[rev]] [-Vn] [-xsuffixes] [file ...]";
|
||||
|
||||
static struct buf revision;
|
||||
|
||||
char *a, **newargv;
|
||||
char const *rev, *p;
|
||||
int changelock, expmode, perform, unlocked, unlockflag, waslocked;
|
||||
struct hshentries *deltas;
|
||||
struct hshentry *delta;
|
||||
struct stat workstat;
|
||||
|
||||
setrid();
|
||||
|
||||
expmode = -1;
|
||||
rev = nil;
|
||||
suffixes = X_DEFAULT;
|
||||
perform = true;
|
||||
unlockflag = false;
|
||||
|
||||
argc = getRCSINIT(argc, argv, &newargv);
|
||||
argv = newargv;
|
||||
for (;;) {
|
||||
if (--argc <= 0) {
|
||||
# if has_dirent
|
||||
argc = get_directory(".", &newargv);
|
||||
argv = newargv;
|
||||
break;
|
||||
# else
|
||||
faterror("no file names specified");
|
||||
# endif
|
||||
}
|
||||
a = *++argv;
|
||||
if (*a++ != '-')
|
||||
break;
|
||||
switch (*a++) {
|
||||
case 'k':
|
||||
if (0 <= expmode)
|
||||
redefined('k');
|
||||
if ((expmode = str2expmode(a)) < 0)
|
||||
goto unknown;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
perform = false;
|
||||
goto handle_revision;
|
||||
|
||||
case 'q':
|
||||
quietflag = true;
|
||||
/* fall into */
|
||||
case 'r':
|
||||
handle_revision:
|
||||
if (*a) {
|
||||
if (rev)
|
||||
warn("redefinition of revision number");
|
||||
rev = a;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
unlockflag = true;
|
||||
goto handle_revision;
|
||||
|
||||
case 'V':
|
||||
setRCSversion(*argv);
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
suffixes = a;
|
||||
break;
|
||||
|
||||
default:
|
||||
unknown:
|
||||
faterror("unknown option: %s%s", *argv, usage);
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
ffree();
|
||||
|
||||
if (!(
|
||||
0 < pairfilenames(
|
||||
argc, argv,
|
||||
unlockflag&perform ? rcswriteopen : rcsreadopen,
|
||||
true, true
|
||||
) &&
|
||||
(workptr = Iopen(workfilename,FOPEN_R_WORK,&workstat))
|
||||
))
|
||||
continue;
|
||||
|
||||
gettree();
|
||||
|
||||
p = 0;
|
||||
if (rev) {
|
||||
if (!fexpandsym(rev, &revision, workptr))
|
||||
continue;
|
||||
p = revision.string;
|
||||
} else if (Head)
|
||||
switch (unlockflag ? findlock(false,&delta) : 0) {
|
||||
default:
|
||||
continue;
|
||||
case 0:
|
||||
p = Dbranch ? Dbranch : "";
|
||||
break;
|
||||
case 1:
|
||||
p = delta->num;
|
||||
break;
|
||||
}
|
||||
delta = 0;
|
||||
deltas = 0; /* Keep lint happy. */
|
||||
if (p && !(delta = genrevs(p,(char*)0,(char*)0,(char*)0,&deltas)))
|
||||
continue;
|
||||
|
||||
waslocked = delta && delta->lockedby;
|
||||
locker_expansion = unlock(delta);
|
||||
unlocked = locker_expansion & unlockflag;
|
||||
changelock = unlocked & perform;
|
||||
if (unlocked<waslocked && workstat.st_mode&(S_IWUSR|S_IWGRP|S_IWOTH))
|
||||
continue;
|
||||
|
||||
if (!dorewrite(unlockflag, changelock))
|
||||
continue;
|
||||
|
||||
if (0 <= expmode)
|
||||
Expand = expmode;
|
||||
else if (
|
||||
waslocked &&
|
||||
Expand == KEYVAL_EXPAND &&
|
||||
WORKMODE(RCSstat.st_mode,true) == workstat.st_mode
|
||||
)
|
||||
Expand = KEYVALLOCK_EXPAND;
|
||||
|
||||
getdesc(false);
|
||||
|
||||
if (
|
||||
!delta ? workstat.st_size!=0 :
|
||||
0 < rcsfcmp(
|
||||
workptr, &workstat,
|
||||
buildrevision(deltas, delta, (FILE*)0, false),
|
||||
delta
|
||||
)
|
||||
)
|
||||
continue;
|
||||
|
||||
if (quietflag < unlocked)
|
||||
aprintf(stdout, "rcs -u%s %s\n", delta->num, RCSfilename);
|
||||
|
||||
if_advise_access(changelock && deltas->first != delta,
|
||||
finptr, MADV_SEQUENTIAL
|
||||
);
|
||||
if (!donerewrite(changelock))
|
||||
continue;
|
||||
|
||||
if (!quietflag)
|
||||
aprintf(stdout, "rm -f %s\n", workfilename);
|
||||
Izclose(&workptr);
|
||||
if (perform && un_link(workfilename) != 0)
|
||||
eerror(workfilename);
|
||||
|
||||
} while (cleanup(), ++argv, 0 < --argc);
|
||||
|
||||
tempunlink();
|
||||
if (!quietflag)
|
||||
Ofclose(stdout);
|
||||
exitmain(exitstatus);
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup()
|
||||
{
|
||||
if (nerror) exitstatus = EXIT_FAILURE;
|
||||
Izclose(&finptr);
|
||||
Izclose(&workptr);
|
||||
Ozclose(&fcopy);
|
||||
Ozclose(&frewrite);
|
||||
dirtempunlink();
|
||||
}
|
||||
|
||||
#if lint
|
||||
# define exiterr rcscleanExit
|
||||
#endif
|
||||
exiting void
|
||||
exiterr()
|
||||
{
|
||||
dirtempunlink();
|
||||
tempunlink();
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static int
|
||||
unlock(delta)
|
||||
struct hshentry *delta;
|
||||
{
|
||||
register struct lock **al, *l;
|
||||
|
||||
if (delta && delta->lockedby && strcmp(getcaller(),delta->lockedby)==0)
|
||||
for (al = &Locks; (l = *al); al = &l->nextlock)
|
||||
if (l->delta == delta) {
|
||||
*al = l->nextlock;
|
||||
delta->lockedby = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if has_dirent
|
||||
static int
|
||||
get_directory(dirname, aargv)
|
||||
char const *dirname;
|
||||
char ***aargv;
|
||||
/*
|
||||
* Put a vector of all DIRNAME's directory entries names into *AARGV.
|
||||
* Ignore names of RCS files.
|
||||
* Yield the number of entries found. Terminate the vector with 0.
|
||||
* Allocate the storage for the vector and entry names.
|
||||
* Do not sort the names. Do not include '.' and '..'.
|
||||
*/
|
||||
{
|
||||
int i, entries = 0, entries_max = 64;
|
||||
size_t chars = 0, chars_max = 1024;
|
||||
size_t *offset = tnalloc(size_t, entries_max);
|
||||
char *a = tnalloc(char, chars_max), **p;
|
||||
DIR *d;
|
||||
struct dirent *e;
|
||||
|
||||
if (!(d = opendir(dirname)))
|
||||
efaterror(dirname);
|
||||
while ((errno = 0, e = readdir(d))) {
|
||||
char const *en = e->d_name;
|
||||
size_t s = strlen(en) + 1;
|
||||
if (en[0]=='.' && (!en[1] || en[1]=='.' && !en[2]))
|
||||
continue;
|
||||
if (rcssuffix(en))
|
||||
continue;
|
||||
while (chars_max < s + chars)
|
||||
a = trealloc(char, a, chars_max<<=1);
|
||||
if (entries == entries_max)
|
||||
offset = trealloc(size_t, offset, entries_max<<=1);
|
||||
offset[entries++] = chars;
|
||||
VOID strcpy(a+chars, en);
|
||||
chars += s;
|
||||
}
|
||||
if (errno || closedir(d) != 0)
|
||||
efaterror(dirname);
|
||||
if (chars)
|
||||
a = trealloc(char, a, chars);
|
||||
else
|
||||
tfree(a);
|
||||
*aargv = p = tnalloc(char*, entries+1);
|
||||
for (i=0; i<entries; i++)
|
||||
*p++ = a + offset[i];
|
||||
*p = 0;
|
||||
tfree(offset);
|
||||
return entries;
|
||||
}
|
||||
#endif
|
||||
7
gnu/usr.bin/rcs/rcsdiff/Makefile
Normal file
7
gnu/usr.bin/rcs/rcsdiff/Makefile
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
PROG= rcsdiff
|
||||
|
||||
SRCS= rcsdiff.c
|
||||
LDADD= -L${.CURDIR}/../lib/obj -lrcs
|
||||
CFLAGS+= -I${.CURDIR}/../lib
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
152
gnu/usr.bin/rcs/rcsdiff/rcsdiff.1
Normal file
152
gnu/usr.bin/rcs/rcsdiff/rcsdiff.1
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
.de Id
|
||||
.ds Rv \\$3
|
||||
.ds Dt \\$4
|
||||
..
|
||||
.Id $Id: rcsdiff.1,v 5.3 1991/04/21 12:00:46 eggert Exp $
|
||||
.ds r \&\s-1RCS\s0
|
||||
.if n .ds - \%--
|
||||
.if t .ds - \(em
|
||||
.TH RCSDIFF 1 \*(Dt GNU
|
||||
.SH NAME
|
||||
rcsdiff \- compare RCS revisions
|
||||
.SH SYNOPSIS
|
||||
.B rcsdiff
|
||||
[
|
||||
.BI \-k subst
|
||||
] [
|
||||
.B \-q
|
||||
] [
|
||||
.BI \-r rev1
|
||||
[
|
||||
.BI \-r rev2
|
||||
] ] [
|
||||
.BI \-V n
|
||||
] [
|
||||
.BI \-x suffixes
|
||||
] [
|
||||
.I "diff options"
|
||||
]
|
||||
.I "file .\|.\|."
|
||||
.SH DESCRIPTION
|
||||
.B rcsdiff
|
||||
runs
|
||||
.BR diff (1)
|
||||
to compare two revisions of each \*r file given.
|
||||
.PP
|
||||
Pathnames matching an \*r suffix denote \*r files;
|
||||
all others denote working files.
|
||||
Names are paired as explained in
|
||||
.BR ci (1).
|
||||
.PP
|
||||
The option
|
||||
.B \-q
|
||||
suppresses diagnostic output.
|
||||
Zero, one, or two revisions may be specified with
|
||||
.BR \-r .
|
||||
The option
|
||||
.BI \-k subst
|
||||
affects keyword substitution when extracting
|
||||
revisions, as described in
|
||||
.BR co (1);
|
||||
for example,
|
||||
.B "\-kk\ \-r1.1\ \-r1.2"
|
||||
ignores differences in keyword values when comparing revisions
|
||||
.B 1.1
|
||||
and
|
||||
.BR 1.2 .
|
||||
To avoid excess output from locker name substitution,
|
||||
.B \-kkvl
|
||||
is assumed if (1) at most one revision option is given,
|
||||
(2) no
|
||||
.B \-k
|
||||
option is given, (3)
|
||||
.B \-kkv
|
||||
is the default keyword substitution, and
|
||||
(4) the working file's mode would be produced by
|
||||
.BR "co\ \-l".
|
||||
See
|
||||
.BR co (1)
|
||||
for details
|
||||
about
|
||||
.B \-V
|
||||
and
|
||||
.BR \-x .
|
||||
Otherwise, all options of
|
||||
.BR diff (1)
|
||||
that apply to regular files are accepted, with the same meaning as for
|
||||
.BR diff .
|
||||
.PP
|
||||
If both
|
||||
.I rev1
|
||||
and
|
||||
.I rev2
|
||||
are omitted,
|
||||
.B rcsdiff
|
||||
compares the latest revision on the
|
||||
default branch (by default the trunk)
|
||||
with the contents of the corresponding working file. This is useful
|
||||
for determining what you changed since the last checkin.
|
||||
.PP
|
||||
If
|
||||
.I rev1
|
||||
is given, but
|
||||
.I rev2
|
||||
is omitted,
|
||||
.B rcsdiff
|
||||
compares revision
|
||||
.I rev1
|
||||
of the \*r file with
|
||||
the contents of the corresponding working file.
|
||||
.PP
|
||||
If both
|
||||
.I rev1
|
||||
and
|
||||
.I rev2
|
||||
are given,
|
||||
.B rcsdiff
|
||||
compares revisions
|
||||
.I rev1
|
||||
and
|
||||
.I rev2
|
||||
of the \*r file.
|
||||
.PP
|
||||
Both
|
||||
.I rev1
|
||||
and
|
||||
.I rev2
|
||||
may be given numerically or symbolically.
|
||||
.SH EXAMPLE
|
||||
The command
|
||||
.LP
|
||||
.B " rcsdiff f.c"
|
||||
.LP
|
||||
compares the latest revision on the default branch of the \*r file
|
||||
to the contents of the working file
|
||||
.BR f.c .
|
||||
.SH ENVIRONMENT
|
||||
.TP
|
||||
.B \s-1RCSINIT\s0
|
||||
options prepended to the argument list, separated by spaces.
|
||||
See
|
||||
.BR ci (1)
|
||||
for details.
|
||||
.SH DIAGNOSTICS
|
||||
Exit status is 0 for no differences during any comparison,
|
||||
1 for some differences, 2 for trouble.
|
||||
.SH IDENTIFICATION
|
||||
Author: Walter F. Tichy.
|
||||
.br
|
||||
Revision Number: \*(Rv; Release Date: \*(Dt.
|
||||
.br
|
||||
Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
|
||||
.br
|
||||
Copyright \(co 1990, 1991 by Paul Eggert.
|
||||
.SH "SEE ALSO"
|
||||
ci(1), co(1), diff(1), ident(1), rcs(1), rcsintro(1), rcsmerge(1), rlog(1)
|
||||
.br
|
||||
Walter F. Tichy,
|
||||
\*r\*-A System for Version Control,
|
||||
.I "Software\*-Practice & Experience"
|
||||
.BR 15 ,
|
||||
7 (July 1985), 637-654.
|
||||
.br
|
||||
422
gnu/usr.bin/rcs/rcsdiff/rcsdiff.c
Normal file
422
gnu/usr.bin/rcs/rcsdiff/rcsdiff.c
Normal file
|
|
@ -0,0 +1,422 @@
|
|||
/*
|
||||
* RCS rcsdiff operation
|
||||
*/
|
||||
/*****************************************************************************
|
||||
* generate difference between RCS revisions
|
||||
*****************************************************************************
|
||||
*/
|
||||
|
||||
/* Copyright (C) 1982, 1988, 1989 Walter Tichy
|
||||
Copyright 1990, 1991 by 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, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Report problems and direct all questions to:
|
||||
|
||||
rcs-bugs@cs.purdue.edu
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* $Log: rcsdiff.c,v $
|
||||
* Revision 5.10 1991/10/07 17:32:46 eggert
|
||||
* Remove lint.
|
||||
*
|
||||
* Revision 5.9 1991/08/19 03:13:55 eggert
|
||||
* Add RCSINIT, -r$. Tune.
|
||||
*
|
||||
* Revision 5.8 1991/04/21 11:58:21 eggert
|
||||
* Add -x, RCSINIT, MS-DOS support.
|
||||
*
|
||||
* Revision 5.7 1990/12/13 06:54:07 eggert
|
||||
* GNU diff 1.15 has -u.
|
||||
*
|
||||
* Revision 5.6 1990/11/01 05:03:39 eggert
|
||||
* Remove unneeded setid check.
|
||||
*
|
||||
* Revision 5.5 1990/10/04 06:30:19 eggert
|
||||
* Accumulate exit status across files.
|
||||
*
|
||||
* Revision 5.4 1990/09/27 01:31:43 eggert
|
||||
* Yield 1, not EXIT_FAILURE, when diffs are found.
|
||||
*
|
||||
* Revision 5.3 1990/09/11 02:41:11 eggert
|
||||
* Simplify -kkvl test.
|
||||
*
|
||||
* Revision 5.2 1990/09/04 17:07:19 eggert
|
||||
* Diff's argv was too small by 1.
|
||||
*
|
||||
* Revision 5.1 1990/08/29 07:13:55 eggert
|
||||
* Add -kkvl.
|
||||
*
|
||||
* Revision 5.0 1990/08/22 08:12:46 eggert
|
||||
* Add -k, -V. Don't use access(). Add setuid support.
|
||||
* Remove compile-time limits; use malloc instead.
|
||||
* Don't pass arguments with leading '+' to diff; GNU DIFF treats them as options.
|
||||
* Add GNU diff's flags. Make lock and temp files faster and safer.
|
||||
* Ansify and Posixate.
|
||||
*
|
||||
* Revision 4.6 89/05/01 15:12:27 narten
|
||||
* changed copyright header to reflect current distribution rules
|
||||
*
|
||||
* Revision 4.5 88/08/09 19:12:41 eggert
|
||||
* Use execv(), not system(); yield exit status like diff(1)s; allow cc -R.
|
||||
*
|
||||
* Revision 4.4 87/12/18 11:37:46 narten
|
||||
* changes Jay Lepreau made in the 4.3 BSD version, to add support for
|
||||
* "-i", "-w", and "-t" flags and to permit flags to be bundled together,
|
||||
* merged in.
|
||||
*
|
||||
* Revision 4.3 87/10/18 10:31:42 narten
|
||||
* Updating version numbers. Changes relative to 1.1 actually
|
||||
* relative to 4.1
|
||||
*
|
||||
* Revision 1.3 87/09/24 13:59:21 narten
|
||||
* Sources now pass through lint (if you ignore printf/sprintf/fprintf
|
||||
* warnings)
|
||||
*
|
||||
* Revision 1.2 87/03/27 14:22:15 jenkins
|
||||
* Port to suns
|
||||
*
|
||||
* Revision 4.1 83/05/03 22:13:19 wft
|
||||
* Added default branch, option -q, exit status like diff.
|
||||
* Added fterror() to replace faterror().
|
||||
*
|
||||
* Revision 3.6 83/01/15 17:52:40 wft
|
||||
* Expanded mainprogram to handle multiple RCS files.
|
||||
*
|
||||
* Revision 3.5 83/01/06 09:33:45 wft
|
||||
* Fixed passing of -c (context) option to diff.
|
||||
*
|
||||
* Revision 3.4 82/12/24 15:28:38 wft
|
||||
* Added call to catchsig().
|
||||
*
|
||||
* Revision 3.3 82/12/10 16:08:17 wft
|
||||
* Corrected checking of return code from diff; improved error msgs.
|
||||
*
|
||||
* Revision 3.2 82/12/04 13:20:09 wft
|
||||
* replaced getdelta() with gettree(). Changed diagnostics.
|
||||
*
|
||||
* Revision 3.1 82/11/28 19:25:04 wft
|
||||
* Initial revision.
|
||||
*
|
||||
*/
|
||||
#include "rcsbase.h"
|
||||
|
||||
#if DIFF_L
|
||||
static char const *setup_label P((struct buf*,char const*,char const[datesize]));
|
||||
#endif
|
||||
static void cleanup P((void));
|
||||
|
||||
static int exitstatus;
|
||||
static RILE *workptr;
|
||||
static struct stat workstat;
|
||||
|
||||
mainProg(rcsdiffId, "rcsdiff", "$Id: rcsdiff.c,v 5.10 1991/10/07 17:32:46 eggert Exp $")
|
||||
{
|
||||
static char const cmdusage[] =
|
||||
"\nrcsdiff usage: rcsdiff [-q] [-rrev1 [-rrev2]] [-Vn] [diff options] file ...";
|
||||
|
||||
int revnums; /* counter for revision numbers given */
|
||||
char const *rev1, *rev2; /* revision numbers from command line */
|
||||
char const *xrev1, *xrev2; /* expanded revision numbers */
|
||||
char const *expandarg, *lexpandarg, *versionarg;
|
||||
#if DIFF_L
|
||||
static struct buf labelbuf[2];
|
||||
int file_labels;
|
||||
char const **diff_label1, **diff_label2;
|
||||
char date2[datesize];
|
||||
#endif
|
||||
char const *cov[9];
|
||||
char const **diffv, **diffp; /* argv for subsidiary diff */
|
||||
char const **pp, *p, *diffvstr;
|
||||
struct buf commarg;
|
||||
struct buf numericrev; /* expanded revision number */
|
||||
struct hshentries *gendeltas; /* deltas to be generated */
|
||||
struct hshentry * target;
|
||||
char *a, *dcp, **newargv;
|
||||
register c;
|
||||
|
||||
exitstatus = DIFF_SUCCESS;
|
||||
|
||||
bufautobegin(&commarg);
|
||||
bufautobegin(&numericrev);
|
||||
revnums = 0;
|
||||
rev1 = rev2 = xrev2 = nil;
|
||||
#if DIFF_L
|
||||
file_labels = 0;
|
||||
#endif
|
||||
expandarg = versionarg = 0;
|
||||
suffixes = X_DEFAULT;
|
||||
|
||||
/* Room for args + 2 i/o [+ 2 labels] + 1 file + 1 trailing null. */
|
||||
diffp = diffv = tnalloc(char const*, argc + 4 + 2*DIFF_L);
|
||||
*diffp++ = nil;
|
||||
*diffp++ = nil;
|
||||
*diffp++ = DIFF;
|
||||
|
||||
argc = getRCSINIT(argc, argv, &newargv);
|
||||
argv = newargv;
|
||||
while (a = *++argv, 0<--argc && *a++=='-') {
|
||||
dcp = a;
|
||||
while (c = *a++) switch (c) {
|
||||
case 'r':
|
||||
switch (++revnums) {
|
||||
case 1: rev1=a; break;
|
||||
case 2: rev2=a; break;
|
||||
default: faterror("too many revision numbers");
|
||||
}
|
||||
goto option_handled;
|
||||
#if DIFF_L
|
||||
case 'L':
|
||||
if (++file_labels == 2)
|
||||
faterror("too many -L options");
|
||||
/* fall into */
|
||||
#endif
|
||||
case 'C': case 'D': case 'F': case 'I':
|
||||
*dcp++ = c;
|
||||
if (*a)
|
||||
do *dcp++ = *a++;
|
||||
while (*a);
|
||||
else {
|
||||
if (!--argc)
|
||||
faterror("-%c needs following argument%s",
|
||||
c, cmdusage
|
||||
);
|
||||
*diffp++ = *argv++;
|
||||
}
|
||||
break;
|
||||
case 'B': case 'H': case 'T':
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
|
||||
case 'h': case 'i': case 'n': case 'p':
|
||||
case 't': case 'u': case 'w':
|
||||
*dcp++ = c;
|
||||
break;
|
||||
case 'q':
|
||||
quietflag=true;
|
||||
break;
|
||||
case 'x':
|
||||
suffixes = *argv + 2;
|
||||
goto option_handled;
|
||||
case 'V':
|
||||
versionarg = *argv;
|
||||
setRCSversion(versionarg);
|
||||
goto option_handled;
|
||||
case 'k':
|
||||
expandarg = *argv;
|
||||
if (0 <= str2expmode(expandarg+2))
|
||||
goto option_handled;
|
||||
/* fall into */
|
||||
default:
|
||||
faterror("unknown option: %s%s", *argv, cmdusage);
|
||||
};
|
||||
option_handled:
|
||||
if (dcp != *argv+1) {
|
||||
*dcp = 0;
|
||||
*diffp++ = *argv;
|
||||
}
|
||||
} /* end of option processing */
|
||||
|
||||
if (argc<1) faterror("no input file%s", cmdusage);
|
||||
|
||||
for (pp = diffv+3, c = 0; pp<diffp; )
|
||||
c += strlen(*pp++) + 1;
|
||||
diffvstr = a = tnalloc(char, c + 1);
|
||||
for (pp = diffv+3; pp<diffp; ) {
|
||||
p = *pp++;
|
||||
*a++ = ' ';
|
||||
while ((*a = *p++))
|
||||
a++;
|
||||
}
|
||||
*a = 0;
|
||||
|
||||
#if DIFF_L
|
||||
diff_label1 = diff_label2 = nil;
|
||||
if (file_labels < 2) {
|
||||
if (!file_labels)
|
||||
diff_label1 = diffp++;
|
||||
diff_label2 = diffp++;
|
||||
}
|
||||
#endif
|
||||
diffp[2] = nil;
|
||||
|
||||
cov[0] = 0;
|
||||
cov[2] = CO;
|
||||
cov[3] = "-q";
|
||||
|
||||
/* now handle all filenames */
|
||||
do {
|
||||
ffree();
|
||||
|
||||
if (pairfilenames(argc, argv, rcsreadopen, true, false) <= 0)
|
||||
continue;
|
||||
diagnose("===================================================================\nRCS file: %s\n",RCSfilename);
|
||||
if (!rev2) {
|
||||
/* Make sure work file is readable, and get its status. */
|
||||
if (!(workptr = Iopen(workfilename,FOPEN_R_WORK,&workstat))) {
|
||||
eerror(workfilename);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
gettree(); /* reads in the delta tree */
|
||||
|
||||
if (Head==nil) {
|
||||
error("no revisions present");
|
||||
continue;
|
||||
}
|
||||
if (revnums==0 || !*rev1)
|
||||
rev1 = Dbranch ? Dbranch : Head->num;
|
||||
|
||||
if (!fexpandsym(rev1, &numericrev, workptr)) continue;
|
||||
if (!(target=genrevs(numericrev.string,(char *)nil,(char *)nil,(char *)nil,&gendeltas))) continue;
|
||||
xrev1=target->num;
|
||||
#if DIFF_L
|
||||
if (diff_label1)
|
||||
*diff_label1 = setup_label(&labelbuf[0], target->num, target->date);
|
||||
#endif
|
||||
|
||||
lexpandarg = expandarg;
|
||||
if (revnums==2) {
|
||||
if (!fexpandsym(
|
||||
*rev2 ? rev2 : Dbranch ? Dbranch : Head->num,
|
||||
&numericrev,
|
||||
workptr
|
||||
))
|
||||
continue;
|
||||
if (!(target=genrevs(numericrev.string,(char *)nil,(char *)nil,(char *)nil,&gendeltas))) continue;
|
||||
xrev2=target->num;
|
||||
} else if (
|
||||
target->lockedby
|
||||
&& !lexpandarg
|
||||
&& Expand == KEYVAL_EXPAND
|
||||
&& WORKMODE(RCSstat.st_mode,true) == workstat.st_mode
|
||||
)
|
||||
lexpandarg = "-kkvl";
|
||||
Izclose(&workptr);
|
||||
#if DIFF_L
|
||||
if (diff_label2)
|
||||
if (revnums == 2)
|
||||
*diff_label2 = setup_label(&labelbuf[1], target->num, target->date);
|
||||
else {
|
||||
time2date(workstat.st_mtime, date2);
|
||||
*diff_label2 = setup_label(&labelbuf[1], workfilename, date2);
|
||||
}
|
||||
#endif
|
||||
|
||||
diagnose("retrieving revision %s\n", xrev1);
|
||||
bufscpy(&commarg, "-p");
|
||||
bufscat(&commarg, xrev1);
|
||||
|
||||
cov[1] = diffp[0] = maketemp(0);
|
||||
pp = &cov[4];
|
||||
*pp++ = commarg.string;
|
||||
if (lexpandarg)
|
||||
*pp++ = lexpandarg;
|
||||
if (versionarg)
|
||||
*pp++ = versionarg;
|
||||
*pp++ = RCSfilename;
|
||||
*pp = 0;
|
||||
|
||||
if (runv(cov)) {
|
||||
error("co failed");
|
||||
continue;
|
||||
}
|
||||
if (!rev2) {
|
||||
diffp[1] = workfilename;
|
||||
if (workfilename[0] == '+') {
|
||||
/* Some diffs have options with leading '+'. */
|
||||
char *dp = ftnalloc(char, strlen(workfilename)+3);
|
||||
diffp[1] = dp;
|
||||
*dp++ = '.';
|
||||
*dp++ = SLASH;
|
||||
VOID strcpy(dp, workfilename);
|
||||
}
|
||||
} else {
|
||||
diagnose("retrieving revision %s\n",xrev2);
|
||||
bufscpy(&commarg, "-p");
|
||||
bufscat(&commarg, xrev2);
|
||||
cov[1] = diffp[1] = maketemp(1);
|
||||
cov[4] = commarg.string;
|
||||
if (runv(cov)) {
|
||||
error("co failed");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!rev2)
|
||||
diagnose("diff%s -r%s %s\n", diffvstr, xrev1, workfilename);
|
||||
else
|
||||
diagnose("diff%s -r%s -r%s\n", diffvstr, xrev1, xrev2);
|
||||
|
||||
switch (runv(diffv)) {
|
||||
case DIFF_SUCCESS:
|
||||
break;
|
||||
case DIFF_FAILURE:
|
||||
if (exitstatus == DIFF_SUCCESS)
|
||||
exitstatus = DIFF_FAILURE;
|
||||
break;
|
||||
default:
|
||||
error("diff failed");
|
||||
}
|
||||
} while (cleanup(),
|
||||
++argv, --argc >=1);
|
||||
|
||||
|
||||
tempunlink();
|
||||
exitmain(exitstatus);
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup()
|
||||
{
|
||||
if (nerror) exitstatus = DIFF_TROUBLE;
|
||||
Izclose(&finptr);
|
||||
Izclose(&workptr);
|
||||
}
|
||||
|
||||
#if lint
|
||||
# define exiterr rdiffExit
|
||||
#endif
|
||||
exiting void
|
||||
exiterr()
|
||||
{
|
||||
tempunlink();
|
||||
_exit(DIFF_TROUBLE);
|
||||
}
|
||||
|
||||
#if DIFF_L
|
||||
static char const *
|
||||
setup_label(b, name, date)
|
||||
struct buf *b;
|
||||
char const *name;
|
||||
char const date[datesize];
|
||||
{
|
||||
char *p;
|
||||
size_t l = strlen(name) + 3;
|
||||
bufalloc(b, l+datesize);
|
||||
p = b->string;
|
||||
VOID sprintf(p, "-L%s\t", name);
|
||||
VOID date2str(date, p+l);
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
7
gnu/usr.bin/rcs/rcsfreeze/Makefile
Normal file
7
gnu/usr.bin/rcs/rcsfreeze/Makefile
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# Do nothing for the following
|
||||
obj clean cleandir depend rcsfreeze all:
|
||||
@echo No need to make $@ for rcsfreeze\; ignored
|
||||
|
||||
install:
|
||||
install -c -o bin -g bin -m 555 rcsfreeze.sh /usr/bin/rcsfreeze
|
||||
install -c -o bin -g bin -m 444 rcsfreeze.1 /usr/share/man/man1
|
||||
68
gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.1
Normal file
68
gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.1
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
.de Id
|
||||
.ds Rv \\$3
|
||||
.ds Dt \\$4
|
||||
..
|
||||
.Id $Id: rcsfreeze.1,v 4.4 1990/11/13 15:43:42 hammer Exp $
|
||||
.ds r \s-1RCS\s0
|
||||
.TH RCSFREEZE 1 \*(Dt GNU
|
||||
.SH NAME
|
||||
rcsfreeze \- freeze a configuration of sources checked in under RCS
|
||||
.SH SYNOPSIS
|
||||
.B rcsfreeze
|
||||
.RI [ "name" ]
|
||||
.SH DESCRIPTION
|
||||
.B rcsfreeze
|
||||
assigns a symbolic revision
|
||||
number to a set of \*r files that form a valid configuration.
|
||||
.PP
|
||||
The idea is to run
|
||||
.B rcsfreeze
|
||||
each time a new version is checked
|
||||
in. A unique symbolic name (\c
|
||||
.BI C_ number,
|
||||
where
|
||||
.I number
|
||||
is increased each time
|
||||
.B rcsfreeze
|
||||
is run) is then assigned to the most
|
||||
recent revision of each \*r file of the main trunk.
|
||||
.PP
|
||||
An optional
|
||||
.I name
|
||||
argument to
|
||||
.B rcsfreeze
|
||||
gives a symbolic name to the configuration.
|
||||
The unique identifier is still generated
|
||||
and is listed in the log file but it will not appear as
|
||||
part of the symbolic revision name in the actual \*r files.
|
||||
.PP
|
||||
A log message is requested from the user for future reference.
|
||||
.PP
|
||||
The shell script works only on all \*r files at one time.
|
||||
All changed files must be checked in already.
|
||||
Run
|
||||
.IR rcsclean (1)
|
||||
first and see whether any sources remain in the current directory.
|
||||
.SH FILES
|
||||
.TP
|
||||
.B RCS/.rcsfreeze.ver
|
||||
version number
|
||||
.TP
|
||||
.B RCS/.rcsfreeze.log
|
||||
log messages, most recent first
|
||||
.SH AUTHOR
|
||||
Stephan v. Bechtolsheim
|
||||
.SH "SEE ALSO"
|
||||
co(1), rcs(1), rcsclean(1), rlog(1)
|
||||
.SH BUGS
|
||||
.B rcsfreeze
|
||||
does not check whether any sources are checked out and modified.
|
||||
.PP
|
||||
Although both source file names and RCS file names are accepted,
|
||||
they are not paired as usual with RCS commands.
|
||||
.PP
|
||||
Error checking is rudimentary.
|
||||
.PP
|
||||
.B rcsfreeze
|
||||
is just an optional example shell script, and should not be taken too seriously.
|
||||
See \s-1CVS\s0 for a more complete solution.
|
||||
100
gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.sh
Normal file
100
gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.sh
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
#! /bin/sh
|
||||
|
||||
# rcsfreeze - assign a symbolic revision number to a configuration of RCS files
|
||||
|
||||
# $Id: rcsfreeze.sh,v 4.4 1991/04/21 11:58:24 eggert Exp $
|
||||
|
||||
# The idea is to run rcsfreeze each time a new version is checked
|
||||
# in. A unique symbolic revision number (C_[number], where number
|
||||
# is increased each time rcsfreeze is run) is then assigned to the most
|
||||
# recent revision of each RCS file of the main trunk.
|
||||
#
|
||||
# If the command is invoked with an argument, then this
|
||||
# argument is used as the symbolic name to freeze a configuration.
|
||||
# The unique identifier is still generated
|
||||
# and is listed in the log file but it will not appear as
|
||||
# part of the symbolic revision name in the actual RCS file.
|
||||
#
|
||||
# A log message is requested from the user which is saved for future
|
||||
# references.
|
||||
#
|
||||
# The shell script works only on all RCS files at one time.
|
||||
# It is important that all changed files are checked in (there are
|
||||
# no precautions against any error in this respect).
|
||||
# file names:
|
||||
# {RCS/}.rcsfreeze.ver version number
|
||||
# {RCS/}.rscfreeze.log log messages, most recent first
|
||||
|
||||
PATH=/usr/gnu/bin:/usr/local/bin:/bin:/usr/bin:/usr/ucb:$PATH
|
||||
export PATH
|
||||
|
||||
DATE=`date` || exit
|
||||
# Check whether we have an RCS subdirectory, so we can have the right
|
||||
# prefix for our paths.
|
||||
if [ -d RCS ]
|
||||
then RCSDIR=RCS/
|
||||
else RCSDIR=
|
||||
fi
|
||||
|
||||
# Version number stuff, log message file
|
||||
VERSIONFILE=${RCSDIR}.rcsfreeze.ver
|
||||
LOGFILE=${RCSDIR}.rcsfreeze.log
|
||||
# Initialize, rcsfreeze never run before in the current directory
|
||||
[ -r $VERSIONFILE ] || { echo 0 >$VERSIONFILE && >>$LOGFILE; } || exit
|
||||
|
||||
# Get Version number, increase it, write back to file.
|
||||
VERSIONNUMBER=`cat $VERSIONFILE` &&
|
||||
VERSIONNUMBER=`expr $VERSIONNUMBER + 1` &&
|
||||
echo $VERSIONNUMBER >$VERSIONFILE || exit
|
||||
|
||||
# Symbolic Revision Number
|
||||
SYMREV=C_$VERSIONNUMBER
|
||||
# Allow the user to give a meaningful symbolic name to the revision.
|
||||
SYMREVNAME=${1-$SYMREV}
|
||||
echo >&2 "rcsfreeze: symbolic revision number computed: \"${SYMREV}\"
|
||||
rcsfreeze: symbolic revision number used: \"${SYMREVNAME}\"
|
||||
rcsfreeze: the two differ only when rcsfreeze invoked with argument
|
||||
rcsfreeze: give log message, summarizing changes (end with EOF or single '.')" \
|
||||
|| exit
|
||||
|
||||
# Stamp the logfile. Because we order the logfile the most recent
|
||||
# first we will have to save everything right now in a temporary file.
|
||||
TMPLOG=/tmp/rcsfrz$$
|
||||
trap 'rm -f $TMPLOG; exit 1' 1 2 13 15
|
||||
# Now ask for a log message, continously add to the log file
|
||||
(
|
||||
echo "Version: $SYMREVNAME($SYMREV), Date: $DATE
|
||||
-----------" || exit
|
||||
while read MESS
|
||||
do
|
||||
case $MESS in
|
||||
.) break
|
||||
esac
|
||||
echo " $MESS" || exit
|
||||
done
|
||||
echo "-----------
|
||||
" &&
|
||||
cat $LOGFILE
|
||||
) >$TMPLOG &&
|
||||
|
||||
# combine old and new logfiles
|
||||
cp $TMPLOG $LOGFILE &&
|
||||
rm -f $TMPLOG || exit
|
||||
trap 1 2 13 15
|
||||
|
||||
# Now the real work begins by assigning a symbolic revision number
|
||||
# to each rcs file. Take the most recent version of the main trunk.
|
||||
|
||||
status=
|
||||
|
||||
for FILE in ${RCSDIR}*
|
||||
do
|
||||
# get the revision number of the most recent revision
|
||||
HEAD=`rlog -h $FILE` &&
|
||||
REV=`echo "$HEAD" | sed -n 's/^head:[ ]*//p'` &&
|
||||
# assign symbolic name to it.
|
||||
echo >&2 "rcsfreeze: $REV $FILE" &&
|
||||
rcs -q -n$SYMREVNAME:$REV $FILE || status=$?
|
||||
done
|
||||
|
||||
exit $status
|
||||
7
gnu/usr.bin/rcs/rcsmerge/Makefile
Normal file
7
gnu/usr.bin/rcs/rcsmerge/Makefile
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
PROG= rcsmerge
|
||||
|
||||
SRCS= rcsmerge.c
|
||||
LDADD= -L${.CURDIR}/../lib/obj -lrcs
|
||||
CFLAGS+= -I${.CURDIR}/../lib
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
140
gnu/usr.bin/rcs/rcsmerge/rcsmerge.1
Normal file
140
gnu/usr.bin/rcs/rcsmerge/rcsmerge.1
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
.de Id
|
||||
.ds Rv \\$3
|
||||
.ds Dt \\$4
|
||||
..
|
||||
.Id $Id: rcsmerge.1,v 5.3 1991/08/19 03:13:55 eggert Exp $
|
||||
.ds r \&\s-1RCS\s0
|
||||
.if n .ds - \%--
|
||||
.if t .ds - \(em
|
||||
.TH RCSMERGE 1 \*(Dt GNU
|
||||
.SH NAME
|
||||
rcsmerge \- merge RCS revisions
|
||||
.SH SYNOPSIS
|
||||
.B rcsmerge
|
||||
.RI [ options ] " file"
|
||||
.SH DESCRIPTION
|
||||
.B rcsmerge
|
||||
incorporates the changes between two revisions
|
||||
of an \*r file into the corresponding working file.
|
||||
.PP
|
||||
Pathnames matching an \*r suffix denote \*r files;
|
||||
all others denote working files.
|
||||
Names are paired as explained in
|
||||
.BR ci (1).
|
||||
.PP
|
||||
At least one revision must be specified with one of the options
|
||||
described below, usually
|
||||
.BR \-r .
|
||||
At most two revisions may be specified.
|
||||
If only one revision is specified, the latest
|
||||
revision on the default branch (normally the highest branch on the trunk)
|
||||
is assumed for the second revision.
|
||||
Revisions may be specified numerically or symbolically.
|
||||
.PP
|
||||
.B rcsmerge
|
||||
prints a warning if there are overlaps, and delimits
|
||||
the overlapping regions as explained in
|
||||
.BR merge (1).
|
||||
The command is useful for incorporating changes into a checked-out revision.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BI \-k subst
|
||||
Use
|
||||
.I subst
|
||||
style keyword substitution.
|
||||
See
|
||||
.BR co (1)
|
||||
for details.
|
||||
For example,
|
||||
.B "\-kk\ \-r1.1\ \-r1.2"
|
||||
ignores differences in keyword values when merging the changes from
|
||||
.B 1.1
|
||||
to
|
||||
.BR 1.2 .
|
||||
.TP
|
||||
.BR \-p [\f2rev\fP]
|
||||
Send the result to standard output instead of overwriting the working file.
|
||||
.TP
|
||||
.BR \-q [\f2rev\fP]
|
||||
Run quietly; do not print diagnostics.
|
||||
.TP
|
||||
.BR \-r [\f2rev\fP]
|
||||
Merge with respect to revision
|
||||
.IR rev .
|
||||
Here an empty
|
||||
.I rev
|
||||
stands for the latest revision on the default branch, normally the head.
|
||||
.TP
|
||||
.BI \-V n
|
||||
Emulate \*r version
|
||||
.IR n .
|
||||
See
|
||||
.BR co (1)
|
||||
for details.
|
||||
.TP
|
||||
.BI \-x "suffixes"
|
||||
Use
|
||||
.I suffixes
|
||||
to characterize \*r files.
|
||||
See
|
||||
.BR ci (1)
|
||||
for details.
|
||||
.SH EXAMPLES
|
||||
Suppose you have released revision 2.8 of
|
||||
.BR f.c .
|
||||
Assume
|
||||
furthermore that after you complete an unreleased revision 3.4, you receive
|
||||
updates to release 2.8 from someone else.
|
||||
To combine the updates to 2.8 and your changes between 2.8 and 3.4,
|
||||
put the updates to 2.8 into file f.c and execute
|
||||
.LP
|
||||
.B " rcsmerge \-p \-r2.8 \-r3.4 f.c >f.merged.c"
|
||||
.PP
|
||||
Then examine
|
||||
.BR f.merged.c .
|
||||
Alternatively, if you want to save the updates to 2.8 in the \*r file,
|
||||
check them in as revision 2.8.1.1 and execute
|
||||
.BR "co \-j":
|
||||
.LP
|
||||
.B " ci \-r2.8.1.1 f.c"
|
||||
.br
|
||||
.B " co \-r3.4 \-j2.8:2.8.1.1 f.c"
|
||||
.PP
|
||||
As another example, the following command undoes the changes
|
||||
between revision 2.4 and 2.8 in your currently checked out revision
|
||||
in
|
||||
.BR f.c .
|
||||
.LP
|
||||
.B " rcsmerge \-r2.8 \-r2.4 f.c"
|
||||
.PP
|
||||
Note the order of the arguments, and that
|
||||
.B f.c
|
||||
will be
|
||||
overwritten.
|
||||
.SH ENVIRONMENT
|
||||
.TP
|
||||
.B \s-1RCSINIT\s0
|
||||
options prepended to the argument list, separated by spaces.
|
||||
See
|
||||
.BR ci (1)
|
||||
for details.
|
||||
.SH DIAGNOSTICS
|
||||
Exit status is 0 for no overlaps, 1 for some overlaps, 2 for trouble.
|
||||
.SH IDENTIFICATION
|
||||
Author: Walter F. Tichy.
|
||||
.br
|
||||
Revision Number: \*(Rv; Release Date: \*(Dt.
|
||||
.br
|
||||
Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
|
||||
.br
|
||||
Copyright \(co 1990, 1991 by Paul Eggert.
|
||||
.SH "SEE ALSO"
|
||||
ci(1), co(1), ident(1), merge(1), rcs(1), rcsdiff(1), rcsintro(1), rlog(1),
|
||||
rcsfile(5)
|
||||
.br
|
||||
Walter F. Tichy,
|
||||
\*r\*-A System for Version Control,
|
||||
.I "Software\*-Practice & Experience"
|
||||
.BR 15 ,
|
||||
7 (July 1985), 637-654.
|
||||
.br
|
||||
252
gnu/usr.bin/rcs/rcsmerge/rcsmerge.c
Normal file
252
gnu/usr.bin/rcs/rcsmerge/rcsmerge.c
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* rcsmerge operation
|
||||
*/
|
||||
/*****************************************************************************
|
||||
* join 2 revisions with respect to a third
|
||||
*****************************************************************************
|
||||
*/
|
||||
|
||||
/* Copyright (C) 1982, 1988, 1989 Walter Tichy
|
||||
Copyright 1990, 1991 by 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, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Report problems and direct all questions to:
|
||||
|
||||
rcs-bugs@cs.purdue.edu
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* $Log: rcsmerge.c,v $
|
||||
* Revision 5.7 1991/11/20 17:58:09 eggert
|
||||
* Don't Iopen(f, "r+"); it's not portable.
|
||||
*
|
||||
* Revision 5.6 1991/08/19 03:13:55 eggert
|
||||
* Add -r$. Tune.
|
||||
*
|
||||
* Revision 5.5 1991/04/21 11:58:27 eggert
|
||||
* Add -x, RCSINIT, MS-DOS support.
|
||||
*
|
||||
* Revision 5.4 1991/02/25 07:12:43 eggert
|
||||
* Merging a revision to itself is no longer an error.
|
||||
*
|
||||
* Revision 5.3 1990/11/01 05:03:50 eggert
|
||||
* Remove unneeded setid check.
|
||||
*
|
||||
* Revision 5.2 1990/09/04 08:02:28 eggert
|
||||
* Check for I/O error when reading working file.
|
||||
*
|
||||
* Revision 5.1 1990/08/29 07:14:04 eggert
|
||||
* Add -q. Pass -L options to merge.
|
||||
*
|
||||
* Revision 5.0 1990/08/22 08:13:41 eggert
|
||||
* Propagate merge's exit status.
|
||||
* Remove compile-time limits; use malloc instead.
|
||||
* Make lock and temp files faster and safer. Ansify and Posixate. Add -V.
|
||||
* Don't use access(). Tune.
|
||||
*
|
||||
* Revision 4.5 89/05/01 15:13:16 narten
|
||||
* changed copyright header to reflect current distribution rules
|
||||
*
|
||||
* Revision 4.4 88/08/09 19:13:13 eggert
|
||||
* Beware merging into a readonly file.
|
||||
* Beware merging a revision to itself (no change).
|
||||
* Use execv(), not system(); yield exit status like diff(1)'s.
|
||||
*
|
||||
* Revision 4.3 87/10/18 10:38:02 narten
|
||||
* Updating version numbers. Changes relative to version 1.1
|
||||
* actually relative to 4.1
|
||||
*
|
||||
* Revision 1.3 87/09/24 14:00:31 narten
|
||||
* Sources now pass through lint (if you ignore printf/sprintf/fprintf
|
||||
* warnings)
|
||||
*
|
||||
* Revision 1.2 87/03/27 14:22:36 jenkins
|
||||
* Port to suns
|
||||
*
|
||||
* Revision 4.1 83/03/28 11:14:57 wft
|
||||
* Added handling of default branch.
|
||||
*
|
||||
* Revision 3.3 82/12/24 15:29:00 wft
|
||||
* Added call to catchsig().
|
||||
*
|
||||
* Revision 3.2 82/12/10 21:32:02 wft
|
||||
* Replaced getdelta() with gettree(); improved error messages.
|
||||
*
|
||||
* Revision 3.1 82/11/28 19:27:44 wft
|
||||
* Initial revision.
|
||||
*
|
||||
*/
|
||||
#include "rcsbase.h"
|
||||
|
||||
static char const co[] = CO;
|
||||
|
||||
mainProg(rcsmergeId, "rcsmerge", "$Id: rcsmerge.c,v 5.7 1991/11/20 17:58:09 eggert Exp $")
|
||||
{
|
||||
static char const cmdusage[] =
|
||||
"\nrcsmerge usage: rcsmerge -rrev1 [-rrev2] [-p] [-Vn] file";
|
||||
static char const quietarg[] = "-q";
|
||||
|
||||
register int i;
|
||||
char *a, **newargv;
|
||||
char const *arg[3];
|
||||
char const *rev[2]; /*revision numbers*/
|
||||
char const *expandarg, *versionarg;
|
||||
int tostdout;
|
||||
int status;
|
||||
RILE *workptr;
|
||||
struct buf commarg;
|
||||
struct buf numericrev; /* holds expanded revision number */
|
||||
struct hshentries *gendeltas; /* deltas to be generated */
|
||||
struct hshentry * target;
|
||||
|
||||
bufautobegin(&commarg);
|
||||
bufautobegin(&numericrev);
|
||||
rev[0] = rev[1] = nil;
|
||||
status = 0; /* Keep lint happy. */
|
||||
tostdout = false;
|
||||
expandarg = versionarg = quietarg; /* i.e. a no-op */
|
||||
suffixes = X_DEFAULT;
|
||||
|
||||
argc = getRCSINIT(argc, argv, &newargv);
|
||||
argv = newargv;
|
||||
while (a = *++argv, 0<--argc && *a++=='-') {
|
||||
switch (*a++) {
|
||||
case 'p':
|
||||
tostdout=true;
|
||||
goto revno;
|
||||
|
||||
case 'q':
|
||||
quietflag = true;
|
||||
revno:
|
||||
if (!*a)
|
||||
break;
|
||||
/* falls into -r */
|
||||
case 'r':
|
||||
if (!rev[0])
|
||||
rev[0] = a;
|
||||
else if (!rev[1])
|
||||
rev[1] = a;
|
||||
else
|
||||
faterror("too many revision numbers");
|
||||
break;
|
||||
case 'x':
|
||||
suffixes = a;
|
||||
break;
|
||||
case 'V':
|
||||
versionarg = *argv;
|
||||
setRCSversion(versionarg);
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
expandarg = *argv;
|
||||
if (0 <= str2expmode(expandarg+2))
|
||||
break;
|
||||
/* fall into */
|
||||
default:
|
||||
faterror("unknown option: %s%s", *argv, cmdusage);
|
||||
};
|
||||
} /* end of option processing */
|
||||
|
||||
if (argc<1) faterror("no input file%s", cmdusage);
|
||||
if (!rev[0]) faterror("no base revision number given");
|
||||
|
||||
/* now handle all filenames */
|
||||
|
||||
if (0 < pairfilenames(argc, argv, rcsreadopen, true, false)) {
|
||||
|
||||
if (argc>2 || (argc==2&&argv[1]!=nil))
|
||||
warn("too many arguments");
|
||||
diagnose("RCS file: %s\n", RCSfilename);
|
||||
if (!(workptr = Iopen(workfilename,
|
||||
FOPEN_R_WORK,
|
||||
(struct stat*)0
|
||||
)))
|
||||
efaterror(workfilename);
|
||||
|
||||
gettree(); /* reads in the delta tree */
|
||||
|
||||
if (Head==nil) faterror("no revisions present");
|
||||
|
||||
if (!*rev[0])
|
||||
rev[0] = Dbranch ? Dbranch : Head->num;
|
||||
if (!fexpandsym(rev[0], &numericrev, workptr))
|
||||
goto end;
|
||||
if (!(target=genrevs(numericrev.string, (char *)nil, (char *)nil, (char *)nil,&gendeltas))) goto end;
|
||||
rev[0] = target->num;
|
||||
if (!rev[1] || !*rev[1])
|
||||
rev[1] = Dbranch ? Dbranch : Head->num;
|
||||
if (!fexpandsym(rev[1], &numericrev, workptr))
|
||||
goto end;
|
||||
if (!(target=genrevs(numericrev.string, (char *)nil, (char *)nil, (char *)nil,&gendeltas))) goto end;
|
||||
rev[1] = target->num;
|
||||
|
||||
if (strcmp(rev[0],rev[1]) == 0) {
|
||||
if (tostdout) {
|
||||
FILE *o;
|
||||
# if text_equals_binary_stdio || text_work_stdio
|
||||
o = stdout;
|
||||
# else
|
||||
if (!(o=fdopen(STDOUT_FILENO,FOPEN_W_WORK)))
|
||||
efaterror("stdout");
|
||||
# endif
|
||||
fastcopy(workptr,o);
|
||||
Ofclose(o);
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
Izclose(&workptr);
|
||||
|
||||
for (i=0; i<2; i++) {
|
||||
diagnose("retrieving revision %s\n", rev[i]);
|
||||
bufscpy(&commarg, "-p");
|
||||
bufscat(&commarg, rev[i]);
|
||||
if (run(
|
||||
(char*)0,
|
||||
/* Do not collide with merger.c maketemp(). */
|
||||
arg[i+1] = maketemp(i+3),
|
||||
co, quietarg, commarg.string, expandarg,
|
||||
versionarg, RCSfilename, (char*)0
|
||||
))
|
||||
faterror("co failed");
|
||||
}
|
||||
diagnose("Merging differences between %s and %s into %s%s\n",
|
||||
rev[0], rev[1], workfilename,
|
||||
tostdout?"; result to stdout":"");
|
||||
|
||||
arg[0] = rev[0] = workfilename;
|
||||
status = merge(tostdout, rev, arg);
|
||||
}
|
||||
|
||||
end:
|
||||
Izclose(&workptr);
|
||||
tempunlink();
|
||||
exitmain(nerror ? DIFF_TROUBLE : status);
|
||||
}
|
||||
|
||||
#if lint
|
||||
# define exiterr rmergeExit
|
||||
#endif
|
||||
exiting void
|
||||
exiterr()
|
||||
{
|
||||
tempunlink();
|
||||
_exit(DIFF_TROUBLE);
|
||||
}
|
||||
397
gnu/usr.bin/rcs/rcstest
Executable file
397
gnu/usr.bin/rcs/rcstest
Executable file
|
|
@ -0,0 +1,397 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Test RCS's functions.
|
||||
# The RCS commands are searched for in the PATH as usual;
|
||||
# to test the working directory's commands, prepend . to your PATH.
|
||||
|
||||
# Test RCS by creating files RCS/a.* and RCS/a.c.
|
||||
# If all goes well, output nothing, and remove the temporary files.
|
||||
# Otherwise, send a message to standard output.
|
||||
# Exit status is 0 if OK, 1 if an RCS bug is found, and 2 if scaffolding fails.
|
||||
# With the -v option, output more debugging info.
|
||||
|
||||
# If diff outputs `No differences encountered' when comparing identical files,
|
||||
# then rcstest may also output these noise lines; ignore them.
|
||||
|
||||
# The current directory and ./RCS must be readable, writable, and searchable.
|
||||
|
||||
# $Id: rcstest,v 5.8 1991/11/20 17:58:10 eggert Exp $
|
||||
|
||||
|
||||
# Copyright 1990, 1991 by 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, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
#
|
||||
# Report problems and direct all questions to:
|
||||
#
|
||||
# rcs-bugs@cs.purdue.edu
|
||||
|
||||
RCSINIT=-x
|
||||
export RCSINIT
|
||||
|
||||
SLASH=/
|
||||
RCSfile=RCS${SLASH}a.c
|
||||
RCS_alt=RCS${SLASH}a.d
|
||||
lockfile=RCS${SLASH}a._
|
||||
|
||||
case $1 in
|
||||
-v) q=; set -x;;
|
||||
'') q=-q;;
|
||||
*) echo >&2 "$0: usage: $0 [-v]"; exit 2
|
||||
esac
|
||||
|
||||
test -d RCS || {
|
||||
echo >&2 "$0: RCS: not a directory; please \`mkdir RCS' first."
|
||||
exit 1
|
||||
}
|
||||
|
||||
rm -f a.* $RCSfile $RCS_alt $lockfile &&
|
||||
echo 1.1 >a.11 &&
|
||||
echo 1.1.1.1 >a.3x1 &&
|
||||
echo 1.2 >a.12 || { echo "#initialization failed"; exit 2; }
|
||||
|
||||
case `diff -c a.11 a.3x1` in
|
||||
*'! 1.1.1.1')
|
||||
diff='diff -c';;
|
||||
*)
|
||||
echo "#warning: diff -c does not work, so diagnostics may be cryptic"
|
||||
diff=diff
|
||||
esac
|
||||
|
||||
rcs -i -L -ta.11 $q a.c &&
|
||||
<$RCSfile || {
|
||||
echo "#rcs -i -L failed; perhaps RCS is not properly installed."
|
||||
exit 1
|
||||
}
|
||||
|
||||
rlog a.c >/dev/null || { echo "#rlog failed on empty RCS file"; exit 1; }
|
||||
rm -f $RCSfile || exit 2
|
||||
|
||||
cp a.11 a.c &&
|
||||
ci -ta.11 -mm $q a.c &&
|
||||
<$RCSfile &&
|
||||
rcs -L $q a.c || { echo "#ci+rcs -L failed"; exit 1; }
|
||||
test ! -f a.c || { echo "#ci did not remove working file"; exit 1; }
|
||||
for l in '' '-l'
|
||||
do
|
||||
co $l $q a.c &&
|
||||
test -f a.c || { echo '#co' $l did not create working file; exit 1; }
|
||||
$diff a.11 a.c || { echo '#ci' followed by co $l is not a no-op; exit 1; }
|
||||
done
|
||||
|
||||
cp a.12 a.c &&
|
||||
ci -mm $q a.c &&
|
||||
co $q a.c &&
|
||||
$diff a.12 a.c || { echo "#ci+co failed"; exit 1; }
|
||||
|
||||
co -r1.1 $q a.c &&
|
||||
$diff a.11 a.c || { echo "#can't retrieve first revision"; exit 1; }
|
||||
|
||||
rm -f a.c &&
|
||||
cp a.3x1 a.c &&
|
||||
ci -r1.1.1 -mm $q a.c &&
|
||||
co -r1.1.1.1 $q a.c &&
|
||||
$diff a.3x1 a.c || { echo "#branches failed"; exit 1; }
|
||||
|
||||
co -l $q a.c &&
|
||||
ci -f -mm $q a.c &&
|
||||
co -r1.3 $q a.c &&
|
||||
$diff a.12 a.c || { echo "#(co -l; ci -f) failed"; exit 1; }
|
||||
|
||||
co -l $q a.c &&
|
||||
echo 1.4 >a.c &&
|
||||
ci -l -mm $q a.c &&
|
||||
echo error >a.c &&
|
||||
ci -mm $q a.c || { echo "#ci -l failed"; exit 1; }
|
||||
|
||||
co -l $q a.c &&
|
||||
echo 1.5 >a.c &&
|
||||
ci -u -mm $q a.c &&
|
||||
<a.c || { echo "#ci -u didn't create a working file"; exit 1; }
|
||||
rm -f a.c &&
|
||||
echo error >a.c || exit 2
|
||||
ci -mm $q a.c 2>/dev/null && { echo "#ci -u didn't unlock the file"; exit 1; }
|
||||
|
||||
rm -f a.c &&
|
||||
rcs -l $q a.c &&
|
||||
co -u $q a.c || { echo "#rcs -l + co -u failed"; exit 1; }
|
||||
rm -f a.c &&
|
||||
echo error >a.c || exit 2
|
||||
ci -mm $q a.c 2>/dev/null && { echo "#co -u didn't unlock the file"; exit 1; }
|
||||
|
||||
rm -f a.c &&
|
||||
cp a.11 a.c &&
|
||||
co -f $q a.c || { echo "#co -f failed"; exit 1; }
|
||||
$diff a.11 a.c >/dev/null && { echo "#co -f had no effect"; exit 1; }
|
||||
|
||||
co -p1.1 $q a.c >a.t &&
|
||||
$diff a.11 a.t || { echo "#co -p failed"; exit 1; }
|
||||
|
||||
for n in n N
|
||||
do
|
||||
rm -f a.c &&
|
||||
co -l $q a.c &&
|
||||
echo $n >a.$n &&
|
||||
cp a.$n a.c &&
|
||||
ci -${n}n -mm $q a.c &&
|
||||
co -rn $q a.c &&
|
||||
$diff a.$n a.c || { echo "#ci -$n failed"; exit 1; }
|
||||
done
|
||||
|
||||
case $LOGNAME in
|
||||
?*) me=$LOGNAME;;
|
||||
*)
|
||||
case $USER in
|
||||
?*) me=$USER;;
|
||||
*)
|
||||
me=`who am i` || exit 2
|
||||
me=`echo "$me" | sed -e 's/ .*//' -e 's/.*!//'`
|
||||
case $me in
|
||||
'') echo >&2 "$0: cannot deduce user name"; exit 2
|
||||
esac
|
||||
esac
|
||||
esac
|
||||
date=`date -u 2>/dev/null` ||
|
||||
date=`TZ=GMT0 date 2>/dev/null` ||
|
||||
date=`TZ= date` || exit 2
|
||||
set $date
|
||||
case $2 in
|
||||
Jan) m=01;; Feb) m=02;; Mar) m=03;; Apr) m=04;; May) m=05;; Jun) m=06;;
|
||||
Jul) m=07;; Aug) m=08;; Sep) m=09;; Oct) m=10;; Nov) m=11;; Dec) m=12;;
|
||||
*) echo >&2 "$0: $2: unknown month name"; exit 2
|
||||
esac
|
||||
case $3 in
|
||||
?) d=0$3;;
|
||||
*) d=$3
|
||||
esac
|
||||
case $6 in
|
||||
[0-9][0-9][0-9][0-9]*) D=$6/$m/$d;;
|
||||
*)
|
||||
case $5 in
|
||||
[0-9][0-9][0-9][0-9]*) D=$5/$m/$d;;
|
||||
*) echo >&2 "$0: bad date format: $date"; exit 2
|
||||
esac
|
||||
esac
|
||||
T=$4
|
||||
case $PWD in
|
||||
'') PWD=`pwd`
|
||||
esac &&
|
||||
co -l $q a.c &&
|
||||
sed 's/@/$/g' >a.kv <<EOF
|
||||
@Author: w @
|
||||
@Date: $D $T @
|
||||
@Header: $PWD$SLASH$RCSfile 2.1 $D $T w s @
|
||||
@Id: a.c 2.1 $D $T w s @
|
||||
@Locker: @
|
||||
@Log: a.c @
|
||||
* Revision 2.1 $D $T w
|
||||
* m
|
||||
*
|
||||
@RCSfile: a.c @
|
||||
@Revision: 2.1 @
|
||||
@Source: $PWD$SLASH$RCSfile @
|
||||
@State: s @
|
||||
EOF
|
||||
test $? = 0 &&
|
||||
sed 's/:.*\$/$/' a.kv >a.k &&
|
||||
sed -e 's/w s [$]/w s '"$me"' $/' -e 's/[$]Locker: /&'"$me/" a.kv >a.kvl &&
|
||||
sed -e '/^\$/!d' -e 's/\$$/: old $/' a.k >a.o &&
|
||||
sed -e 's/\$[^ ]*: //' -e 's/ \$//' a.kv >a.v &&
|
||||
cp a.o a.c &&
|
||||
ci -d"$date" -ss -ww -u2.1 -mm $q a.c &&
|
||||
$diff a.kv a.c || { echo "#keyword expansion failed"; exit 1; }
|
||||
co -p -ko $q a.c >a.oo &&
|
||||
$diff a.o a.oo || { echo "#co -p -ko failed"; exit 1; }
|
||||
cp a.kv a.o || exit 2
|
||||
rcs -o2.1 $q a.c &&
|
||||
rcs -l $q a.c &&
|
||||
ci -k -u $q a.c &&
|
||||
$diff a.kv a.c || { echo "#ci -k failed"; exit 1; }
|
||||
sed '/^[^$]/d' a.kv >a.i &&
|
||||
ident a.c >a.i1 &&
|
||||
sed -e 1d -e 's/^[ ]*//' a.i1 >a.i2 &&
|
||||
$diff a.i a.i2 || { echo "#ident failed"; exit 1; }
|
||||
|
||||
rcs -i $q a.c 2>/dev/null && { echo "#rcs -i permitted existing file"; exit 1; }
|
||||
|
||||
co -l $q a.c &&
|
||||
echo 2.2 >a.c &&
|
||||
ci -mm $q a.c &&
|
||||
echo 1.1.1.2 >a.c &&
|
||||
rcs -l1.1.1 $q a.c &&
|
||||
ci -r1.1.1.2 -mm $q a.c &&
|
||||
rcs -b1.1.1 $q a.c &&
|
||||
test " `co -p $q a.c`" = ' 1.1.1.2' || { echo "#rcs -b1.1.1 failed"; exit 1; }
|
||||
rcs -b $q a.c &&
|
||||
test " `co -p $q a.c`" = ' 2.2' || { echo "#rcs -b failed"; exit 1; }
|
||||
|
||||
echo 2.3 >a.c || exit 2
|
||||
rcs -U $q a.c || { echo "#rcs -U failed"; exit 1; }
|
||||
ci -mm $q a.c || { echo "#rcs -U didn't unset strict locking"; exit 1; }
|
||||
rcs -L $q a.c || { echo "#rcs -L failed"; exit 1; }
|
||||
echo error >a.c || exit 2
|
||||
ci -mm $q a.c 2>/dev/null && { echo "#ci retest failed"; exit 1; }
|
||||
|
||||
rm -f a.c &&
|
||||
log0=`rlog -h a.c` &&
|
||||
co -l $q a.c &&
|
||||
ci -mm $q a.c &&
|
||||
log1=`rlog -h a.c` &&
|
||||
test " $log0" = " $log1" || { echo "#unchanged ci didn't revert"; exit 1; }
|
||||
|
||||
rm -f a.c &&
|
||||
rcs -nN:1.1 $q a.c &&
|
||||
co -rN $q a.c &&
|
||||
$diff a.11 a.c || { echo "#rcs -n failed"; exit 1; }
|
||||
|
||||
rcs -NN:2.1 $q a.c &&
|
||||
co -rN $q a.c &&
|
||||
$diff a.kv a.c || { echo "#rcs -N failed"; exit 1; }
|
||||
|
||||
co -l $q a.c &&
|
||||
rcs -c':::' $q a.c &&
|
||||
echo '$''Log$' >a.c &&
|
||||
ci -u -mm $q a.c &&
|
||||
test " `sed '$!d' a.c`" = ' :::' || { echo "#rcs -c failed"; exit 1; }
|
||||
|
||||
rcs -o2.2: $q a.c &&
|
||||
co $q a.c &&
|
||||
$diff a.kv a.c || { echo "#rcs -o failed"; exit 1; }
|
||||
|
||||
rcsdiff -r1.1 -r2.1 $q a.c >a.0
|
||||
case $? in
|
||||
1) ;;
|
||||
*) echo "#rcsdiff bad status"; exit 1
|
||||
esac
|
||||
diff a.11 a.kv >a.1
|
||||
$diff a.0 a.1 || { echo "#rcsdiff failed"; exit 1; }
|
||||
|
||||
rcs -l2.1 $q a.c || { echo "#rcs -l2.1 failed"; exit 1; }
|
||||
for i in k kv kvl o v
|
||||
do
|
||||
rm -f a.c &&
|
||||
cp a.$i a.c &&
|
||||
rcsdiff -k$i $q a.c || { echo "#rcsdiff -k$i failed"; exit 1; }
|
||||
done
|
||||
co -p1.1 -ko $q a.c >a.t &&
|
||||
$diff a.11 a.t || { echo "#co -p1.1 -ko failed"; exit 1; }
|
||||
rcs -u2.1 $q a.c || { echo "#rcs -u2.1 failed"; exit 1; }
|
||||
|
||||
rm -f a.c &&
|
||||
co -l $q a.c &&
|
||||
cat >a.c <<'EOF'
|
||||
2.2
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
EOF
|
||||
test $? = 0 &&
|
||||
ci -l -mm $q a.c &&
|
||||
co -p2.2 $q a.c | sed -e s/2.2/2.3/ -e s/b/b1/ >a.c &&
|
||||
ci -l -mm $q a.c &&
|
||||
co -p2.2 $q a.c | sed -e s/2.2/new/ -e s/d/d1/ >a.c || exit 2
|
||||
cat >a.0 <<'EOF'
|
||||
2.3
|
||||
a
|
||||
b1
|
||||
c
|
||||
d1
|
||||
EOF
|
||||
cat >a.1 <<'EOF'
|
||||
<<<<<<< a.c
|
||||
new
|
||||
=======
|
||||
2.3
|
||||
>>>>>>> 2.3
|
||||
a
|
||||
b1
|
||||
c
|
||||
d1
|
||||
EOF
|
||||
rcsmerge -r2.2 -r2.3 $q a.c
|
||||
case $? in
|
||||
0)
|
||||
if $diff a.0 a.c >/dev/null
|
||||
then echo "#warning: diff3 -E does not work, " \
|
||||
"so merge and rcsmerge ignore overlaps and suppress overlap lines."
|
||||
else
|
||||
$diff a.1 a.c || { echo "#rcsmerge failed (status 0)"; exit 1; }
|
||||
echo "#warning: The diff3 lib program exit status ignores overlaps," \
|
||||
"so rcsmerge does not warn about overlap lines that it generates."
|
||||
fi
|
||||
;;
|
||||
1)
|
||||
$diff a.1 a.c || { echo "#rcsmerge failed (status 1)"; exit 1; }
|
||||
;;
|
||||
*)
|
||||
echo "#rcsmerge bad status"; exit 1
|
||||
esac
|
||||
|
||||
nl='
|
||||
'
|
||||
{
|
||||
co -p $q a.c | tr "$nl" '\200' >a.24 &&
|
||||
cp a.24 a.c &&
|
||||
ciOut=`(ci -l -mm $q a.c 2>&1)` &&
|
||||
case $ciOut in
|
||||
?*) echo >&2 "$ciOut"
|
||||
esac &&
|
||||
co -p $q a.c | tr '\200' "$nl" >a.c &&
|
||||
rcsdiff -r2.3 $q a.c >/dev/null &&
|
||||
|
||||
echo 2.5 >a.c &&
|
||||
ci -l -mm $q a.c &&
|
||||
cp a.24 a.c &&
|
||||
rcsdiff -r2.4 $q a.c >/dev/null
|
||||
} || echo "#warning: Traditional diff is used, so RCS is limited to text files."
|
||||
|
||||
rcs -u -o2.4: $q a.c || { echo "#rcs -u -o failed"; exit 1; }
|
||||
|
||||
rcs -i -Aa.c -t- $q a.d || { echo "#rcs -i -A failed"; exit 1; }
|
||||
|
||||
rlog -r2.1 a.c >a.t &&
|
||||
grep '^checked in with -k' a.t >/dev/null &&
|
||||
sed '/^checked in with -k/d' a.t >a.u &&
|
||||
$diff - a.u <<EOF
|
||||
|
||||
RCS file: $RCSfile
|
||||
Working file: a.c
|
||||
head: 2.3
|
||||
branch:
|
||||
locks: strict
|
||||
access list:
|
||||
symbolic names:
|
||||
N: 2.1
|
||||
n: 1.8
|
||||
comment leader: ":::"
|
||||
keyword substitution: kv
|
||||
total revisions: 13; selected revisions: 1
|
||||
description:
|
||||
1.1
|
||||
----------------------------
|
||||
revision 2.1
|
||||
date: $D $T; author: w; state: s; lines: +13 -1
|
||||
=============================================================================
|
||||
EOF
|
||||
test $? = 0 || { echo "#rlog failed"; exit 1; }
|
||||
|
||||
|
||||
test ! -f $lockfile || { echo "#lock file not removed"; exit 1; }
|
||||
|
||||
exec rm -f a.* $RCSfile $RCS_alt
|
||||
7
gnu/usr.bin/rcs/rlog/Makefile
Normal file
7
gnu/usr.bin/rcs/rlog/Makefile
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
PROG= rlog
|
||||
|
||||
SRCS= rlog.c
|
||||
LDADD= -L${.CURDIR}/../lib/obj -lrcs
|
||||
CFLAGS+= -I${.CURDIR}/../lib
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
260
gnu/usr.bin/rcs/rlog/rlog.1
Normal file
260
gnu/usr.bin/rcs/rlog/rlog.1
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
.de Id
|
||||
.ds Rv \\$3
|
||||
.ds Dt \\$4
|
||||
..
|
||||
.Id $Id: rlog.1,v 5.3 1991/08/22 06:50:48 eggert Exp $
|
||||
.ds g \&\s-1UTC\s0
|
||||
.ds r \&\s-1RCS\s0
|
||||
.if n .ds - \%--
|
||||
.if t .ds - \(em
|
||||
.TH RLOG 1 \*(Dt GNU
|
||||
.SH NAME
|
||||
rlog \- print log messages and other information about RCS files
|
||||
.SH SYNOPSIS
|
||||
.B rlog
|
||||
.RI [ " options " ] " file " .\|.\|.
|
||||
.SH DESCRIPTION
|
||||
.B rlog
|
||||
prints information about \*r files.
|
||||
.PP
|
||||
Pathnames matching an \*r suffix denote \*r files;
|
||||
all others denote working files.
|
||||
Names are paired as explained in
|
||||
.BR ci (1).
|
||||
.PP
|
||||
.B rlog
|
||||
prints the following information for each
|
||||
\*r file: \*r pathname, working pathname, head (i.e., the number
|
||||
of the latest revision on the trunk), default branch, access list, locks,
|
||||
symbolic names, suffix, total number of revisions,
|
||||
number of revisions selected for printing, and
|
||||
descriptive text. This is followed by entries for the selected revisions in
|
||||
reverse chronological order for each branch. For each revision,
|
||||
.B rlog
|
||||
prints revision number, author, date/time, state, number of
|
||||
lines added/deleted (with respect to the previous revision),
|
||||
locker of the revision (if any), and log message.
|
||||
All times are displayed in Coordinated Universal Time (\*g).
|
||||
Without options,
|
||||
.B rlog
|
||||
prints complete information.
|
||||
The options below restrict this output.
|
||||
.nr n \w'\f3\-V\fP\f2n\fP '+1n-1/1n
|
||||
.TP \nn
|
||||
.B \-L
|
||||
Ignore \*r files that have no locks set.
|
||||
This is convenient in combination with
|
||||
.BR \-h ,
|
||||
.BR \-l ,
|
||||
and
|
||||
.BR \-R .
|
||||
.TP
|
||||
.B \-R
|
||||
Print only the name of the \*r file.
|
||||
This is convenient for translating a
|
||||
working pathname into an \*r pathname.
|
||||
.TP
|
||||
.B \-h
|
||||
Print only the \*r pathname, working pathname, head,
|
||||
default branch, access list, locks,
|
||||
symbolic names, and suffix.
|
||||
.TP
|
||||
.B \-t
|
||||
Print the same as
|
||||
.BR \-h ,
|
||||
plus the descriptive text.
|
||||
.TP
|
||||
.B \-b
|
||||
Print information about the revisions on the default branch, normally
|
||||
the highest branch on the trunk.
|
||||
.TP
|
||||
.BI \-d "dates"
|
||||
Print information about revisions with a checkin date/time in the ranges given by
|
||||
the semicolon-separated list of
|
||||
.IR dates .
|
||||
A range of the form
|
||||
.IB d1 < d2
|
||||
or
|
||||
.IB d2 > d1
|
||||
selects the revisions that were deposited between
|
||||
.I d1
|
||||
and
|
||||
.I d2
|
||||
inclusive.
|
||||
A range of the form
|
||||
.BI < d
|
||||
or
|
||||
.IB d >
|
||||
selects
|
||||
all revisions dated
|
||||
.I d
|
||||
or earlier.
|
||||
A range of the form
|
||||
.IB d <
|
||||
or
|
||||
.BI > d
|
||||
selects
|
||||
all revisions dated
|
||||
.I d
|
||||
or later.
|
||||
A range of the form
|
||||
.I d
|
||||
selects the single, latest revision dated
|
||||
.I d
|
||||
or earlier.
|
||||
The date/time strings
|
||||
.IR d ,
|
||||
.IR d1 ,
|
||||
and
|
||||
.I d2
|
||||
are in the free format explained in
|
||||
.BR co (1).
|
||||
Quoting is normally necessary, especially for
|
||||
.B <
|
||||
and
|
||||
.BR > .
|
||||
Note that the separator is
|
||||
a semicolon.
|
||||
.TP
|
||||
.BR \-l [\f2lockers\fP]
|
||||
Print information about locked revisions only.
|
||||
In addition, if the comma-separated list
|
||||
.I lockers
|
||||
of login names is given,
|
||||
ignore all locks other than those held by the
|
||||
.IR lockers .
|
||||
For example,
|
||||
.B "rlog\ \-L\ \-R\ \-lwft\ RCS/*"
|
||||
prints the name of \*r files locked by the user
|
||||
.BR wft .
|
||||
.TP
|
||||
.BR \-r [\f2revisions\fP]
|
||||
prints information about revisions given in the comma-separated list
|
||||
.I revisions
|
||||
of revisions and ranges.
|
||||
A range
|
||||
.IB rev1 : rev2
|
||||
means revisions
|
||||
.I rev1
|
||||
to
|
||||
.I rev2
|
||||
on the same branch,
|
||||
.BI : rev
|
||||
means revisions from the beginning of the branch up to and including
|
||||
.IR rev ,
|
||||
and
|
||||
.IB rev :
|
||||
means revisions starting with
|
||||
.I rev
|
||||
to the end of the branch containing
|
||||
.IR rev .
|
||||
An argument that is a branch means all
|
||||
revisions on that branch.
|
||||
A range of branches means all revisions
|
||||
on the branches in that range.
|
||||
A branch followed by a
|
||||
.B .\&
|
||||
means the latest revision in that branch.
|
||||
A bare
|
||||
.B \-r
|
||||
with no
|
||||
.I revisions
|
||||
means the latest revision on the default branch, normally the trunk.
|
||||
.TP
|
||||
.BI \-s states
|
||||
prints information about revisions whose state attributes match one of the
|
||||
states given in the comma-separated list
|
||||
.IR states .
|
||||
.TP
|
||||
.BR \-w [\f2logins\fP]
|
||||
prints information about revisions checked in by users with
|
||||
login names appearing in the comma-separated list
|
||||
.IR logins .
|
||||
If
|
||||
.I logins
|
||||
is omitted, the user's login is assumed.
|
||||
.TP
|
||||
.BI \-V n
|
||||
Emulate \*r version
|
||||
.I n
|
||||
when generating logs.
|
||||
See
|
||||
.BR co (1)
|
||||
for more.
|
||||
.TP
|
||||
.BI \-x "suffixes"
|
||||
Use
|
||||
.I suffixes
|
||||
to characterize \*r files.
|
||||
See
|
||||
.BR ci (1)
|
||||
for details.
|
||||
.PP
|
||||
.B rlog
|
||||
prints the intersection of the revisions selected with
|
||||
the options
|
||||
.BR \-d ,
|
||||
.BR \-l ,
|
||||
.BR \-s ,
|
||||
and
|
||||
.BR \-w ,
|
||||
intersected
|
||||
with the union of the revisions selected by
|
||||
.B \-b
|
||||
and
|
||||
.BR \-r .
|
||||
.SH EXAMPLES
|
||||
.LP
|
||||
.nf
|
||||
.B " rlog \-L \-R RCS/*"
|
||||
.B " rlog \-L \-h RCS/*"
|
||||
.B " rlog \-L \-l RCS/*"
|
||||
.B " rlog RCS/*"
|
||||
.fi
|
||||
.LP
|
||||
The first command prints the names of all \*r files in the subdirectory
|
||||
.B RCS
|
||||
that have locks. The second command prints the headers of those files,
|
||||
and the third prints the headers plus the log messages of the locked revisions.
|
||||
The last command prints complete information.
|
||||
.SH ENVIRONMENT
|
||||
.TP
|
||||
.B \s-1RCSINIT\s0
|
||||
options prepended to the argument list, separated by spaces.
|
||||
See
|
||||
.BR ci (1)
|
||||
for details.
|
||||
.SH DIAGNOSTICS
|
||||
The exit status is zero if and only if all operations were successful.
|
||||
.SH IDENTIFICATION
|
||||
Author: Walter F. Tichy.
|
||||
.br
|
||||
Revision Number: \*(Rv; Release Date: \*(Dt.
|
||||
.br
|
||||
Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
|
||||
.br
|
||||
Copyright \(co 1990, 1991 by Paul Eggert.
|
||||
.SH "SEE ALSO"
|
||||
ci(1), co(1), ident(1), rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1),
|
||||
rcsfile(5)
|
||||
.br
|
||||
Walter F. Tichy,
|
||||
\*r\*-A System for Version Control,
|
||||
.I "Software\*-Practice & Experience"
|
||||
.BR 15 ,
|
||||
7 (July 1985), 637-654.
|
||||
.SH BUGS
|
||||
The separator for revision ranges in the
|
||||
.B \-r
|
||||
option used to be
|
||||
.B \-
|
||||
instead of
|
||||
.BR : ,
|
||||
but this leads to confusion when symbolic names contain
|
||||
.BR \- .
|
||||
For backwards compatibility
|
||||
.B "rlog \-r"
|
||||
still supports the old
|
||||
.B \-
|
||||
separator, but it warns about this obsolete use.
|
||||
.br
|
||||
1204
gnu/usr.bin/rcs/rlog/rlog.c
Normal file
1204
gnu/usr.bin/rcs/rlog/rlog.c
Normal file
File diff suppressed because it is too large
Load diff
339
gnu/usr.bin/tar/COPYING
Normal file
339
gnu/usr.bin/tar/COPYING
Normal file
|
|
@ -0,0 +1,339 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
1732
gnu/usr.bin/tar/ChangeLog
Normal file
1732
gnu/usr.bin/tar/ChangeLog
Normal file
File diff suppressed because it is too large
Load diff
14
gnu/usr.bin/tar/Makefile
Normal file
14
gnu/usr.bin/tar/Makefile
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
PROG= tar
|
||||
SRCS= buffer.c create.c diffarch.c extract.c fnmatch.c getdate.y \
|
||||
getoldopt.c getopt.c getopt1.c gnu.c list.c mangle.c names.c port.c \
|
||||
regex.c rtapelib.c tar.c update.c version.c
|
||||
CFLAGS+= -DRETSIGTYPE=void -DDIRENT=1 -DHAVE_SYS_MTIO_H=1 -DHAVE_UNISTD_H=1
|
||||
CFLAGS+= -DHAVE_GETGRGID=1 -DHAVE_GETPWUID=1 -DHAVE_STRING_H=1
|
||||
CFLAGS+= -DHAVE_LIMITS_H=1 -DHAVE_STRSTR=1 -DHAVE_VALLOC=1 -DHAVE_MKDIR=1
|
||||
CFLAGS+= -DHAVE_MKNOD=1 -DHAVE_RENAME=1 -DHAVE_FTRUNCATE=1 -DHAVE_GETCWD=1
|
||||
CFLAGS+= -DHAVE_VPRINTF=1 -DNEEDPAD -I${.CURDIR}
|
||||
CFLAGS+= -DDEF_AR_FILE=\"/dev/rst0\" -DDEFBLOCKING=20
|
||||
NOMAN=noman
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
.include "../../usr.bin/Makefile.inc"
|
||||
185
gnu/usr.bin/tar/Makefile.gnu
Normal file
185
gnu/usr.bin/tar/Makefile.gnu
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
# Generated automatically from Makefile.in by configure.
|
||||
# Un*x Makefile for GNU tar program.
|
||||
# Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
#### Start of system configuration section. ####
|
||||
|
||||
srcdir = .
|
||||
VPATH = .
|
||||
|
||||
# If you use gcc, you should either run the fixincludes script that
|
||||
# comes with it or else use gcc with the -traditional option. Otherwise
|
||||
# ioctl calls will be compiled incorrectly on some systems.
|
||||
CC = gcc
|
||||
YACC = bison -y
|
||||
INSTALL = /usr/local/bin/install -c
|
||||
INSTALL_PROGRAM = $(INSTALL)
|
||||
INSTALL_DATA = $(INSTALL) -m 644
|
||||
|
||||
# Things you might add to DEFS:
|
||||
# -DSTDC_HEADERS If you have ANSI C headers and libraries.
|
||||
# -DHAVE_UNISTD_H If you have unistd.h.
|
||||
# -DHAVE_STRING_H If you don't have ANSI C headers but have string.h.
|
||||
# -DHAVE_LIMITS_H If you have limits.h.
|
||||
# -DBSD42 If you have sys/dir.h (unless you use -DPOSIX),
|
||||
# sys/file.h, and st_blocks in `struct stat'.
|
||||
# -DDIRENT If you have dirent.h.
|
||||
# -DSYSNDIR Old Xenix systems (sys/ndir.h).
|
||||
# -DSYSDIR Old BSD systems (sys/dir.h).
|
||||
# -DNDIR Old System V systems (ndir.h).
|
||||
# -DMAJOR_IN_MKDEV If major, minor, makedev defined in sys/mkdev.h.
|
||||
# -DMAJOR_IN_SYSMACROS If major, minor, makedev defined in sys/sysmacros.h.
|
||||
# -DRETSIGTYPE=int If your signal handlers return int, not void.
|
||||
# -DHAVE_SYS_MTIO_H If you have sys/mtio.h (magtape ioctls).
|
||||
# -DHAVE_SYS_GENTAPE_H If you have sys/gentape.h (ISC magtape ioctls).
|
||||
# -DHAVE_NETDB_H To use rexec for remote tape operations
|
||||
# instead of forking rsh or remsh.
|
||||
# -DNO_REMOTE If you have neither a remote shell nor rexec.
|
||||
# -DHAVE_VPRINTF If you have vprintf function.
|
||||
# -DHAVE_DOPRNT If you have _doprnt function (but lack vprintf).
|
||||
# -DHAVE_FTIME If you have ftime system call.
|
||||
# -DHAVE_STRSTR If you have strstr function.
|
||||
# -DHAVE_VALLOC If you have valloc function.
|
||||
# -DHAVE_MKDIR If you have mkdir and rmdir system calls.
|
||||
# -DHAVE_MKNOD If you have mknod system call.
|
||||
# -DHAVE_RENAME If you have rename system call.
|
||||
# -DHAVE_GETCWD If not POSIX.1 but have getcwd function.
|
||||
# -DHAVE_FTRUNCATE If you have ftruncate system call.
|
||||
# -DV7 On Version 7 Unix (not tested in a long time).
|
||||
# -DEMUL_OPEN3 If you lack a 3-argument version of open, and want
|
||||
# to emulate it with system calls you do have.
|
||||
# -DNO_OPEN3 If you lack the 3-argument open and want to
|
||||
# disable the tar -k option instead of emulating open.
|
||||
# -DXENIX If you have sys/inode.h and need it to be included.
|
||||
|
||||
DEF_AR_FILE = /dev/rst0
|
||||
DEFBLOCKING = 20
|
||||
DEFS = -DRETSIGTYPE=void -DDIRENT=1 -DHAVE_SYS_MTIO_H=1 -DHAVE_UNISTD_H=1 -DHAVE_GETGRGID=1 -DHAVE_GETPWUID=1 -DHAVE_STRING_H=1 -DHAVE_LIMITS_H=1 -DHAVE_STRSTR=1 -DHAVE_VALLOC=1 -DHAVE_MKDIR=1 -DHAVE_MKNOD=1 -DHAVE_RENAME=1 -DHAVE_FTRUNCATE=1 -DHAVE_GETCWD=1 -DHAVE_VPRINTF=1 -DDEF_AR_FILE=\"$(DEF_AR_FILE)\" -DDEFBLOCKING=$(DEFBLOCKING)
|
||||
|
||||
# Set this to rtapelib.o unless you defined NO_REMOTE, in which case
|
||||
# make it empty.
|
||||
RTAPELIB = rtapelib.o
|
||||
LIBS =
|
||||
|
||||
CFLAGS = -g
|
||||
LDFLAGS = -g
|
||||
|
||||
prefix = /usr/bin
|
||||
exec_prefix = $(prefix)
|
||||
|
||||
# Prefix for each installed program, normally empty or `g'.
|
||||
binprefix =
|
||||
|
||||
# The directory to install tar in.
|
||||
bindir = $(exec_prefix)/bin
|
||||
|
||||
# Where to put the rmt executable.
|
||||
libdir = /sbin
|
||||
|
||||
# The directory to install the info files in.
|
||||
infodir = $(prefix)/info
|
||||
|
||||
#### End of system configuration section. ####
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
SRC1 = tar.c create.c extract.c buffer.c getoldopt.c update.c gnu.c mangle.c
|
||||
SRC2 = version.c list.c names.c diffarch.c port.c fnmatch.c getopt.c malloc.c
|
||||
SRC3 = getopt1.c regex.c getdate.y getdate.c alloca.c
|
||||
SRCS = $(SRC1) $(SRC2) $(SRC3)
|
||||
OBJ1 = tar.o create.o extract.o buffer.o getoldopt.o update.o gnu.o mangle.o
|
||||
OBJ2 = version.o list.o names.o diffarch.o port.o fnmatch.o getopt.o
|
||||
OBJ3 = getopt1.o regex.o getdate.o $(RTAPELIB)
|
||||
OBJS = $(OBJ1) $(OBJ2) $(OBJ3)
|
||||
AUX = README INSTALL NEWS COPYING ChangeLog Makefile.in makefile.pc \
|
||||
configure configure.in \
|
||||
tar.h fnmatch.h pathmax.h port.h open3.h getopt.h regex.h \
|
||||
rmt.h rmt.c rtapelib.c \
|
||||
msd_dir.h msd_dir.c tcexparg.c \
|
||||
level-0 level-1 backup-specs dump-remind getpagesize.h
|
||||
# tar.texinfo tar.info* texinfo.tex \
|
||||
|
||||
all: tar rmt
|
||||
# tar.info
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) $(CPPFLAGS) $(DEFS) -I$(srcdir) -I. $<
|
||||
|
||||
tar: $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
|
||||
|
||||
rmt: rmt.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(srcdir)/rmt.c $(LIBS)
|
||||
|
||||
tar.info: tar.texinfo
|
||||
makeinfo $(srcdir)/tar.texinfo
|
||||
|
||||
install: all
|
||||
$(INSTALL_PROGRAM) tar $(bindir)/$(binprefix)tar
|
||||
-test ! -f rmt || $(INSTALL_PROGRAM) rmt $(libdir)/rmt
|
||||
# for file in $(srcdir)/tar.info*; \
|
||||
# do $(INSTALL_DATA) $$file $(infodir)/$$file; \
|
||||
# done
|
||||
|
||||
uninstall:
|
||||
rm -f $(bindir)/$(binprefix)tar $(infodir)/tar.info*
|
||||
-rm -f $(libdir)/rmt
|
||||
|
||||
$(OBJS): tar.h pathmax.h port.h
|
||||
regex.o buffer.o tar.o: regex.h
|
||||
tar.o fnmatch.o: fnmatch.h
|
||||
|
||||
getdate.c: getdate.y
|
||||
$(YACC) $(srcdir)/getdate.y
|
||||
mv y.tab.c getdate.c
|
||||
# getdate.y has 8 shift/reduce conflicts.
|
||||
|
||||
TAGS: $(SRCS)
|
||||
etags $(SRCS)
|
||||
|
||||
clean:
|
||||
rm -f *.o tar rmt core
|
||||
mostlyclean: clean
|
||||
|
||||
distclean: clean
|
||||
rm -f Makefile config.status
|
||||
|
||||
realclean: distclean
|
||||
rm -f TAGS *.info* getdate.c y.tab.c
|
||||
|
||||
shar: $(SRCS) $(AUX)
|
||||
shar $(SRCS) $(AUX) | gzip > tar-`sed -e '/version_string/!d' -e 's/[^0-9.]*\([0-9.]*\).*/\1/' -e q version.c`.shar.z
|
||||
|
||||
dist: $(SRCS) $(AUX)
|
||||
echo tar-`sed -e '/version_string/!d' -e 's/[^0-9.]*\([0-9.]*\).*/\1/' -e q version.c` > .fname
|
||||
-rm -rf `cat .fname`
|
||||
mkdir `cat .fname`
|
||||
for file in $(SRCS) $(AUX); do \
|
||||
ln $$file `cat .fname` || cp $$file `cat .fname`; done
|
||||
tar chzf `cat .fname`.tar.z `cat .fname`
|
||||
-rm -rf `cat .fname` .fname
|
||||
|
||||
tar.zoo: $(SRCS) $(AUX)
|
||||
-rm -rf tmp.dir
|
||||
-mkdir tmp.dir
|
||||
-rm tar.zoo
|
||||
for X in $(SRCS) $(AUX) ; do echo $$X ; sed 's/$$/
/' $$X > tmp.dir/$$X ; done
|
||||
cd tmp.dir ; zoo aM ../tar.zoo *
|
||||
-rm -rf tmp.dir
|
||||
|
||||
# Prevent GNU make v3 from overflowing arg limit on SysV.
|
||||
.NOEXPORT:
|
||||
40
gnu/usr.bin/tar/README
Normal file
40
gnu/usr.bin/tar/README
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
Hey! Emacs! Yo! This is -*- Text -*- !!!
|
||||
|
||||
This GNU tar 1.11.2. Please send bug reports, etc., to
|
||||
bug-gnu-utils@prep.ai.mit.edu. This is a beta-test release. Please
|
||||
try it out. There is no manual; the release of version 1.12 will
|
||||
contain a manual.
|
||||
|
||||
GNU tar is based heavily on John Gilmore's public domain tar, but with
|
||||
added features. The manual is currently being written.
|
||||
|
||||
This distribution also includes rmt, the remote tape server (which
|
||||
normally must reside in /etc). The mt tape drive control program is
|
||||
in the GNU cpio distribution.
|
||||
|
||||
See the file INSTALL for compilation and installation instructions for Unix.
|
||||
See the file NEWS for information on all that is new in this version
|
||||
of tar.
|
||||
|
||||
makefile.pc is a makefile for Turbo C 2.0 on MS-DOS.
|
||||
|
||||
Various people have been having problems using floppies on a NeXT. In
|
||||
order to have them work right, you need to kill the automounting
|
||||
program which tries to monut floppies as soon as they are added.
|
||||
|
||||
If you want to do incremental dumps, use the distributed backup
|
||||
scripts. They are what we use at the FSF to do all our backups. Most
|
||||
importantly, do not use --incremental (-G) or --after-date (-N) or
|
||||
--newer-mtime to do incremental dumps. The only option that works
|
||||
correctly for this purpose is --listed-incremental. (When extracting
|
||||
incremental dumps, use --incremental (-G).)
|
||||
|
||||
If your system needs to link with -lPW to get alloca, but has
|
||||
rename in the C library (so HAVE_RENAME is defined), -lPW might
|
||||
give you an incorrect version of rename. On HP-UX this manifests
|
||||
itself as an undefined data symbol called "Error" when linking cp, ln,
|
||||
and mv. If this happens, use `ar x' to extract alloca.o from libPW.a
|
||||
and `ar rc' to put it in a library liballoca.a, and put that in LIBS
|
||||
instead of -lPW. This problem does not occur when using gcc, which
|
||||
has alloca built in.
|
||||
|
||||
1584
gnu/usr.bin/tar/buffer.c
Normal file
1584
gnu/usr.bin/tar/buffer.c
Normal file
File diff suppressed because it is too large
Load diff
1454
gnu/usr.bin/tar/create.c
Normal file
1454
gnu/usr.bin/tar/create.c
Normal file
File diff suppressed because it is too large
Load diff
759
gnu/usr.bin/tar/diffarch.c
Normal file
759
gnu/usr.bin/tar/diffarch.c
Normal file
|
|
@ -0,0 +1,759 @@
|
|||
/* Diff files from a tar archive.
|
||||
Copyright (C) 1988, 1992, 1993 Free Software Foundation
|
||||
|
||||
This file is part of GNU Tar.
|
||||
|
||||
GNU Tar 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.
|
||||
|
||||
GNU Tar 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 GNU Tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/*
|
||||
* Diff files from a tar archive.
|
||||
*
|
||||
* Written 30 April 1987 by John Gilmore, ihnp4!hoptoad!gnu.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#ifndef STDC_HEADERS
|
||||
extern int errno;
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef BSD42
|
||||
#include <sys/file.h>
|
||||
#else
|
||||
#ifndef V7
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_MTIO_H
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mtio.h>
|
||||
#endif
|
||||
|
||||
#include "tar.h"
|
||||
#include "port.h"
|
||||
#include "rmt.h"
|
||||
|
||||
#ifndef S_ISLNK
|
||||
#define lstat stat
|
||||
#endif
|
||||
|
||||
extern void *valloc ();
|
||||
|
||||
extern union record *head; /* Points to current tape header */
|
||||
extern struct stat hstat; /* Stat struct corresponding */
|
||||
extern int head_standard; /* Tape header is in ANSI format */
|
||||
|
||||
void decode_header ();
|
||||
void diff_sparse_files ();
|
||||
void fill_in_sparse_array ();
|
||||
void fl_read ();
|
||||
long from_oct ();
|
||||
int do_stat ();
|
||||
extern void print_header ();
|
||||
int read_header ();
|
||||
void saverec ();
|
||||
void sigh ();
|
||||
extern void skip_file ();
|
||||
extern void skip_extended_headers ();
|
||||
int wantbytes ();
|
||||
|
||||
extern FILE *msg_file;
|
||||
|
||||
int now_verifying = 0; /* Are we verifying at the moment? */
|
||||
|
||||
int diff_fd; /* Descriptor of file we're diffing */
|
||||
|
||||
char *diff_buf = 0; /* Pointer to area for reading
|
||||
file contents into */
|
||||
|
||||
char *diff_dir; /* Directory contents for LF_DUMPDIR */
|
||||
|
||||
int different = 0;
|
||||
|
||||
/*struct sp_array *sparsearray;
|
||||
int sp_ar_size = 10;*/
|
||||
/*
|
||||
* Initialize for a diff operation
|
||||
*/
|
||||
void
|
||||
diff_init ()
|
||||
{
|
||||
/*NOSTRICT*/
|
||||
diff_buf = (char *) valloc ((unsigned) blocksize);
|
||||
if (!diff_buf)
|
||||
{
|
||||
msg ("could not allocate memory for diff buffer of %d bytes",
|
||||
blocksize);
|
||||
exit (EX_ARGSBAD);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Diff a file against the archive.
|
||||
*/
|
||||
void
|
||||
diff_archive ()
|
||||
{
|
||||
register char *data;
|
||||
int check, namelen;
|
||||
int err;
|
||||
long offset;
|
||||
struct stat filestat;
|
||||
int compare_chunk ();
|
||||
int compare_dir ();
|
||||
int no_op ();
|
||||
#ifndef __MSDOS__
|
||||
dev_t dev;
|
||||
ino_t ino;
|
||||
#endif
|
||||
char *get_dir_contents ();
|
||||
long from_oct ();
|
||||
|
||||
errno = EPIPE; /* FIXME, remove perrors */
|
||||
|
||||
saverec (&head); /* Make sure it sticks around */
|
||||
userec (head); /* And go past it in the archive */
|
||||
decode_header (head, &hstat, &head_standard, 1); /* Snarf fields */
|
||||
|
||||
/* Print the record from 'head' and 'hstat' */
|
||||
if (f_verbose)
|
||||
{
|
||||
if (now_verifying)
|
||||
fprintf (msg_file, "Verify ");
|
||||
print_header ();
|
||||
}
|
||||
|
||||
switch (head->header.linkflag)
|
||||
{
|
||||
|
||||
default:
|
||||
msg ("Unknown file type '%c' for %s, diffed as normal file",
|
||||
head->header.linkflag, current_file_name);
|
||||
/* FALL THRU */
|
||||
|
||||
case LF_OLDNORMAL:
|
||||
case LF_NORMAL:
|
||||
case LF_SPARSE:
|
||||
case LF_CONTIG:
|
||||
/*
|
||||
* Appears to be a file.
|
||||
* See if it's really a directory.
|
||||
*/
|
||||
namelen = strlen (current_file_name) - 1;
|
||||
if (current_file_name[namelen] == '/')
|
||||
goto really_dir;
|
||||
|
||||
|
||||
if (do_stat (&filestat))
|
||||
{
|
||||
if (head->header.isextended)
|
||||
skip_extended_headers ();
|
||||
skip_file ((long) hstat.st_size);
|
||||
different++;
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if (!S_ISREG (filestat.st_mode))
|
||||
{
|
||||
fprintf (msg_file, "%s: not a regular file\n",
|
||||
current_file_name);
|
||||
skip_file ((long) hstat.st_size);
|
||||
different++;
|
||||
goto quit;
|
||||
}
|
||||
|
||||
filestat.st_mode &= 07777;
|
||||
if (filestat.st_mode != hstat.st_mode)
|
||||
sigh ("mode");
|
||||
if (filestat.st_uid != hstat.st_uid)
|
||||
sigh ("uid");
|
||||
if (filestat.st_gid != hstat.st_gid)
|
||||
sigh ("gid");
|
||||
if (filestat.st_mtime != hstat.st_mtime)
|
||||
sigh ("mod time");
|
||||
if (head->header.linkflag != LF_SPARSE &&
|
||||
filestat.st_size != hstat.st_size)
|
||||
{
|
||||
sigh ("size");
|
||||
skip_file ((long) hstat.st_size);
|
||||
goto quit;
|
||||
}
|
||||
|
||||
diff_fd = open (current_file_name, O_NDELAY | O_RDONLY | O_BINARY);
|
||||
|
||||
if (diff_fd < 0 && !f_absolute_paths)
|
||||
{
|
||||
char tmpbuf[NAMSIZ + 2];
|
||||
|
||||
tmpbuf[0] = '/';
|
||||
strcpy (&tmpbuf[1], current_file_name);
|
||||
diff_fd = open (tmpbuf, O_NDELAY | O_RDONLY);
|
||||
}
|
||||
if (diff_fd < 0)
|
||||
{
|
||||
msg_perror ("cannot open %s", current_file_name);
|
||||
if (head->header.isextended)
|
||||
skip_extended_headers ();
|
||||
skip_file ((long) hstat.st_size);
|
||||
different++;
|
||||
goto quit;
|
||||
}
|
||||
/*
|
||||
* Need to treat sparse files completely differently here.
|
||||
*/
|
||||
if (head->header.linkflag == LF_SPARSE)
|
||||
diff_sparse_files (hstat.st_size);
|
||||
else
|
||||
wantbytes ((long) (hstat.st_size), compare_chunk);
|
||||
|
||||
check = close (diff_fd);
|
||||
if (check < 0)
|
||||
msg_perror ("Error while closing %s", current_file_name);
|
||||
|
||||
quit:
|
||||
break;
|
||||
|
||||
#ifndef __MSDOS__
|
||||
case LF_LINK:
|
||||
if (do_stat (&filestat))
|
||||
break;
|
||||
dev = filestat.st_dev;
|
||||
ino = filestat.st_ino;
|
||||
err = stat (current_link_name, &filestat);
|
||||
if (err < 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
fprintf (msg_file, "%s: does not exist\n", current_file_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg_perror ("cannot stat file %s", current_file_name);
|
||||
}
|
||||
different++;
|
||||
break;
|
||||
}
|
||||
if (filestat.st_dev != dev || filestat.st_ino != ino)
|
||||
{
|
||||
fprintf (msg_file, "%s not linked to %s\n", current_file_name, current_link_name);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef S_ISLNK
|
||||
case LF_SYMLINK:
|
||||
{
|
||||
char linkbuf[NAMSIZ + 3];
|
||||
check = readlink (current_file_name, linkbuf,
|
||||
(sizeof linkbuf) - 1);
|
||||
|
||||
if (check < 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
fprintf (msg_file,
|
||||
"%s: no such file or directory\n",
|
||||
current_file_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg_perror ("cannot read link %s", current_file_name);
|
||||
}
|
||||
different++;
|
||||
break;
|
||||
}
|
||||
|
||||
linkbuf[check] = '\0'; /* Null-terminate it */
|
||||
if (strncmp (current_link_name, linkbuf, check) != 0)
|
||||
{
|
||||
fprintf (msg_file, "%s: symlink differs\n",
|
||||
current_link_name);
|
||||
different++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef S_IFCHR
|
||||
case LF_CHR:
|
||||
hstat.st_mode |= S_IFCHR;
|
||||
goto check_node;
|
||||
#endif
|
||||
|
||||
#ifdef S_IFBLK
|
||||
/* If local system doesn't support block devices, use default case */
|
||||
case LF_BLK:
|
||||
hstat.st_mode |= S_IFBLK;
|
||||
goto check_node;
|
||||
#endif
|
||||
|
||||
#ifdef S_ISFIFO
|
||||
/* If local system doesn't support FIFOs, use default case */
|
||||
case LF_FIFO:
|
||||
#ifdef S_IFIFO
|
||||
hstat.st_mode |= S_IFIFO;
|
||||
#endif
|
||||
hstat.st_rdev = 0; /* FIXME, do we need this? */
|
||||
goto check_node;
|
||||
#endif
|
||||
|
||||
check_node:
|
||||
/* FIXME, deal with umask */
|
||||
if (do_stat (&filestat))
|
||||
break;
|
||||
if (hstat.st_rdev != filestat.st_rdev)
|
||||
{
|
||||
fprintf (msg_file, "%s: device numbers changed\n", current_file_name);
|
||||
different++;
|
||||
break;
|
||||
}
|
||||
#ifdef S_IFMT
|
||||
if (hstat.st_mode != filestat.st_mode)
|
||||
#else /* POSIX lossage */
|
||||
if ((hstat.st_mode & 07777) != (filestat.st_mode & 07777))
|
||||
#endif
|
||||
{
|
||||
fprintf (msg_file, "%s: mode or device-type changed\n", current_file_name);
|
||||
different++;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LF_DUMPDIR:
|
||||
data = diff_dir = get_dir_contents (current_file_name, 0);
|
||||
if (data)
|
||||
{
|
||||
wantbytes ((long) (hstat.st_size), compare_dir);
|
||||
free (data);
|
||||
}
|
||||
else
|
||||
wantbytes ((long) (hstat.st_size), no_op);
|
||||
/* FALL THROUGH */
|
||||
|
||||
case LF_DIR:
|
||||
/* Check for trailing / */
|
||||
namelen = strlen (current_file_name) - 1;
|
||||
really_dir:
|
||||
while (namelen && current_file_name[namelen] == '/')
|
||||
current_file_name[namelen--] = '\0'; /* Zap / */
|
||||
|
||||
if (do_stat (&filestat))
|
||||
break;
|
||||
if (!S_ISDIR (filestat.st_mode))
|
||||
{
|
||||
fprintf (msg_file, "%s is no longer a directory\n", current_file_name);
|
||||
different++;
|
||||
break;
|
||||
}
|
||||
if ((filestat.st_mode & 07777) != (hstat.st_mode & 07777))
|
||||
sigh ("mode");
|
||||
break;
|
||||
|
||||
case LF_VOLHDR:
|
||||
break;
|
||||
|
||||
case LF_MULTIVOL:
|
||||
namelen = strlen (current_file_name) - 1;
|
||||
if (current_file_name[namelen] == '/')
|
||||
goto really_dir;
|
||||
|
||||
if (do_stat (&filestat))
|
||||
break;
|
||||
|
||||
if (!S_ISREG (filestat.st_mode))
|
||||
{
|
||||
fprintf (msg_file, "%s: not a regular file\n",
|
||||
current_file_name);
|
||||
skip_file ((long) hstat.st_size);
|
||||
different++;
|
||||
break;
|
||||
}
|
||||
|
||||
filestat.st_mode &= 07777;
|
||||
offset = from_oct (1 + 12, head->header.offset);
|
||||
if (filestat.st_size != hstat.st_size + offset)
|
||||
{
|
||||
sigh ("size");
|
||||
skip_file ((long) hstat.st_size);
|
||||
different++;
|
||||
break;
|
||||
}
|
||||
|
||||
diff_fd = open (current_file_name, O_NDELAY | O_RDONLY | O_BINARY);
|
||||
|
||||
if (diff_fd < 0)
|
||||
{
|
||||
msg_perror ("cannot open file %s", current_file_name);
|
||||
skip_file ((long) hstat.st_size);
|
||||
different++;
|
||||
break;
|
||||
}
|
||||
err = lseek (diff_fd, offset, 0);
|
||||
if (err != offset)
|
||||
{
|
||||
msg_perror ("cannot seek to %ld in file %s", offset, current_file_name);
|
||||
different++;
|
||||
break;
|
||||
}
|
||||
|
||||
wantbytes ((long) (hstat.st_size), compare_chunk);
|
||||
|
||||
check = close (diff_fd);
|
||||
if (check < 0)
|
||||
{
|
||||
msg_perror ("Error while closing %s", current_file_name);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/* We don't need to save it any longer. */
|
||||
saverec ((union record **) 0);/* Unsave it */
|
||||
}
|
||||
|
||||
int
|
||||
compare_chunk (bytes, buffer)
|
||||
long bytes;
|
||||
char *buffer;
|
||||
{
|
||||
int err;
|
||||
|
||||
err = read (diff_fd, diff_buf, bytes);
|
||||
if (err != bytes)
|
||||
{
|
||||
if (err < 0)
|
||||
{
|
||||
msg_perror ("can't read %s", current_file_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (msg_file, "%s: could only read %d of %d bytes\n", current_file_name, err, bytes);
|
||||
}
|
||||
different++;
|
||||
return -1;
|
||||
}
|
||||
if (bcmp (buffer, diff_buf, bytes))
|
||||
{
|
||||
fprintf (msg_file, "%s: data differs\n", current_file_name);
|
||||
different++;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
compare_dir (bytes, buffer)
|
||||
long bytes;
|
||||
char *buffer;
|
||||
{
|
||||
if (bcmp (buffer, diff_dir, bytes))
|
||||
{
|
||||
fprintf (msg_file, "%s: data differs\n", current_file_name);
|
||||
different++;
|
||||
return -1;
|
||||
}
|
||||
diff_dir += bytes;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sigh about something that differs.
|
||||
*/
|
||||
void
|
||||
sigh (what)
|
||||
char *what;
|
||||
{
|
||||
|
||||
fprintf (msg_file, "%s: %s differs\n",
|
||||
current_file_name, what);
|
||||
}
|
||||
|
||||
void
|
||||
verify_volume ()
|
||||
{
|
||||
int status;
|
||||
#ifdef MTIOCTOP
|
||||
struct mtop t;
|
||||
int er;
|
||||
#endif
|
||||
|
||||
if (!diff_buf)
|
||||
diff_init ();
|
||||
#ifdef MTIOCTOP
|
||||
t.mt_op = MTBSF;
|
||||
t.mt_count = 1;
|
||||
if ((er = rmtioctl (archive, MTIOCTOP, &t)) < 0)
|
||||
{
|
||||
if (errno != EIO || (er = rmtioctl (archive, MTIOCTOP, &t)) < 0)
|
||||
{
|
||||
#endif
|
||||
if (rmtlseek (archive, 0L, 0) != 0)
|
||||
{
|
||||
/* Lseek failed. Try a different method */
|
||||
msg_perror ("Couldn't rewind archive file for verify");
|
||||
return;
|
||||
}
|
||||
#ifdef MTIOCTOP
|
||||
}
|
||||
}
|
||||
#endif
|
||||
ar_reading = 1;
|
||||
now_verifying = 1;
|
||||
fl_read ();
|
||||
for (;;)
|
||||
{
|
||||
status = read_header ();
|
||||
if (status == 0)
|
||||
{
|
||||
unsigned n;
|
||||
|
||||
n = 0;
|
||||
do
|
||||
{
|
||||
n++;
|
||||
status = read_header ();
|
||||
}
|
||||
while (status == 0);
|
||||
msg ("VERIFY FAILURE: %d invalid header%s detected!", n, n == 1 ? "" : "s");
|
||||
}
|
||||
if (status == 2 || status == EOF)
|
||||
break;
|
||||
diff_archive ();
|
||||
}
|
||||
ar_reading = 0;
|
||||
now_verifying = 0;
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
do_stat (statp)
|
||||
struct stat *statp;
|
||||
{
|
||||
int err;
|
||||
|
||||
err = f_follow_links ? stat (current_file_name, statp) : lstat (current_file_name, statp);
|
||||
if (err < 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
fprintf (msg_file, "%s: does not exist\n", current_file_name);
|
||||
}
|
||||
else
|
||||
msg_perror ("can't stat file %s", current_file_name);
|
||||
/* skip_file((long)hstat.st_size);
|
||||
different++;*/
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* JK
|
||||
* Diff'ing a sparse file with its counterpart on the tar file is a
|
||||
* bit of a different story than a normal file. First, we must know
|
||||
* what areas of the file to skip through, i.e., we need to contruct
|
||||
* a sparsearray, which will hold all the information we need. We must
|
||||
* compare small amounts of data at a time as we find it.
|
||||
*/
|
||||
|
||||
void
|
||||
diff_sparse_files (filesize)
|
||||
int filesize;
|
||||
|
||||
{
|
||||
int sparse_ind = 0;
|
||||
char *buf;
|
||||
int buf_size = RECORDSIZE;
|
||||
union record *datarec;
|
||||
int err;
|
||||
long numbytes;
|
||||
/* int amt_read = 0;*/
|
||||
int size = filesize;
|
||||
|
||||
buf = (char *) ck_malloc (buf_size * sizeof (char));
|
||||
|
||||
fill_in_sparse_array ();
|
||||
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
datarec = findrec ();
|
||||
if (!sparsearray[sparse_ind].numbytes)
|
||||
break;
|
||||
|
||||
/*
|
||||
* 'numbytes' is nicer to write than
|
||||
* 'sparsearray[sparse_ind].numbytes' all the time ...
|
||||
*/
|
||||
numbytes = sparsearray[sparse_ind].numbytes;
|
||||
|
||||
lseek (diff_fd, sparsearray[sparse_ind].offset, 0);
|
||||
/*
|
||||
* take care to not run out of room in our buffer
|
||||
*/
|
||||
while (buf_size < numbytes)
|
||||
{
|
||||
buf = (char *) ck_realloc (buf, buf_size * 2 * sizeof (char));
|
||||
buf_size *= 2;
|
||||
}
|
||||
while (numbytes > RECORDSIZE)
|
||||
{
|
||||
if ((err = read (diff_fd, buf, RECORDSIZE)) != RECORDSIZE)
|
||||
{
|
||||
if (err < 0)
|
||||
msg_perror ("can't read %s", current_file_name);
|
||||
else
|
||||
fprintf (msg_file, "%s: could only read %d of %d bytes\n",
|
||||
current_file_name, err, numbytes);
|
||||
break;
|
||||
}
|
||||
if (bcmp (buf, datarec->charptr, RECORDSIZE))
|
||||
{
|
||||
different++;
|
||||
break;
|
||||
}
|
||||
numbytes -= err;
|
||||
size -= err;
|
||||
userec (datarec);
|
||||
datarec = findrec ();
|
||||
}
|
||||
if ((err = read (diff_fd, buf, numbytes)) != numbytes)
|
||||
{
|
||||
if (err < 0)
|
||||
msg_perror ("can't read %s", current_file_name);
|
||||
else
|
||||
fprintf (msg_file, "%s: could only read %d of %d bytes\n",
|
||||
current_file_name, err, numbytes);
|
||||
break;
|
||||
}
|
||||
|
||||
if (bcmp (buf, datarec->charptr, numbytes))
|
||||
{
|
||||
different++;
|
||||
break;
|
||||
}
|
||||
/* amt_read += numbytes;
|
||||
if (amt_read >= RECORDSIZE) {
|
||||
amt_read = 0;
|
||||
userec(datarec);
|
||||
datarec = findrec();
|
||||
}*/
|
||||
userec (datarec);
|
||||
sparse_ind++;
|
||||
size -= numbytes;
|
||||
}
|
||||
/*
|
||||
* if the number of bytes read isn't the
|
||||
* number of bytes supposedly in the file,
|
||||
* they're different
|
||||
*/
|
||||
/* if (amt_read != filesize)
|
||||
different++;*/
|
||||
userec (datarec);
|
||||
free (sparsearray);
|
||||
if (different)
|
||||
fprintf (msg_file, "%s: data differs\n", current_file_name);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* JK
|
||||
* This routine should be used more often than it is ... look into
|
||||
* that. Anyhow, what it does is translate the sparse information
|
||||
* on the header, and in any subsequent extended headers, into an
|
||||
* array of structures with true numbers, as opposed to character
|
||||
* strings. It simply makes our life much easier, doing so many
|
||||
* comparisong and such.
|
||||
*/
|
||||
void
|
||||
fill_in_sparse_array ()
|
||||
{
|
||||
int ind;
|
||||
|
||||
/*
|
||||
* allocate space for our scratch space; it's initially
|
||||
* 10 elements long, but can change in this routine if
|
||||
* necessary
|
||||
*/
|
||||
sp_array_size = 10;
|
||||
sparsearray = (struct sp_array *) ck_malloc (sp_array_size * sizeof (struct sp_array));
|
||||
|
||||
/*
|
||||
* there are at most five of these structures in the header
|
||||
* itself; read these in first
|
||||
*/
|
||||
for (ind = 0; ind < SPARSE_IN_HDR; ind++)
|
||||
{
|
||||
if (!head->header.sp[ind].numbytes)
|
||||
break;
|
||||
sparsearray[ind].offset =
|
||||
from_oct (1 + 12, head->header.sp[ind].offset);
|
||||
sparsearray[ind].numbytes =
|
||||
from_oct (1 + 12, head->header.sp[ind].numbytes);
|
||||
}
|
||||
/*
|
||||
* if the header's extended, we gotta read in exhdr's till
|
||||
* we're done
|
||||
*/
|
||||
if (head->header.isextended)
|
||||
{
|
||||
/* how far into the sparsearray we are 'so far' */
|
||||
static int so_far_ind = SPARSE_IN_HDR;
|
||||
union record *exhdr;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
exhdr = findrec ();
|
||||
for (ind = 0; ind < SPARSE_EXT_HDR; ind++)
|
||||
{
|
||||
if (ind + so_far_ind > sp_array_size - 1)
|
||||
{
|
||||
/*
|
||||
* we just ran out of room in our
|
||||
* scratch area - realloc it
|
||||
*/
|
||||
sparsearray = (struct sp_array *)
|
||||
ck_realloc (sparsearray,
|
||||
sp_array_size * 2 * sizeof (struct sp_array));
|
||||
sp_array_size *= 2;
|
||||
}
|
||||
/*
|
||||
* convert the character strings into longs
|
||||
*/
|
||||
sparsearray[ind + so_far_ind].offset =
|
||||
from_oct (1 + 12, exhdr->ext_hdr.sp[ind].offset);
|
||||
sparsearray[ind + so_far_ind].numbytes =
|
||||
from_oct (1 + 12, exhdr->ext_hdr.sp[ind].numbytes);
|
||||
}
|
||||
/*
|
||||
* if this is the last extended header for this
|
||||
* file, we can stop
|
||||
*/
|
||||
if (!exhdr->ext_hdr.isextended)
|
||||
break;
|
||||
else
|
||||
{
|
||||
so_far_ind += SPARSE_EXT_HDR;
|
||||
userec (exhdr);
|
||||
}
|
||||
}
|
||||
/* be sure to skip past the last one */
|
||||
userec (exhdr);
|
||||
}
|
||||
}
|
||||
907
gnu/usr.bin/tar/extract.c
Normal file
907
gnu/usr.bin/tar/extract.c
Normal file
|
|
@ -0,0 +1,907 @@
|
|||
/* Extract files from a tar archive.
|
||||
Copyright (C) 1988, 1992, 1993 Free Software Foundation
|
||||
|
||||
This file is part of GNU Tar.
|
||||
|
||||
GNU Tar 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.
|
||||
|
||||
GNU Tar 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 GNU Tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/*
|
||||
* Extract files from a tar archive.
|
||||
*
|
||||
* Written 19 Nov 1985 by John Gilmore, ihnp4!hoptoad!gnu.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#ifndef STDC_HEADERS
|
||||
extern int errno;
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
time_t time ();
|
||||
|
||||
#ifdef BSD42
|
||||
#include <sys/file.h>
|
||||
#else
|
||||
#ifndef V7
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef NO_OPEN3
|
||||
/* We need the #define's even though we don't use them. */
|
||||
#include "open3.h"
|
||||
#endif
|
||||
|
||||
#ifdef EMUL_OPEN3
|
||||
/* Simulated 3-argument open for systems that don't have it */
|
||||
#include "open3.h"
|
||||
#endif
|
||||
|
||||
#include "tar.h"
|
||||
#include "port.h"
|
||||
|
||||
#if defined(_POSIX_VERSION)
|
||||
#include <utime.h>
|
||||
#else
|
||||
struct utimbuf
|
||||
{
|
||||
long actime;
|
||||
long modtime;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
extern FILE *msg_file;
|
||||
|
||||
extern union record *head; /* Points to current tape header */
|
||||
extern struct stat hstat; /* Stat struct corresponding */
|
||||
extern int head_standard; /* Tape header is in ANSI format */
|
||||
|
||||
extern char *save_name;
|
||||
extern long save_totsize;
|
||||
extern long save_sizeleft;
|
||||
|
||||
int confirm ();
|
||||
void decode_header ();
|
||||
void extract_mangle ();
|
||||
void extract_sparse_file ();
|
||||
long from_oct ();
|
||||
void gnu_restore ();
|
||||
extern void print_header ();
|
||||
extern void skip_file ();
|
||||
extern void skip_extended_headers ();
|
||||
extern void pr_mkdir ();
|
||||
void saverec ();
|
||||
|
||||
int make_dirs (); /* Makes required directories */
|
||||
|
||||
static time_t now = 0; /* Current time */
|
||||
static we_are_root = 0; /* True if our effective uid == 0 */
|
||||
static int notumask = ~0; /* Masks out bits user doesn't want */
|
||||
|
||||
/*
|
||||
* "Scratch" space to store the information about a sparse file before
|
||||
* writing the info into the header or extended header
|
||||
*/
|
||||
/*struct sp_array *sparsearray;*/
|
||||
|
||||
/* number of elts storable in the sparsearray */
|
||||
/*int sp_array_size = 10;*/
|
||||
|
||||
struct saved_dir_info
|
||||
{
|
||||
char *path;
|
||||
int mode;
|
||||
int atime;
|
||||
int mtime;
|
||||
struct saved_dir_info *next;
|
||||
};
|
||||
|
||||
struct saved_dir_info *saved_dir_info_head;
|
||||
|
||||
/*
|
||||
* Set up to extract files.
|
||||
*/
|
||||
void
|
||||
extr_init ()
|
||||
{
|
||||
int ourmask;
|
||||
|
||||
now = time ((time_t *) 0);
|
||||
if (geteuid () == 0)
|
||||
we_are_root = 1;
|
||||
|
||||
/*
|
||||
* We need to know our umask. But if f_use_protection is set,
|
||||
* leave our kernel umask at 0, and our "notumask" at ~0.
|
||||
*/
|
||||
ourmask = umask (0); /* Read it */
|
||||
if (!f_use_protection)
|
||||
{
|
||||
(void) umask (ourmask); /* Set it back how it was */
|
||||
notumask = ~ourmask; /* Make umask override permissions */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Extract a file from the archive.
|
||||
*/
|
||||
void
|
||||
extract_archive ()
|
||||
{
|
||||
register char *data;
|
||||
int fd, check, namelen, written, openflag;
|
||||
long size;
|
||||
struct utimbuf acc_upd_times;
|
||||
register int skipcrud;
|
||||
register int i;
|
||||
/* int sparse_ind = 0;*/
|
||||
union record *exhdr;
|
||||
struct saved_dir_info *tmp;
|
||||
/* int end_nulls; */
|
||||
|
||||
saverec (&head); /* Make sure it sticks around */
|
||||
userec (head); /* And go past it in the archive */
|
||||
decode_header (head, &hstat, &head_standard, 1); /* Snarf fields */
|
||||
|
||||
if (f_confirm && !confirm ("extract", current_file_name))
|
||||
{
|
||||
if (head->header.isextended)
|
||||
skip_extended_headers ();
|
||||
skip_file ((long) hstat.st_size);
|
||||
saverec ((union record **) 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Print the record from 'head' and 'hstat' */
|
||||
if (f_verbose)
|
||||
print_header ();
|
||||
|
||||
/*
|
||||
* Check for fully specified pathnames and other atrocities.
|
||||
*
|
||||
* Note, we can't just make a pointer to the new file name,
|
||||
* since saverec() might move the header and adjust "head".
|
||||
* We have to start from "head" every time we want to touch
|
||||
* the header record.
|
||||
*/
|
||||
skipcrud = 0;
|
||||
while (!f_absolute_paths
|
||||
&& '/' == current_file_name[skipcrud])
|
||||
{
|
||||
static int warned_once = 0;
|
||||
|
||||
skipcrud++; /* Force relative path */
|
||||
if (!warned_once++)
|
||||
{
|
||||
msg ("Removing leading / from absolute path names in the archive.");
|
||||
}
|
||||
}
|
||||
|
||||
switch (head->header.linkflag)
|
||||
{
|
||||
|
||||
default:
|
||||
msg ("Unknown file type '%c' for %s, extracted as normal file",
|
||||
head->header.linkflag, skipcrud + current_file_name);
|
||||
/* FALL THRU */
|
||||
|
||||
/*
|
||||
* JK - What we want to do if the file is sparse is loop through
|
||||
* the array of sparse structures in the header and read in
|
||||
* and translate the character strings representing 1) the offset
|
||||
* at which to write and 2) how many bytes to write into numbers,
|
||||
* which we store into the scratch array, "sparsearray". This
|
||||
* array makes our life easier the same way it did in creating
|
||||
* the tar file that had to deal with a sparse file.
|
||||
*
|
||||
* After we read in the first five (at most) sparse structures,
|
||||
* we check to see if the file has an extended header, i.e.,
|
||||
* if more sparse structures are needed to describe the contents
|
||||
* of the new file. If so, we read in the extended headers
|
||||
* and continue to store their contents into the sparsearray.
|
||||
*/
|
||||
case LF_SPARSE:
|
||||
sp_array_size = 10;
|
||||
sparsearray = (struct sp_array *) ck_malloc (sp_array_size * sizeof (struct sp_array));
|
||||
for (i = 0; i < SPARSE_IN_HDR; i++)
|
||||
{
|
||||
sparsearray[i].offset =
|
||||
from_oct (1 + 12, head->header.sp[i].offset);
|
||||
sparsearray[i].numbytes =
|
||||
from_oct (1 + 12, head->header.sp[i].numbytes);
|
||||
if (!sparsearray[i].numbytes)
|
||||
break;
|
||||
}
|
||||
|
||||
/* end_nulls = from_oct(1+12, head->header.ending_blanks);*/
|
||||
|
||||
if (head->header.isextended)
|
||||
{
|
||||
/* read in the list of extended headers
|
||||
and translate them into the sparsearray
|
||||
as before */
|
||||
|
||||
/* static */ int ind = SPARSE_IN_HDR;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
|
||||
exhdr = findrec ();
|
||||
for (i = 0; i < SPARSE_EXT_HDR; i++)
|
||||
{
|
||||
|
||||
if (i + ind > sp_array_size - 1)
|
||||
{
|
||||
/*
|
||||
* realloc the scratch area
|
||||
* since we've run out of room --
|
||||
*/
|
||||
sparsearray = (struct sp_array *)
|
||||
ck_realloc (sparsearray,
|
||||
2 * sp_array_size * (sizeof (struct sp_array)));
|
||||
sp_array_size *= 2;
|
||||
}
|
||||
if (!exhdr->ext_hdr.sp[i].numbytes)
|
||||
break;
|
||||
sparsearray[i + ind].offset =
|
||||
from_oct (1 + 12, exhdr->ext_hdr.sp[i].offset);
|
||||
sparsearray[i + ind].numbytes =
|
||||
from_oct (1 + 12, exhdr->ext_hdr.sp[i].numbytes);
|
||||
}
|
||||
if (!exhdr->ext_hdr.isextended)
|
||||
break;
|
||||
else
|
||||
{
|
||||
ind += SPARSE_EXT_HDR;
|
||||
userec (exhdr);
|
||||
}
|
||||
}
|
||||
userec (exhdr);
|
||||
}
|
||||
|
||||
/* FALL THRU */
|
||||
case LF_OLDNORMAL:
|
||||
case LF_NORMAL:
|
||||
case LF_CONTIG:
|
||||
/*
|
||||
* Appears to be a file.
|
||||
* See if it's really a directory.
|
||||
*/
|
||||
namelen = strlen (skipcrud + current_file_name) - 1;
|
||||
if (current_file_name[skipcrud + namelen] == '/')
|
||||
goto really_dir;
|
||||
|
||||
/* FIXME, deal with protection issues */
|
||||
again_file:
|
||||
openflag = (f_keep ?
|
||||
O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_EXCL :
|
||||
O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_TRUNC)
|
||||
| ((head->header.linkflag == LF_SPARSE) ? 0 : O_APPEND);
|
||||
/*
|
||||
* JK - The last | is a kludge to solve the problem
|
||||
* the O_APPEND flag causes with files we are
|
||||
* trying to make sparse: when a file is opened
|
||||
* with O_APPEND, it writes to the last place
|
||||
* that something was written, thereby ignoring
|
||||
* any lseeks that we have done. We add this
|
||||
* extra condition to make it able to lseek when
|
||||
* a file is sparse, i.e., we don't open the new
|
||||
* file with this flag. (Grump -- this bug caused
|
||||
* me to waste a good deal of time, I might add)
|
||||
*/
|
||||
|
||||
if (f_exstdout)
|
||||
{
|
||||
fd = 1;
|
||||
goto extract_file;
|
||||
}
|
||||
#ifdef O_CTG
|
||||
/*
|
||||
* Contiguous files (on the Masscomp) have to specify
|
||||
* the size in the open call that creates them.
|
||||
*/
|
||||
if (head->header.linkflag == LF_CONTIG)
|
||||
fd = open ((longname ? longname : head->header.name)
|
||||
+ skipcrud,
|
||||
openflag | O_CTG,
|
||||
hstat.st_mode, hstat.st_size);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef NO_OPEN3
|
||||
/*
|
||||
* On raw V7 we won't let them specify -k (f_keep), but
|
||||
* we just bull ahead and create the files.
|
||||
*/
|
||||
fd = creat ((longname
|
||||
? longname
|
||||
: head->header.name) + skipcrud,
|
||||
hstat.st_mode);
|
||||
#else
|
||||
/*
|
||||
* With 3-arg open(), we can do this up right.
|
||||
*/
|
||||
fd = open (skipcrud + current_file_name,
|
||||
openflag, hstat.st_mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
if (make_dirs (skipcrud + current_file_name))
|
||||
goto again_file;
|
||||
msg_perror ("Could not create file %s",
|
||||
skipcrud + current_file_name);
|
||||
if (head->header.isextended)
|
||||
skip_extended_headers ();
|
||||
skip_file ((long) hstat.st_size);
|
||||
goto quit;
|
||||
}
|
||||
|
||||
extract_file:
|
||||
if (head->header.linkflag == LF_SPARSE)
|
||||
{
|
||||
char *name;
|
||||
int namelen;
|
||||
|
||||
/*
|
||||
* Kludge alert. NAME is assigned to header.name
|
||||
* because during the extraction, the space that
|
||||
* contains the header will get scribbled on, and
|
||||
* the name will get munged, so any error messages
|
||||
* that happen to contain the filename will look
|
||||
* REAL interesting unless we do this.
|
||||
*/
|
||||
namelen = strlen (skipcrud + current_file_name) + 1;
|
||||
name = (char *) ck_malloc ((sizeof (char)) * namelen);
|
||||
bcopy (skipcrud + current_file_name, name, namelen);
|
||||
size = hstat.st_size;
|
||||
extract_sparse_file (fd, &size, hstat.st_size, name);
|
||||
}
|
||||
else
|
||||
for (size = hstat.st_size;
|
||||
size > 0;
|
||||
size -= written)
|
||||
{
|
||||
|
||||
/* long offset,
|
||||
numbytes;*/
|
||||
|
||||
if (f_multivol)
|
||||
{
|
||||
save_name = current_file_name;
|
||||
save_totsize = hstat.st_size;
|
||||
save_sizeleft = size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Locate data, determine max length
|
||||
* writeable, write it, record that
|
||||
* we have used the data, then check
|
||||
* if the write worked.
|
||||
*/
|
||||
data = findrec ()->charptr;
|
||||
if (data == NULL)
|
||||
{ /* Check it... */
|
||||
msg ("Unexpected EOF on archive file");
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* JK - If the file is sparse, use the sparsearray
|
||||
* that we created before to lseek into the new
|
||||
* file the proper amount, and to see how many
|
||||
* bytes we want to write at that position.
|
||||
*/
|
||||
/* if (head->header.linkflag == LF_SPARSE) {
|
||||
off_t pos;
|
||||
|
||||
pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0);
|
||||
printf("%d at %d\n", (int) pos, sparse_ind);
|
||||
written = sparsearray[sparse_ind++].numbytes;
|
||||
} else*/
|
||||
written = endofrecs ()->charptr - data;
|
||||
if (written > size)
|
||||
written = size;
|
||||
errno = 0;
|
||||
check = write (fd, data, written);
|
||||
/*
|
||||
* The following is in violation of strict
|
||||
* typing, since the arg to userec
|
||||
* should be a struct rec *. FIXME.
|
||||
*/
|
||||
userec ((union record *) (data + written - 1));
|
||||
if (check == written)
|
||||
continue;
|
||||
/*
|
||||
* Error in writing to file.
|
||||
* Print it, skip to next file in archive.
|
||||
*/
|
||||
if (check < 0)
|
||||
msg_perror ("couldn't write to file %s",
|
||||
skipcrud + current_file_name);
|
||||
else
|
||||
msg ("could only write %d of %d bytes to file %s",
|
||||
check, written, skipcrud + current_file_name);
|
||||
skip_file ((long) (size - written));
|
||||
break; /* Still do the close, mod time, chmod, etc */
|
||||
}
|
||||
|
||||
if (f_multivol)
|
||||
save_name = 0;
|
||||
|
||||
/* If writing to stdout, don't try to do anything
|
||||
to the filename; it doesn't exist, or we don't
|
||||
want to touch it anyway */
|
||||
if (f_exstdout)
|
||||
break;
|
||||
|
||||
/* if (head->header.isextended) {
|
||||
register union record *exhdr;
|
||||
register int i;
|
||||
|
||||
for (i = 0; i < 21; i++) {
|
||||
long offset;
|
||||
|
||||
if (!exhdr->ext_hdr.sp[i].numbytes)
|
||||
break;
|
||||
offset = from_oct(1+12,
|
||||
exhdr->ext_hdr.sp[i].offset);
|
||||
written = from_oct(1+12,
|
||||
exhdr->ext_hdr.sp[i].numbytes);
|
||||
lseek(fd, offset, 0);
|
||||
check = write(fd, data, written);
|
||||
if (check == written) continue;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}*/
|
||||
check = close (fd);
|
||||
if (check < 0)
|
||||
{
|
||||
msg_perror ("Error while closing %s",
|
||||
skipcrud + current_file_name);
|
||||
}
|
||||
|
||||
|
||||
set_filestat:
|
||||
|
||||
/*
|
||||
* If we are root, set the owner and group of the extracted
|
||||
* file. This does what is wanted both on real Unix and on
|
||||
* System V. If we are running as a user, we extract as that
|
||||
* user; if running as root, we extract as the original owner.
|
||||
*/
|
||||
if (we_are_root || f_do_chown)
|
||||
{
|
||||
if (chown (skipcrud + current_file_name,
|
||||
hstat.st_uid, hstat.st_gid) < 0)
|
||||
{
|
||||
msg_perror ("cannot chown file %s to uid %d gid %d",
|
||||
skipcrud + current_file_name,
|
||||
hstat.st_uid, hstat.st_gid);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the modified time of the file.
|
||||
*
|
||||
* Note that we set the accessed time to "now", which
|
||||
* is really "the time we started extracting files".
|
||||
* unless f_gnudump is used, in which case .st_atime is used
|
||||
*/
|
||||
if (!f_modified)
|
||||
{
|
||||
/* fixme if f_gnudump should set ctime too, but how? */
|
||||
if (f_gnudump)
|
||||
acc_upd_times.actime = hstat.st_atime;
|
||||
else
|
||||
acc_upd_times.actime = now; /* Accessed now */
|
||||
acc_upd_times.modtime = hstat.st_mtime; /* Mod'd */
|
||||
if (utime (skipcrud + current_file_name,
|
||||
&acc_upd_times) < 0)
|
||||
{
|
||||
msg_perror ("couldn't change access and modification times of %s", skipcrud + current_file_name);
|
||||
}
|
||||
}
|
||||
/* We do the utime before the chmod because some versions of
|
||||
utime are broken and trash the modes of the file. Since
|
||||
we then change the mode anyway, we don't care. . . */
|
||||
|
||||
/*
|
||||
* If '-k' is not set, open() or creat() could have saved
|
||||
* the permission bits from a previously created file,
|
||||
* ignoring the ones we specified.
|
||||
* Even if -k is set, if the file has abnormal
|
||||
* mode bits, we must chmod since writing or chown() has
|
||||
* probably reset them.
|
||||
*
|
||||
* If -k is set, we know *we* created this file, so the mode
|
||||
* bits were set by our open(). If the file is "normal", we
|
||||
* skip the chmod. This works because we did umask(0) if -p
|
||||
* is set, so umask will have left the specified mode alone.
|
||||
*/
|
||||
if ((!f_keep)
|
||||
|| (hstat.st_mode & (S_ISUID | S_ISGID | S_ISVTX)))
|
||||
{
|
||||
if (chmod (skipcrud + current_file_name,
|
||||
notumask & (int) hstat.st_mode) < 0)
|
||||
{
|
||||
msg_perror ("cannot change mode of file %s to %ld",
|
||||
skipcrud + current_file_name,
|
||||
notumask & (int) hstat.st_mode);
|
||||
}
|
||||
}
|
||||
|
||||
quit:
|
||||
break;
|
||||
|
||||
case LF_LINK:
|
||||
again_link:
|
||||
{
|
||||
struct stat st1, st2;
|
||||
|
||||
check = link (current_link_name, skipcrud + current_file_name);
|
||||
|
||||
if (check == 0)
|
||||
break;
|
||||
if (make_dirs (skipcrud + current_file_name))
|
||||
goto again_link;
|
||||
if (f_gnudump && errno == EEXIST)
|
||||
break;
|
||||
if (stat (current_link_name, &st1) == 0
|
||||
&& stat (current_file_name + skipcrud, &st2) == 0
|
||||
&& st1.st_dev == st2.st_dev
|
||||
&& st1.st_ino == st2.st_ino)
|
||||
break;
|
||||
msg_perror ("Could not link %s to %s",
|
||||
skipcrud + current_file_name,
|
||||
current_link_name);
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef S_ISLNK
|
||||
case LF_SYMLINK:
|
||||
again_symlink:
|
||||
check = symlink (current_link_name,
|
||||
skipcrud + current_file_name);
|
||||
/* FIXME, don't worry uid, gid, etc... */
|
||||
if (check == 0)
|
||||
break;
|
||||
if (make_dirs (current_file_name + skipcrud))
|
||||
goto again_symlink;
|
||||
msg_perror ("Could not create symlink to %s",
|
||||
current_link_name);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef S_IFCHR
|
||||
case LF_CHR:
|
||||
hstat.st_mode |= S_IFCHR;
|
||||
goto make_node;
|
||||
#endif
|
||||
|
||||
#ifdef S_IFBLK
|
||||
case LF_BLK:
|
||||
hstat.st_mode |= S_IFBLK;
|
||||
#endif
|
||||
#if defined(S_IFCHR) || defined(S_IFBLK)
|
||||
make_node:
|
||||
check = mknod (current_file_name + skipcrud,
|
||||
(int) hstat.st_mode, (int) hstat.st_rdev);
|
||||
if (check != 0)
|
||||
{
|
||||
if (make_dirs (skipcrud + current_file_name))
|
||||
goto make_node;
|
||||
msg_perror ("Could not make %s",
|
||||
current_file_name + skipcrud);
|
||||
break;
|
||||
};
|
||||
goto set_filestat;
|
||||
#endif
|
||||
|
||||
#ifdef S_ISFIFO
|
||||
/* If local system doesn't support FIFOs, use default case */
|
||||
case LF_FIFO:
|
||||
make_fifo:
|
||||
check = mkfifo (current_file_name + skipcrud,
|
||||
(int) hstat.st_mode);
|
||||
if (check != 0)
|
||||
{
|
||||
if (make_dirs (current_file_name + skipcrud))
|
||||
goto make_fifo;
|
||||
msg_perror ("Could not make %s",
|
||||
skipcrud + current_file_name);
|
||||
break;
|
||||
};
|
||||
goto set_filestat;
|
||||
#endif
|
||||
|
||||
case LF_DIR:
|
||||
case LF_DUMPDIR:
|
||||
namelen = strlen (current_file_name + skipcrud) - 1;
|
||||
really_dir:
|
||||
/* Check for trailing /, and zap as many as we find. */
|
||||
while (namelen
|
||||
&& current_file_name[skipcrud + namelen] == '/')
|
||||
current_file_name[skipcrud + namelen--] = '\0';
|
||||
if (f_gnudump)
|
||||
{ /* Read the entry and delete files
|
||||
that aren't listed in the archive */
|
||||
gnu_restore (skipcrud);
|
||||
|
||||
}
|
||||
else if (head->header.linkflag == LF_DUMPDIR)
|
||||
skip_file ((long) (hstat.st_size));
|
||||
|
||||
|
||||
again_dir:
|
||||
check = mkdir (skipcrud + current_file_name,
|
||||
(we_are_root ? 0 : 0300) | (int) hstat.st_mode);
|
||||
if (check != 0)
|
||||
{
|
||||
struct stat st1;
|
||||
|
||||
if (make_dirs (skipcrud + current_file_name))
|
||||
goto again_dir;
|
||||
/* If we're trying to create '.', let it be. */
|
||||
if (current_file_name[skipcrud + namelen] == '.' &&
|
||||
(namelen == 0 ||
|
||||
current_file_name[skipcrud + namelen - 1] == '/'))
|
||||
goto check_perms;
|
||||
if (errno == EEXIST
|
||||
&& stat (skipcrud + current_file_name, &st1) == 0
|
||||
&& (S_ISDIR (st1.st_mode)))
|
||||
break;
|
||||
msg_perror ("Could not create directory %s", skipcrud + current_file_name);
|
||||
break;
|
||||
}
|
||||
|
||||
check_perms:
|
||||
if (!we_are_root && 0300 != (0300 & (int) hstat.st_mode))
|
||||
{
|
||||
hstat.st_mode |= 0300;
|
||||
msg ("Added write and execute permission to directory %s",
|
||||
skipcrud + current_file_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are root, set the owner and group of the extracted
|
||||
* file. This does what is wanted both on real Unix and on
|
||||
* System V. If we are running as a user, we extract as that
|
||||
* user; if running as root, we extract as the original owner.
|
||||
*/
|
||||
if (we_are_root || f_do_chown)
|
||||
{
|
||||
if (chown (skipcrud + current_file_name,
|
||||
hstat.st_uid, hstat.st_gid) < 0)
|
||||
{
|
||||
msg_perror ("cannot chown file %s to uid %d gid %d",
|
||||
skipcrud + current_file_name,
|
||||
hstat.st_uid, hstat.st_gid);
|
||||
}
|
||||
}
|
||||
|
||||
if (!f_modified)
|
||||
{
|
||||
tmp = ((struct saved_dir_info *)
|
||||
ck_malloc (sizeof (struct saved_dir_info)));
|
||||
tmp->path = (char *) ck_malloc (strlen (skipcrud
|
||||
+ current_file_name) + 1);
|
||||
strcpy (tmp->path, skipcrud + current_file_name);
|
||||
tmp->mode = hstat.st_mode;
|
||||
tmp->atime = hstat.st_atime;
|
||||
tmp->mtime = hstat.st_mtime;
|
||||
tmp->next = saved_dir_info_head;
|
||||
saved_dir_info_head = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This functions exactly as the code for set_filestat above. */
|
||||
if ((!f_keep)
|
||||
|| (hstat.st_mode & (S_ISUID | S_ISGID | S_ISVTX)))
|
||||
{
|
||||
if (chmod (skipcrud + current_file_name,
|
||||
notumask & (int) hstat.st_mode) < 0)
|
||||
{
|
||||
msg_perror ("cannot change mode of file %s to %ld",
|
||||
skipcrud + current_file_name,
|
||||
notumask & (int) hstat.st_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LF_VOLHDR:
|
||||
if (f_verbose)
|
||||
{
|
||||
printf ("Reading %s\n", current_file_name);
|
||||
}
|
||||
break;
|
||||
|
||||
case LF_NAMES:
|
||||
extract_mangle (head);
|
||||
break;
|
||||
|
||||
case LF_MULTIVOL:
|
||||
msg ("Can't extract '%s'--file is continued from another volume\n", current_file_name);
|
||||
skip_file ((long) hstat.st_size);
|
||||
break;
|
||||
|
||||
case LF_LONGNAME:
|
||||
case LF_LONGLINK:
|
||||
msg ("Visible long name error\n");
|
||||
skip_file ((long) hstat.st_size);
|
||||
break;
|
||||
}
|
||||
|
||||
/* We don't need to save it any longer. */
|
||||
saverec ((union record **) 0);/* Unsave it */
|
||||
}
|
||||
|
||||
/*
|
||||
* After a file/link/symlink/dir creation has failed, see if
|
||||
* it's because some required directory was not present, and if
|
||||
* so, create all required dirs.
|
||||
*/
|
||||
int
|
||||
make_dirs (pathname)
|
||||
char *pathname;
|
||||
{
|
||||
char *p; /* Points into path */
|
||||
int madeone = 0; /* Did we do anything yet? */
|
||||
int save_errno = errno; /* Remember caller's errno */
|
||||
int check;
|
||||
|
||||
if (errno != ENOENT)
|
||||
return 0; /* Not our problem */
|
||||
|
||||
for (p = index (pathname, '/'); p != NULL; p = index (p + 1, '/'))
|
||||
{
|
||||
/* Avoid mkdir of empty string, if leading or double '/' */
|
||||
if (p == pathname || p[-1] == '/')
|
||||
continue;
|
||||
/* Avoid mkdir where last part of path is '.' */
|
||||
if (p[-1] == '.' && (p == pathname + 1 || p[-2] == '/'))
|
||||
continue;
|
||||
*p = 0; /* Truncate the path there */
|
||||
check = mkdir (pathname, 0777); /* Try to create it as a dir */
|
||||
if (check == 0)
|
||||
{
|
||||
/* Fix ownership */
|
||||
if (we_are_root)
|
||||
{
|
||||
if (chown (pathname, hstat.st_uid,
|
||||
hstat.st_gid) < 0)
|
||||
{
|
||||
msg_perror ("cannot change owner of %s to uid %d gid %d", pathname, hstat.st_uid, hstat.st_gid);
|
||||
}
|
||||
}
|
||||
pr_mkdir (pathname, p - pathname, notumask & 0777);
|
||||
madeone++; /* Remember if we made one */
|
||||
*p = '/';
|
||||
continue;
|
||||
}
|
||||
*p = '/';
|
||||
if (errno == EEXIST) /* Directory already exists */
|
||||
continue;
|
||||
/*
|
||||
* Some other error in the mkdir. We return to the caller.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
errno = save_errno; /* Restore caller's errno */
|
||||
return madeone; /* Tell them to retry if we made one */
|
||||
}
|
||||
|
||||
void
|
||||
extract_sparse_file (fd, sizeleft, totalsize, name)
|
||||
int fd;
|
||||
long *sizeleft, totalsize;
|
||||
char *name;
|
||||
{
|
||||
/* register char *data;*/
|
||||
union record *datarec;
|
||||
int sparse_ind = 0;
|
||||
int written, count;
|
||||
|
||||
/* assuming sizeleft is initially totalsize */
|
||||
|
||||
|
||||
while (*sizeleft > 0)
|
||||
{
|
||||
datarec = findrec ();
|
||||
if (datarec == NULL)
|
||||
{
|
||||
msg ("Unexpected EOF on archive file");
|
||||
return;
|
||||
}
|
||||
lseek (fd, sparsearray[sparse_ind].offset, 0);
|
||||
written = sparsearray[sparse_ind++].numbytes;
|
||||
while (written > RECORDSIZE)
|
||||
{
|
||||
count = write (fd, datarec->charptr, RECORDSIZE);
|
||||
if (count < 0)
|
||||
msg_perror ("couldn't write to file %s", name);
|
||||
written -= count;
|
||||
*sizeleft -= count;
|
||||
userec (datarec);
|
||||
datarec = findrec ();
|
||||
}
|
||||
|
||||
count = write (fd, datarec->charptr, written);
|
||||
|
||||
if (count < 0)
|
||||
{
|
||||
msg_perror ("couldn't write to file %s", name);
|
||||
}
|
||||
else if (count != written)
|
||||
{
|
||||
msg ("could only write %d of %d bytes to file %s", count,
|
||||
totalsize, name);
|
||||
skip_file ((long) (*sizeleft));
|
||||
}
|
||||
|
||||
written -= count;
|
||||
*sizeleft -= count;
|
||||
userec (datarec);
|
||||
}
|
||||
free (sparsearray);
|
||||
/* if (end_nulls) {
|
||||
register int i;
|
||||
|
||||
printf("%d\n", (int) end_nulls);
|
||||
for (i = 0; i < end_nulls; i++)
|
||||
write(fd, "\000", 1);
|
||||
}*/
|
||||
userec (datarec);
|
||||
}
|
||||
|
||||
/* Set back the utime and mode for all the extracted directories. */
|
||||
void
|
||||
restore_saved_dir_info ()
|
||||
{
|
||||
struct utimbuf acc_upd_times;
|
||||
|
||||
while (saved_dir_info_head != NULL)
|
||||
{
|
||||
/* fixme if f_gnudump should set ctime too, but how? */
|
||||
if (f_gnudump)
|
||||
acc_upd_times.actime = saved_dir_info_head->atime;
|
||||
else
|
||||
acc_upd_times.actime = now; /* Accessed now */
|
||||
acc_upd_times.modtime = saved_dir_info_head->mtime; /* Mod'd */
|
||||
if (utime (saved_dir_info_head->path, &acc_upd_times) < 0)
|
||||
{
|
||||
msg_perror ("couldn't change access and modification times of %s",
|
||||
saved_dir_info_head->path);
|
||||
}
|
||||
if ((!f_keep) || (saved_dir_info_head->mode & (S_ISUID | S_ISGID | S_ISVTX)))
|
||||
{
|
||||
if (chmod (saved_dir_info_head->path,
|
||||
notumask & saved_dir_info_head->mode) < 0)
|
||||
{
|
||||
msg_perror ("cannot change mode of file %s to %ld",
|
||||
saved_dir_info_head->path,
|
||||
notumask & saved_dir_info_head->mode);
|
||||
}
|
||||
}
|
||||
saved_dir_info_head = saved_dir_info_head->next;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue