mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-09 10:00:39 +00:00
Remove old version of awk.
This commit is contained in:
parent
9addf1c150
commit
60e8807fae
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=30416
|
@ -1,25 +0,0 @@
|
|||
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 <michal@gortel.phys.UAlberta.CA> (Atari, NeXT, DEC 3100)
|
||||
Mike Lijewski <mjlx@eagle.cnsf.cornell.edu> (IBM RS6000)
|
||||
Scott Deifik <scottd@amgen.com> (MSDOS 2.14 and 2.15)
|
||||
Kent Williams (MSDOS 2.11)
|
||||
Conrad Kwok (MSDOS earlier versions)
|
||||
Scott Garfinkle (MSDOS earlier versions)
|
||||
Kai Uwe Rommel <rommel@ars.muc.de> (OS/2)
|
||||
Darrel Hankerson <hankedr@mail.auburn.edu> (OS/2)
|
||||
Mark Moraes <Mark-Moraes@deshaw.com> (Code Center, Purify)
|
||||
Kaveh Ghazi <ghazi@noc.rutgers.edu> (Lots of Unix variants)
|
||||
|
||||
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".
|
|
@ -1,340 +0,0 @@
|
|||
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.
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
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 developer(s) to help keep themselves on track, please
|
||||
don't bug us too much about schedules or what all this really means.
|
||||
|
||||
(An `x' indicates that some progress has been made, but that the feature is
|
||||
not complete yet.)
|
||||
|
||||
For 2.16
|
||||
========
|
||||
x Move to autoconf-based configure system.
|
||||
|
||||
x Research awk `fflush' function.
|
||||
|
||||
x Generalize IGNORECASE
|
||||
any value makes it work, not just numeric non-zero
|
||||
make it apply to *all* string comparisons
|
||||
|
||||
x Fix FILENAME to have an initial value of "", not "-"
|
||||
|
||||
In 2.17
|
||||
=======
|
||||
x 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
|
||||
|
||||
x Split() with null string as third arg to split up strings
|
||||
|
||||
x Analogously, setting FS="" would split the input record into individual
|
||||
characters.
|
||||
|
||||
x Clean up code by isolating system-specific functions in separate files.
|
||||
|
||||
Undertake significant directory reorganization.
|
||||
|
||||
x Extensive manual cleanup:
|
||||
Use of texinfo 2.0 features
|
||||
Lots more examples
|
||||
Document all of the above.
|
||||
|
||||
x Go to POSIX regexps
|
||||
|
||||
Make regex + dfa less dependant on gawk header file includes
|
||||
|
||||
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
|
||||
========
|
||||
DBM storage of awk arrays. Try to allow multiple dbm packages
|
||||
|
||||
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.
|
||||
|
||||
? Have strftime() pay attention to the value of ENVIRON["TZ"]
|
||||
|
||||
For 2.19
|
||||
========
|
||||
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.
|
||||
|
||||
Do an optimization pass over parse tree?
|
||||
|
||||
For 2.20 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 and CONVFMT 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.
|
||||
|
||||
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
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
|
||||
Number of input records in one file: MAX_LONG
|
||||
Number of input records total: MAX_LONG
|
1480
gnu/usr.bin/awk/NEWS
1480
gnu/usr.bin/awk/NEWS
File diff suppressed because it is too large
Load diff
|
@ -1,35 +0,0 @@
|
|||
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@noc.rutgers.edu (Kaveh R. Ghazi):
|
||||
|
||||
arch configured as:
|
||||
---- --------------
|
||||
Dec Alpha OSF 1.3 osf1
|
||||
Hpux 9.0 hpux8x
|
||||
NeXTStep 2.0 next20
|
||||
Sgi Irix 4.0.5 (/bin/cc) sgi405.cc
|
||||
Stardent Titan 1500 OSv2.5 sysv3
|
||||
Stardent Vistra (i860) SVR4 sysv4
|
||||
Solaris 2.3 solaris2.cc
|
||||
SunOS 4.1.3 sunos41
|
||||
Tektronix XD88 (UTekV 3.2e) sysv3
|
||||
Tektronix 4300 (UTek 4.0) utek
|
||||
Ultrix 4.2 ultrix41
|
|
@ -1,95 +0,0 @@
|
|||
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" )
|
||||
}
|
||||
}'
|
|
@ -1,10 +0,0 @@
|
|||
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. The interactions with the lexer and yyerror need reworking. It is possible
|
||||
to get line numbers that are one line off if --compat or --posix is
|
||||
true and either `next file' or `delete array' are used.
|
||||
|
||||
Really the whole lexical analysis stuff needs reworking.
|
|
@ -1,125 +0,0 @@
|
|||
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 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 NEWS 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.
|
||||
|
||||
A quick overview of the installation process is in the file INSTALL.
|
||||
|
||||
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 or OS/2 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.
|
||||
(However, it does not discuss OS/2 configuration, see README.pc for
|
||||
the details. The manual is being massively revised for 2.16.)
|
||||
|
||||
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.115, 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-3528, 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
|
||||
michal@gortel.phys.ualberta.ca (e-mail only)
|
||||
|
||||
OS/2:
|
||||
Kai Uwe Rommel
|
||||
rommel@ars.muc.de (e-mail only)
|
||||
Darrel Hankerson
|
||||
hankedr@mail.auburn.edu (e-mail only)
|
|
@ -1,515 +0,0 @@
|
|||
/*
|
||||
* array.c - routines for associative arrays.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Tree walks (``for (iggy in foo)'') and array deletions use expensive
|
||||
* linear searching. So what we do is start out with small arrays and
|
||||
* grow them as needed, so that our arrays are hopefully small enough,
|
||||
* most of the time, that they're pretty full and we're not looking at
|
||||
* wasted space.
|
||||
*
|
||||
* The decision is made to grow the array if the average chain length is
|
||||
* ``too big''. This is defined as the total number of entries in the table
|
||||
* divided by the size of the array being greater than some constant.
|
||||
*/
|
||||
|
||||
#define AVG_CHAIN_MAX 10 /* don't want to linear search more than this */
|
||||
|
||||
#include "awk.h"
|
||||
|
||||
static NODE *assoc_find P((NODE *symbol, NODE *subs, int hash1));
|
||||
static void grow_table P((NODE *symbol));
|
||||
|
||||
NODE *
|
||||
concat_exp(tree)
|
||||
register NODE *tree;
|
||||
{
|
||||
register NODE *r;
|
||||
char *str;
|
||||
char *s;
|
||||
size_t len;
|
||||
int offset;
|
||||
size_t 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 < symbol->array_size; 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;
|
||||
}
|
||||
free(symbol->var_array);
|
||||
symbol->var_array = NULL;
|
||||
symbol->array_size = symbol->table_size = 0;
|
||||
symbol->flags &= ~ARRAYMAXED;
|
||||
}
|
||||
|
||||
/*
|
||||
* calculate the hash function of the string in subs
|
||||
*/
|
||||
unsigned int
|
||||
hash(s, len, hsize)
|
||||
register const char *s;
|
||||
register size_t len;
|
||||
unsigned long hsize;
|
||||
{
|
||||
register unsigned long h = 0;
|
||||
|
||||
#ifdef this_is_really_slow
|
||||
|
||||
register unsigned long g;
|
||||
|
||||
while (len--) {
|
||||
h = (h << 4) + *s++;
|
||||
g = (h & 0xf0000000);
|
||||
if (g) {
|
||||
h = h ^ (g >> 24);
|
||||
h = h ^ g;
|
||||
}
|
||||
}
|
||||
|
||||
#else /* this_is_really_slow */
|
||||
/*
|
||||
* This is INCREDIBLY ugly, but fast. We break the string up into 8 byte
|
||||
* units. On the first time through the loop we get the "leftover bytes"
|
||||
* (strlen % 8). On every other iteration, we perform 8 HASHC's so we handle
|
||||
* all 8 bytes. Essentially, this saves us 7 cmp & branch instructions. If
|
||||
* this routine is heavily used enough, it's worth the ugly coding.
|
||||
*
|
||||
* OZ's original sdbm hash, copied from Margo Seltzers db package.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Even more speed: */
|
||||
/* #define HASHC h = *s++ + 65599 * h */
|
||||
/* Because 65599 = pow(2,6) + pow(2,16) - 1 we multiply by shifts */
|
||||
#define HASHC htmp = (h << 6); \
|
||||
h = *s++ + htmp + (htmp << 10) - h
|
||||
|
||||
unsigned long htmp;
|
||||
|
||||
h = 0;
|
||||
|
||||
#if defined(VAXC)
|
||||
/*
|
||||
* [This was an implementation of "Duff's Device", but it has been
|
||||
* redone, separating the switch for extra iterations from the loop.
|
||||
* This is necessary because the DEC VAX-C compiler is STOOPID.]
|
||||
*/
|
||||
switch (len & (8 - 1)) {
|
||||
case 7: HASHC;
|
||||
case 6: HASHC;
|
||||
case 5: HASHC;
|
||||
case 4: HASHC;
|
||||
case 3: HASHC;
|
||||
case 2: HASHC;
|
||||
case 1: HASHC;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (len > (8 - 1)) {
|
||||
register size_t loop = len >> 3;
|
||||
do {
|
||||
HASHC;
|
||||
HASHC;
|
||||
HASHC;
|
||||
HASHC;
|
||||
HASHC;
|
||||
HASHC;
|
||||
HASHC;
|
||||
HASHC;
|
||||
} while (--loop);
|
||||
}
|
||||
#else /* !VAXC */
|
||||
/* "Duff's Device" for those who can handle it */
|
||||
if (len > 0) {
|
||||
register size_t loop = (len + 8 - 1) >> 3;
|
||||
|
||||
switch (len & (8 - 1)) {
|
||||
case 0:
|
||||
do { /* All fall throughs */
|
||||
HASHC;
|
||||
case 7: HASHC;
|
||||
case 6: HASHC;
|
||||
case 5: HASHC;
|
||||
case 4: HASHC;
|
||||
case 3: HASHC;
|
||||
case 2: HASHC;
|
||||
case 1: HASHC;
|
||||
} while (--loop);
|
||||
}
|
||||
}
|
||||
#endif /* !VAXC */
|
||||
#endif /* this_is_really_slow - not */
|
||||
|
||||
if (h >= hsize)
|
||||
h %= hsize;
|
||||
return h;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 0
|
||||
/*
|
||||
* Disable this code for now. It screws things up if we have
|
||||
* a ``for (iggy in foo)'' in progress. Interestingly enough,
|
||||
* this was not a problem in 2.15.3, only in 2.15.4. I'm not
|
||||
* sure why it works in 2.15.3.
|
||||
*/
|
||||
if (prev) { /* move found to front of chain */
|
||||
prev->ahnext = bucket->ahnext;
|
||||
bucket->ahnext = symbol->var_array[hash1];
|
||||
symbol->var_array[hash1] = bucket;
|
||||
}
|
||||
#endif
|
||||
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, (unsigned long) symbol->array_size);
|
||||
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);
|
||||
|
||||
if (symbol->var_array == 0) {
|
||||
symbol->type = Node_var_array;
|
||||
symbol->array_size = symbol->table_size = 0; /* sanity */
|
||||
symbol->flags &= ~ARRAYMAXED;
|
||||
grow_table(symbol);
|
||||
hash1 = hash(subs->stptr, subs->stlen,
|
||||
(unsigned long) symbol->array_size);
|
||||
} else {
|
||||
hash1 = hash(subs->stptr, subs->stlen,
|
||||
(unsigned long) symbol->array_size);
|
||||
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);
|
||||
|
||||
/* first see if we would need to grow the array, before installing */
|
||||
symbol->table_size++;
|
||||
if ((symbol->flags & ARRAYMAXED) == 0
|
||||
&& symbol->table_size/symbol->array_size > AVG_CHAIN_MAX) {
|
||||
grow_table(symbol);
|
||||
/* have to recompute hash value for new size */
|
||||
hash1 = hash(subs->stptr, subs->stlen,
|
||||
(unsigned long) symbol->array_size);
|
||||
}
|
||||
|
||||
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, (unsigned long) symbol->array_size);
|
||||
|
||||
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);
|
||||
symbol->table_size--;
|
||||
if (symbol->table_size <= 0) {
|
||||
memset(symbol->var_array, '\0',
|
||||
sizeof(NODE *) * symbol->array_size);
|
||||
symbol->table_size = symbol->array_size = 0;
|
||||
symbol->flags &= ~ARRAYMAXED;
|
||||
free((char *) symbol->var_array);
|
||||
symbol->var_array = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
assoc_scan(symbol, lookat)
|
||||
NODE *symbol;
|
||||
struct search *lookat;
|
||||
{
|
||||
lookat->sym = symbol;
|
||||
lookat->idx = 0;
|
||||
lookat->bucket = NULL;
|
||||
lookat->retval = NULL;
|
||||
if (symbol->var_array != NULL)
|
||||
assoc_next(lookat);
|
||||
}
|
||||
|
||||
void
|
||||
assoc_next(lookat)
|
||||
struct search *lookat;
|
||||
{
|
||||
register NODE *symbol = lookat->sym;
|
||||
|
||||
if (symbol == NULL)
|
||||
fatal("null symbol in assoc_next");
|
||||
if (symbol->var_array == NULL || lookat->idx > symbol->array_size) {
|
||||
lookat->retval = NULL;
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* This is theoretically unsafe. The element bucket might have
|
||||
* been freed if the body of the scan did a delete on the next
|
||||
* element of the bucket. The only way to do that is by array
|
||||
* reference, which is unlikely. Basically, if the user is doing
|
||||
* anything other than an operation on the current element of an
|
||||
* assoc array while walking through it sequentially, all bets are
|
||||
* off. (The safe way is to register all search structs on an
|
||||
* array with the array, and update all of them on a delete or
|
||||
* insert)
|
||||
*/
|
||||
if (lookat->bucket != NULL) {
|
||||
lookat->retval = lookat->bucket->ahname;
|
||||
lookat->bucket = lookat->bucket->ahnext;
|
||||
return;
|
||||
}
|
||||
for (; lookat->idx < symbol->array_size; lookat->idx++) {
|
||||
NODE *bucket;
|
||||
|
||||
if ((bucket = symbol->var_array[lookat->idx]) != NULL) {
|
||||
lookat->retval = bucket->ahname;
|
||||
lookat->bucket = bucket->ahnext;
|
||||
lookat->idx++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
lookat->retval = NULL;
|
||||
lookat->bucket = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* grow_table --- grow a hash table */
|
||||
|
||||
static void
|
||||
grow_table(symbol)
|
||||
NODE *symbol;
|
||||
{
|
||||
NODE **old, **new, *chain, *next;
|
||||
int i, j;
|
||||
unsigned long hash1;
|
||||
unsigned long oldsize, newsize;
|
||||
/*
|
||||
* This is an array of primes. We grow the table by an order of
|
||||
* magnitude each time (not just doubling) so that growing is a
|
||||
* rare operation. We expect, on average, that it won't happen
|
||||
* more than twice. The final size is also chosen to be small
|
||||
* enough so that MS-DOG mallocs can handle it. When things are
|
||||
* very large (> 8K), we just double more or less, instead of
|
||||
* just jumping from 8K to 64K.
|
||||
*/
|
||||
static long sizes[] = { 13, 127, 1021, 8191, 16381, 32749, 65497 };
|
||||
|
||||
/* find next biggest hash size */
|
||||
oldsize = symbol->array_size;
|
||||
newsize = 0;
|
||||
for (i = 0, j = sizeof(sizes)/sizeof(sizes[0]); i < j; i++) {
|
||||
if (oldsize < sizes[i]) {
|
||||
newsize = sizes[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newsize == oldsize) { /* table already at max (!) */
|
||||
symbol->flags |= ARRAYMAXED;
|
||||
return;
|
||||
}
|
||||
|
||||
/* allocate new table */
|
||||
emalloc(new, NODE **, newsize * sizeof(NODE *), "grow_table");
|
||||
memset(new, '\0', newsize * sizeof(NODE *));
|
||||
|
||||
/* brand new hash table, set things up and return */
|
||||
if (symbol->var_array == NULL) {
|
||||
symbol->table_size = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* old hash table there, move stuff to new, free old */
|
||||
old = symbol->var_array;
|
||||
for (i = 0; i < oldsize; i++) {
|
||||
if (old[i] == NULL)
|
||||
continue;
|
||||
|
||||
for (chain = old[i]; chain != NULL; chain = next) {
|
||||
next = chain->ahnext;
|
||||
hash1 = hash(chain->ahname->stptr,
|
||||
chain->ahname->stlen, newsize);
|
||||
|
||||
/* remove from old list, add to new */
|
||||
chain->ahnext = new[hash1];
|
||||
new[hash1] = chain;
|
||||
|
||||
}
|
||||
}
|
||||
free(old);
|
||||
|
||||
done:
|
||||
/*
|
||||
* note that symbol->table_size does not change if an old array,
|
||||
* and is explicitly set to 0 if a new one.
|
||||
*/
|
||||
symbol->var_array = new;
|
||||
symbol->array_size = newsize;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,790 +0,0 @@
|
|||
/*
|
||||
* awk.h -- Definitions for gawk.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 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 "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#ifndef LIMITS_H_MISSING
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
#include <setjmp.h>
|
||||
#include <varargs.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#if !defined(errno) && !defined(MSDOS) && !defined(OS2)
|
||||
extern int errno;
|
||||
#endif
|
||||
#ifdef __GNU_LIBRARY__
|
||||
#ifndef linux
|
||||
#include <signum.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* ----------------- System dependencies (with more includes) -----------*/
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
# include <floatingpoint.h>
|
||||
#endif
|
||||
|
||||
#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>
|
||||
|
||||
#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 */
|
||||
#if !defined(MSDOS) && !defined(_MSC_VER)
|
||||
#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)
|
||||
#if defined(_MSC_VER)
|
||||
#include <malloc.h>
|
||||
#else
|
||||
extern char *alloca();
|
||||
#endif /* _MSC_VER */
|
||||
#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 size_t 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();
|
||||
extern int getpgrp P((void));
|
||||
#endif /*VMS*/
|
||||
|
||||
#define GNU_REGEX
|
||||
#ifdef GNU_REGEX
|
||||
#include "gnuregex.h"
|
||||
#include "dfa.h"
|
||||
typedef struct Regexp {
|
||||
struct re_pattern_buffer pat;
|
||||
struct re_registers regs;
|
||||
struct dfa 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);
|
||||
#ifndef __MINT__
|
||||
#undef NGROUPS_MAX
|
||||
#endif /* __MINT__ */
|
||||
#endif
|
||||
|
||||
#ifndef DEFPATH
|
||||
#define DEFPATH ".:/usr/local/lib/awk:/usr/lib/awk"
|
||||
#endif
|
||||
|
||||
#ifndef ENVSEP
|
||||
#define ENVSEP ':'
|
||||
#endif
|
||||
|
||||
extern double double_to_int P((double d));
|
||||
|
||||
/* ------------------ 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;
|
||||
long ll;
|
||||
} 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;
|
||||
long xl;
|
||||
} 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;
|
||||
size_t 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 */
|
||||
# define ARRAYMAXED 256 /* array is at max size */
|
||||
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 array_size sub.nodep.l.ll
|
||||
#define table_size sub.nodep.x.xl
|
||||
|
||||
#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
|
||||
|
||||
typedef struct for_loop_header {
|
||||
NODE *init;
|
||||
NODE *cond;
|
||||
NODE *incr;
|
||||
} FOR_LOOP_HEADER;
|
||||
|
||||
/* for "for(iggy in foo) {" */
|
||||
struct search {
|
||||
NODE *sym;
|
||||
size_t idx;
|
||||
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
|
||||
|
||||
#ifndef INT_MAX
|
||||
#define INT_MAX (~(1 << (sizeof (int) * 8 - 1)))
|
||||
#endif
|
||||
#ifndef LONG_MAX
|
||||
#define LONG_MAX (~(1 << (sizeof (long) * 8 - 1)))
|
||||
#endif
|
||||
#ifndef ULONG_MAX
|
||||
#define ULONG_MAX (~(unsigned long)0)
|
||||
#endif
|
||||
#ifndef LONG_MIN
|
||||
#define LONG_MIN (-LONG_MAX - 1)
|
||||
#endif
|
||||
#define HUGE INT_MAX
|
||||
|
||||
/* -------------------------- External variables -------------------------- */
|
||||
/* gawk builtin variables */
|
||||
extern long NF;
|
||||
extern long NR;
|
||||
extern long 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)
|
||||
#define get_lhs(p, a) r_get_lhs((p), (a))
|
||||
#undef freenode
|
||||
#else
|
||||
#define get_lhs(p, a) ((p)->type == Node_var ? (&(p)->var_value) : \
|
||||
r_get_lhs((p), (a)))
|
||||
#define tree_eval(t) (_t = (t),_t == NULL ? Nnull_string : \
|
||||
(_t->type == Node_param_list ? r_tree_eval(_t) : \
|
||||
(_t->type == Node_val ? _t : \
|
||||
(_t->type == Node_var ? _t->var_value : \
|
||||
r_tree_eval(_t)))))
|
||||
#endif
|
||||
|
||||
#define make_number(x) mk_number((x), (unsigned int)(MALLOC|NUM|NUMBER))
|
||||
#define tmp_number(x) mk_number((x), (unsigned int)(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((const char *s, size_t len, unsigned long hsize));
|
||||
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((const 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 **r_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((const char *name, const char *mode));
|
||||
extern int pathopen P((const 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 */
|
||||
extern void err P((const char *s, const char *emsg, va_list argp));
|
||||
#if _MSC_VER == 510
|
||||
extern void msg P((va_list va_alist, ...));
|
||||
extern void warning P((va_list va_alist, ...));
|
||||
extern void fatal P((va_list va_alist, ...));
|
||||
#else
|
||||
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, size_t len, int ignorecase, int dfa));
|
||||
extern int research P((Regexp *rp, char *str, int start,
|
||||
size_t 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 */
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,306 +0,0 @@
|
|||
/*
|
||||
* config.h -- configuration definitions for gawk.
|
||||
*
|
||||
* For generic 4.4 alpha
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1991, 1992, 1993 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
|
||||
|
||||
/*
|
||||
* LIMITS_H_MISSING
|
||||
*
|
||||
* You don't have a <limits.h> include file.
|
||||
*/
|
||||
/* #define LIMITS_H_MISSING 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 */
|
||||
|
||||
/*
|
||||
* TM_ZONE_MISSING
|
||||
*
|
||||
* Your "struct tm" is missing the tm_zone field.
|
||||
* If this is the case *and* strftime() is missing *and* tzname is missing,
|
||||
* define this.
|
||||
*/
|
||||
/* #define TM_ZONE_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
|
||||
|
||||
/*
|
||||
* getpgrp() in sysvr4 and POSIX takes no argument
|
||||
*/
|
||||
/* #define GETPGRP_NOARG 0 */
|
||||
|
||||
/*
|
||||
* define const to nothing if not __STDC__
|
||||
*/
|
||||
#ifndef __STDC__
|
||||
#define const
|
||||
#endif
|
||||
|
||||
/* If svr4 and not gcc */
|
||||
/* #define SVR4 0 */
|
||||
#ifdef SVR4
|
||||
#define __svr4__ 1
|
||||
#endif
|
||||
|
||||
/* anything that follows is for system-specific short-term kludges */
|
File diff suppressed because it is too large
Load diff
|
@ -1,360 +0,0 @@
|
|||
/* dfa.h - declarations for GNU deterministic regexp compiler
|
||||
Copyright (C) 1988 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Written June, 1988 by Mike Haertel */
|
||||
|
||||
/* FIXME:
|
||||
2. We should not export so much of the DFA internals.
|
||||
In addition to clobbering modularity, we eat up valuable
|
||||
name space. */
|
||||
|
||||
/* Number of bits in an unsigned char. */
|
||||
#define CHARBITS 8
|
||||
|
||||
/* First integer value that is greater than any character code. */
|
||||
#define NOTCHAR (1 << CHARBITS)
|
||||
|
||||
/* INTBITS need not be exact, just a lower bound. */
|
||||
#define INTBITS (CHARBITS * sizeof (int))
|
||||
|
||||
/* Number of ints required to hold a bit for every character. */
|
||||
#define CHARCLASS_INTS ((NOTCHAR + INTBITS - 1) / INTBITS)
|
||||
|
||||
/* Sets of unsigned characters are stored as bit vectors in arrays of ints. */
|
||||
typedef int charclass[CHARCLASS_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. */
|
||||
|
||||
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. */
|
||||
|
||||
ENDLINE, /* ENDLINE is a terminal symbol that matches
|
||||
the empty string if it is at the end of
|
||||
a line. */
|
||||
|
||||
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. */
|
||||
|
||||
REPMN, /* REPMN is a lexical token corresponding
|
||||
to the {m,n} construct. REPMN never
|
||||
appears in the compiled token vector. */
|
||||
|
||||
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. */
|
||||
|
||||
ORTOP, /* OR at the toplevel in the parse tree.
|
||||
This is used for a boyer-moore heuristic. */
|
||||
|
||||
LPAREN, /* LPAREN never appears in the parse tree,
|
||||
it is only a lexeme. */
|
||||
|
||||
RPAREN, /* RPAREN never appears in the parse tree. */
|
||||
|
||||
CSET /* CSET and (and any value greater) is a
|
||||
terminal symbol that matches any of a
|
||||
class of characters. */
|
||||
} token;
|
||||
|
||||
/* Sets are stored in an array in the compiled dfa; the index of the
|
||||
array corresponding to a given set token is given by SET_INDEX(t). */
|
||||
#define SET_INDEX(t) ((t) - CSET)
|
||||
|
||||
/* 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 dfa 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;
|
||||
|
||||
/* Element of a list of strings, at least one of which is known to
|
||||
appear in any R.E. matching the DFA. */
|
||||
struct dfamust
|
||||
{
|
||||
int exact;
|
||||
char *must;
|
||||
struct dfamust *next;
|
||||
};
|
||||
|
||||
/* A compiled regular expression. */
|
||||
struct dfa
|
||||
{
|
||||
/* Stuff built by the scanner. */
|
||||
charclass *charclasses; /* Array of character sets for CSET tokens. */
|
||||
int cindex; /* Index for adding new charclasses. */
|
||||
int calloc; /* Number of charclasses 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 dfaparse(). */
|
||||
|
||||
/* Stuff owned by the state builder. */
|
||||
dfa_state *states; /* States of the dfa. */
|
||||
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
|
||||
dfaexec 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. */
|
||||
struct dfamust *musts; /* List of strings, at least one of which
|
||||
is known to appear in any r.e. matching
|
||||
the dfa. */
|
||||
};
|
||||
|
||||
/* Some macros for user access to dfa 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, dfa) \
|
||||
SUCCEEDS_IN_CONTEXT((dfa).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, dfa) (-(dfa).states[state].first_end)
|
||||
|
||||
/* Entry points. */
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
/* dfasyntax() takes two arguments; the first sets the syntax bits described
|
||||
earlier in this file, and the second sets the case-folding flag. */
|
||||
extern void dfasyntax(reg_syntax_t, int);
|
||||
|
||||
/* Compile the given string of the given length into the given struct dfa.
|
||||
Final argument is a flag specifying whether to build a searching or an
|
||||
exact matcher. */
|
||||
extern void dfacomp(char *, size_t, struct dfa *, int);
|
||||
|
||||
/* Execute the given struct dfa 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 *dfaexec(struct dfa *, char *, char *, int, int *, int *);
|
||||
|
||||
/* Free the storage held by the components of a struct dfa. */
|
||||
extern void dfafree(struct dfa *);
|
||||
|
||||
/* Entry points for people who know what they're doing. */
|
||||
|
||||
/* Initialize the components of a struct dfa. */
|
||||
extern void dfainit(struct dfa *);
|
||||
|
||||
/* Incrementally parse a string of given length into a struct dfa. */
|
||||
extern void dfaparse(char *, size_t, struct dfa *);
|
||||
|
||||
/* Analyze a parsed regexp; second argument tells whether to build a searching
|
||||
or an exact matcher. */
|
||||
extern void dfaanalyze(struct dfa *, int);
|
||||
|
||||
/* Compute, for each possible character, the transitions out of a given
|
||||
state, storing them in an array of integers. */
|
||||
extern void dfastate(int, struct dfa *, int []);
|
||||
|
||||
/* Error handling. */
|
||||
|
||||
/* dfaerror() is called by the regexp routines whenever an error occurs. It
|
||||
takes a single argument, a NUL-terminated string describing the error.
|
||||
The default dfaerror() prints the error message to stderr and exits.
|
||||
The user can provide a different dfafree() if so desired. */
|
||||
extern void dfaerror(const char *);
|
||||
|
||||
#else /* ! __STDC__ */
|
||||
extern void dfasyntax(), dfacomp(), dfafree(), dfainit(), dfaparse();
|
||||
extern void dfaanalyze(), dfastate(), dfaerror();
|
||||
extern char *dfaexec();
|
||||
#endif /* ! __STDC__ */
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,678 +0,0 @@
|
|||
/*
|
||||
* field.c - routines for dealing with fields and record parsing
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 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"
|
||||
|
||||
typedef void (* Setfunc) P((int, char*, int, NODE *));
|
||||
|
||||
static long (*parse_field) P((int, char **, int, NODE *,
|
||||
Regexp *, Setfunc, NODE *));
|
||||
static void rebuild_record P((void));
|
||||
static long re_parse_field P((int, char **, int, NODE *,
|
||||
Regexp *, Setfunc, NODE *));
|
||||
static long def_parse_field P((int, char **, int, NODE *,
|
||||
Regexp *, Setfunc, NODE *));
|
||||
static long sc_parse_field P((int, char **, int, NODE *,
|
||||
Regexp *, Setfunc, NODE *));
|
||||
static long fw_parse_field P((int, char **, int, NODE *,
|
||||
Regexp *, Setfunc, NODE *));
|
||||
static void set_element P((int, char *, int, NODE *));
|
||||
static void grow_fields_arr P((long 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 long parse_high_water=0; /* field number that we have parsed so far */
|
||||
static long 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)
|
||||
long 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 size_t tlen;
|
||||
register NODE *tmp;
|
||||
NODE *ofs;
|
||||
char *ops;
|
||||
register char *cops;
|
||||
register NODE **ptr;
|
||||
register size_t 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 ((long)tlen < 0)
|
||||
tlen = 0;
|
||||
emalloc(ops, char *, tlen + 2, "rebuild_record");
|
||||
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 = (long) 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 long
|
||||
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;
|
||||
Setfunc 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 && (*scan == ' ' || *scan == '\t' || *scan == '\n'))
|
||||
scan++;
|
||||
field = scan;
|
||||
while (scan < end
|
||||
&& research(rp, scan, 0, (end - scan), 1) != -1
|
||||
&& nf < up_to) {
|
||||
if (REEND(rp, scan) == RESTART(rp, scan)) { /* null match */
|
||||
scan++;
|
||||
if (scan == end) {
|
||||
(*set)(++nf, field, (int)(scan - field), n);
|
||||
up_to = nf;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
(*set)(++nf, field,
|
||||
(int)(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 long
|
||||
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;
|
||||
Setfunc 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 long
|
||||
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;
|
||||
Setfunc 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;) {
|
||||
field = scan;
|
||||
while (*scan != fschar)
|
||||
scan++;
|
||||
(*set)(++nf, field, (int)(scan - field), n);
|
||||
if (scan == end)
|
||||
break;
|
||||
scan++;
|
||||
if (scan == end) { /* FS at end of record */
|
||||
(*set)(++nf, field, 0, n);
|
||||
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 long
|
||||
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;
|
||||
Setfunc set; /* routine to set the value of the parsed field */
|
||||
NODE *n;
|
||||
{
|
||||
register char *scan = *buf;
|
||||
register long 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;
|
||||
long (*parseit)P((int, char **, int, NODE *,
|
||||
Regexp *, Setfunc, NODE *));
|
||||
Regexp *rp = NULL;
|
||||
|
||||
|
||||
/*
|
||||
* do dupnode(), to avoid problems like
|
||||
* x = split(a[1], a, "blah")
|
||||
* since we assoc_clear the array. gack.
|
||||
* this also gives up complete call by value semantics.
|
||||
*/
|
||||
tmp = tree_eval(tree->lnode);
|
||||
t1 = dupnode(tmp);
|
||||
free_temp(tmp);
|
||||
|
||||
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));
|
||||
unref(t1);
|
||||
free_temp(t3);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void
|
||||
set_FS()
|
||||
{
|
||||
char buf[10];
|
||||
NODE *fs;
|
||||
|
||||
/*
|
||||
* If changing the way fields are split, obey least-suprise
|
||||
* semantics, and force $0 to be split totally.
|
||||
*/
|
||||
if (fields_arr != NULL)
|
||||
(void) get_field(HUGE - 1, 0);
|
||||
|
||||
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 if (fs->stptr[0] == '\\')
|
||||
/* yet another special case */
|
||||
strcpy(buf, "[\\\\]");
|
||||
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;
|
||||
|
||||
/*
|
||||
* If changing the way fields are split, obey least-suprise
|
||||
* semantics, and force $0 to be split totally.
|
||||
*/
|
||||
if (fields_arr != NULL)
|
||||
(void) get_field(HUGE - 1, 0);
|
||||
|
||||
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;
|
||||
}
|
|
@ -1,757 +0,0 @@
|
|||
/* Getopt for GNU.
|
||||
NOTE: getopt is now part of the C library, so if you don't know what
|
||||
"Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
|
||||
before changing it!
|
||||
|
||||
Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 1994
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#if defined (emacs) || defined (CONFIG_BROKETS)
|
||||
/* We use <config.h> instead of "config.h" so that a compilation
|
||||
using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
|
||||
(which it would do because it found this file in $srcdir). */
|
||||
#include <config.h>
|
||||
#else
|
||||
#include "config.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef __STDC__
|
||||
/* This is a separate conditional since some stdc systems
|
||||
reject `defined (const)'. */
|
||||
#ifndef const
|
||||
#define const
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */
|
||||
#ifndef _NO_PROTO
|
||||
#define _NO_PROTO
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* Comment out all this code if we are using the GNU C Library, and are not
|
||||
actually compiling the library itself. This code is part of the GNU C
|
||||
Library, but also included in many other GNU distributions. Compiling
|
||||
and linking in this code is a waste when using the GNU C library
|
||||
(especially if it is a shared library). Rather than having every GNU
|
||||
program understand `configure --with-gnu-libc' and omit the object files,
|
||||
it is simpler to just do this in the source for each such file. */
|
||||
|
||||
#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
|
||||
|
||||
|
||||
/* This needs to come after some library #include
|
||||
to get __GNU_LIBRARY__ defined. */
|
||||
#if defined(__GNU_LIBRARY__) || defined(STDC_HEADERS)
|
||||
/* Don't include stdlib.h for non-GNU C libraries because some of them
|
||||
contain conflicting prototypes for getopt. */
|
||||
#include <stdlib.h>
|
||||
#else
|
||||
extern char *getenv ();
|
||||
#endif /* __GNU_LIBRARY || STDC_HEADERS */
|
||||
|
||||
/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
|
||||
long-named option. Because this is not POSIX.2 compliant, it is
|
||||
being phased out. */
|
||||
/* #define GETOPT_COMPAT */
|
||||
|
||||
/* This version of `getopt' appears to the caller like standard Unix `getopt'
|
||||
but it behaves differently for the user, since it allows the user
|
||||
to intersperse the options with the other arguments.
|
||||
|
||||
As `getopt' works, it permutes the elements of ARGV so that,
|
||||
when it is done, all the options precede everything else. Thus
|
||||
all application programs are extended to handle flexible argument order.
|
||||
|
||||
Setting the environment variable POSIXLY_CORRECT disables permutation.
|
||||
Then the behavior is completely standard.
|
||||
|
||||
GNU application programs can use a third alternative mode in which
|
||||
they can distinguish the relative order of options and other arguments. */
|
||||
|
||||
#include "getopt.h"
|
||||
|
||||
/* For communication from `getopt' to the caller.
|
||||
When `getopt' finds an option that takes an argument,
|
||||
the argument value is returned here.
|
||||
Also, when `ordering' is RETURN_IN_ORDER,
|
||||
each non-option ARGV-element is returned here. */
|
||||
|
||||
char *optarg = 0;
|
||||
|
||||
/* Index in ARGV of the next element to be scanned.
|
||||
This is used for communication to and from the caller
|
||||
and for communication between successive calls to `getopt'.
|
||||
|
||||
On entry to `getopt', zero means this is the first call; initialize.
|
||||
|
||||
When `getopt' returns EOF, this is the index of the first of the
|
||||
non-option elements that the caller should itself scan.
|
||||
|
||||
Otherwise, `optind' communicates from one call to the next
|
||||
how much of ARGV has been scanned so far. */
|
||||
|
||||
/* XXX 1003.2 says this must be 1 before any call. */
|
||||
int optind = 0;
|
||||
|
||||
/* The next char to be scanned in the option-element
|
||||
in which the last option character we returned was found.
|
||||
This allows us to pick up the scan where we left off.
|
||||
|
||||
If this is zero, or a null string, it means resume the scan
|
||||
by advancing to the next ARGV-element. */
|
||||
|
||||
static char *nextchar;
|
||||
|
||||
/* Callers store zero here to inhibit the error message
|
||||
for unrecognized options. */
|
||||
|
||||
int opterr = 1;
|
||||
|
||||
/* Set to an option character which was unrecognized.
|
||||
This must be initialized on some systems to avoid linking in the
|
||||
system's own getopt implementation. */
|
||||
|
||||
int optopt = '?';
|
||||
|
||||
/* Describe how to deal with options that follow non-option ARGV-elements.
|
||||
|
||||
If the caller did not specify anything,
|
||||
the default is REQUIRE_ORDER if the environment variable
|
||||
POSIXLY_CORRECT is defined, PERMUTE otherwise.
|
||||
|
||||
REQUIRE_ORDER means don't recognize them as options;
|
||||
stop option processing when the first non-option is seen.
|
||||
This is what Unix does.
|
||||
This mode of operation is selected by either setting the environment
|
||||
variable POSIXLY_CORRECT, or using `+' as the first character
|
||||
of the list of option characters.
|
||||
|
||||
PERMUTE is the default. We permute the contents of ARGV as we scan,
|
||||
so that eventually all the non-options are at the end. This allows options
|
||||
to be given in any order, even with programs that were not written to
|
||||
expect this.
|
||||
|
||||
RETURN_IN_ORDER is an option available to programs that were written
|
||||
to expect options and other ARGV-elements in any order and that care about
|
||||
the ordering of the two. We describe each non-option ARGV-element
|
||||
as if it were the argument of an option with character code 1.
|
||||
Using `-' as the first character of the list of option characters
|
||||
selects this mode of operation.
|
||||
|
||||
The special argument `--' forces an end of option-scanning regardless
|
||||
of the value of `ordering'. In the case of RETURN_IN_ORDER, only
|
||||
`--' can cause `getopt' to return EOF with `optind' != ARGC. */
|
||||
|
||||
static enum
|
||||
{
|
||||
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
|
||||
} ordering;
|
||||
|
||||
#if defined(__GNU_LIBRARY__) || defined(STDC_HEADERS)
|
||||
/* We want to avoid inclusion of string.h with non-GNU libraries
|
||||
because there are many ways it can cause trouble.
|
||||
On some systems, it contains special magic macros that don't work
|
||||
in GCC. */
|
||||
#include <string.h>
|
||||
#define my_index strchr
|
||||
#else
|
||||
|
||||
/* Avoid depending on library functions or files
|
||||
whose names are inconsistent. */
|
||||
|
||||
static char *
|
||||
my_index (str, chr)
|
||||
const char *str;
|
||||
int chr;
|
||||
{
|
||||
while (*str)
|
||||
{
|
||||
if (*str == chr)
|
||||
return (char *) str;
|
||||
str++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If using GCC, we can safely declare strlen this way.
|
||||
If not using GCC, it is ok not to declare it.
|
||||
(Supposedly there are some machines where it might get a warning,
|
||||
but changing this conditional to __STDC__ is too risky.) */
|
||||
#ifdef __GNUC__
|
||||
#ifdef IN_GCC
|
||||
#include "gstddef.h"
|
||||
#else
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
extern size_t strlen (const char *);
|
||||
#endif
|
||||
|
||||
#endif /* __GNU_LIBRARY__ || STDC_HEADERS */
|
||||
|
||||
/* 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 bottom = first_nonopt;
|
||||
int middle = last_nonopt;
|
||||
int top = optind;
|
||||
char *tem;
|
||||
|
||||
/* Exchange the shorter segment with the far end of the longer segment.
|
||||
That puts the shorter segment into the right place.
|
||||
It leaves the longer segment in the right place overall,
|
||||
but it consists of two parts that need to be swapped next. */
|
||||
|
||||
while (top > middle && middle > bottom)
|
||||
{
|
||||
if (top - middle > middle - bottom)
|
||||
{
|
||||
/* Bottom segment is the short one. */
|
||||
int len = middle - bottom;
|
||||
register int i;
|
||||
|
||||
/* Swap it with the top part of the top segment. */
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tem = argv[bottom + i];
|
||||
argv[bottom + i] = argv[top - (middle - bottom) + i];
|
||||
argv[top - (middle - bottom) + i] = tem;
|
||||
}
|
||||
/* Exclude the moved bottom segment from further swapping. */
|
||||
top -= len;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Top segment is the short one. */
|
||||
int len = top - middle;
|
||||
register int i;
|
||||
|
||||
/* Swap it with the bottom part of the bottom segment. */
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tem = argv[bottom + i];
|
||||
argv[bottom + i] = argv[middle + i];
|
||||
argv[middle + i] = tem;
|
||||
}
|
||||
/* Exclude the moved top segment from further swapping. */
|
||||
bottom += len;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update records for the slots the non-options now occupy. */
|
||||
|
||||
first_nonopt += (optind - last_nonopt);
|
||||
last_nonopt = optind;
|
||||
}
|
||||
|
||||
/* Scan elements of ARGV (whose length is ARGC) for option characters
|
||||
given in OPTSTRING.
|
||||
|
||||
If an element of ARGV starts with '-', and is not exactly "-" or "--",
|
||||
then it is an option element. The characters of this element
|
||||
(aside from the initial '-') are option characters. If `getopt'
|
||||
is called repeatedly, it returns successively each of the option characters
|
||||
from each of the option elements.
|
||||
|
||||
If `getopt' finds another option character, it returns that character,
|
||||
updating `optind' and `nextchar' so that the next call to `getopt' can
|
||||
resume the scan with the following option character or ARGV-element.
|
||||
|
||||
If there are no more option characters, `getopt' returns `EOF'.
|
||||
Then `optind' is the index in ARGV of the first ARGV-element
|
||||
that is not an option. (The ARGV-elements have been permuted
|
||||
so that those that are not options now come last.)
|
||||
|
||||
OPTSTRING is a string containing the legitimate option characters.
|
||||
If an option character is seen that is not listed in OPTSTRING,
|
||||
return '?' after printing an error message. If you set `opterr' to
|
||||
zero, the error message is suppressed but we still return '?'.
|
||||
|
||||
If a char in OPTSTRING is followed by a colon, that means it wants an arg,
|
||||
so the following text in the same ARGV-element, or the text of the following
|
||||
ARGV-element, is returned in `optarg'. Two colons mean an option that
|
||||
wants an optional arg; if there is text in the current ARGV-element,
|
||||
it is returned in `optarg', otherwise `optarg' is set to zero.
|
||||
|
||||
If OPTSTRING starts with `-' or `+', it requests different methods of
|
||||
handling the non-option ARGV-elements.
|
||||
See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
|
||||
|
||||
Long-named options begin with `--' instead of `-'.
|
||||
Their names may be abbreviated as long as the abbreviation is unique
|
||||
or is an exact match for some defined option. If they have an
|
||||
argument, it follows the option name in the same ARGV-element, separated
|
||||
from the option name by a `=', or else the in next ARGV-element.
|
||||
When `getopt' finds a long-named option, it returns 0 if that option's
|
||||
`flag' field is nonzero, the value of the option's `val' field
|
||||
if the `flag' field is zero.
|
||||
|
||||
The elements of ARGV aren't really const, because we permute them.
|
||||
But we pretend they're const in the prototype to be compatible
|
||||
with other systems.
|
||||
|
||||
LONGOPTS is a vector of `struct option' terminated by an
|
||||
element containing a name which is zero.
|
||||
|
||||
LONGIND returns the index in LONGOPT of the long-named option found.
|
||||
It is only valid when a long-named option has been found by the most
|
||||
recent call.
|
||||
|
||||
If LONG_ONLY is nonzero, '-' as well as '--' can introduce
|
||||
long-named options. */
|
||||
|
||||
int
|
||||
_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
|
||||
int argc;
|
||||
char *const *argv;
|
||||
const char *optstring;
|
||||
const struct option *longopts;
|
||||
int *longind;
|
||||
int long_only;
|
||||
{
|
||||
int option_index;
|
||||
|
||||
optarg = 0;
|
||||
|
||||
/* Initialize the internal data when the first call is made.
|
||||
Start processing options with ARGV-element 1 (since ARGV-element 0
|
||||
is the program name); the sequence of previously skipped
|
||||
non-option ARGV-elements is empty. */
|
||||
|
||||
if (optind == 0)
|
||||
{
|
||||
first_nonopt = last_nonopt = optind = 1;
|
||||
|
||||
nextchar = NULL;
|
||||
|
||||
/* Determine how to handle the ordering of options and nonoptions. */
|
||||
|
||||
if (optstring[0] == '-')
|
||||
{
|
||||
ordering = RETURN_IN_ORDER;
|
||||
++optstring;
|
||||
}
|
||||
else if (optstring[0] == '+')
|
||||
{
|
||||
ordering = REQUIRE_ORDER;
|
||||
++optstring;
|
||||
}
|
||||
else if (getenv ("POSIXLY_CORRECT") != NULL)
|
||||
ordering = REQUIRE_ORDER;
|
||||
else
|
||||
ordering = PERMUTE;
|
||||
}
|
||||
|
||||
if (nextchar == NULL || *nextchar == '\0')
|
||||
{
|
||||
if (ordering == PERMUTE)
|
||||
{
|
||||
/* If we have just processed some options following some non-options,
|
||||
exchange them so that the options come first. */
|
||||
|
||||
if (first_nonopt != last_nonopt && last_nonopt != optind)
|
||||
exchange ((char **) argv);
|
||||
else if (last_nonopt != optind)
|
||||
first_nonopt = optind;
|
||||
|
||||
/* Now skip any additional non-options
|
||||
and extend the range of non-options previously skipped. */
|
||||
|
||||
while (optind < argc
|
||||
&& (argv[optind][0] != '-' || argv[optind][1] == '\0')
|
||||
#ifdef GETOPT_COMPAT
|
||||
&& (longopts == NULL
|
||||
|| argv[optind][0] != '+' || argv[optind][1] == '\0')
|
||||
#endif /* GETOPT_COMPAT */
|
||||
)
|
||||
optind++;
|
||||
last_nonopt = optind;
|
||||
}
|
||||
|
||||
/* Special ARGV-element `--' means premature end of options.
|
||||
Skip it like a null option,
|
||||
then exchange with previous non-options as if it were an option,
|
||||
then skip everything else like a non-option. */
|
||||
|
||||
if (optind != argc && !strcmp (argv[optind], "--"))
|
||||
{
|
||||
optind++;
|
||||
|
||||
if (first_nonopt != last_nonopt && last_nonopt != optind)
|
||||
exchange ((char **) argv);
|
||||
else if (first_nonopt == last_nonopt)
|
||||
first_nonopt = optind;
|
||||
last_nonopt = argc;
|
||||
|
||||
optind = argc;
|
||||
}
|
||||
|
||||
/* If we have done all the ARGV-elements, stop the scan
|
||||
and back over any non-options that we skipped and permuted. */
|
||||
|
||||
if (optind == argc)
|
||||
{
|
||||
/* Set the next-arg-index to point at the non-options
|
||||
that we previously skipped, so the caller will digest them. */
|
||||
if (first_nonopt != last_nonopt)
|
||||
optind = first_nonopt;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
/* If we have come to a non-option and did not permute it,
|
||||
either stop the scan or describe it to the caller and pass it by. */
|
||||
|
||||
if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
|
||||
#ifdef GETOPT_COMPAT
|
||||
&& (longopts == NULL
|
||||
|| argv[optind][0] != '+' || argv[optind][1] == '\0')
|
||||
#endif /* GETOPT_COMPAT */
|
||||
)
|
||||
{
|
||||
if (ordering == REQUIRE_ORDER)
|
||||
return EOF;
|
||||
optarg = argv[optind++];
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We have found another option-ARGV-element.
|
||||
Start decoding its characters. */
|
||||
|
||||
nextchar = (argv[optind] + 1
|
||||
+ (longopts != NULL && argv[optind][1] == '-'));
|
||||
}
|
||||
|
||||
if (longopts != NULL
|
||||
&& ((argv[optind][0] == '-'
|
||||
&& (argv[optind][1] == '-' || long_only))
|
||||
#ifdef GETOPT_COMPAT
|
||||
|| argv[optind][0] == '+'
|
||||
#endif /* GETOPT_COMPAT */
|
||||
))
|
||||
{
|
||||
const struct option *p;
|
||||
char *s = nextchar;
|
||||
int exact = 0;
|
||||
int ambig = 0;
|
||||
const struct option *pfound = NULL;
|
||||
int indfound;
|
||||
|
||||
while (*s && *s != '=')
|
||||
s++;
|
||||
|
||||
/* Test all options for either exact match or abbreviated matches. */
|
||||
for (p = longopts, option_index = 0; p->name;
|
||||
p++, option_index++)
|
||||
if (!strncmp (p->name, nextchar, s - nextchar))
|
||||
{
|
||||
if (s - nextchar == strlen (p->name))
|
||||
{
|
||||
/* Exact match found. */
|
||||
pfound = p;
|
||||
indfound = option_index;
|
||||
exact = 1;
|
||||
break;
|
||||
}
|
||||
else if (pfound == NULL)
|
||||
{
|
||||
/* First nonexact match found. */
|
||||
pfound = p;
|
||||
indfound = option_index;
|
||||
}
|
||||
else
|
||||
/* Second nonexact match found. */
|
||||
ambig = 1;
|
||||
}
|
||||
|
||||
if (ambig && !exact)
|
||||
{
|
||||
if (opterr)
|
||||
fprintf (stderr, "%s: option `%s' is ambiguous\n",
|
||||
argv[0], argv[optind]);
|
||||
nextchar += strlen (nextchar);
|
||||
optind++;
|
||||
return '?';
|
||||
}
|
||||
|
||||
if (pfound != NULL)
|
||||
{
|
||||
option_index = indfound;
|
||||
optind++;
|
||||
if (*s)
|
||||
{
|
||||
/* Don't test has_arg with >, because some C compilers don't
|
||||
allow it to be used on enums. */
|
||||
if (pfound->has_arg)
|
||||
optarg = s + 1;
|
||||
else
|
||||
{
|
||||
if (opterr)
|
||||
{
|
||||
if (argv[optind - 1][1] == '-')
|
||||
/* --option */
|
||||
fprintf (stderr,
|
||||
"%s: option `--%s' doesn't allow an argument\n",
|
||||
argv[0], pfound->name);
|
||||
else
|
||||
/* +option or -option */
|
||||
fprintf (stderr,
|
||||
"%s: option `%c%s' doesn't allow an argument\n",
|
||||
argv[0], argv[optind - 1][0], pfound->name);
|
||||
}
|
||||
nextchar += strlen (nextchar);
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
else if (pfound->has_arg == 1)
|
||||
{
|
||||
if (optind < argc)
|
||||
optarg = argv[optind++];
|
||||
else
|
||||
{
|
||||
if (opterr)
|
||||
fprintf (stderr, "%s: option `%s' requires an argument\n",
|
||||
argv[0], argv[optind - 1]);
|
||||
nextchar += strlen (nextchar);
|
||||
return optstring[0] == ':' ? ':' : '?';
|
||||
}
|
||||
}
|
||||
nextchar += strlen (nextchar);
|
||||
if (longind != NULL)
|
||||
*longind = option_index;
|
||||
if (pfound->flag)
|
||||
{
|
||||
*(pfound->flag) = pfound->val;
|
||||
return 0;
|
||||
}
|
||||
return pfound->val;
|
||||
}
|
||||
/* Can't find it as a long option. If this is not getopt_long_only,
|
||||
or the option starts with '--' or is not a valid short
|
||||
option, then it's an error.
|
||||
Otherwise interpret it as a short option. */
|
||||
if (!long_only || argv[optind][1] == '-'
|
||||
#ifdef GETOPT_COMPAT
|
||||
|| argv[optind][0] == '+'
|
||||
#endif /* GETOPT_COMPAT */
|
||||
|| my_index (optstring, *nextchar) == NULL)
|
||||
{
|
||||
if (opterr)
|
||||
{
|
||||
if (argv[optind][1] == '-')
|
||||
/* --option */
|
||||
fprintf (stderr, "%s: unrecognized option `--%s'\n",
|
||||
argv[0], nextchar);
|
||||
else
|
||||
/* +option or -option */
|
||||
fprintf (stderr, "%s: unrecognized option `%c%s'\n",
|
||||
argv[0], argv[optind][0], nextchar);
|
||||
}
|
||||
nextchar = (char *) "";
|
||||
optind++;
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
/* Look at and handle the next option-character. */
|
||||
|
||||
{
|
||||
char c = *nextchar++;
|
||||
char *temp = my_index (optstring, c);
|
||||
|
||||
/* Increment `optind' when we start to process its last character. */
|
||||
if (*nextchar == '\0')
|
||||
++optind;
|
||||
|
||||
if (temp == NULL || c == ':')
|
||||
{
|
||||
if (opterr)
|
||||
{
|
||||
#if 0
|
||||
if (c < 040 || c >= 0177)
|
||||
fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
|
||||
argv[0], c);
|
||||
else
|
||||
fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
|
||||
#else
|
||||
/* 1003.2 specifies the format of this message. */
|
||||
fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
|
||||
#endif
|
||||
}
|
||||
optopt = c;
|
||||
return '?';
|
||||
}
|
||||
if (temp[1] == ':')
|
||||
{
|
||||
if (temp[2] == ':')
|
||||
{
|
||||
/* This is an option that accepts an argument optionally. */
|
||||
if (*nextchar != '\0')
|
||||
{
|
||||
optarg = nextchar;
|
||||
optind++;
|
||||
}
|
||||
else
|
||||
optarg = 0;
|
||||
nextchar = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is an option that requires an argument. */
|
||||
if (*nextchar != '\0')
|
||||
{
|
||||
optarg = nextchar;
|
||||
/* If we end this ARGV-element by taking the rest as an arg,
|
||||
we must advance to the next element now. */
|
||||
optind++;
|
||||
}
|
||||
else if (optind == argc)
|
||||
{
|
||||
if (opterr)
|
||||
{
|
||||
#if 0
|
||||
fprintf (stderr, "%s: option `-%c' requires an argument\n",
|
||||
argv[0], c);
|
||||
#else
|
||||
/* 1003.2 specifies the format of this message. */
|
||||
fprintf (stderr, "%s: option requires an argument -- %c\n",
|
||||
argv[0], c);
|
||||
#endif
|
||||
}
|
||||
optopt = c;
|
||||
if (optstring[0] == ':')
|
||||
c = ':';
|
||||
else
|
||||
c = '?';
|
||||
}
|
||||
else
|
||||
/* We already incremented `optind' once;
|
||||
increment it again when taking next ARGV-elt as argument. */
|
||||
optarg = argv[optind++];
|
||||
nextchar = NULL;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
getopt (argc, argv, optstring)
|
||||
int argc;
|
||||
char *const *argv;
|
||||
const char *optstring;
|
||||
{
|
||||
return _getopt_internal (argc, argv, optstring,
|
||||
(const struct option *) 0,
|
||||
(int *) 0,
|
||||
0);
|
||||
}
|
||||
|
||||
#endif /* _LIBC or not __GNU_LIBRARY__. */
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
/* Compile with -DTEST to make an executable for use in testing
|
||||
the above definition of `getopt'. */
|
||||
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int c;
|
||||
int digit_optind = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int this_option_optind = optind ? optind : 1;
|
||||
|
||||
c = getopt (argc, argv, "abc:d:0123456789");
|
||||
if (c == EOF)
|
||||
break;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
if (digit_optind != 0 && digit_optind != this_option_optind)
|
||||
printf ("digits occur in two different argv-elements.\n");
|
||||
digit_optind = this_option_optind;
|
||||
printf ("option %c\n", c);
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
printf ("option a\n");
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
printf ("option b\n");
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
printf ("option c with value `%s'\n", optarg);
|
||||
break;
|
||||
|
||||
case '?':
|
||||
break;
|
||||
|
||||
default:
|
||||
printf ("?? getopt returned character code 0%o ??\n", c);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
{
|
||||
printf ("non-option ARGV-elements: ");
|
||||
while (optind < argc)
|
||||
printf ("%s ", argv[optind++]);
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
#endif /* TEST */
|
|
@ -1,129 +0,0 @@
|
|||
/* Declarations for getopt.
|
||||
Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifndef _GETOPT_H
|
||||
#define _GETOPT_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* For communication from `getopt' to the caller.
|
||||
When `getopt' finds an option that takes an argument,
|
||||
the argument value is returned here.
|
||||
Also, when `ordering' is RETURN_IN_ORDER,
|
||||
each non-option ARGV-element is returned here. */
|
||||
|
||||
extern char *optarg;
|
||||
|
||||
/* Index in ARGV of the next element to be scanned.
|
||||
This is used for communication to and from the caller
|
||||
and for communication between successive calls to `getopt'.
|
||||
|
||||
On entry to `getopt', zero means this is the first call; initialize.
|
||||
|
||||
When `getopt' returns EOF, this is the index of the first of the
|
||||
non-option elements that the caller should itself scan.
|
||||
|
||||
Otherwise, `optind' communicates from one call to the next
|
||||
how much of ARGV has been scanned so far. */
|
||||
|
||||
extern int optind;
|
||||
|
||||
/* Callers store zero here to inhibit the error message `getopt' prints
|
||||
for unrecognized options. */
|
||||
|
||||
extern int opterr;
|
||||
|
||||
/* Set to an option character which was unrecognized. */
|
||||
|
||||
extern int optopt;
|
||||
|
||||
/* Describe the long-named options requested by the application.
|
||||
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
|
||||
of `struct option' terminated by an element containing a name which is
|
||||
zero.
|
||||
|
||||
The field `has_arg' is:
|
||||
no_argument (or 0) if the option does not take an argument,
|
||||
required_argument (or 1) if the option requires an argument,
|
||||
optional_argument (or 2) if the option takes an optional argument.
|
||||
|
||||
If the field `flag' is not NULL, it points to a variable that is set
|
||||
to the value given in the field `val' when the option is found, but
|
||||
left unchanged if the option is not found.
|
||||
|
||||
To have a long-named option do something other than set an `int' to
|
||||
a compiled-in constant, such as set a value from `optarg', set the
|
||||
option's `flag' field to zero and its `val' field to a nonzero
|
||||
value (the equivalent single-letter option character, if there is
|
||||
one). For long options that have a zero `flag' field, `getopt'
|
||||
returns the contents of the `val' field. */
|
||||
|
||||
struct option
|
||||
{
|
||||
#ifdef __STDC__
|
||||
const char *name;
|
||||
#else
|
||||
char *name;
|
||||
#endif
|
||||
/* has_arg can't be an enum because some compilers complain about
|
||||
type mismatches in all the code that assumes it is an int. */
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
|
||||
/* Names for the values of the `has_arg' field of `struct option'. */
|
||||
|
||||
#define no_argument 0
|
||||
#define required_argument 1
|
||||
#define optional_argument 2
|
||||
|
||||
#ifdef __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 */
|
|
@ -1,187 +0,0 @@
|
|||
/* getopt_long and getopt_long_only entry points for GNU getopt.
|
||||
Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#if defined (emacs) || defined (CONFIG_BROKETS)
|
||||
/* We use <config.h> instead of "config.h" so that a compilation
|
||||
using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
|
||||
(which it would do because it found this file in $srcdir). */
|
||||
#include <config.h>
|
||||
#else
|
||||
#include "config.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "getopt.h"
|
||||
|
||||
#ifndef __STDC__
|
||||
/* This is a separate conditional since some stdc systems
|
||||
reject `defined (const)'. */
|
||||
#ifndef const
|
||||
#define const
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* Comment out all this code if we are using the GNU C Library, and are not
|
||||
actually compiling the library itself. This code is part of the GNU C
|
||||
Library, but also included in many other GNU distributions. Compiling
|
||||
and linking in this code is a waste when using the GNU C library
|
||||
(especially if it is a shared library). Rather than having every GNU
|
||||
program understand `configure --with-gnu-libc' and omit the object files,
|
||||
it is simpler to just do this in the source for each such file. */
|
||||
|
||||
#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
|
||||
|
||||
|
||||
/* This needs to come after some library #include
|
||||
to get __GNU_LIBRARY__ defined. */
|
||||
#if defined(__GNU_LIBRARY__) || defined(OS2) || defined(MSDOS) || defined(atarist)
|
||||
#include <stdlib.h>
|
||||
#else
|
||||
char *getenv ();
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
int
|
||||
getopt_long (argc, argv, options, long_options, opt_index)
|
||||
int argc;
|
||||
char *const *argv;
|
||||
const char *options;
|
||||
const struct option *long_options;
|
||||
int *opt_index;
|
||||
{
|
||||
return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
|
||||
}
|
||||
|
||||
/* Like getopt_long, but '-' as well as '--' can indicate a long option.
|
||||
If an option that starts with '-' (not '--') doesn't match a long option,
|
||||
but does match a short option, it is parsed as a short option
|
||||
instead. */
|
||||
|
||||
int
|
||||
getopt_long_only (argc, argv, options, long_options, opt_index)
|
||||
int argc;
|
||||
char *const *argv;
|
||||
const char *options;
|
||||
const struct option *long_options;
|
||||
int *opt_index;
|
||||
{
|
||||
return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
|
||||
}
|
||||
|
||||
|
||||
#endif /* _LIBC or not __GNU_LIBRARY__. */
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int c;
|
||||
int digit_optind = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int this_option_optind = optind ? optind : 1;
|
||||
int option_index = 0;
|
||||
static struct option long_options[] =
|
||||
{
|
||||
{"add", 1, 0, 0},
|
||||
{"append", 0, 0, 0},
|
||||
{"delete", 1, 0, 0},
|
||||
{"verbose", 0, 0, 0},
|
||||
{"create", 0, 0, 0},
|
||||
{"file", 1, 0, 0},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
c = getopt_long (argc, argv, "abc:d:0123456789",
|
||||
long_options, &option_index);
|
||||
if (c == EOF)
|
||||
break;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 0:
|
||||
printf ("option %s", long_options[option_index].name);
|
||||
if (optarg)
|
||||
printf (" with arg %s", optarg);
|
||||
printf ("\n");
|
||||
break;
|
||||
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
if (digit_optind != 0 && digit_optind != this_option_optind)
|
||||
printf ("digits occur in two different argv-elements.\n");
|
||||
digit_optind = this_option_optind;
|
||||
printf ("option %c\n", c);
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
printf ("option a\n");
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
printf ("option b\n");
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
printf ("option c with value `%s'\n", optarg);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
printf ("option d with value `%s'\n", optarg);
|
||||
break;
|
||||
|
||||
case '?':
|
||||
break;
|
||||
|
||||
default:
|
||||
printf ("?? getopt returned character code 0%o ??\n", c);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
{
|
||||
printf ("non-option ARGV-elements: ");
|
||||
while (optind < argc)
|
||||
printf ("%s ", argv[optind++]);
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
#endif /* TEST */
|
1283
gnu/usr.bin/awk/io.c
1283
gnu/usr.bin/awk/io.c
File diff suppressed because it is too large
Load diff
|
@ -1,321 +0,0 @@
|
|||
/*
|
||||
* iop.c - do i/o related things.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 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 32*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 */
|
||||
char rs;
|
||||
int saw_newline = 0, eat_whitespace = 0; /* used iff grRS==0 */
|
||||
|
||||
if (iop->cnt == EOF) { /* previous read hit EOF */
|
||||
*out = NULL;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
if (grRS == 0) { /* special case: grRS == "" */
|
||||
rs = '\n';
|
||||
} 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 */
|
||||
|
||||
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
|
||||
&& (*bp == ' ' || *bp == '\t' || *bp == '\n'))
|
||||
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)) {
|
||||
*out = NULL;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
iop->off = bp;
|
||||
bp--;
|
||||
if (*bp != rs)
|
||||
bp++;
|
||||
*bp = '\0';
|
||||
if (grRS == 0) {
|
||||
/* there could be more newlines left, clean 'em out now */
|
||||
while (*(iop->off) == rs && iop->off <= iop->end)
|
||||
(iop->off)++;
|
||||
|
||||
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
|
|
@ -1,823 +0,0 @@
|
|||
/*
|
||||
* main.c -- Expression tree constructors and main program for gawk.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 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 __FreeBSD__
|
||||
#include <locale.h>
|
||||
#endif
|
||||
#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;
|
||||
|
||||
long NF;
|
||||
long NR;
|
||||
long 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;
|
||||
/* the + on the front tells GNU getopt not to rearrange argv */
|
||||
const char *optlist = "+F:f:v:W:m:";
|
||||
int stopped_early = 0;
|
||||
int old_optind;
|
||||
extern int optind;
|
||||
extern int opterr;
|
||||
extern char *optarg;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
(void) setlocale(LC_ALL, "");
|
||||
#endif
|
||||
#ifdef __EMX__
|
||||
_response(&argc, &argv);
|
||||
_wildcard(&argc, &argv);
|
||||
setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
|
||||
#endif
|
||||
|
||||
(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();
|
||||
|
||||
#ifdef fpsetmask
|
||||
fpsetmask(~0xff);
|
||||
#endif
|
||||
/* we do error messages ourselves on invalid options */
|
||||
opterr = 0;
|
||||
|
||||
/* option processing. ready, set, go! */
|
||||
for (optopt = 0, old_optind = 1;
|
||||
(c = getopt_long(argc, argv, optlist, optab, NULL)) != EOF;
|
||||
optopt = 0, old_optind = optind) {
|
||||
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 'm':
|
||||
/*
|
||||
* Research awk extension.
|
||||
* -mf=nnn set # fields, gawk ignores
|
||||
* -mr=nnn set record length, ditto
|
||||
*/
|
||||
if (do_lint)
|
||||
warning("-m[fr] option irrelevant");
|
||||
if ((optarg[0] != 'r' && optarg[0] != 'f')
|
||||
|| optarg[1] != '=')
|
||||
warning("-m option usage: -m[fn]=nnn");
|
||||
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 (optarg[0] == '\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 0:
|
||||
/*
|
||||
* getopt_long found an option that sets a variable
|
||||
* instead of returning a letter. Do nothing, just
|
||||
* cycle around for the next one.
|
||||
*/
|
||||
break;
|
||||
|
||||
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.
|
||||
*
|
||||
* However, it's never simple. If optopt is set,
|
||||
* an option that requires an argument didn't get the
|
||||
* argument. We care because if opterr is 0, then
|
||||
* getopt_long won't print the error message for us.
|
||||
*/
|
||||
if (! do_posix
|
||||
&& (optopt == 0 || strchr(optlist, optopt) == NULL)) {
|
||||
/*
|
||||
* can't just do optind--. In case of an
|
||||
* option with >=2 letters, getopt_long
|
||||
* won't have incremented optind.
|
||||
*/
|
||||
optind = old_optind;
|
||||
stopped_early = 1;
|
||||
goto out;
|
||||
} else if (optopt)
|
||||
/* Use 1003.2 required message format */
|
||||
fprintf (stderr,
|
||||
"%s: option requires an argument -- %c\n",
|
||||
myname, optopt);
|
||||
/* else
|
||||
let getopt print error message for us */
|
||||
break;
|
||||
}
|
||||
}
|
||||
out:
|
||||
|
||||
if (do_nostalgia)
|
||||
nostalgia();
|
||||
|
||||
/* check for POSIXLY_CORRECT environment variable */
|
||||
if (! do_posix && getenv("POSIXLY_CORRECT") != NULL) {
|
||||
do_posix = 1;
|
||||
if (do_lint)
|
||||
warning(
|
||||
"environment variable `POSIXLY_CORRECT' set: turning on --posix");
|
||||
}
|
||||
|
||||
/* 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 || stopped_early) /* no args left or no program */
|
||||
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 (do_lint && begin_block == NULL && expression_value == NULL
|
||||
&& end_block == NULL)
|
||||
warning("no program");
|
||||
|
||||
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;
|
||||
{
|
||||
const char *opt1 = " -f progfile [--]";
|
||||
#if defined(MSDOS) || defined(OS2) || defined(VMS)
|
||||
const char *opt2 = " [--] \"program\"";
|
||||
#else
|
||||
const char *opt2 = " [--] 'program'";
|
||||
#endif
|
||||
const char *regops = " [POSIX or GNU style options]";
|
||||
|
||||
fprintf(stderr, "Usage:\t%s%s%s file ...\n\t%s%s%s file ...\n",
|
||||
myname, regops, opt1, myname, regops, opt2);
|
||||
|
||||
/* GNU long options info. Gack. */
|
||||
fputs("POSIX 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-m[fr]=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);
|
||||
#ifdef NOSTALGIA
|
||||
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";
|
||||
|
||||
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); *//* don't do that - we want to
|
||||
avoid mismatched types */
|
||||
|
||||
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, strlen(str), 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;
|
||||
const char *name;
|
||||
NODETYPE type;
|
||||
const 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((char *) vp->name,
|
||||
node(vp->strval == 0 ? make_number(vp->numval)
|
||||
: make_string((char *) vp->strval,
|
||||
strlen(vp->strval)),
|
||||
vp->type, (NODE *) NULL));
|
||||
if (vp->assign)
|
||||
(*(vp->assign))();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
load_environ()
|
||||
{
|
||||
#if !defined(MSDOS) && !defined(OS2) && !(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, *cp2;
|
||||
int badvar;
|
||||
Func_ptr after_assign = NULL;
|
||||
NODE *var;
|
||||
NODE *it;
|
||||
NODE **lhs;
|
||||
|
||||
cp = strchr(arg, '=');
|
||||
if (cp != NULL) {
|
||||
*cp++ = '\0';
|
||||
/* first check that the variable name has valid syntax */
|
||||
badvar = 0;
|
||||
if (! isalpha(arg[0]) && arg[0] != '_')
|
||||
badvar = 1;
|
||||
else
|
||||
for (cp2 = arg+1; *cp2; cp2++)
|
||||
if (! isalnum(*cp2) && *cp2 != '_') {
|
||||
badvar = 1;
|
||||
break;
|
||||
}
|
||||
if (badvar)
|
||||
fatal("illegal name `%s' in variable assignment", arg);
|
||||
|
||||
/*
|
||||
* 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 (cp[0] == '\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);
|
||||
/* per GNU coding standards, exit successfully, do nothing else */
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* this mess will improve in 2.16 */
|
||||
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(OS2) || defined(atarist)
|
||||
char *q;
|
||||
|
||||
for (p = filespec; (p = strchr(p, '\\')); *p = '/')
|
||||
;
|
||||
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);
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
/*
|
||||
* msg.c - routines for error messages
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 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)
|
||||
const char *s;
|
||||
const 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;
|
||||
(void) putc('(', stderr);
|
||||
if (file)
|
||||
(void) fprintf(stderr, "FILENAME=%s ", file);
|
||||
(void) fprintf(stderr, "FNR=%ld) ", 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);
|
||||
}
|
|
@ -1,463 +0,0 @@
|
|||
/*
|
||||
* node.c -- routines for node management
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 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;
|
||||
|
||||
#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;
|
||||
} else
|
||||
newflags = 0;
|
||||
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 const 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;
|
||||
double val;
|
||||
|
||||
#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
|
||||
|
||||
/* not an integral value, or out of range */
|
||||
if ((val = double_to_int(s->numbr)) != s->numbr
|
||||
|| val < LONG_MIN || val > LONG_MAX) {
|
||||
#ifdef GFMT_WORKAROUND
|
||||
NODE *dummy, *r;
|
||||
unsigned short oflags;
|
||||
extern NODE *format_tree P((const char *, int, NODE *));
|
||||
extern NODE **fmt_list; /* declared in eval.c */
|
||||
|
||||
/* create dummy node for a sole use of format_tree */
|
||||
getnode(dummy);
|
||||
dummy->lnode = s;
|
||||
dummy->rnode = NULL;
|
||||
oflags = s->flags;
|
||||
s->flags |= PERM; /* prevent from freeing by format_tree() */
|
||||
r = format_tree(CONVFMT, fmt_list[CONVFMTidx]->stlen, dummy);
|
||||
s->flags = oflags;
|
||||
s->stfmt = (char)CONVFMTidx;
|
||||
s->stlen = r->stlen;
|
||||
s->stptr = r->stptr;
|
||||
freenode(r); /* Do not free_temp(r)! We want */
|
||||
freenode(dummy); /* to keep s->stptr == r->stpr. */
|
||||
|
||||
goto no_malloc;
|
||||
#else
|
||||
/*
|
||||
* no need for a "replacement" formatting by gawk,
|
||||
* just use sprintf
|
||||
*/
|
||||
sprintf(sp, CONVFMT, s->numbr);
|
||||
s->stlen = strlen(sp);
|
||||
s->stfmt = (char)CONVFMTidx;
|
||||
#endif /* GFMT_WORKAROUND */
|
||||
} else {
|
||||
/* integral value */
|
||||
/* force conversion to long only once */
|
||||
register long num = (long) val;
|
||||
if (num < NVAL && num >= 0) {
|
||||
sp = (char *) values[num];
|
||||
s->stlen = 1;
|
||||
} else {
|
||||
(void) sprintf(sp, "%ld", num);
|
||||
s->stlen = strlen(sp);
|
||||
}
|
||||
s->stfmt = -1;
|
||||
}
|
||||
emalloc(s->stptr, char *, s->stlen + 2, "force_string");
|
||||
memcpy(s->stptr, sp, s->stlen+1);
|
||||
no_malloc:
|
||||
s->stref = 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);
|
||||
r->stptr[r->stlen] = '\0';
|
||||
}
|
||||
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->flags = 0;
|
||||
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 +0,0 @@
|
|||
#define PATCHLEVEL 5
|
|
@ -1,122 +0,0 @@
|
|||
/*
|
||||
* protos.h -- function prototypes for when the headers don't have them.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1991, 1992, 1993 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));
|
||||
|
||||
#if !defined(sun) && !defined(__sun__)
|
||||
extern void free P((aptr_t));
|
||||
#endif
|
||||
extern char *getenv P((const char *));
|
||||
|
||||
extern char *strcpy P((char *, const char *));
|
||||
extern char *strcat P((char *, const char *));
|
||||
extern int strcmp P((const char *, const char *));
|
||||
extern char *strncpy P((char *, const char *, size_t));
|
||||
extern int strncmp P((const char *, const char *, size_t));
|
||||
#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 size_t strlen P((const char *));
|
||||
extern long strtol P((const char *, char **, int));
|
||||
#if !defined(_MSC_VER) && !defined(__GNU_LIBRARY__)
|
||||
extern size_t strftime P((char *, size_t, const char *, const struct tm *));
|
||||
#endif
|
||||
#ifdef __STDC__
|
||||
extern time_t time P((time_t *));
|
||||
#else
|
||||
extern long time();
|
||||
#endif
|
||||
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 *, const char *, ...));
|
||||
#if !defined(MSDOS) && !defined(__GNU_LIBRARY__)
|
||||
#ifdef __STDC__
|
||||
extern size_t fwrite P((const aptr_t, size_t, size_t, FILE *));
|
||||
#else
|
||||
extern int fwrite();
|
||||
#endif
|
||||
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((const char *, const 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((const 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((const char *, mode_t));
|
||||
extern int open P((const char *, int, ...));
|
||||
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 *, ... */));
|
||||
#ifndef __STDC__
|
||||
extern int read P((int, char *, int));
|
||||
#endif
|
||||
extern int wait P((int *));
|
||||
extern void _exit P((int));
|
||||
|
||||
#ifdef NON_STD_SPRINTF
|
||||
extern char *sprintf P((char *, const char*, ...));
|
||||
#else
|
||||
extern int sprintf P((char *, const char*, ...));
|
||||
#endif /* SPRINTF_INT */
|
||||
|
||||
#undef aptr_t
|
|
@ -1,212 +0,0 @@
|
|||
/*
|
||||
* re.c - compile regular expressions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1991, 1992, 1993 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;
|
||||
size_t len;
|
||||
int ignorecase;
|
||||
int dfa;
|
||||
{
|
||||
Regexp *rp;
|
||||
const char *rerr;
|
||||
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, unsigned 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 ((rerr = re_compile_pattern(temp, len, &(rp->pat))) != NULL)
|
||||
fatal("%s: /%s/", rerr, temp);
|
||||
if (dfa && !ignorecase) {
|
||||
dfacomp(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 size_t len;
|
||||
int need_start;
|
||||
{
|
||||
char *ret = str;
|
||||
|
||||
if (rp->dfa) {
|
||||
char save;
|
||||
int count = 0;
|
||||
int try_backref;
|
||||
|
||||
/*
|
||||
* dfa likes to stick a '\n' right after the matched
|
||||
* text. So we just save and restore the character.
|
||||
*/
|
||||
save = str[start+len];
|
||||
ret = dfaexec(&(rp->dfareg), str+start, str+start+len, 1,
|
||||
&count, &try_backref);
|
||||
str[start+len] = save;
|
||||
}
|
||||
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)
|
||||
dfafree(&(rp->dfareg));
|
||||
free(rp);
|
||||
}
|
||||
|
||||
void
|
||||
dfaerror(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()
|
||||
{
|
||||
reg_syntax_t syn = RE_SYNTAX_AWK;
|
||||
|
||||
(void) re_set_syntax(syn);
|
||||
dfasyntax(syn, 0);
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
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.
|
||||
`delete array'. OS/2 port added. */
|
||||
|
Loading…
Reference in a new issue