summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Dalley <kevin@seti.org>1996-02-04 20:35:04 +0000
committerKevin Dalley <kevin@seti.org>1996-02-04 20:35:04 +0000
commitda4093813c9d227e0a1378ce362c4c291263dc93 (patch)
tree4b29e114a804b92d85c81eca4c785b84eaa2147f
parentf2d3ffa59ed8c17c0fd8f70094385c1d0e054a63 (diff)
downloadfindutils-da4093813c9d227e0a1378ce362c4c291263dc93.tar.gz
GNU findutils package version 4.1FINDUTILS-4_1FINDUTILS
-rw-r--r--COPYING901
-rw-r--r--ChangeLog6656
-rw-r--r--INSTALL203
-rw-r--r--Makefile.am74
-rw-r--r--Makefile.in140
-rw-r--r--NEWS1411
-rw-r--r--README35
-rw-r--r--TODO54
-rw-r--r--acconfig.h36
-rw-r--r--config.h.in171
-rwxr-xr-xconfigure2774
-rw-r--r--configure.in89
-rw-r--r--doc/Makefile.am77
-rw-r--r--doc/Makefile.in121
-rw-r--r--doc/find.info113
-rw-r--r--doc/find.info-11581
-rw-r--r--doc/find.info-21069
-rw-r--r--doc/find.texi4684
-rw-r--r--doc/perm.texi141
-rw-r--r--doc/texinfo.tex4365
-rw-r--r--find/Makefile.am52
-rw-r--r--find/Makefile.in160
-rw-r--r--find/defs.h681
-rw-r--r--find/find.11792
-rw-r--r--find/find.c1626
-rw-r--r--find/fstype.c465
-rw-r--r--find/parser.c3864
-rw-r--r--find/pred.c2513
-rw-r--r--find/tree.c1492
-rw-r--r--find/util.c1101
-rw-r--r--find/version.c1
-rwxr-xr-xinstall-sh238
-rw-r--r--lib/Makefile.am55
-rw-r--r--lib/Makefile.in136
-rw-r--r--lib/alloca.c492
-rw-r--r--lib/dirname.c70
-rw-r--r--lib/error.c119
-rw-r--r--lib/fileblocks.c66
-rw-r--r--lib/filemode.c237
-rw-r--r--lib/fnmatch.c200
-rw-r--r--lib/fnmatch.h67
-rw-r--r--lib/getline.c126
-rw-r--r--lib/getopt.c748
-rw-r--r--lib/getopt.h129
-rw-r--r--lib/getopt1.c180
-rw-r--r--lib/idcache.c210
-rw-r--r--lib/listfile.c370
-rw-r--r--lib/memcmp.c32
-rw-r--r--lib/memset.c29
-rw-r--r--lib/mktime.c502
-rw-r--r--lib/modechange.c341
-rw-r--r--lib/modechange.h55
-rw-r--r--lib/modetype.h81
-rw-r--r--lib/nextelem.c37
-rw-r--r--lib/pathmax.h53
-rw-r--r--lib/regex.c5244
-rw-r--r--lib/regex.h487
-rw-r--r--lib/savedir.c131
-rw-r--r--lib/stpcpy.c32
-rw-r--r--lib/strdup.c43
-rw-r--r--lib/strftime.c469
-rw-r--r--lib/strspn.c23
-rw-r--r--lib/strstr.c44
-rw-r--r--lib/strtol.c186
-rw-r--r--lib/wait.h15
-rw-r--r--lib/xgetcwd.c78
-rw-r--r--lib/xmalloc.c95
-rw-r--r--lib/xstrdup.c36
-rw-r--r--locate/Makefile.am64
-rw-r--r--locate/Makefile.in222
-rw-r--r--locate/bigram.c45
-rw-r--r--locate/code.c167
-rw-r--r--locate/frcode.c309
-rw-r--r--locate/locate.1197
-rw-r--r--locate/locate.c2043
-rw-r--r--locate/locatedb.577
-rw-r--r--locate/locatedb.h52
-rw-r--r--locate/updatedb.180
-rw-r--r--locate/updatedb.sh322
-rwxr-xr-xmkinstalldirs32
-rw-r--r--stamp-h.in2
-rw-r--r--testsuite/Makefile.am36
-rw-r--r--testsuite/Makefile.in118
-rw-r--r--testsuite/config/unix.exp109
-rw-r--r--testsuite/inputs/eof.xi5
-rw-r--r--testsuite/inputs/eofstr.xi5
-rw-r--r--testsuite/inputs/files.xi22
-rw-r--r--testsuite/inputs/files0.xibin0 -> 753 bytes
-rw-r--r--testsuite/inputs/quotes.xi5
-rw-r--r--testsuite/xargs.gnu/0n3.exp1
-rw-r--r--testsuite/xargs.gnu/0n3.xo8
-rw-r--r--testsuite/xargs.gnu/nothing.exp1
-rw-r--r--testsuite/xargs.gnu/nothing.xo1
-rw-r--r--testsuite/xargs.gnu/r.exp1
-rw-r--r--testsuite/xargs.posix/hithere.exp1
-rw-r--r--testsuite/xargs.posix/hithere.xo2
-rw-r--r--testsuite/xargs.posix/n3.exp1
-rw-r--r--testsuite/xargs.posix/n3.xo8
-rw-r--r--testsuite/xargs.posix/quotes.exp1
-rw-r--r--testsuite/xargs.posix/quotes.xo2
-rw-r--r--testsuite/xargs.posix/s47.exp1
-rw-r--r--testsuite/xargs.posix/s47.xo18
-rw-r--r--testsuite/xargs.posix/s470.exp1
-rw-r--r--testsuite/xargs.posix/s470.xo2
-rw-r--r--testsuite/xargs.posix/s48.exp1
-rw-r--r--testsuite/xargs.posix/s48.xo22
-rw-r--r--testsuite/xargs.posix/s6.exp1
-rw-r--r--testsuite/xargs.sysv/eEOF.exp1
-rw-r--r--testsuite/xargs.sysv/eEOF.xo1
-rw-r--r--testsuite/xargs.sysv/eof.exp1
-rw-r--r--testsuite/xargs.sysv/eof.xo1
-rw-r--r--testsuite/xargs.sysv/iARG.exp1
-rw-r--r--testsuite/xargs.sysv/iARG.xo22
-rw-r--r--testsuite/xargs.sysv/iquotes.exp1
-rw-r--r--testsuite/xargs.sysv/iquotes.xo5
-rw-r--r--testsuite/xargs.sysv/l1n4.exp1
-rw-r--r--testsuite/xargs.sysv/l1n4.xo6
-rw-r--r--testsuite/xargs.sysv/l2.exp1
-rw-r--r--testsuite/xargs.sysv/l2.xo11
-rw-r--r--xargs/Makefile.am20
-rw-r--r--xargs/Makefile.in156
-rw-r--r--xargs/xargs.1491
-rw-r--r--xargs/xargs.c1256
123 files changed, 28020 insertions, 27838 deletions
diff --git a/COPYING b/COPYING
index 44325404..a43ea212 100644
--- a/COPYING
+++ b/COPYING
@@ -1,627 +1,285 @@
-
GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
+ Version 2, June 1991
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ 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 GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users. We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors. You can apply it to
+ 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
-them 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.
+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 prevent others from denying you
-these rights or asking you to surrender the rights. Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
+ 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 pass on to the recipients the same
-freedoms that you received. 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.
-
- Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
- For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software. For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
- Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so. This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software. The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable. Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products. If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
- Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary. To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
+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.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey 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;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
+
+ 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.
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
+ 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 convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Use with the GNU Affero General Public License.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time. Such new versions will
+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 that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- 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.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-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.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
+
+ 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
@@ -629,15 +287,15 @@ 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
-state the exclusion of warranty; and each file should have at least
+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) <year> <name of author>
+ Copyright (C) 19yy <name of author>
- This program is free software: you can redistribute it and/or modify
+ 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 3 of the License, or
+ 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,
@@ -646,31 +304,36 @@ the "copyright" line and a pointer to where the full notice is found.
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, see <http://www.gnu.org/licenses/>.
+ 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 does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
- <program> Copyright (C) <year> <name of author>
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ 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, your program's commands
-might be different; for a GUI interface, you would use an "about box".
+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:
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-<http://www.gnu.org/licenses/>.
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
- The GNU 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 Lesser General
-Public License instead of this License. But first, please read
-<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+ <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.
diff --git a/ChangeLog b/ChangeLog
index 1f73281c..b0de6e5e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6392 +1,3 @@
-2008-03-09 James Youngman <jay@gnu.org>
-
- Fix (documentation) bug #20873, / and . in file names for -path.
- * doc/find.texi (Full Name Patterns): Mention that * in the "find
- -path" pattern will match both / and leading dots.
-
-2008-03-08 Jim Meyering <meyering@redhat.com>
-
- Fix doc typos.
- * doc/find-maint.texi (Security): s/ongest/longest/
- (Making Releases): s/the the/the/
-
- Avoid link failure with gcc -fno-common.
- * find.c (program_name, starting_desc): Declare "extern".
-
-2008-02-15 Eric Blake <ebb9@byu.net>
-
- Avoid compiler warnings.
- * find/pred.c (pred_name_common): Remove unused variable.
- * locate/locate.c (print_stats): Avoid undefined format string.
-
-2008-02-15 James Youngman <jay@gnu.org>
-
- * README-CVS: Explain how to update the translations from the
- translation project.
-
- * NEWS, configure.ac: Change release number to 4.3.14-CVS.
-
-2008-02-13 Ralf Wildenhues <Ralf.Wildenhues@gmx.de> (tiny change)
-
- * import-gnulib.config: Add progname.
-
- * lib/Makefile.am (LDADD): Use @LIBINTL@ instead of @INTLLIBS@.
-
- * xargs/xargs.1: Fix a couple of typos.
-
-2008-02-12 James Youngman <jay@gnu.org>
-
- Updated translations: German, Irish, Dutch, Polish, Vietnamese.
- * po/de.po, po/ga.po, po/nl.po, po/pl.po, po/vi.po: Updated from
- the Translation Project.
-
- Fix Savannah bug #22056, -Xtime tests are off by one second.
- * find/defs.h (struct options): Change cur_day_start from time_t
- to strct timespec.
- * find/util.c (set_option_defaults): Likewise.
- * find/parser.c (get_relative_timestamp): Change the origin
- argument from time_t to struct timespec.
- (estimate_timestamp_success_rate): Ignore the nanoseconds field of
- the timestamp when estimating the probable success rate.
- (parse_daystart): Handle the nanoseconds field too.
- (do_parse_xmin): The origin argument to get_relative_timestamp()
- is of type struct timespec, not time_t.
- (parse_used): Likewise.
- (parse_time): Likewise.
- * find/pred.c (pred_timewindow): in the COMP_EQ case, accept times
- exactly at the end of the window and do not accept times exactly
- at the start (reversing the previous treatment of the bounds).
- * find/testsuite/Makefile.am (EXTRA_DIST_EXP): Added test for
- -mtime 0; find.posix/mtime0.{exp,xo}.
- * NEWS: mention this bugfix.
-
-2008-02-09 James Youngman <jay@gnu.org>
-
- * doc/find.texi (xargs options): Moved documentation of xargs'
- options into this new section.
- (Invoking the shell from xargs): New section providing examples
- about "xargs sh -c '...'".
-
- * xargs/xargs.1: Indicate that the "sh -c" trick with xargs
- achieves the same thing as BSD's "xargs -o", but in a more
- flexible way.
-
- * locate/updatedb.sh: Actually rename the old database to the new
- one atomically, instead of just claiming the rename is atomic in a
- comment :) This fixes Savannah bug #22057.
-
- * find/find.c (ngettext): Introduce a new macro to help with
- internationalising plurals. Use it to allow better
- translations of format strings.
- * locate/locate.c: Likewise.
-
-2008-01-07 James Youngman <jay@gnu.org>
-
- * xargs/xargs.c: (main): Standardise on "Warning" instead of
- "warning" in messages.
-
- * xargs/xargs.c: (add_proc): Use x2nrealloc to extend the pids
- array, rather than doubling the size of the buffer (since the old
- aproach was vulnerable to overflow).
-
- Reap all available child processes before every fork. This fixes
- Savannah bug #21960.
- * xargs/xargs.c: (proc_max): since this is a non-negative
- quantity, make it unsigned.
- (procs_executing): Likewise.
- (pids_alloc): Likewise (using size_t).
- (procs_executed): In order to prevent possible overflow, make this
- a boolean, not a count. We only cared if the previous counter was
- zero or not, anwyay.
- (add_proc): Set procs_executed to true rather than incrementing it.
- (wait_for_proc): When called, always reap all available children.
- Add an extra argument which is the minimum number of children we
- must reap before returning.
- (wait_for_proc_all): Pass the new extra argument.
- (xargs_do_exec): Call wait_for_proc() to reap all available
- children before forking a new child. Modify other calls to
- wait_for_proc to pass the new extra argument.
- * NEWS: Mention this change.
-
-2007-12-20 James Youngman <jay@gnu.org>
-
- * find/fstype.c, find/ftsfind.c, find/parser.c, find/pred.c,
- find/tree.c, lib/regextype.c, locate/locate.c, xargs/xargs.c,
- find.c: Backed out positional paremeter change, as the use of
- positional parameters was over-complex and unnecessary. We'll
- re-apply the pluralisation support change soon, but without the
- positional parameters.
-
-2007-12-20 Jakub Bogusz <qboosh@pld-linux.org> (tiny change)
-
- * xargs/xargs.c (parse_num): Corrected typo in format string
- message.
-
-2007-12-20 Clytie Siddall <clytie@riverland.net.au> (tiny change)
-
- * find/find.c (wd_sanity_check): Corrected typo in the format
- string for an error message, which might cause a crash in
- "oldfind" if a directory we moved into turned out to be a symbolic
- link that moved while we were trying to change directory.
-
-2007-12-20 James Youngman <jay@gnu.org>
-
- * configure.ac: Advance the version number, as we are moving on
- from 4.3.12.
- * NEWS: Likewise
-
-2007-12-19 James Youngman <jay@gnu.org>
-
- * find/find.c (ngettext): Introduce a new macro to help with
- internationalising plurals. Use it with positional parameters in
- order to allow better translations of format strings.
- * find/fstype.c, find/ftsfind.c, find/parser.c, find/pred.c,
- find/tree.c, lib/regextype.c, locate/locate.c, xargs/xargs.c: Likewise.
-
-2007-12-19 Benno Schulenberg <coordinator@translationproject.org> (tiny change)
-
- * find/find.1: Corrected two typos.
-
-2007-12-19 James Youngman <jay@gnu.org>
-
- * po/nl.po: Updated Dutch translation from the Translation project.
- * po/pl.po: Likewise for the Polish translation.
- * po/sv.po: Likewise for the Swedish translation.
- * po/vi.po: Likewise for the Vietnamese translation.
-
-2007-12-13 Eric Blake <ebb9@byu.net>
-
- Allow bootstrapping with autoconf 2.61a.
- * configure.ac (AC_AIX, AC_ISC_POSIX): Delete, now that gnulib
- takes care of this.
- (jy_AC_TYPE_INTMAX_T): Delete, now that gnulib stdint module takes
- care of this.
-
-2007-12-09 James Youngman <jay@gnu.org>
-
- * doc/perm.texi: Updated from the upstream source.
-
- * po/nl.po, po/pt.po: Updated from the Translation Project.
-
-2007-12-08 James Youngman <jay@gnu.org>
-
- * xargs/xargs.1: Added examples on stdin handling and more
- efficient core file deletion.
- * NEWS: Mention this.
-
- * doc/.cvsignore: Ignore regexprops-generic.texi.
- * doc/.gitignore: ditto
-
-2007-12-04 James Youngman <jay@gnu.org>
-
- Fix Savannah bug #15384, find misbehaves when parent directory is
- not readable.
- * find/testsuite/find.posix/parent.exp: New test
- * find/testsuite/find.posix/parent.xo: New test
- * find/testsuite/Makefile.am (EXTRA_DIST_EXP, EXTRA_DIST_XO):
- Added parent.exp, parent.xo.
- * find/find.c (safely_chdir): If safely_chdir_nofollow fails with
- SafeChdirFailDestUnreadable, fall back on safely_chdir_lstat.
-
- * find/find.1: Formatting fixes; options should be in bold.
-
-2007-12-02 James Youngman <jay@gnu.org>
-
- Fix Savannah bug #20802, find -delete anomalies
- * find/pred.c (pred_delete): Set find's exit status to nonzero if
- -delete fails.
- * find/find.1 (-delete): Document this.
- * doc/find.texi (Delete Files): Document this.
- * NEWS: Mention the fix.
-
-2007-11-30 James Youngman <jay@gnu.org>
-
- Fix Savannah bug #20865 (-prune -delete without an explicit
- -depth is now an error).
- * find/parser.c (check_option_combinations): Diagnose the
- situation where -delete and -prune are both used, because -delete
- turns on -depth and -depth makes -prune do nothing.
- * find/tree.c (build_expression_tree): call
- check_option_combinations().
- * find/defs.h (struct options): Add new boolean field
- explicit_depth.
- Also declare check_option_combinations.
- * find/util.c (set_option_defaults): Initialise explicit_depth.
- * NEWS: Mention this fix.
-
-2007-11-29 James Youngman <jay@gnu.org>
-
- Support the generation of regexprops-generic.texi.
- * lib/regextype.h (get_regex_type_context): Used to indicate if a
- particular type of regular expression is of interest for
- regexprops.texi (which is findutils-specific) or
- regexprops-generic.texi (which is not). The "context" is simply
- a flag set in a word.
- * lib/regextype.c (get_regex_type_context): Implement this.
- (regex_map): Assign a context to each regular expression type.
- * lib/regexprops.c: Use the context information from regextype.c
- to decide which regular expression types to docuemnt in the
- output. The selection is indicated on the command line; "generic"
- and "findutils" are supported.
- (copying): New function, which emits a copyright header into the
- output.
- (comment): New function for emitting a comment.
- (ignore): New function which returns nonzero when the indicated
- type of regular expression is not of interest for this version of
- the document.
- (menu): Miss out the non-interesteing regex types.
- (get_next): Returns the regex type name for the "next" pointer,
- taking into account which regex types are ignored.
- (describe_all): Take into account which regex types are ignored,
- and emit a copying header also. Include a comment indicating
- which "context" was of interest when generating the output.
- * doc/Makefile.am: Add regexprops-generic.texi. Generate this
- file from regexprops.c.
-
- Check gnulib out with native git, rather than git-cvspserver.
- This fixes Savannah bug #21568, for the second time.
- * import-gnulib.config (gnulib_version): Switch to using a git
- commit id and native git, since git-cvspserver silently fails to
- support "cvs update -D".
- * import-gnulib.sh (do_checkout): Check gnulib out with git rather
- than CVS.
- (main): Require 'git' to be available.
- (move_cvsdir): Remove any pre-existing gnulib-cvs directory.
- * doc/find-maint.texi (Using the GNU Portability Library): Desribe
- how we now obtain gnulib. Update the instructions on how we patch
- gnulib.
- * .gitignore: Ignore gnulib-git, not gnulib-cvs
- * .cvsignore: Ditto
- * Makefile.am (findutils-check-smells): Change from gnulib-cvs to
- gnulib-git.
- * README-CVS: Mention the extra dependency on git.
- * NEWS: Mention this change.
-
- Add test case for Savannah bug #20803 (-prune return value).
- * find/testsuite/find.posix/prune-result.exp: New test for
- Savannah bug #20803.
- * find/testsuite/find.posix/prune-result.xo: Expected otuput for
- new test prune-result.exp.
- * find/testsuite/Makefile.am (EXTRA_DIST_EXP): Added
- find.posix/prune-result.exp
- (EXTRA_DIST_XO): Added find.posix/prune-result.xo
-
-2007-11-27 James Youngman <jay@gnu.org>
-
- * find/pred.c (pred_prune): Always return true. This fixes
- Savannah bug #20803.
- * doc/find.texi (Directories): Document the change to -prune.
- * find/find.1: Document the change.
- * NEWS: Mention the fix.
-
-2007-11-26 James Youngman <jay@gnu.org>
-
- Fix Savannah bug #20970, handling of trailing slashes with -name.
- * find/pred.c (pred_name_common): Strip trailing slashes from the
- pathname before applying fnmatch() to it. This fixes Savannah bug
- #20970.
- * find/testsuite/find.posix/nameslash.exp: Test case for bug #20970.
- * find/testsuite/find.posix/nameslash.xo: Expected output file for
- same.
- * find/testsuite/Makefile.am (EXTRA_DIST_EXP): Added nameslash.exp.
- (EXTRA_DIST_XO): Added nameslash.xo.
-
- Fix Savannah bug #21634, No copy of FDL1.2 included in source
- code.
- * doc/find.texi: Change license to the GNU Free Documentation
- License 1.2.
- (GNU Free Documentation License): Include fdl.texi
- * doc/find-maint.texi (GNU Free Documentation License): Include a
- copy of the FDL (it was already under this license).
- * doc/Makefile.am (find_maint_TEXINFOS): Include fdl.texi
- (find_TEXINFOS): Include fdl.texi
- * import-gnulib.config (modules): Include gpl-3.0 and fdl.
-
- * doc/perm.texi: Added copyright license, following the license of
- the original source document (perm.texi from coreutils).
-
-2007-11-25 James Youngman <jay@gnu.org>
-
- * Makefile.am (jy-regex-fix): Comment that the regex.c fix needs
- to stay until we no longer support Automate-1.9.
-
- * doc/perm.texi (Mode Structure): Fix setgid/setuid typo.
-
-2007-11-24 James Youngman <jay@gnu.org>
-
- * doc/find.texi (Mode Bits): Correct the warning about the change
- in behaviour of -perm /000 to indicate that the change has
- happened now. This fixes Savannah bug #21628.
- * NEWS: Mention this.
-
-2007-11-22 James Youngman <jay@gnu.org>
-
- POSIXLY_CORRECT turns off warnings.
- * find/defs.h (struct options): Added member posixly_correct.
- This is set when the POSIXLY_CORRECT environment variable is set.
- * find/util.c (set_option_defaults): Set options.posixly_correct
- if the POSIXLY_CORRECT environment variable is set.
- (set_option_defaults): Turn off warnings when POSIXLY_CORRECT is
- in force.
- * find/find.1: Document this.
- (Environment Variables): Likewise.
- (Warning Messages): Likewise.
-
- Non-POSIX compliant arguments to -perm generate an error when
- POSIXLY_CORRECT is set.
- * find/parser.c (parse_table): Indicate which primaries are
- defined by POSIX.
- (non_posix_mode): New function; issues an error message when a
- non-POSIX-compliant argument to -perm is used (and POSIXLY_CORRECT
- is in force).
- (parse_perm): Call non_posix_mode when a non-POSIX-compliant mode
- argument is seen.
- * find/testsuite/find.gnu/posix-perminvalid.exp: New file; tests
- invalid arguments to -perm.
- * find/testsuite/Makefile.am (EXTRA_DIST_EXP): Add
- posix-perminvalid.exp.
- * find/find.1: Document this.
- * doc/find.texi (Mode Bits): Likewise
- (Environment Variables): Likewise
-
-
- * xargs/xargs.1: Options should be bold, not italic; filenames
- should also be italic. OPTIONS should be a section, not a
- subsection. In the description of --max-lines, "max-args" was
- corrected to "max-lines". Turn off hyphenation in the SYNOPSIS
- section. This fixes Savannah bug #21270.
-
-2007-11-13 James Youngman <jay@gnu.org>
-
- * NEWS, configure.ac: Prepare for the release of findutils-4.3.10.
-
- * import-gnulib.sh (usage): If the existing CVS working tree for
- gnulib in the source tree does not yet point at the
- git-cvs-pserver repository, move the old gnulib working tree out
- of the way and do a fresh checkout. This fixes Savannah bug
- #21568.
-
-2007-11-11 James Youngman <jay@gnu.org>
-
-
- * configure.ac: Prepared for release of findutils-4.3.9.
- * NEWS: Likewise.
-
- * po/POTFILES.in: Use gnulib/lib/getdate.y rather than
- gnulib/lib/getdate.c, because the former is the source file, and
- because without this change the update-po target of po/Makefile
- fails.
-
- * import-gnulib.config (gnulib_version): Move to gnulib
- 2007-11-10.
-
- * po/hu.po, po/nl.po: Updated from Translation Project.
-
-2007-09-08 James Youngman <jay@gnu.org>
-
- Better documentation on $PATH security checks.
- * doc/find.texi (Single File): Better explanation of what makes
- certain values of $PATH insecure. This fixes Savannah bug
- #20951.
- * find/find.1 (-execdir): Likewise.
-
- Document interaction of -depth/-delete/-prune.
- * doc/find.texi (Directories): Mention that "-prune ... -delete"
- will not do what you want and will cause the deletion of more
- files than you probably intended.
- (Delete Files): Likewise, suggest using "-depth" when testing
- command lines you plan to eventually add "-delete" to.
- (Cleaning Up): Add -depth explicitly to an example which uses
- -delete.
- * find/find.1 (-depth): Mention that -delete also implies -depth.
- (-delete): Warn against putting -delete first.
- (-prune): Also warn against -prune ... -delete.
- NEWS: Mention these changes.
-
-2007-08-23 Eric Blake <ebb9@byu.net>
-
- Pick up gnulib change to getline module.
- * import-gnulib.config (gnulib_version): Bump date.
- * locate/bigram.c: Use <stdio.h>, not getline.h.
- * locate/code.c: Likewise.
- * locate/frcode.c: Likewise.
- * locate/locate.c: Likewise.
-
- * po/ChangeLog: Delete, merge into this file.
-
-2007-08-23 James Youngman <jay@gnu.org>
-
- * po/nl.po: Updated from Translation Project
-
- * find/parser.c (check_path_safety): Assume the path is safe is
- $PATH is not set. This avoids a segfault in that situation
- and thus fixes Savannah bug #20834.
-
-2007-08-22 James Youngman <jay@gnu.org>
-
- * find/parser.c (parse_path): This is the 'canonical' name once
- again.
- (parse_wholename): This is not.
- (parse_ipath): No longer deprecated.
- * NEWS: Mention this.
-
-2007-08-22 Eric Blake <ebb9@byu.net>
-
- Fix Savannah bug #20871.
- * find/find.c (main): Remove bogus assertion.
- * NEWS: Document the fix.
-
- Update to recent gnulib addition of idcache.h.
- * lib/listfile.c (getuser, getgroup): Use header rather than
- declaring things ourself.
- * po/POTFILES.in (locate/frcode.c): Add missing file.
-
-2007-08-21 Eric Blake <ebb9@byu.net>
-
- Fix for Savannah bug #20273, find -ok with seekable stdin.
- * find/find.c (main): Use close_stdin, not close_stdout.
- * import-gnulib.config (gnulib_version): Pick up yesno tests.
- * NEWS: Document the change.
- * build-aux/.cvsignore: Ignore compile.
-
-2007-08-20 Paul Eggert <eggert@cs.ucla.edu>
- and Eric Blake <ebb9@byu.net>
-
- Improve translation of xstrtol messages.
- * import-gnulib.config (destdir): Upgrade gnulib to 2007-08-11.
- * locate/locate.c (dolocate): Adjust to API change of xstrtol
- gnulib module.
- * po/POTFILES.in: Likewise.
- * NEWS: Document the enhancement.
-
-2007-08-20 James Youngman <jay@gnu.org>
-
- * doc/find.texi (Directories): Clarify that built commands which
- have not been executed yet will be executed before find quits,
- even with -quit. Also clarify the difference between -prune and
- -quit.
-
-2007-08-18 Eric Blake <ebb9@byu.net>
-
- Fix Savannah bug #20751.
- * lib/listfile.c (list_file): Accomodate gnulib change of 3 Jul
- 2006.
- * NEWS: Document this.
- Reported by Nigel Stepp.
- * THANKS: Sort and update.
- * AUTHORS: Add myself.
-
-2007-08-05 Eric Blake <ebb9@byu.net>
-
- Fix Savannah bugs #20662, #20688.
- * find/find.c (at_top): Avoid memory leak.
- * find/pred.c (do_fprintf, pred_iname, pred_name): Likewise.
- (pred_name_common): New function, factored from pred_iname and
- pred_name.
- * find/parser.c (check_name_arg): Let -nowarn silence -name /.
- * locate/locate.c (visit_basename): Avoid memory leak.
- * NEWS: Document the changes.
- * doc/find.texi (Warning Messages): Document -nowarn's effect on
- -name and -iname.
- * find/testsuite/find.gnu/name-slash.exp: New test, to ensure
- 20662 doesn't regress on '-name /', and that 20688 silences the
- warning.
- * find/testsuite/find.gnu/printf-slash.exp: Likewise.
- * find/testsuite/find.gnu/name-slash.xo: Expected results.
- * find/testsuite/find.gnu/printf-slash.xo: Likewise.
- * find/testsuite/Makefile.am (EXTRA_DIST_XO, EXTRA_DIST_EXP):
- Distribute new tests.
-
-2007-07-31 Eric Blake <ebb9@byu.net>
-
- Allow choice of default arg size, Savannah bug #20594.
- * configure.ac (DEFAULT_ARG_SIZE): Check environment for a default
- size override.
- * lib/buildcmd.c (bc_use_sensible_arg_max): Use default size from
- configure, if requested.
- * README (DEFAULT_ARG_SIZE): Mention the ability to tune this at
- configure time.
- * NEWS: Document the change.
-
-2007-07-29 James Youngman <jay@gnu.org>
-
- * po/tr.po: Updated from Translation Project.
-
-2007-07-26 Eric Blake <ebb9@byu.net>
-
- * doc/.cvsignore: Ignore more generated documentation.
-
-2007-07-23 Eric Blake <ebb9@byu.net>
-
- * find/parser.c (parse_version): Avoid compiler warning.
- * locate/code.c (includes): Likewise.
-
-2007-07-22 Eric Blake <ebb9@byu.net>
-
- * po/POTFILES.in: Add lib/findutils-version.c.
-
-2007-07-22 James Youngman <jay@gnu.org>
-
- * find/find.1: Corrected a number of typos and fixed up the
- alphabetical section ordering. This fixes Savannah bug #20552.
-
- Version banners now comply with the GNU coding standard.
- * find/parser.c (parse_version): Use display_findutils_version()
- instead of printing the information manually. Don't include
- gnulib-version.h since we no longer directly use that header.
- * lib/findutils-version.c: Added
- * lib/findutils-version.h: Added
- * import-gnulib.config (modules): Added version-etc and
- version-etc-fsf.
- * lib/Makefile.am (libfind_a_SOURCES): added findutils-version.c.
- * find/version.c: Removed
- * find/Makefile.am: Remove version.c
- * locate/Makefile.am: Don't link ../find/version.o
- * xargs/Makefile.am: Ditto
- * xargs/xargs.c (main): Use display_findutils_version()
- * locate/code.c (main): Ditto
- * locate/frcode.c (main): Ditto
- * locate/locate.c (dolocate): Ditto
- * locate/updatedb.sh (version): Display copyright information in
- the right format. Also ensure that we exit with a nonzero status
- if there was an output error for --help and --version.
- * find/testsuite/config/unix.exp (find_version): Adjust for
- --version format change
- * locate/testsuite/config/unix.exp (locate_version): Ditto
- * xargs/testsuite/config/unix.exp (xargs_version): Ditto
- * NEWS: Mention the change
-
-2007-07-19 Eric Blake <ebb9@byu.net>
-
- * po/POTFILES.in: Update to reflect current location of
- translatable strings.
-
-2007-07-17 Eric Blake <ebb9@byu.net>
-
- Ensure 'make distcheck' can pass on cygwin.
- * configure.in: Rename...
- * configure.ac: ...to this, to match automake recommendations.
- * NEWS: Add release dates.
- * doc/find-maint.texi: Remove trailing whitespace.
- (Documentation): Document where release dates are usefully
- recorded.
- * locate/Makefile.am (AM_INSTALLCHECK_STD_OPTIONS_EXEMPT): Be
- aware of .exe.
- * .cvsignore: Ignore 'make dist' files.
- * po/.cvsignore: Ignore remove-potcdate.sed.
-
-2007-07-14 Eric Blake <ebb9@byu.net>
-
- * import-gnulib.config (gnulib_version): Bump date, to pick
- up fix in canonicalize module testing.
-
-2007-07-06 James Youngman <jay@gnu.org>
-
- * po/uk.po, po/nl.po, po/vi.po: Updated from Translation Project.
-
-2007-07-04 James Youngman <jay@gnu.org>
-
- * NEWS: Fixed typos in description of bugfix for bug #20310.
-
-2007-07-03 James Youngman <jay@gnu.org>
-
- Fix Savannah bug #20310.
- * m4/nullsort.m4: If we are cross compiling, assume "sort -z" does
- not work on the target.
-
- Manpage improvements.
- * find/find.1: More consistent use of quotation marks.
- * locate/locate.1 (HISTORY): New section.
-
-2007-07-02 James Youngman <jay@gnu.org>
-
- * import-gnulib.sh: (run_gnulib_tool): Don't pass --gpl3 to
- gnulib-tool, since the program does not have that option (that was
- a local change which proved not to be necessary).
-
- GPL3 migration.
- * COPYING: Migrate to version 3 of the GNU General Public license.
- * Makefile.am: ditto
- * build-aux/check-testfiles.sh: ditto
- * build-aux/src-sniff.py: ditto
- * debian/copyright: ditto
- * doc/find-maint.texi: ditto
- * find/defs.h: ditto
- * find/find.c: ditto
- * find/finddata.c: ditto
- * find/fstype.c: ditto
- * find/ftsfind.c: ditto
- * find/parser.c: ditto
- * find/pred.c: ditto
- * find/testsuite/config/unix.exp: ditto
- * find/tree.c: ditto
- * find/util.c: ditto
- * import-gnulib.config: ditto
- * import-gnulib.sh: ditto
- * lib/buildcmd.c: ditto
- * lib/buildcmd.h: ditto
- * lib/dircallback.c: ditto
- * lib/dircallback.h: ditto
- * lib/extendbuf.c: ditto
- * lib/extendbuf.h: ditto
- * lib/forcefindlib.c: ditto
- * lib/gnulib-version.h: ditto
- * lib/listfile.c: ditto
- * lib/listfile.h: ditto
- * lib/modetype.h: ditto
- * lib/nextelem.c: ditto
- * lib/nextelem.h: ditto
- * lib/printquoted.c: ditto
- * lib/printquoted.h: ditto
- * lib/qmark.c: ditto
- * lib/regexprops.c: ditto
- * lib/regextype.c: ditto
- * lib/regextype.h: ditto
- * lib/savedirinfo.c: ditto
- * lib/savedirinfo.h: ditto
- * lib/strspn.c: ditto
- * lib/wait.h: ditto
- * lib/waitpid.c: ditto
- * locate/bigram.c: ditto
- * locate/code.c: ditto
- * locate/frcode.c: ditto
- * locate/locate.c: ditto
- * locate/locatedb.h: ditto
- * locate/testsuite/config/unix.exp: ditto
- * locate/updatedb.sh: ditto
- * locate/word_io.c: ditto
- * po/fetch-po-files: ditto
- * xargs/testsuite/config/unix.exp: ditto
- * xargs/xargs.c: ditto
-
- Typo fixes.
- * doc/find.texi (Deleting Files): Fixed a typo.
- (Deleting Files): Likewise.
-
- New worked example for find.
- * doc/find.texi (Copying A Subset of Files): Added a new worked
- example.
-
- * doc/find.texi (Updating A Timestamp File): Indicate that %A@ now
- includes a sub-second part on many systems.
-
- Include <fcntl.h> unconditionally.
- * import-gnulib.config (modules): Also use the fcntl module.
- * find/find.c: #include <fcntl.h> unconditionally, since
- gnulib provides it if it is absent.
- * find/fstype.c: Likewise.
- * find/ftsfind.c: Likewise.
- * find/parser.c: Likewise.
- * find/util.c: Likewise.
- * locate/locate.c: Likewise.
-
-2007-06-30 Eric Blake <ebb9@byu.net>
-
- * find/pred.c (pred_timewindow): Avoid gcc warnings.
- (format_date): Likewise.
- * find/tree.c (calculate_derived_rates): Likewise.
- * locate/word_io.c (getword): Likewise.
-
-2007-06-30 James Youngman <jay@gnu.org>
-
- * find/find.1 (EXAMPLES): Added an example of using find and cpio -p
- to copy a directory tree, with pruning and omitted files.
-
- * find/pred.c (format_date): Use verify_true for constant
- conditions rather than assert.
- * xargs/xargs.c (main): Ditto.
-
- Enhancements to the code smell detector.
- * Makefile.am (findutils-check-smells): Automate the calling of
- build-aux/src-sniff.py.
- * build-aux/src-sniff.py: Rework to use a list of regex-based
- sniffers, to allow checking types of file other than C. Allow
- file-based regex sniffers to give an indication of the line number
- where they think the problem (or part of the problem) exists.
- Added code smell detectors for a sample Bourne shell problem and
- for out-of-date FSF addresses.
-
- * find/tree.c (get_pred_cost): Eliminate unused variable.
-
- Fix Savannah bug #20263 in a more portable way.
- * find/tree.c (cost_table_comparison): Avoid casting function
- pointers to poiter-to-object, since this is not portable (or
- of course conforming). Instead, use memcmp().
-
-2007-06-28 Eric Blake <ebb9@byu.net>
-
- * import-gnulib.sh (run_gnulib_tool): Speed operation when
- updating an existing tree.
-
- Allow 'make check' to work without prior 'make all'.
- * find/Makefile.am (SUBDIRS): Build in . before testsuite.
- * locate/Makefile.am (SUBDIRS): Likewise.
- * xargs/Makefile.am (SUBDIRS): Likewise.
-
- Fix Savannah bug #20273, xargs -E with seekable stdin.
- * import-gnulib.config (modules): Sort, add closein.
- * xargs/testsuite/Makefile.am (EXTRA_DIST_EXP, EXTRA_DIST_XO)
- (EXTRA_DIST_XI): Add new test.
- * xargs/testsuite/config/unix.exp (xargs_start): Support optional
- argument to allow test to run a subshell.
- * xargs/testsuite/inputs/sv-bug-20273.xi: New file.
- * xargs/testsuite/xargs.posix/sv-bug-20273.xo: Likewise.
- * xargs/testsuite/xargs.posix/sv-but-20273.exp: Likewise.
- * xargs/xargs.c (main): Use close_stdin, not close_stdout.
- * NEWS: Document the fix.
-
-2007-06-27 James Youngman <jay@gnu.org>
-
- Added a maintenance manual.
- * doc/find-maint.texi: New file.
- * doc/Makefile.am (info_TEXINFOS): Added doc/find-main.texi.
- * doc/find.texi (Introduction): Fixed typo.
-
-2007-06-26 Eric Blake <ebb9@byu.net>
-
- * import-gnulib.config (modules): Allow ./configure
- --disable-assert.
-
-2007-06-26 James Youngman <jay@gnu.org>
-
- * build-aux/src-sniff.py: Detect uses of struct stat where the
- header file was not included.
- * find/find.c: Fix this, and uses of assert without a following
- space (the coding standard requires a space, but there are still
- a number of cases where other functions are called with no
- following space).
- * find/fstype.c: Ditto.
- * find/ftsfind.c: Ditto.
- * find/parser.c: Ditto.
- * find/pred.c: Ditto.
- * find/tree.c: Ditto.
- * find/util.c: Ditto.
- * lib/buildcmd.c: Ditto.
- * lib/buildcmd.h: Ditto.
- * lib/extendbuf.c: Ditto.
- * locate/frcode.c: Ditto.
- * locate/locate.c: Ditto.
- * locate/word_io.c: Ditto.
- * xargs/xargs.c: Ditto.
-
- * find/tree.c (cost_table_comparison): Avoid < comparison between
- function pointer types. Instead cast the function pointers to
- (const void*). Both alternatives are undefined C, but the former
- actually fails to compile on some systems. This fixes Savannah
- bug #20263.
- * NEWS: mention the fix
-
- * find/tree.c (calculate_derived_rates): Removed assignment to
- rate variable following an assert(0) call, which had been added to
- silence a "used before initialised" warning, and replace it with a
- call to abort, which (a) correctly halts execution if _NDEBUG is
- defined and (b) more accurately documents what's happening.
-
- * find/parser.c (get_stat_Ytime): Removed redundant call to abort.
-
- * find/util.c (debug_stat): For consistency, use assert (0) rather
- than assert (false).
-
-2007-06-26 James Youngman <jay@gnu.org>
-
- * README-alpha: Mention the findutils-patches mailng list and the
- archives for findutils-patches and bug-findutils.
-
- * po/bg.po: Updated from Translation Project.
-
-2007-06-25 James Youngman <jay@gnu.org>
-
- * po/sv.po: Updated Swedish translation.
-
-2007-06-24 James Youngman <jay@gnu.org>
-
- * build-aux/.gitignore, debian/.gitignore, doc/.gitignore,
- find/.gitignore, find/testsuite/.gitignore, .gitignore,
- lib/.gitignore, locate/.gitignore, locate/testsuite/.gitignore,
- m4/.gitignore, po/.gitignore, xargs/.gitignore,
- xargs/testsuite/.gitignore: New files to make it more painless to
- track findutils sources with git.
-
- * NEWS: Mention the previous change to doc/find.texi.
-
-2007-06-23 James Youngman <jay@gnu.org>
-
- * doc/find.texi (Introduction): Recommend that people check they
- are using the latest version before reporting a bug.
-
-2007-06-22 James Youngman <jay@gnu.org>
-
- Better documentation for the fractional part of seconds fields for
- -printf and similar actions.
- * doc/find.texi (Time Components): Point out that the seconds
- field of the timestamp is often printed out with a fractional part
- of unspecified length and precision. The '%Tc' field has no
- seconds part.
- (Combined Time Formats): Point out the same thing for '%T@'.
- * find/find.1 (%A): Point out the same thing.
- * NEWS: Mention these changes.
-
- Fix various lint-type complaints taken from the rules in the
- coreutils Makefile.maint file (see build-aux/src-sniff.py).
- * xargs/xargs.c: Removed unnecessary parentheses in "#if defined"
- checks.
- (main): Don't cast the return value of xmalloc.
- (add_proc): Don't cast the return value of xmalloc.
- * lib/regextype.c: Don't include quotearg.h, we don't need it.
- * lib/dircallback.c, lib/nextelem.c, lib/prontquoted.c,
- lib/qmark.c, lib/strspn.c, lib/waitpid.c: Assume config.h is available.
- * lib/extendbuf.c: Ditto
- * lib/listfile.c: Ditto. Also removed unnecessary parentheses in
- "#if defined" checks.
- (get_link_name): Don't cast the result of xmalloc.
- * lib/bigram.c: Removed unnecessary parentheses in "#if defined"
- checks.
- * lib/savedirinfo.c: Assume config.h is available. Also removed
- unnecessary parentheses in "#if defined" checks.
- * lib/buildcmd.c (bc_do_insert): Don'tcast the result of xmalloc().
- * find/tree.c (build_expression_tree): Don't cast the argument to free().
- * find/ftsfind.c (set_close_on_exec): Removed unnecessary
- parentheses in "#if defined" checks. Also changed "filesystem" ->
- "file system"
- * find/util.c (check_nofollow): Removed unnecessary parentheses in
- "#if defined" checks.
- * find/parser.c (estimate_fstype_success_rate): ditto.
- (insert_regex): Do not cast the result of xmaloc(). Removed unnecessary
- parentheses in "#if defined" checks. Also changed "filesystem" ->
- "file system"
- * find/pred.c: ditto
- * find/find.c: "the the" -> "the", "filesystem" -> "file system"
- * find/fstype.c: "filesystem" -> "file system" (in comments and
- static functions)
- * locate/frcode.c: Removed unnecessary parentheses in "#if
- defined" checks.
- * locate/locate.c (search_one_database): Don't cast the return
- value of xmalloc.
- (dolocate): Mark error message for translation.
-
-2007-06-21 Eric Blake <ebb9@byu.net>
-
- * locate/.cvsignore: Ignore dblocation.texi.
- * build-aux/.cvsignore: Ignore Makefile.
- * locate/locate.c (set_max_db_age): Fix typo in error message.
-
-2007-06-19 Eric Blake <ebb9@byu.net>
-
- Fix compilation on cygwin, Savannah bug #20210.
- * import-gnulib.config (gnulib_version): Import strcasestr and
- updated canonicalize-lgpl-tests.
- * lib/dircallback.c (includes): Track gnulib changes.
-
-2007-06-14 James Youngman <jay@gnu.org>
-
- * find/parser.c (parse_time): Use the variable comp, which holds
- the planned comparison type, rather than the structure tval, which
- has not been initialised yet and contains a random value. This
- fixes Savannah bug #20139.
- * NEWS: Mention the bugfix.
-
-2007-06-13 James Youngman <jay@gnu.org>
-
- * po/pl.po: Updated Polish translation.
-
-2007-06-12 James Youngman <jay@gnu.org>
-
- Release 4.3.8.
-
- * find/find.1 (HISTORY): Document when the find tests -readable,
- -writable, -executable and the option -regextype were introduced.
-
-2007-06-12 Nix <nix@esperi.org.uk> (trivial change)
-
- * locate/locate.c (drop_privs): Use groups[0] rather than
- groups[1], since groups[] is a one-element array. This is a
- buffer overrun affecting root only. In theory it could affect
- setuid installations, but I (James Youngman) cannot find an explot
- mechanism for it. This fixes Savannah bug#20157.
- * NEWS: Mention this fix.
-
-2007-06-12 James Youngman <jay@gnu.org>
-
- Make the test suite work when run as root.
- * find/testsuite/config/unix.exp (fs_superuser): Abstract out the
- check which discovers if we have superuser privileges on the
- filesystem (taken from access.exp).
- * find/testsuite/find.gnu/access.exp: Call fs_superuser.
- * find/testsuite/find.gnu/fprint-unwritable.exp: Use fs_superuser.
-
- * po/vi.po, ga.po, nl.po: Updated translations
- * po/findutils.pot: Updated template file
-
-2007-06-09 James Youngman <jay@gnu.org>
-
- Release 4.3.7.
-
- Check that we can correctly read old-format databases which are
- big-endian or little endian.
- * locate/testsuite/config/unix.exp (locate_from_db): New function;
- supports testing locate against a provided database.
- * locate/testsuite/locate.gnu/bigendian.exp: New test; make sure
- we can read an old-format big-endian database.
- * locate/testsuite/locate.gnu/bigendian.xo: Expected output from
- bigendian.exp test.
- * locate/testsuite/locate.gnu/littleendian.exp: New test; make sure
- we can read an old-format little-endian database.
- * locate/testsuite/locate.gnu/locateddb.old.powerpc.xi: Old format
- big endian database file, for supporting bigendian.exp.
- * locate/testsuite/locate.gnu/littleendian.xo: Expected output from
- littleendian.exp test.
- * locate/testsuite/locate.gnu/locateddb.old.x86.xi: Old format
- little endian database file, for supporting littleendian.exp.
- * locate/testsuite/Makefile.am: Distribute littleendian.exp,
- bigendian.exp and related .xi and .xo files.
-
-
- * doc/find.texi (Size Directives): Compare %b with %s/512, not
- %s/1024. This fixes (again) Savannah bug #19596.
- * NEWS: mention the fix.
-
- Avoid using the non-portable function putw().
- * locate/locatedb.h: Declare putword().
- * locate/frcode.c: Include <stdbool.h> as locatedb.h now requires
- it.
- * locate/code.c (main): Use putword() rather than putw(), because
- the latter was removed from SUSv3. This fixes Savannah bug #19980.
- Also include <stdbool.h> as locatedb.h now requires this.
- * locate/word_io.c (putword): Define the new function putword.
-
- Ensure that <config.h> is included before any system header
- * find/defs.h: Do not include <config.h> from "defs.h". Instead
- just complain if it was not already included, since it needs to
- be included first of all, even before system headers (in case
- gnulib had replaced a system header). Check
- ALREADY_INCLUDED_CONFIG_H to determine this.
- * configure.in: Always define ALREADY_INCLUDED_CONFIG_H in
- config.h.
- * find/find.c: Include config.h before defs.h.
- * find/finddata.c: ditto.
- * find/fstfind.c: ditto.
- * find/parser.c: ditto.
- * find/pred.c: ditto.
- * find/util.c: ditto
- * find/tree.c: ditto (fixing Savannah bug #20128).
-
- * m4/noreturn.m4 (jy_AC_ATTRIBUTE_NORETURN): Use AC_LANG_PROGRAM
- inside AC_COMPILE_IFELSE.
-
- * doc/find.texi (Security Considerations for locate): Discuss in
- detail the buffer overrun when reading old-format locate
- databases. This is CVE reference CVE-2007-2452.
-
-2007-06-05 James Youngman <jay@gnu.org>
-
- Guess the byte-order of old-format locate databases.
- * locate/word_io.c (getword): Make the endian_state_flag parameter
- an enum rather than an int. If we are in the initial ("don't
- know") byte-order guessing state and the swapped value is out of
- range, use this as evidence that the byte order is native.
- * locate/locatedb.h: Declare getword accordingly.
- * locate/locate.c (struct process_data): Added endian_state
- member, which remembers for us what the big/little endian order
- guessing state is when we read an old-format database.
- (visit_old_format): Use the procdata.endian_state rather than a
- local variable, so that the information can persist across calls.
- (i_am_little_endian): Locate figures out if we needed to byteswap
- the words in an old-format database, but that is an implementation
- detail. Therefore we figure out our own byte order so that we can
- produce a more relevant message for --statistics. The
- i_am_little_endian() returns nonzero if the current host has
- little-endian byte order.
- (search_one_database): Report the byte-order of old-format
- databases.
-
-2007-06-04 James Youngman <jay@gnu.org>
-
- * locate/testsuite/Makefile.am (EXTRA_DIST_XO, EXTRA_DIST_EXP):
- Added old_prefix.exp and old_prefix.xo, a new test case for long
- shared rpefixes with the old database format.
-
- * locate/locate.c (visit_old_format): Use getword() from word_io.c
- instead of getw(), because getw() is not in POSIX.
- * locate/word_io.c: New file, providing replacement for getw().
- * locate/locatedb.h: Declare getword()
- * locate/Makefile.am (locate_SOURCES): Added word_io.c
-
- * locate/testsuite/config/unix.exp (locate_start): Make the
- failure messages slightly more explicit; indicate what went wrong
- when a test fails.
-
-2007-06-03 James Youngman <jay@gnu.org>
-
- * locate/locate.c (visit_old_format, extend, toolong): Extend the
- buffer used to build the current pathname when reading an
- old-format database. The new function extend is called to do
- this. The new function toolong is called to report a fatal error
- when the buffer size would otherwise exceed SIZE_MAX. This fixes
- Savannah bug #20014, which is a security-related problem with the
- CVE identifier CVE-2007-2452.
-
- * configure.in: Determine if the setgroups function is available,
- and set HAVE_SETGROUPS if so.
- * locate/locate.c (drop_privs): Call setgroups() only if
- HAVE_SETGROUPS indicates that it is available. This fixes
- Savannah bug #19981.
-
- * po/vi.po: Updated Vietnamese translation
-
-2007-05-31 James Youngman <jay@gnu.org>
-
- * find/parser.c (parse_time): Once we have determined the
- comparison type, restore the original time argument since
- get_relative_timestamp() also wants to see it. This fixes
- Savannah bug #20005.
-
- * po/findutils.pot, ga.po, pt.po, tr.po, pl.po: updated from the TP
- website.
-
-2007-05-31 Jakub Bogusz <qboosh@pld-linux.org> (trivial change)
-
- * find/parser.c (parse_group): Correct typo in error message.
- (check_path_safety): same
-
-2007-05-27 James Youngman <jay@gnu.org>
-
- * import-gnulib.config (modules): Import sys_stat.
- (gnulib_version): Update to 2007-05-26. This fixes a compilation
- error in stdlib.h with the DEC C compiler. This fixes Savannah
- bug# 19983.
-
- * find/parser.c (safe_atoi): New function, like atoi, but which
- calls error(1, ...) when the argument is invalid or out of range.
- (parse_group): Use safe_atoi.
- (insert_depthspec): Use safe_atoi
- (parse_user): Use safe_atoi
-
- * configure.in: Check for fabs in libm (fixing a compilation error
- on Solaris).
-
- * import-gnulib.config (modules): Import the wcwidth module to
- provide it on those systems (such as BeOS) which lack it.
-
- * find/pred.c (file_sparseness): If st_blocks is not present in
- struct stat, the file has a sparseness of 1.0.
-
- * doc/find.texi (Size Directives): Document the %S format
- directive for -printf.
-
- * find/pred.c (mode_to_filetype): Don't use S_IFSOCK on systems
- which lack that macro. POSIX systems are allowed to lack
- sockets (it's an XSI extension).
- (file_sparseness): If struct stat lacks st_blocks, assume all
- files have a spearseness of 1.0.
-
- * import-gnulib.config (modules): Import fchdir inorder to fix an
- undefined-symbol error for fchdir on BeOS.
-
-2007-05-26 James Youngman <jay@gnu.org>
-
- Code refactoring in locate.
- * locate/locate.c (visit): New function, into which we factor out
- the traversal of the inspector list.
- (process_simple): Use visit().
- (process_or): Use visit().
- (process_and): Use visit().
-
- Speed improvements in locate for unibyte locales.
- * locate/locate.c (visit_substring_match_nocasefold_wide): Renamed
- from visit_substring_match_nocasefold.
- (visit_substring_match_casefold_wide): Renamed from
- visit_substring_match_casefold.
- (visit_substring_match_casefold_narrow): Special case of
- visit_substring_match_casefold_wide which we use for unibyte
- locales; we use strcasestr() rather than mbscasestr().
- (visit_substring_match_nocasefold_narrow): Ditto, using strstr()
- instead of mbsstr().
-
- * find/parser.c (parse_gid): Return an explicit boolean constant
- rather than automatically converting from a pointer, because the
- gnulib substitute for bool (or _Bool) in c89 environments lacking
- bool does not support that conversion. One affected system is Sun
- WorkShop Compilers 5.0 98/12/15 C 5.0 on Solaris 7. This is
- Savannah bug #19970, reported by Nelson Beebe.
- (parse_inum): Ditto.
- (parse_links): Ditto.
- (parse_uid): Ditto.
- (check_path_safety): declarations need to go before code, not
- interspersed. Move declaration of char* s.
-
- * xargs/testsuite/xargs.posix/rc-125.exp: Explain Savannah bug
- #19969. This bug is not yet fixed.
-
- * find/defs.h: #include <stdint_.h>, for uintmax_t. This should
- fix a compilation error on DEC C V5.9-005 on Digital UNIX V4.0F
- (Rev. 1229). This is Savannah bug #19965, reported by Nelson
- Beebe.
-
- * find/defs.h: Don't include <errno.h>, since it is not needed in
- the header file itself. The "extern int errno;" declaration is
- now obsolete.
- * find/parser.c: Include <errno.h>
- * find/pred.c: Dito
- * find/util.c: Ditto
-
-2007-05-24 James Youngman <jay@gnu.org>
-
- * find/util.c (check_nofollow): If O_NOFOLLOW is defined but 0,
- act as if it is undefined. This should prevent a runtime
- assertion failure on IRIX 6.5. This fixes Savannah bug #19948,
- reported by Nelson Beebe.
-
- * m4/noreturn.m4: New file, testing for support of __attribute__
- ((__noreturn__)). Defines jy_AC_ATTRIBUTE_NORETURN and sets
- HAVE_ATTRIBUTE_NORETURN.
- * configure.in: Call jy_AC_ATTRIBUTE_NORETURN.
- * find/defs.h (ATTRIBUTE_NORETURN): Define to nothing if
- HAVE_ATTRIBUTE_NORETURN is not set in config.h. This should fix a
- compilation error with non-GCC compilers. This is Savannah bug
- #19967, reported by Nelson Beebe.
-
- * configure.in (FINDLIBS): Update FINDLIBS to link against -lm for
- modf. This fixed a link error on HP-UX. This fixes Savannah
- bug #19966, reported by Nelson Beebe.
- * find/Makefile.am (LDADD): Use @FINDLIBS@
-
-2007-05-21 James Youngman <jay@gnu.org>
-
- Release 4.3.6.
-
- * build-aux/Makefile.am (EXTRA_DIST): Added man-lint.sh.
-
- * locate/locate.c (drop_privs): pass the correct list of groups to
- setgroups(). Previously, if root invoked locate, their group ID
- would have been set to a random value. The same bug also caused
- an array overrun past the end of the local array groups[]. The
- variable which gets overwritten by the buffer overrun on x86 is
- 'what'. The value of that variable is always changed before it is
- used, and so I believe that this buffer overrun will not cause a
- crash. The only effect of the bug therefore would be for locate
- to change group to a random group ID since groups[0] is
- uninitialised. On my test system this random group ID is 0
- anyway. The effect does not depend on any externally-controllable
- information, so it is unlikely this is exploitable. This bug is
- detailed as bug# 19923.
-
-2007-05-19 James Youngman <jay@gnu.org>
-
- * find/find.1: Spurious .R directives (.R is not a directive)
- should be .B. This fixes Savannah bug #19871.
- * build-aux/man-lint.sh: New file; verifies that the specified
- manual pages do not provoke error messages from troff. This is
- used to detect further occurrences of Savannah bug #19871.
- * find/Makefile.am (dist-hook): Run findutils-check-manpages,
- which invokes man-lint.sh.
- * locate/Makefile.am (dist-hook): ditto
- * xargs/Makefile.am (dist-hook): ditto
-
- * .cvsignore: Ignore ylwrap, which automake-1.10 wants us to have
- a copy of for some reason
-
- * import-gnulib.sh (main): New option -a which just runs the
- autotools without reimporting gnulib.
-
- * Makefile.am (jy-regex-fix): The previous explanatory comment
- refers to the jy-regex-fix target, not to dist-hook, so it has
- been moved.
-
-2007-05-08 James Youngman <jay@gnu.org>
-
- * find/defs.h (struct predicate.args): str is now const.
-
- * find/parser.c (get_comp_type): get_comp_type now takes a const
- char* parameter.
- (get_num): ditto
- (get_relative_timestamp): ditto. Also use collect_arg().
- (collect_arg_stat_info): New function; collects a command-line
- argument and returns its xstat information, in one go.
- error(1,...) is called if the stat fails.
- (parse_anewer): Use collect_arg().
- (parse_cnewer): ditto
- (parse_fprint): ditto
- (parse_fstype): ditto
- (parse_group): ditto
- (parse_ilname): ditto
- (parse_iname): ditto
- (parse_iwholename): ditto
- (parse_lname): ditto
- (insert_depthspec): ditto
- (parse_name): ditto
- (parse_newer): ditto
- (parse_wholename): ditto
- (parse_perm): ditto
- (parse_regextype): ditto
- (insert_regex): ditto
- (parse_samefile): ditto
- (parse_used): ditto
- (parse_user): ditto
- (insert_type): ditto
- (parse_time): ditto
- (parse_size): When the size argument is invalid but consists only
- of a valid suffix char, avoid issuing an error message about a
- blank argument. Append the suffix letter again.
- (parse_xdev, parse_ignore_race, parse_noignore_race, parse_warn,
- parse_xtype): Remove casts to void for some function parameters
- that were, in fact, used.
-
- * find/testsuite/find.gnu/fprint-unwritable.exp: new test
- * find/testsuite/find.gnu/fprint0_stdout.exp: new test
- * find/testsuite/find.gnu/fprint0_stdout.xo: new test
- * find/testsuite/find.gnu/mindepth-arg.exp: new test
- * find/testsuite/find.gnu/mindepth-arg.xo: new test
- * find/testsuite/find.gnu/mindepth-badarg.exp: new test
- * find/testsuite/find.gnu/print_stdout.exp: new test
- * find/testsuite/find.gnu/print_stdout.xo: new test
- * find/testsuite/find.gnu/samefile-missing.exp: new test
- * find/testsuite/find.gnu/samefile-p-brokenlink.exp: new test
- * find/testsuite/find.gnu/samefile-p-brokenlink.xo: new test
- * find/testsuite/find.gnu/used-invarg.exp: new test
- * find/testsuite/find.gnu/used-missing.exp: new test
- * find/testsuite/find.gnu/user-invalid.exp: new test
- * find/testsuite/find.posix/group-empty.exp: new test
- * find/testsuite/find.posix/group-missing.exp: new test
- * find/testsuite/find.posix/name-missing.exp: new test
- * find/testsuite/find.posix/size-invalid.exp: new test
- * find/testsuite/find.posix/size-missing.exp: new test
- * find/testsuite/find.posix/typearg.exp: new test
- * find/testsuite/find.posix/user-empty.exp: new test
- * find/testsuite/find.posix/user-missing.exp: new test
-
-2007-05-06 James Youngman <jay@gnu.org>
-
- * find/tree.c: (costlookup): Added pred_fls to the optimiser's
- predicate cost lookup table.
-
- * lib/printquoted.c (print_quoted): Change return value from void
- to int, to allow the caller to detect failures.
- * lib/printquoted.h (print_quoted): Change declaration
- accordingly.
-
- * find/defs.h (struct format_val): Incldue a 'filename' member so
- that we can provide more useful error messages (e.g. when we fail
- to flush or close an output file).
- (nonfatal_file_error): declare new function.
-
- * find/util.c (traverse_tree): Utility function which calls a
- callback on every node of the parse tree.
- (flush_and_close_output_files): Flush all output streams. Close
- all output files. Report any errors.
- (cleanup): Use traverse_tree() to invoke
- complete_pending_execdirs().
- (report_file_err): refactored error reporting function, extracted
- from fatal_file_error.
- (nonfatal_file_error): New function.
-
- * find/pred.c (checked_fprintf): New function, which performa an
- fprinf(), and checkes the result. If the operation resulted in an
- error, a nonfatal error message is issued.
- (checked_print_quoted): Ditto, for print_quoted rather than
- fprintf.
- (checked_fwrite): Ditto for fwrite instead of fprintf.
- (checked_fflush): Ditto for fflush
- (do_fprintf): Use the checked_*() functions rather than their
- direct counterparts, to ensure that I/O errors are detected. This
- fixes Savannah bug #19416.
- (pred_fls): Use args.printf_vec instead of args.stream, which has
- now been removed.
- (pred_ls): just call pred_fls.
- (pred_fprint0): use args.printf_vec, instead of the now removed
- args.stream.
- (pred_print0): just call pred_fprint0
-
- * find/parser.c: (insert_fprintf): Make the caller collect the
- format argument from the argument list.
- (open_output_file): Enhance to set up defaults in
- our_pred->args.printf_vec as well as opening the output file.
- Also record the filename for possible later use in an error
- message.
- (collect_arg): Convenience function for collecting an argument
- from the argument list.
- (insert_fls): Refactored the body of parse_fls out so that
- parse_ls can use it.
- (parse_fls): call insert_fls.
- (parse_ls): ditto
- (parse_fprint): Instead of setting up our_pred->args.printf_vec
- manually, call open_output_file() to do it.
- (parse_print): Same, but by calling open_stdout().
- (insert_fprint): Make the caller collect the filename argument,
- and delegate the setup of our_pred->args.printf_vec to either
- open_output_file() (for parse_fprint and parse_fprint0) or
- open_stdout (parse_print0).
- (parse_fprint0): Use collect_arg().
- (parse_print0): Use insert_fprint(), just like parse_fprint0.
- (parse_printf): Use collect_arg().
- (parse_fprintf): Use collect_arg().
-
-2007-05-05 James Youngman <jay@gnu.org>
-
- Release 4.3.5.
-
- * find/parser.c (parse_samefile): Hold a file descriptor open on
- the reference file in order to prevent pred_samefile getting
- fooled by inode reuse. Pay attention to race conditions on
- systems lacking O_NOFOLLOW when the -P option is in force. This
- fixes Savannah bug #19806.
-
- * find/defs.h (struct samefile_file_id): New struct, like dir_id
- but including a file descriptor on the reference file.
-
- * find/pred.c (pred_type): -type should return false if the file
- has mode 00000, as opposed to having an assertion failure. This
- fixes Savannah bug #16378.
-
- * find/ftsfind.c (consider_visiting): Issue a warning message if
- none of the mode bits are set for a file (i.e. st_mode==00000).
- * find/util.c (get_statinfo): ditto
- * find/util.c (hook_fstatat): Introduced debug code (normally
- disabled) for testing Savannah bug #16378.
-
-2007-05-01 James Youngman <jay@gnu.org>
-
- * find/find.c (wd_sanity_check): corrected the type of %ld fprintf
- arguments in error messages.
- * find/fstype.c: include "error.h" for the declaratio of error().
- * find/ftsfind.c: include "error.h" for the declaratio of
- error(). Include dircallback.h for the correct declararion of
- run_in_dir().
- * find/parser.c: include getdate.h (for declaration of getdate)
- and error.h (for the declaration of error).
- (find_parser): Removed unused variable p.
- * find/pred.c (pred_timewindow): Removed unused variable delta.
- (do_fprintf): Removed unused variable cc.
- * find/tree.c: Include error.h (for the declaration of error()).
- (build_expression_tree): removed sourious extra arguments in call
- to error().
- * find/util.c: include error.h.
- * lib/buildcmd.h (get_line_max): Comment out unused function.
- * lib/listfile.c: Include dircallback.h.
- * locate/code.c: Include errno.h, erorr.h, progname.h and
- xlloc.h.
- (inerr): New function for reporting read errors.
- (outerr): New function for reporting output errors.
- (main): Call inerror when fgets fails. Call outerr when fwrite
- or putc or putw fails.
- * locate/frcode.c (put_short): Return boolean value indicating
- success.
- (outerr): New function for reporting write errors.
- (main): Call outerr if call to putc() or puts() or put_short()
- fails.
- * locate/locate.c (search_one_database): diagnose corruption if a
- traditional-style database is too short to include a complete
- bigram table.
-
-2007-04-30 James Youngman <jay@gnu.org>
-
- * find/defs.h: Change all predicate functions to take a const
- char* argument as the pathname, not a char*. Modify the parser
- table definition accordingly.
- * find/parser.c: Ditto
- * find/pred.c: Ditto
- * find/pred.c (do_fprintf): copy the pathname string for the %H
- and %h cases, since we can no longer modify the string in place.
- * lib/listfile.c (print_name, list_file,
- print_name_without_quoting, print_name_with_quoting): Use const
- char * param for pathname.
- * lib/listfile.h (list_file): Use const char * param for
- pathname.
-
-2007-04-29 James Youngman <jay@gnu.org>
-
- * find/defs.h: Declare fatal_file_error(), a function for
- reporting immediately-fatal file errors, which appropriately
- quotes the file name. The function does not return. Also define
- ATTRIBUTE_NORETURN. Record the currently-required quoting style
- in struct options.
-
- * find/find.c, find/ftsfind.c, find/parser.c, find/pred.c,
- find/util.c: Call fatal_file_error() for fatal file errors. Use
- quotearg_n_style() to quote filenames which are used in error
- message that aren't fatal. Use options.err_quoting_style as the
- quoting style. This fixes Savannah bug #18203.
- * locate/locate.c: ditto
- * xargs/xargs.c: ditto
-
- * lib/listfile.c: To use alloca, just #include <alloca.h>. Gnulib
- handles the rest. Also these days, <stdlib.h> and <string.h> can
- just be included unconditionally.
- * lib/qmark.c: Fixed comment on first line describing the module.
-
-2007-04-29 Michael Haubenwallner <michael.haubenwallner@salomon.at> (Trivial Change)
-
- * find/defs.h (pred_open) Rename to pred_openparen to avoid
- problems with the macrtos which build the parser tabnles on
- platforms where 'open' is in fact a macro whcih expands to
- open64. The problem was that token pasting put pred_open64 into
- the parser table, but the function was still defined as
- parse_open. This fixes Savannah bug #19371.
- (pred_close): ditto
- * find/parser.c (parse_open, parse_close): ditto. Also change
- repferences to pred_open and pred_close similarly.
- * find/parser.c (parse_openparen, parse_closeparen): ditto
-
-2007-04-28 James Youngman <jay@gnu.org>
-
- * find/testsuite/find.gnu/deletedir.exp,
- find/testsuite/find.gnu/deletedir.xo: New test.
- * find/testsuite/find.gnu/deletefile.exp,
- find/testsuite/find.gnu/deletefile.xo: New test.
- * find/testsuite/Makefile.am: Distribute the new tests
- deletefile.exp and deletedir,exp, with their expected-output (.xo)
- files too.
- * find/testsuite/config/unix.exp (find_start): Add a new "setup"
- parameter called just before each time find is invoked. This
- allows last-minute tasks to be performed. This feature is
- essential for find commands that modify the filesystem, since
- otherwise we cannot use our strategy of invoking both binaries at
- each optimisation level.
-
- * find/util.c (optionh_stat, optionp_stat, optionl_stat): Assert
- that state.cwd_dir_fd is valid.
-
- * find/parser.c (parse_delete): Set need_stat to false, since we
- don't need the stat information in pred_delete.
- * find/pred.c (pred_delete): If unlinkat() with a zero flags
- parameter fails with errno==EISDIR, just try again with
- flags=AT_REMOVEDIR. That way we normally avoid the cost of a
- stat. If we happen to have the stat information to hand anyway,
- we make sure we get it right the first time.
-
- * lib/buildcmd.c (bc_init_controlinfo): Eliminate confusing extra
- variable arg_max. Add return value
- BC_INIT_CANNOT_ACCOMODATE_HEADROOM for the case where the
- environment itself is not too large, but the required headroom
- cannot also be accomodated. The caller now passes in the amount
- of headroom required.
- (bc_use_sensible_arg_max): Use the environment size consistently;
- this is accounted for already in posix_arg_size_max, so there is
- no need to re-measure the size of the environment.
- * lib/buildcmd.h: Define BC_INIT_CANNOT_ACCOMODATE_HEADROOM and
- add the headroom parameter to the prototype of bc_init_controlinfo().
- * xargs/xargs.c (main): Define XARGS_POSIX_HEADROOM as 2048 and
- use that symbolic value. Pass XARGS_POSIX_HEADROOM to
- bc_init_controlinfo(). Handle the case where
- BC_INIT_CANNOT_ACCOMODATE_HEADROOM is returned by
- bc_init_controlinfo().
- * find/parser.c (new_insert_exec_ok): Pass the required headroom to
- bc_init_controlinfo() and handle the error return
- BC_INIT_CANNOT_ACCOMODATE_HEADROOM.
-
- * xargs/xargs.1: Correct the description of the default value and
- maximum value for the -s option of xargs.
-
- * xargs/xargs.c (main): Modify the assertions not to assume that
- bc_ctl.arg_max is 2KiB less than ARG_MAX, since sysconfig() may
- have returned a value for _SC_ARG_MAX which is greater. For
- example, AIX 5.3 can do this. This should fix Savannah bug
- #19391.
-
-2007-04-25 James Youngman <jay@gnu.org>
-
- * find/tree.c (predlist_dump, predlist_merge_nosort): These
- functions were unused and commented out. Removed.
- (mark_stat) No longer used. Removed.
- (mark_type) No longer used. Removed.
-
- * find/parser.c (new_insert_exec_ok): When checking for {} in the
- arguments to -exec..., use mbsstr() rather than strstr() in order
- to cope bettwe with multibyte locales.
-
- * lib/buildcmd.c: Don't define mbsstr() locally. Instead, call
- gnulib's mbsstr().
-
-2007-04-24 James Youngman <jay@gnu.org>
-
- * lib/buildcmd.c: Added some comments outlining how we might
- change the implementation to support figuring out the real ARG_MAX
- limit.
-
-2007-04-23 James Youngman <jay@gnu.org>
-
- * find/defs.h (struct predicate_performance_info): New data
- structure for holding perofmance statistics.
- (struct predicate: include predicate_performance_info
- (apply_predicate): change from macro to function
- (pred_is): new macro, for predicate identity testing
- (enum DebugOption): Added DebugSuccessRates
- * find/find.1: Document option "-D rates" which turns on
- DebugSuccessRates.
- * doc/find.texi: ditto
- * find.c (main): Call show_success_rates() before exiting.
- (apply_predicate): remove the macro defintion, declare equivalent
- function in defs.h.
- * find/ftsfind.c (main): Call show_success_rates() before
- exiting. Use apply_predicate().
- (show_outstanding_execdirs): use pred_is().
-
-
-
-2007-04-22 Eric Blake <ebb9@byu.net>
-
- * xargs/xargs.c (main): Don't assume LINE_MAX exists (i.e. is
- #defined).
-
- * locate/updatedb.sh (PRUNEPATHS): Exclude /proc by default.
-
-2007-04-22 James Youngman <jay@gnu.org>
-
- * doc/Makefile.am: When cross-compiling, 'make clean' should not
- delete doc/regexprops.texi, becaue we can't regenerate it. Fixes
- Savannah bug #19658.
-
- * locate/Makefile.am (BUILT_SOURCES): Automatically generate
- dblocation.texi, which records the default database location.
- * doc/find.texi: Collect the default database location from
- ../locate/dblocation.texi, and use LOCATE_DB in various places.
- Document the fact that updatedb can generate slocate-compatible
- databases. Document the --dbformat option of updatedb.
- * locate/frcode.c (main): Implemented the -S option which allows the
- generation of an slocate secure database.
- * locate/updatedb.sh: New option --dbformat which selects which
- database format to use.
- * locate/updatedb.1 (--dbformat): Document the new option.
-
-
- * find/testsuite/find.gnu/access.exp: fixed a typo which prevented
- the test correctly being skipped when run as root. This re-fixes
- Savannah bug# 18414, I hope.
-
-2007-04-21 James Youngman <jay@gnu.org>
-
- Release 4.3.4.
-
- * find/locate/locatedb.5: Clarifications to the description of the
- LOCATE02 format. Organised the material under a number of
- headings. Documented the slocate database format.
-
-2007-04-21 James Youngman <jay@gnu.org>
-
- * find/testuite/Makefile.am (EXTRA_DIST_EXP): added
- find/testsuite/find.posix/sv-bug-19617.exp
-
-2007-04-20 Maxim V. Dziumanenko <dziumanenko@gmail.com>
-
- * po/uk.po: New Ukranian translation.
- * configure.in: Added "uk" for Ukranian.
-
-2007-04-19 Peter Breitenlohner <peb@mppmu.mpg.de> (Trivial change)
-
- * locate/bigram.c (main): Set the initial pathname to the empty
- string, to avoid decompression problems if the initial pathname
- begins with a space. This fixes Savannah bug #19484.
- * locate/code.c (main): ditto
-
-2007-04-19 James Youngman <jay@gnu.org>
-
- * locate/updatedb.1 (--help): Option name should be bold, not
- italic.
-
- * find/testsuite/find.gnu/execdir-hier.exp: Avoid running
- -execdir based tests if "." is on $PATH. Fixes Savannah bug
- #19634.
- * find/testsuite/find.gnu/execdir-in-unreadable.exp: ditto
-
- * find/testsuite/config/unix.exp (touch): New procedure touch,
- replacing "exec touch" for greater efficiency.
- * find/testsuite/find.posix/depth1.exp: Change "exec touch" to
- "touch".
- * find/testsuite/find.posix/files-not-expressions1.exp: ditto
- * find/testsuite/find.posix/files-not-expressions2.exp: ditto
- * find/testsuite/find.posix/files-not-expressions3.exp: ditto
- * find/testsuite/find.posix/links.exp: ditto
- * find/testsuite/find.posix/perm-vanilla.exp: ditto
- * find/testsuite/find.posix/sv-bug-15235.exp: ditto
- * /find/testsuite/find.posix/sv-bug-19613.exp: ditto
-
- * find/testsuite/find.gnu/access.exp: Fix savannah bug #18414 by
- skipping the test if the user can read any file (e.g. is root or
- is an Admin user under Cygwin).
-
-2007-04-17 James Youngman <jay@gnu.org>
-
- * import-gnulib.config (gnulib_version): Use the 2007-04-17
- version of gnulib to fix a compilation error on Cygwin. This
- fixes Savannah bug #19619.
-
- * find/testsuite/find.posix/sv-bug-19605.exp: New test, for
- Savannah bug #19605.
- * find/testsuite/find.posix/sv-bug-19617.exp: New test, for
- Savannah bug #19617.
- * find/ftsfind.c (consider_visiting): if fts_read() returns
- enf->fts_info==FTS_NS, check for and diagnose a symbolic link
- loop. This fixes Savannah bugs #19605 and #19617.
-
- * find/find.c (process_path): collect the stat information for
- directories even if we already have the mode information, because
- we need to use the members st_nlink and st_rdev in for the leaf
- optimisation and loop detection, respectively. This fixes
- Savannah bug #19616.
-
- * find/ftsfind.c (is_fts_enabled): Return a copy of ftsoptions,
- not a copy of the (uninitialised) input argument. This fixes
- Savannah bug #19615.
-
- * find/ftsfind.c (consider_visiting): If fts_read() returned
- FTS_NS, then remember that the stat information is not valid, and
- therefore don't set state.have_type or state.have_stat. This
- fixes Savannah bug #19613.
-
- * find/testsuite/find.posix/sv-bug-91613.exp,
- * find/testsuite/find.posix/sv-bug-91613.xo: New test for Savannah
- bug 19613 (assertion failure on symbolic link loop).
-
- * find/testsuite/config/unix.exp: Correctly diagnose a test case
- which fails because find was expected to fail and instead
- succeeded.
- * find/testsuite/find.gnu/exec-many-rtn-failure.exp: The child
- process in this test should return non-zero, not zero. Therefore
- run "false" instead of "true".
-
-2007-04-15 James Youngman <jay@gnu.org>
-
- Release 4.3.3.
-
- * find/find.1: "-printf %b": blocks are 512 bytes. Fixes
- Savannah bug #19596.
-
- * doc/Makefile.am (regexprops.texi): Do not use $(RM) because many
- versions od make do not set it, and so it expands to nothing.
- This avoids suprious emission of the regexprops.texi file to stdout.
-
- * find/find.c (main, safely_chdir_lstat, safely_chdir_nofollow):
- Only use O_LARGEFILE if it is #defined (NetBSD-3.1 does not define
- it).
- * find/ftsfind.c (main): ditto
- * find/pred.c (pred_empty, prep_child_for_exec): ditto
-
-
- * import-gnulib.config: Update to gnuliv 2007-04-14.
-
- * lib/Makefile.am, import-gnulib.sh: Create lib/gnulib-version.c
- in import-gnulib.sh, not in lib/Makefile.
-
- * build-aux/Makefile.am: New file; distribute check-tstfiles.sh.
-
- * locate/Makefile.am: mkinstalldirs is now in build-aux.
-
- * doc/Makefile.am: We also need getdate.texi.
-
-2007-04-14 James Youngman <jay@gnu.org>
-
- * doc/.cvsignore: Ignore getdate.texi
-
- * find/defs.h: #include "buildcmd.h" near the top of the file, not
- in the middle.
-
- * all: Pass O_LARGEFILE when opening directories.
-
- * all: Changes to allow us to use the FTS_CWDFD mode of fts().
- These are quite extensive changes, and are detailed below.
-
- * find/defs.h (struct exec_val): New member dirfd, the directory
- in which the exec should take place.
- (is_fts_enabled): Tell the caller which flags are passed to
- fts_open().
- (get_start_dirfd): New function. Returns value of start_desc.
- (get_current_dirfd): New function. Returns the fd of the
- directory fts is currently traversing. If this is the current
- directory, AT_FDCWD is returned.
- (complete_pending_execdirs): takes a new argument, indicating
- where the exec is to take place. Ugh.
- (get_info): the file name is taken from state.rel_pathname, so
- we don't need it as a function argument.
- (enum DebugOption): Added DebugExec ("-D exec").
- (struct state): Added cwd_dir_fd, the directory we are examining
- with fts(). If fts() is not in use, this is AT_FDCWD. Also added
- execdirs_outstanding, which is a boolean which tells us if there
- are any not-yet-execed -execdir or -okdir actions (with +). This
- is not really used yet.
- * find/ftsfind.c (set_close_on_exec): New function.
- (get_current_dirfd): Return an fd open on the directory that fts()
- is currently examining.
- (left_dir): Signal that our previous ides of which dirctory fts is
- searching is now out of date.
- (inside_dir): Indicate which directory fts is now searching.
- (complete_execdirs_cb): Callback for run_in_dir() to complete
- pending execdirs in this directory.
- (show_outstanding_execdirs): Supports "-D exec"
- consider_visiting(): Do not allow building-up of pending execdirs,
- as a workaround to Savannah bug #18466.
- (ftsoptions): Make this a static module variable.
- * find/parser.c (insert_exec_ok): New parameter describing which
- directory the exec should occur in.
- (parse_version): for FTS, add a list of options being used.
- * find/pred.c (pred_and, pred_comma): No need to pass the relative
- path name to get_info(), it can pull it from state.rel_pathname.
- (pred_delete): use unlinkat().
- (pred_empty): use openat().
- (new_impl_pred_exec): Accept an fd parameter describing where the
- exec is to take place.
- (pred_executable, pred_writable, pred_readable): Use run_in_dir()
- to ensure that access() is called in a working directory which is
- suitable for the pathname we pass in.
- (prep_child_for_exec): In the child process, change to the
- appropriate directory becore the exec().
- * find/util.c (debugassoc): Support "-D exec".
- (get_info): No longer need to pass the relative path to
- get_statinfo().
- (do_complete_pending_execdirs): Refactored body of what used to be
- complete_pending_execdirs().
- (complete_pending_execdirs): Pull body out into
- do_complete_pending_execdirs() and call that only if there is work
- to do.
- (fallback_stat, optionh_stat, optionp_stat, optionl_stat): Use fstatat().
- (get_start_dirfd): New access function for starting_desc.
- * find/testsuite/find.gnu/execdir-hier.exp: New test
- * find/testsuite/find.gnu/execdir-hier.xo: Expected outut for new test
- * lib/dircallback.c, lib/dircallback.h: New function,
- run_in_dir(), which runs a callback function in a specified
- directory.
- * lib/listfile.c: Use run_in_dir() to call readlink() in the right
- directory.
- (get_link_name_at): Call get_link_name_cb via run_in_dir.
- (get_link_name_cb): New callback function, wrappting
- get_link_name().
-
- * find/testsuite/find.gnu/execdir-pwd.exp: Since we have disabled
- thebuilding-up of command lines for -execdir, Savannah bug #18466
- has been neutralised (but not fixed - we just don't allow the
- problem circumstance to occur).
-
-2007-04-09 James Youngman <jay@gnu.org>
-
- * doc/find.texi: Change fully-specified @node directives to
- single-argument @node directives in order to accomodate the
- inclusion of getdate.texi.
-
- * doc/find.texi: Document -newerXY.
-
- * doc/find.texi (Security Considerations): updated to describe
- differences in the fts-based implementation.
-
- * find/find.1: Indicate that testing the birth time where this is
- not supported produces a negative result for files where the birth
- time is not known (or a fatal error if the file of interest is a
- reference file).
-
-2007-04-08 James Youngman <jay@gnu.org>
-
- * configure.in: Set @AUXDIR@ (to the location of the build-aux
- directory).
- * build-aux/check-testfiles.sh: New script, which checks that all
- the DejaGnu test files have been included in the distribution and
- (more helpfully) lists any that are missing.
- * Makefile.am (findutils-check-testfiles): Use
- build-aux/check-testfiles.sh.
- * locate/testsuite/Makefile.am (EXTRA_DIST_EXP): distribute
- locate/testsuite/locate.gnu/sv-bug-14535.exp.
-
- * config.rpath, depcomp, missing: Moved into build-aux/.
- * configure.in(AC_CONFIG_AUX_DIR): Find aux files in $SRCDIR/build-aux,
- not in $SRCDIR.
-
-2007-03-31 James Youngman <jay@gnu.org>
-
- * find/tree.c (build_expression_tree): Issue more specific error
- messages; distinguish the case where the predicate is invalid from
- the cases where a required argument is missing, and a supplied
- argument is invalid.
-
- * import-gnulib.config (gnulib_version): Update to 2007-03-30
- version of gnulib.
-
-2007-03-28 James Youngman <jay@gnu.org>
-
- * find/defs.h (set_stat_placeholders): utility function for
- initialising the sturct stat fields that NetBSD doesn't always set
- (like st_birthtime where the file is on a filesystem not
- supporting birthtime).
- * find/util.c: set_stat_placeholders(): new function
- (get_statinfo): Call set_stat_placeholders().
- (optionh_stat, optionl_stat, optionp_stat): ditto
- * find/find.c (main, wd_sanity_check, safely_chdir_lstat,
- process_dir): use set_stat_placeholders().
- * find/parser.c (parse_anewer, parse_cnewer, parse_newer,
- parse_newerXY): ditto.
- (get_stat_Ytime): Support birth time ('B').
- (parse_newerXY): Support st_birthtime.
- * find/fstype.c (set_fstype_devno): Use set_stat_placeholders().
- * find/pred.c (pred_xtype): Use set_stat_placeholders().
- (pred_newerXY): Support birth time.
- (pred_fprintf, format_date): ditto ("%Bx").
-
-2007-03-25 James Youngman <jay@gnu.org>
-
- * xargs/xargs.c (main): For "xargs --show-limits" where stdin is a
- terminal, warn the user that the program specified (or /bin/echo)
- will be run at least once, if that is what will happen.
-
-2007-03-24 James Youngman <jay@gnu.org>
-
- * import-gnulib.sh: Added option -d, allowing the user to use a
- local version of gnulib, perhaps because they have local changes.
-
-2007-03-13 James Youngman <jay@gnu.org>
-
- * find/parser.c (parse_quit): Estimated success rate of -quit is
- 100%.
-
-2007-03-08 James Youngman <jay@gnu.org>
-
- * find/find.1 (TESTS): Document -newerXY, indicate that reference
- files are only examined once.
- (HISTORY): Indicate when various features were added
- (BUGS): Indicate that -ok ignores LC_COLLATE.
-
-2007-03-07 James Youngman <jay@gnu.org>
-
- * import-gnulib.config: (gnulib_version): Use gnulib version
- 2007-03-05
- (modules): Added getdate
-
- * find/Makefile.am (LDADD): Added @LIB_CLOCK_GETTIME@ for
- clock_gettime(), if it is available.
-
- * find/defs.h: (enum xval): New enumeration, representing the
- value of X used in the -newerXY test. It is stored in the reftime
- member of 'union args'.
- (struct predicate): reftime is also used by -newerXY.
- (enum arg_type): Added ARG_SPECIAL_PARSE for -newerXY, because the
- parsing function needs to look at the name of the test.
- (struct options): start_time is now a struct timespec, not a
- time_t.
-
- * find/parser.c: (parse_newerXY): New parsing function for
- -newerXY, a feature copied from FreeBSD (also present other BSD
- implementations too)
- (get_stat_Ytime): New function; returns st_atime, st_mtime or
- st_ctime from struct stat, as a timespec, as required according to
- the value of Y in -newerXY.
- (found_parser): Factored the tail out of find_parser.
- (find_parser): Moved tail into found_parser. Add special handling
- for -newerXY.
- (do_parse_xmin): New argument xv, indicating the value to which
- predicate->reftime.xval should be set.
- (parse_amin): Pass XVAL_ATIME to do_parse_xmin.
- (parse_cmin): Pass XVAL_CTIME to do_parse_xmin.
- (parse_mmin): Pass XVAL_MTIME to do_parse_xmin.
- (parse_newer): Set args.reftime.xval to XVAL_MTIME.
-
- * find/pred.c (pred_table): added pred_XY.
- (pred_fls): options.start_time is now a struct timespec, so just
- pass the tv_sec member to list_file.
- (pred_ls): ditto
- (pred_newerXY): New function, implementing -newerXY.
-
- * find/tree.c (costlookup): pred_newerXY needs stat information.
- (build_expression_tree): For predicates of type ARG_SPECIAL_PARSE,
- pass them in the name of the predicate (that is, don't advance
- argc).
-
- * find/util.c (now): New function for setting options.start_time.
- Use nanoseconds where it is available.
- (set_option_defaults): Use now() rather than time().
-
-2007-03-03 James Youngman <jay@gnu.org>
-
- * import-gnulib.sh: Pass --with-tests to gnulib-tool so that relevant
- gnulib unit tests are built and are run for "make check".
-
- * configure.in (AC_CONFIG_FILES): Add tests/Makefile (the makefile
- for the gnulib unit tests).
-
- * Makefile.am: Add 'tests' to SUBDIRS.
-
- * .cvsignore: Add 'tests'.
-
- * import-gnulib.config (modules): Also use Gnulib modules
- mbscasestr and mbsstr in order to perform correct string searching
- in multibyte strings, in order to fix Savannah bug #14535.
-
- * locate/testsuite/locate.gnu/sv-bug-14535.exp: new test case for
- Savannah bug #14535.
-
- * locale/locate.c (visit_substring_match_nocasefold): Use mbsstr
- rather than strstr, in order to correctly support multibyte
- strings.
- (visit_substring_match_casefold): Use mbscasestr rather than
- strstr in order to correctly support case-folding in a multibyte
- environment (e.g. with UTF-8 characters outside the normal ASCII
- range). This fixes Savannah bug #14535.
- (struct casefolder): No longer needed, removed
- (visit_casefold): No longer needed, removed.
- (lc_strcpy): No longer needed, removed.
- (search_one_database): Removed redundant variable need_fold and
- the code which used to set it. It had controlled the adding of
- the visitor function visit_casefold, but that function itself is
- no longer required. Also there is now no need to pass in a
- lower-case argument to visit_substring_match_casefold, so don't
- pass that in the context argument.
-
- * locate/locate.c (usage): Fixed typo.
-
-2007-03-01 James Youngman <jay@gnu.org>
-
- * doc/find.texi (Multiple Files): Document the construct
- -exec sh -c 'cmd "$@" final-args' {} + - fixing Savannah bug
- #18554.
-
-2007-02-28 James Youngman <jay@gnu.org>
-
- * import-gnulib.config: New file. Specifies which version of
- Gnulib we need to check out and build from.
-
- * import-gnulib.sh: Use import-gnulib.config.
-
- * README-CVS: Describe the new method of building from CVS.
-
- * lib/gnulib-version.h, lib/gnulib-version.sh: New files; code for
- reporting which version of Gnulib we built findutils from.
-
- * lib/Makefile.am: Build gnulib-version.c out of
- ./gnulib-version.config by using lib/gnulib-version.sh.
-
- * Makefile.am: Ship import-gnulib.config and import-gnulib.sh.
-
- * .cvsignore: Ignore gnulib-cvs
-
- * lib/.cvsignore: Ignore gnulib-version.c
-
- * find/parser.c, locate/code.c, locate/locate.c, xargs/xargs.c:
- Report which version of Gnulib we were built from.
-
-2007-02-25 James Youngman <jay@gnu.org>
-
- * find/find.c (process_dir): Removed duplicated (shadow)
- declaration of did_stat. Assert that we did not use subdirs_left
- if subdirs_unreliable is true.
-
- * find/parser.c (parse_size): Removed unused variable rate.
- (parse_time): Removed unused variable num_days_approx.
- (get_num): Removed unused variables ok and suffixes.
-
- * find/pred.c (do_fprintf): Indicate that the function needs a
- return value (referring to Savannah bug #19146).
-
- * find/tree.c (predlist_dump): Commented out unused function
- (predlist_merge_nosort): Commented out unused function
- (getrate): Returns type is float, so return 1.0f not 1.0.
- (calculate_derived_rates): Removed unused variable rate. Use a
- switch statement rater than ifs.
-
- * find/util.c (usage): Removed unused variable i.
-
- * lib/buildcmd.c (bc_do_insert): Removed unused variable
- need_prefix.
- (bc_init_controlinfo): annotate a line (with #warning) which is
- probably a bug.
-
- * locate/locate.c: #include <grp.h> for the benefit of the
- setgroups() call in drop_privs.
- (slocate_db_pathname): Commented out unused variable.
- (set_max_db_age): error command has no format directive, so
- remove the unused extra argument.
- (looking_at_slocate_db): Removed unused variables magic and
- lenwanted. Fix bug where result is indeterminate (due to falling
- off the end of the function) if the first character is a nondigit.
- (search_one_database): Eliminate (spurious) compiler warning
- rlating to possible use before initialisation of slocate_seclevel.
-
- * xargs/xargs.c (get_char_oct_or_hex_escape): Eliminate spurious
- compiler warning on variable p.
- (main): Removed unused varible env_too_big
-
-
-2007-02-24 James Youngman <jay@gnu.org>
-
- * find/parser.c (pred_sanity_check): define this function even for
- _NDEBUG, but do nothing in that case.
- (estimate_timestamp_success_rate): correct (invert) the sense of
- the subtraction used to find the file's age.
-
- * import-gnulib.sh (findutils_modules): Import Gnulib modules
- xstrtod and timespec.
-
- * find/parser.c (get_comp_type): Refactored out of get_num.
- (get_num): call get_comp_type to find the comparison type.
- (get_relative_timestamp): new function replacing get_num_days.
- (get_num_days): Remove.
- (do_parse_xmin): Support fractional arguments and
- nanosecond timestamps.
- (parse_used): ditto
- (parse_time): ditto
-
- * xargs/xargs.c (read_line): Give a warning message if a NUL is
- found in the input (this function is called only when -0 is not in
- effect).
-
- * xargs/xargs.c (nullwarning_given): New variable indicating if
- the NULL character warning had already been issued.
-
- * doc/find.texi (Multiple Files): Describe how trailing blanks are
- handled when -L is in effect.
-
- * xargs/xargs.c (read_line): Use an enum rather than
- preprocessor macro values for the lexer state.
-
- * lib/savedirinfo.c (free_dirinfo): Fixed memory leak (trivial
- patch from Supriya Kannery)
-
-2007-01-22 James Youngman <jay@gnu.org>
-
- * .cvsignore (install-sh): Ignore, since the install-sh file is no
- longer held in the findutils CVS repository.
-
- * find/testsuite/config/unix.exp (find_start): allow a test to be
- skipped for either the old or the new find executable.
- * find/testsuite/find.gnu/execdir-pwd.exp,
- find/testsuite/Makefile.am:
- New test, covering Savannah bug #18466. This test currently fails
- for the ftsfind binary and passes for the oldfind binary. Due to
- a limitation in the way that we perform the test, we can't tell
- the test suite to expect a failure in the new binary but not the
- old. Therefore we skip the test for the old binary.
-
- * lib/regeprops.c (describe_regex_syntax): fixed a typo in the text
- * doc/find.texi (Multiple Files): fixed a typo
-
-2007-01-16 James Youngman <jay@gnu.org>
-
- (ctime_format): format the time manually (rather than using ctime)
- in order to include the sub-second part of the time.
- (weekdays, months): new static variables used by ctime_format.
- (format_date): append a the sub-second part of the timestamp to
- the seconds part of date/time output.
-
-2007-01-15 James Youngman <jay@gnu.org>
-
- * find/defs.h (time_val): define struct; use timespec to hold time
- in the 'reftime' member.
- (args): use struct timespec instead of time_t for predicates
- -newer, -anewer, -cnewer. * find/parser.c (includes): include
- stat-time.h.
- (parse_anewer, parse_cnewer, parse_newer): use struct timespec to
- hold timestamps. * find/pred.c (compare_ts): new function for
- comparing timestamps in struct timespec.
- (pred_anewer, pred_cnewer, pred_newer): use compare_ts() to
- compare timestamps (hence takinng acoung of sub-second
- granularity).
- * find/ftsfind.c: Various improvements to comments.
- (is_fts_enabled): Newline before function name to comply with GNU
- coding standard.
-
-2007-01-13 James Youngman <jay@gnu.org>
-
- * lib/regexprops.c (describe_regex_syntax): fixed typo
-
- * xargs/xargs.c (read_line): Fixed Savannah bug# 18714; VT and FF
- are not separators, according to POSIX (in the POSIX locale).
-
- * xargs/testsuite/Makefile.am,
- xargs/testsuite/input/formfeeds.xi,
- xargs/testsuite/input/verticaltabs.xi,
- xargs/testsuite/xargs.posix/sv-bug-18714.exp,
- xargs/testsuite/xargs.posix/sv-bug-18714.xo,
- xargs/testsuite/xargs.posix/sv-bug-18714b.exp,
- xargs/testsuite/xargs.posix/sv-bug-18714b.xo: Tests for Savannah
- bug #18714.
-
- * xargs/xargs.c (usage): Removed suprious "[" in --help output
- (fixes Savannah bug #18384).
-
- * locate/locate.c: Implement the option --max-database-age.
- (main) Accept the option.
- (set_max_db_age): Parse the argument.
-
- * locate/locate.c (dolocate): If the database is more than N days
- old, indicate its actual age in the warning message we produce.
-
- * locate/locate.1, docs/find.texi: Document --max-database-age
-
- * THANKS: Thank Dean Gaudet for the idea of -sparse.
-
- * po/findutils.pot: Updated from Translation Project
-
- * po/ga.po, po/pl.po, po/nl.po, po/tr.po, po/hu.po: Updated from
- the Translation Project
-
-2007-01-09 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
-
- * doc/find.texi: Fix some typos. (trivial change)
-
-2007-01-07 James Youngman <jay@gnu.org>
-
- * find/parser.c (parse_perm), find/testsuite/find.gnu/perm000.exp,
- find/testsuite/find.gnu/perm000.xo: -perm /000 is now quivalent
- to -perm -000, as dscussed in Savannah bug #14748. The warning
- message we issue when the user does this now explains that the
- defintion changed as we promised it would in 2005.
-
- * xargs/xargs.c (read_line): Correctly handle quoted empty
- arguments occurring first or last on a line (by adding an empty
- argument to the output). Fixes Savannah bug #18713.
-
- * xargs/testsuite/xargs.sysv/sv-bug-18713.exp,
- xargs/testsuite/xargs.sysv/sv-bug-18713.xo,
- xargs/testsuite/input/empty.xi: Test case for Savannah bug #18713.
-
-
-2006-12-29 James Youngman <jay@gnu.org>
-
- * find/testsuite/config/unix.exp:
- Verify that find_start is invoked with wither a p (pass) or an f
- (fail) argument.
-
- * lib/listfile.c, lib/listfile.h:
- define find_blocksize() and provide a declaration for get_link_name()
-
- * find/testsuite/config/unix.exp: Updated copyright years.
-
- * find/testsuite/find.gnu/execdir-one.exp, find/testsuite/find.gnu/execdir-root-only.exp, find/testsuite/find.gnu/sv-bug-12230.exp, find/testsuite/find.gnu/sv-bug-17782.exp, find/testsuite/config/unix.exp:
- Avoid tests using -execdir if $PATH contains a relative directory
-
- * find/parser.c:
- Also flag $PATH values containing relative directories as being dangerous.
-
- * find/parser.c, find/defs.h, find/util.c:
- Instead of selecting the old or new exec handling code with the NEW_EXEC macro, just use the new code all the time
-
- * locate/testsuite/config/unix.exp:
- Fixed Savannah bug #13252, test suite failure caused by the fact that 'file normalize' is not available in Tcl 8.3
-
- * NEWS, find/pred.c:
- Fixed Savannah bug #18433, compilation failure with configure --enable-debug
-
-2006-12-28 James Youngman <jay@gnu.org>
-
- * NEWS: Document addition of %S.
-
- * find/defs.h, find/find.1, find/parser.c, find/pred.c:
- Implemented %S (sparseness) printf format, and general refactoring and cleanup of printf predicate
-
-2006-12-01 James Youngman <jay@gnu.org>
-
- * NEWS, configure.in: Begin work on findutils 4.2.30
-
- * find/find.c:
- Fix compilation error for oldfind if --enable-debug was passed to configure
-
- * NEWS, configure.in: Prepare for work on findutils-4.3.3
-
-2006-11-25 James Youngman <jay@gnu.org>
-
- Release 4.3.2.
-
- * find/testsuite/Makefile.am: Added test case for Savannah bug #17782
-
- * doc/textinfo.tex: Removed; we now use the version supplied
- by automake.
-
- * m4/mkinstalldirs.m4: Added this file. It's an excerpt from an
- old version of gnulib's m4/nls.po file. The current version of
- gnulib does not expand MKINSTALLDIRS, but gettext-0.14.6's version
- of po/Makefile.in.in expects it to be expanded. This m4 file
- fills the gap.
-
-2006-11-20 James Youngman <jay@gnu.org>
-
- * po/et.po, po/bg.po, po/pl.po, po/nl.po, po/tr.po: Updated
- translations for Bulgarian, Estonian, Dutch, Polish and Turkish.
-
-2006-11-08 James Youngman <jay@gnu.org>
-
- * find/testsuite/Makefile.am:
- Oops, indicate the right directory for the new test files
-
- * ChangeLog, depcomp, doc/texinfo.tex, find/ftsfind.c, find/testsuite/Makefile.am, find/testsuite/find.gnu/sv-bug-18222.exp, find/testsuite/find.gnu/sv-bug-18222.xo, install-sh:
- Savannah bug#18222 - test case
-
- * ChangeLog, lib/buildcmd.c:
- Fixed Svannah bug #17782 ('./' prefix added at start of arg while it should be added at the start of the expansion of {})
-
- * find/ftsfind.c (process_all_startpoints): Set
- state.starting_path_length for every pathname argument.
- This fixes Savannah bug #18222.
-
- * find/pred.c (pred_prune): -prune should have an effect only if we are
- currently considering a directory (Savannah bug #15531).
-
-2006-10-15 James Youngman <jay@gnu.org>
-
- * lib/buildcmd.c: Fixed Savannah bug #17782, in which "find
- -execdir echo "foo {}" runs 'echo ./foo filename' instead of the
- correct command 'echo foo ./filename'.
-
- * po/hu.po, po/sl.po: Updated Hungarian and Slovenian po files
-
-2006-08-21 James Youngman <jay@gnu.org>
-
- * find/parser.c, find/testsuite/Makefile.am, find/testsuite/find.gnu/sv-bug-17490.exp:
- Fixed Savannah bug #17490, which was a coiredump when -regex ZZZ was the final test on the command line
-
-2006-08-20 James Youngman <jay@gnu.org>
-
- * find/parser.c: Merged the fix for the trailing % in "find -printf".
-
-2006-08-20 Paul Eggert <eggert@cs.ucla.edu>
-
- Port recent fixes for symbolic modes involving X from gnulib,
- and clarify the documentation in this area.
- * doc/find.texi: Use "file mode bits" when talking about
- all the file mode bits (including setuid, setgid, and sticky),
- and "permissions" when talking only about permissions bits
- (read, write, execute/search). Use "execute/search" to
- talk about the x bit, since it means both. You do not need
- permission to the linked-to file to follow a symlink for
- syscalls like "stat", but you do need search permission for
- the directories you traverse. Clarify the explanation of
- -perm. Use "that" instead of "which" when "which" isn't
- quite correct English.
- (Mode Bits): Renamed from Permissions. All uses changed.
- * doc/perm.texi: Sync from coreutils 6.0.
- * find/defs.h (struct perm_val.val): Now an array of two items,
- one for non-directories, and one for directories. This is
- to handle symbolic modes like +X correctly.
- * find/parser.c (parse_perm): Likewise. Also, adjust to
- latest gnulib interface for mode_adjust.
- * find/pred.c (pred_perm): Likewise.
- * find/testsuite/Makefile.am (EXTRA_DIST_XO): Add find.posix/perm-X.xo.
- (EXTRA_DIST_EXP): Add find.posix/perm-X.exp.
- * find/testsuite/find.posix/perm-X.exp: New file.
- * find/testsuite/find.posix/perm-X.so: New file.
-
-2006-08-19 Paul Eggert <eggert@cs.ucla.edu>
-
- Port to latest gnulib, and simplify the bootstrapping procedure.
- * intl: Remove this directory and everything in it.
- * depcomp, install-sh, missing, mkinstalldirs, doc/texinfo.tex:
- Remove these files from CVS, as they are now gotten from gnulib.
- * README-CVS: Don't recommend "autoreconf -i", as it doesn't work
- for us.
- * import-gnulib.sh (findutils_files): New var. Grab this stuff
- from gnulib.
- (findutils_modules): Add fopen-safer; remove stdio-safer. This
- adjusts to latest gnulib.
- (modules): Remove obsolete reference to intl_modules.
- * .cvsignore: Remove stamp-h; add stamp-h1.
- * doc/.cvsignore: Add regexprops.texi.
- * find/.cvsignore: Add oldfind.
- * lib/.cvsignore: Add .deps, regexprops.
- * m4/.cvsignore: Add Makefile.
- * po/.cvsignore: Add stamp-po.
-
-2006-08-19 James Youngman <jay@gnu.org>
-
- * locate/testsuite/config/unix.exp, locate/testsuite/locate.gnu/bigprefix1.exp:
- Explicit checks for parefixes which are within range of a short, but outside the one-byte range
-
- * locate/testsuite/locate.gnu/bigprefix1.exp, locate/testsuite/locate.gnu/exceedshort.exp, locate/testsuite/locate.gnu/space1st.exp:
- New file.
-
- * locate/testsuite/Makefile.am, locate/testsuite/locate.gnu/exceedshort.exp, locate/testsuite/locate.gnu/space1st.exp:
- Patch from Tavis Ormandy; check frcode handles initial space end encodes paths with more than 2^16 characters in the common prefix (trivial change)
-
- * locate/frcode.c: Changes to avoid overflows
-
-2006-08-11 James Youngman <jay@gnu.org>
-
- * locate/frcode.c:
- Avoid producing an invalid database if the first item begins with a space
-
-2006-08-10 James Youngman <jay@gnu.org>
-
- * find/pred.c, import-gnulib.sh, lib/listfile.c:
- Updated callers of the gnnulib filemode module so that they work with the 2006-07-09 version of gnulib
-
- * config.rpath: Updated config.rpath from autotools
-
-2006-08-08 James Youngman <jay@gnu.org>
-
- * locate/locatedb.h:
- Automatically verify (at compile time) that the frcode datastream
- cannot get desynchronised.
-
- * find/ftsfind.c:
- Fixed Savannah bug #10494 (-maxdepth does not yield the same stat savinf in ftsfind as oldfind)
-
- * find/ftsfind.c: display fts_level for find -D search
-
- * find/util.c: Support find -D search
-
- * locate/locate.c:
- If the user specified -E but the database is an slocate database, do
- not produce a list of files they cannot stat. Issue an error message
- explaining the problem.
-
- * locate/locate.c:
- Issue states messages in a way which indicates more clearly what's
- happening when the numbers are reduced because not every filename
- matched the pattern.
-
- * locate/locate.c: Better error checking in drop_privs().
-
-2006-08-07 James Youngman <jay@gnu.org>
-
- * NEWS, locate/locate.c, locate/locatedb.h:
- Added support for slocate database format
-
- * xargs/xargs.c:
- Removed unused code (tivial patch from Miloslav Trmac).
-
- * xargs/xargs.c: Removed unused code.
-
- * doc/find.texi:
- Clarify that the output format for locate -S differs from BSD's.
-
- * NEWS, find/find.1:
- Savannah bug #15360: explain global vs. positional options more clearly in the manual page
-
- * NEWS: Typo in subsection header (* should be **).
-
- * NEWS, find/find.1:
- Savannah bug #15360: explain global vs. positional options more clearly in the manual page
-
- * doc/find.texi: Fixed some clumsy phrasing
-
- * NEWS, configure.in:
- Now diverging again from the released tarball, so change once more to -CVS version number suffixes
-
-2006-08-06 James Youngman <jay@gnu.org>
-
- * locate/locate.c: Fixed a typo in a comment.
-
- * NEWS, configure.in: Moving on towards 4.3.2...
-
- Release 4.3.1.
-
- * find/testsuite/config/unix.exp:
- Check that we can see the find.o file in the right position relative
- to $base_dir to ensure that we are indeed testing the program we just built.
-
- * find/testsuite/config/unix.exp:
- Be more paranoid about whether we're really checking the right version
- of find.
-
- * NEWS, configure.in: Prepare for release of 4.3.1
-
- * doc/find.texi: Document the -O and -D options
-
- * find/defs.h, find/find.1, find/util.c:
- 'find -D help' now explains the available debugging options
-
- * po/be.po, po/bg.po, po/ca.po, po/da.po, po/de.po, po/el.po, po/eo.po, po/es.po, po/et.po, po/fi.po, po/findutils.pot, po/fr.po, po/ga.po, po/gl.po, po/hr.po, po/hu.po, po/id.po, po/it.po, po/ja.po, po/ko.po, po/lg.po, po/ms.po, po/nl.po, po/pl.po, po/pt.po, po/pt_BR.po, po/ro.po, po/ru.po, po/rw.po, po/sk.po, po/sl.po, po/sr.po, po/sv.po, po/tr.po, po/vi.po, po/zh_CN.po, po/zh_TW.po:
- Make dist changed all the po files again
-
-2006-08-05 James Youngman <jay@gnu.org>
-
- * NEWS: Described more changes in 4.3.1.
-
- * locate/testsuite/config/unix.exp:
- Set the environment variable so that updatedb knows where to find it; it's not in BINDIR yet during 'make check'
-
- * po/be.po, po/bg.po, po/ca.po, po/da.po, po/de.po, po/el.po, po/eo.po, po/es.po, po/et.po, po/fi.po, po/findutils.pot, po/fr.po, po/ga.po, po/gl.po, po/hr.po, po/hu.po, po/id.po, po/it.po, po/ja.po, po/ko.po, po/lg.po, po/ms.po, po/nl.po, po/pl.po, po/pt.po, po/pt_BR.po, po/ro.po, po/ru.po, po/rw.po, po/sk.po, po/sl.po, po/sr.po, po/sv.po, po/tr.po, po/vi.po, po/zh_CN.po, po/zh_TW.po:
- Make dist changed all the po files again :)
-
- * po/et.po, po/vi.po: UPdated the Estonian and Vietnamese translations
-
- * NEWS, configure.in: Prepare for release of findutils-4.2.28
-
- * po/sv.po, po/tr.po, po/vi.po, po/zh_CN.po, po/zh_TW.po, po/be.po, po/bg.po, po/ca.po, po/da.po, po/de.po, po/el.po, po/eo.po, po/es.po, po/et.po, po/fi.po, po/findutils.pot, po/fr.po, po/ga.po, po/gl.po, po/hr.po, po/hu.po, po/id.po, po/it.po, po/ja.po, po/ko.po, po/lg.po, po/ms.po, po/nl.po, po/pl.po, po/pt.po, po/pt_BR.po, po/ro.po, po/ru.po, po/rw.po, po/sk.po, po/sl.po, po/sr.po:
- Make dist changed all the po files again :)
-
- * configure.in: Added Bulgarian translation.
-
- * po/bg.po: Include Bulgarian translation
-
- * configure.in: Added Bulgarian translation.
-
- * po/et.po, po/vi.po: Updated Estonian and Vietnamese translations
-
- * NEWS: Removed spurious comma.
-
- * NEWS: Listed the updated translations.
-
- * find/parser.c, lib/buildcmd.c, lib/buildcmd.h, xargs/xargs.c:
- Fixed Savannah bug#16738, find does not subtract environment size in find .. -exec {} +
-
- * NEWS: Updated the list of bugfixes etc.
-
-2006-06-15 James Youngman <jay@gnu.org>
-
- * NEWS: Described recent changes
-
- * configure.in: fix to how we invoke the gnulib regex module
-
- * find/find.1:
- Savannah bug #16269: avoid confusion over what type of quotes to use
- in an example.
-
- * find/parser.c: Option -nowarn should not itself produce a warning
-
- * find/defs.h: Remoevd useless declaration of last_pred
-
-2006-06-14 James Youngman <jay@gnu.org>
-
- * po/be.po, po/ca.po, po/da.po, po/de.po, po/el.po, po/eo.po, po/es.po, po/et.po, po/fi.po, po/findutils.pot, po/fr.po, po/ga.po, po/gl.po, po/hr.po, po/hu.po, po/id.po, po/it.po, po/ja.po, po/ko.po, po/lg.po, po/ms.po, po/nl.po, po/pl.po, po/pt.po, po/pt_BR.po, po/ro.po, po/ru.po, po/rw.po, po/sk.po, po/sl.po, po/sr.po, po/sv.po, po/tr.po, po/vi.po, po/zh_CN.po, po/zh_TW.po:
- Updated translation files ga pl sv tr nl ca vi bg fr
-
- * locate/updatedb.sh:
- Fixed Savannah bug #16579 (su false should be su -c false)
-
-2006-04-01 James Youngman <jay@gnu.org>
-
- * find/find.c:
- Fixed Savannah bug #15800: "Hard link count is wrong" reports wrong
- directory name.
-
-2006-03-31 James Youngman <jay@gnu.org>
-
- * po/hu.po: Updated Hungarian translation
-
-2006-01-04 James Youngman <jay@gnu.org>
-
- * find/testsuite/find.posix/sizetype.exp, find/testsuite/find.posix/sizetype.xo, find/testsuite/find.posix/typesize.exp, find/testsuite/find.posix/typesize.xo:
- Additional tests for -type -size and -size -type
-
- * NEWS, doc/find.texi, find/defs.h, find/find.1, find/find.c, find/ftsfind.c, find/parser.c, find/pred.c, find/testsuite/Makefile.am, find/testsuite/config/unix.exp, find/testsuite/find.gnu/depth-d.exp, find/tree.c, find/util.c, po/be.po, po/ca.po, po/da.po, po/de.po, po/el.po, po/eo.po, po/es.po, po/et.po, po/fi.po, po/findutils.pot, po/fr.po, po/ga.po, po/gl.po, po/hr.po, po/hu.po, po/id.po, po/it.po, po/ja.po, po/ko.po, po/lg.po, po/ms.po, po/nl.po, po/pl.po, po/pt.po, po/pt_BR.po, po/ro.po, po/ru.po, po/rw.po, po/sk.po, po/sl.po, po/sr.po, po/sv.po, po/tr.po, po/vi.po, po/zh_CN.po, po/zh_TW.po:
- Initial implementation of a cost-based optimiser
-
-2005-12-23 James Youngman <jay@gnu.org>
-
- * find/parser.c: Refactor of parse_[acm]time
-
- * find/defs.h, find/find.c, find/finddata.c, find/ftsfind.c, find/tree.c, find/util.c:
- last_pred can be a static in tree.c rather than a global variable
-
- * find/tree.c, find/finddata.c:
- Moved some global data out of finddata.o and into static variables in tree.c
-
- * NEWS, find/find.c, find/fstype.c, find/ftsfind.c, find/parser.c, find/pred.c, lib/buildcmd.c, lib/buildcmd.h, lib/regexprops.c, lib/regextype.c, lib/regextype.h, lib/savedirinfo.c, locate/locate.c, xargs/xargs.c:
- Fixed many compilation warnings
-
- * find/find.c, find/ftsfind.c, find/util.c:
- Evaluating the predicates can change the contents of the data structure (for example to add another exec item)
-
- * find/defs.h, find/find.c, find/ftsfind.c, find/tree.c, find/util.c:
- Re-factored a lot of common expression-handling code out of find.c and ftsfind.c, mainly into tree.c
-
- * find/find.c, find/ftsfind.c, find/tree.c:
- Savannah bug #15271: more helpful error messages for cases where there is a missing expression
-
-2005-12-20 James Youngman <jay@gnu.org>
-
- * NEWS, doc/find.texi, find/defs.h, find/find.1, find/find.c, find/ftsfind.c, find/testsuite/Makefile.am, find/testsuite/find.posix/sv-bug-15235.exp, find/testsuite/find.posix/sv-bug-15235.xo, find/tree.c, find/util.c:
- Savannah bug #15195: more helpful error messages for 'find . ( )' or 'find . \!'
-
- * ChangeLog: Added entries for recent changes.
-
- * find/defs.h, find/find.c, find/ftsfind.c, find/testsuite/find.posix/bracket-depth.exp, find/util.c:
- Further fix to bug# 15235: a leading comma is a filename not an expression
-
- * find/defs.h, find/parser.c, find/testsuite/Makefile.am, find/testsuite/find.posix/empty-parens.exp, find/tree.c:
- Accept 'find ( -depth )' but reject 'find ( )'
-
- * po/be.po, po/ca.po, po/da.po, po/de.po, po/el.po, po/eo.po, po/es.po, po/et.po, po/fi.po, po/findutils.pot, po/fr.po, po/ga.po, po/gl.po, po/hr.po, po/hu.po, po/id.po, po/it.po, po/ja.po, po/ko.po, po/lg.po, po/ms.po, po/nl.po, po/pl.po, po/pt.po, po/pt_BR.po, po/ro.po, po/ru.po, po/rw.po, po/sk.po, po/sl.po, po/sr.po, po/sv.po, po/tr.po, po/vi.po, po/zh_CN.po, po/zh_TW.po:
- did make dist
-
- * find/testsuite/find.gnu/delete.exp:
- Use the new find program, and the new way of locating it (/ instead of )
-
- * find/testsuite/Makefile.am: Added bracket-depth.exp.
-
- * NEWS, configure.in: We have moved on from 4.3.0
-
- * find/defs.h, find/find.c, find/ftsfind.c, find/testsuite/Makefile.am, find/testsuite/find.gnu/delete.exp, find/testsuite/find.posix/files-not-expressions1.exp, find/testsuite/find.posix/files-not-expressions1.xo, find/testsuite/find.posix/files-not-expressions2.exp, find/testsuite/find.posix/files-not-expressions2.xo, find/testsuite/find.posix/files-not-expressions3.exp, find/testsuite/find.posix/files-not-expressions3.xo, find/util.c:
- Avoid getting confused by filename arguments of which the first
- character looks like a predicate, for example ',x' or '!x' or
- '(x' (Savannah bug #15235).
-
-2005-12-20 James Youngman <jay@gnu.org>
-
- * find/defs.h, find/find.c, find/ftsfind.c,
- find/testsuite/find.posix/bracket-depth.exp, find/util.c: Further
- fix to bug# 15235: a leading comma is a filename not an expression
-
- * find/defs.h, find/parser.c, find/testsuite/Makefile.am,
- find/testsuite/find.posix/empty-parens.exp, find/tree.c: Accept
- 'find ( -depth )' but reject 'find ( )'
-
- * find/testsuite/find.gnu/delete.exp: Use the new find program,
- and the new way of locating it ($OLDFIND/$FTSFIND instead of $FIND)
-
- * find/testsuite/Makefile.am: Added bracket-depth.exp.
-
- * NEWS, configure.in: We have moved on from 4.3.0
-
- * find/defs.h, find/find.c, find/ftsfind.c,
- find/testsuite/Makefile.am, find/testsuite/find.gnu/delete.exp,
- find/testsuite/find.posix/files-not-expressions1.exp,
- find/testsuite/find.posix/files-not-expressions1.xo,
- find/testsuite/find.posix/files-not-expressions2.exp,
- find/testsuite/find.posix/files-not-expressions2.xo,
- find/testsuite/find.posix/files-not-expressions3.exp,
- find/testsuite/find.posix/files-not-expressions3.xo, find/util.c:
- Avoid getting confused by filename arguments of which the first
- character looks like a predicate, for example ',x' or '!x' or '(x'
- (Savannah bug #15235).
-
-2005-12-19 James Youngman <jay@gnu.org>
-
- * find/testsuite/config/unix.exp:
- Run every test twice, once with the old (non-fts) binary and once with
- the new (fts-enabled) binary.
-
-2005-12-19 Eric Blake <ebb9@byu.net>
-
- * find/testsuite/Makefile.am,
- find/testsuite/find.posix/sv-bug-15235.xo,
- find/testsuite/find.posix/sv-bug-15235.exp: New tests for Savannah
- bug 15235.
-
- * NEWS, find/find.1, doc/find.texi (Invoking find): Document bug
- fix for Savannah bug 15235.
-
-2005-12-16 James Youngman <jay@gnu.org>
-
- * xargs/xargs.1, xargs/xargs.c: Fixed bug# 15211, that xargs
- --show-limits is not documented in the manpage or in the usage
- message
-
-2005-12-12 James Youngman <jay@gnu.org>
-
- Release 4.3.0.
-
- * find/testsuite/find.gnu/access.exp:
- Don't leave junk files lying around the place
-
- * README-CVS: Update the the instructions for getting gnulib; the
- CVS arrangements at Savannah have changed.
-
- * ChangeLog, NEWS, doc/find.texi, doc/perm.texi, find/defs.h, find/parser.c:
- Merged changes from 4.2.x branch again
-
- * NEWS, doc/find.texi, find/defs.h, find/find.c, find/ftsfind.c,
- find/parser.c, find/pred.c, find/util.c, lib/listfile.c,
- lib/listfile.h: Initial code to allow control over how -ls quote
- (or does not quote) control characters; not enabled yet
-
-2005-12-11 James Youngman <jay@gnu.org>
-
- * ChangeLog, THANKS, xargs/xargs.c:
- Fixed spelling errors in Bob Proulx's name. Sorry, Bob.
-
-2005-12-10 James Youngman <jay@gnu.org>
-
- * doc/perm.texi:
- Aaron Hawley: Updated perm.texi from the coreutils distribution
-
- * find/parser.c:
- Avoid using entries which have the same name as POSIX library
- functions (fprintf, printf, exec) as the implementation is allowed to
- #define these. That generates hard-to-grok compilation errors.
-
-2005-12-10 Andreas Metzler <gnu@downhill.at.eu.org>
-
- * ChangeLog, NEWS, configure.in, find/defs.h, find/parser.c:
- Applied patch from Andreas Metzler fixing Savannah bug #15181:
- implicit declaration of parse_openparen
-
-2005-12-08 James Youngman <jay@gnu.org>
-
- * doc/find.texi: Typo and spelling corrections from Aaron Hawley
-
-2005-12-05 James Youngman <jay@gnu.org>
-
- * Released findutils-4.2.27
-
-2005-12-05 James Youngman <jay@gnu.org>
-
- * doc/find.texi, find/find.1, locate/locate.1, xargs/xargs.1:
- Savannah patch #3775 from Aaron Hawley: reconciling man pages
- differences; did not apply the patch, but resolved all the
- remaining issues manually by updating the documentation (mostly
- the Texinfo documentation, which was missing a number of specific
- technical statements about the behaviour of various options)
-
-2005-12-04 James Youngman <jay@gnu.org>
-
- * doc/find.texi: Document --show-limits
-
- * xargs/xargs.c:
- Correctly display the size of the argument buffer we really allocated.
-
- * doc/find.texi, find/find.1, find/parser.c, find/pred.c, NEWS:
- Savannah bug #14748 (which this change does NOT fix): issue
- warning of future changes in the behaviour of -perm /000
-
-2005-11-30 James Youngman <jay@gnu.org>
-
- * xargs/xargs.c:
- Typo correction from Benno Schulenberg <benno@nietvergeten.nl>
- (trivial change)
-
-2005-11-29 James Youngman <jay@gnu.org>
-
- * xargs/xargs.c:
- Typo "Ilegal"; change to "Invalid" since this is not really illegal!
- Bug report by Primoz Peterlin.
-
- * lib/regexprops.c, xargs/xargs.c:
- Prefer the word 'Invalid' or the phrase 'not allowed' over
- 'Illegal', as per the GNU coding standards, and as per the
- suggestion from Benno Schulenberg
-
-2005-11-24 James Youngman <jay@gnu.org>
-
- * NEWS, lib/buildcmd.c, lib/buildcmd.h: Merge to trunk from 4.2.x fixes
-
- * lib/buildcmd.h:
- Deleted inaccurate comment about the default value of ctl->args_per_exec.
-
- * NEWS, lib/buildcmd.c, lib/buildcmd.h:
- Be more conservative about the total number of arguments we will
- allow (to avoid exec limits on Linux/PPC)
-
-2005-11-23 James Youngman <jay@gnu.org>
-
- * NEWS: Bug #14921 has been fixed.
-
- * find/fstype.c:
- Savannah bug #14921: when a Linux bind filesystem is in use, find
- would expand '-printf %F' to 'none' if a bind mount targetted the same
- filesystem as the one containing the file to be described.
-
- * NEWS: Updated to describe recent changes
-
- * doc/find.texi, find/find.1: Documented find -printf %M
-
- * lib/buildcmd.c, xargs/testsuite/Makefile.am,
- xargs/testsuite/xargs.posix/arg_max_32bit_linux_bug.exp,
- xargs/testsuite/xargs.posix/arg_max_32bit_linux_bug.xo,
- xargs/testsuite/xargs.posix/arg_max_64bit_linux_bug.exp,
- xargs/testsuite/xargs.posix/arg_max_64bit_linux_bug.xo:
- Ensure that the test suite still passes even if the current
- system's value of ARG_MAX is different from the development/test
- system
-
- * lib/buildcmd.c: reindent and untabify
-
- * configure.in: The CVS code is moving on from the previous release.
-
-2005-11-22 James Youngman <jay@gnu.org>
-
- * ChangeLog: Updated with recent changes.
-
-2005-11-21 James Youngman <jay@gnu.org>
-
- * locate/testsuite/config/unix.exp:
- Even if we expect locate to return a nonzero status, the test should
- still fail if updatedb fails!
-
- * locate/testsuite/locate.gnu/ignore_case2.exp:
- Set the current directory for updatedb. This test case is supposed to
- fail because the filename is not matched, not because updatedb fails!
-
- * locate/updatedb.sh:
- Check the binaries actually exist in the place we expect.
-
-2005-11-20 James Youngman <jay@gnu.org>
-
- * locate/locate.1, xargs/xargs.1: Escape '-' as '\-' where appropriate.
-
- * find/find.1:
- Escape '-' as '\-' where appropriate. Fixes last part of bug #14556.
-
-2005-11-19 James Youngman <jay@gnu.org>
-
- * doc/find.texi, find/find.1:
- Applied edited form of Andreas Metzler's -perm /mode documentation
- patch resolving Savannah bug #14619.
-
- * lib/extendbuf.c:
- In the success case, extendbuf() should preserve the previous value of
- errno. Fixes Savannah bug #14842.
-
- * xargs/testsuite/Makefile.am: Added new test files
-
- * find/find.1:
- Correctly indicate the default regular expression syntax (fixes
- Savannah bug #14836).
-
- * NEWS, configure.in: Released findutils-4.2.26
-
- * ChangeLog, NEWS, lib/buildcmd.c,
- xargs/testsuite/inputs/16383-ys.xi,
- xargs/testsuite/inputs/32767-ys.xi,
- xargs/testsuite/xargs.posix/arg_max_32bit_linux_bug.exp,
- xargs/testsuite/xargs.posix/arg_max_32bit_linux_bug.xo,
- xargs/testsuite/xargs.posix/arg_max_64bit_linux_bug.exp,
- xargs/testsuite/xargs.posix/arg_max_64bit_linux_bug.xo: Applied
- bugfix from Jim Meyering (tiny change), where many short arguments
- would cause xargs (and probably find -exec .. {} +) to fail
- because execve() returns E2BIG, which we should avoid
-
- * xargs/testsuite/inputs/16383-ys.xi,
- xargs/testsuite/inputs/32767-ys.xi,
- xargs/testsuite/xargs.posix/arg_max_32bit_linux_bug.exp,
- xargs/testsuite/xargs.posix/arg_max_32bit_linux_bug.xo,
- xargs/testsuite/xargs.posix/arg_max_64bit_linux_bug.exp,
- xargs/testsuite/xargs.posix/arg_max_64bit_linux_bug.xo: New file.
-
- * po/be.po, ca.po, da.po, de.po, el.po, eo.po, es.po, et.po, fi.po,
- findutils.pot, fr.po, ga.po, gl.po, hr.po, hu.po, id.po, it.po,
- ja.po, ko.po, lg.po, ms.po, nl.po, pl.po, pt.po, pt_BR.po, ro.po,
- ru.po, rw.po, sk.po, sl.po, sr.po, sv.po, tr.po, vi.po, zh_CN.po,
- zh_TW.po: Updated Portuguese .po file and did update-po
-
-2005-11-18 Jim Meyering <jim@meyering.net> (tiny change)
-
- * lib/buildcmd.c (bc_push_arg): When exec'ing, don't exceed
- Linux's limit on the maximum number of command line arguments.
-
-2005-11-11 James Youngman <jay@gnu.org>
-
- * NEWS, find/find.c, find/fstype.c: Savannah bug #14922: if we need the
- list of mounted filesystems but it is not available, exit fatally
- with a message. If it is not available but we don't need it,
- there is no need for an error.
-
- * po/ro.po, ru.po, rw.po, sk.po, sl.po, sr.po, sv.po, tr.po, vi.po,
- zh_CN.po, zh_TW.po, ko.po, lg.po, ms.po, nl.po, pl.po, pt.po,
- pt_BR.po, be.po, ca.po, da.po, de.po, el.po, eo.po, es.po, et.po,
- fi.po, findutils.pot, fr.po, ga.po, gl.po, hr.po, hu.po, id.po,
- it.po, ja.po: Updated Polish translation
-
-2005-10-31 James Youngman <jay@gnu.org>
-
- * doc/find.texi:
- Removed redundant additional description of "--regextype".
-
-2005-10-08 James Youngman <jay@gnu.org>
-
- * find/find.c, lib/regextype.c: Fixed Savannah bug #14616, which
- was that c99 code had crept in and it didn't compile on c89
- compilers
-
- * doc/find.texi: Savannah patch #4371 from Andreas Metzler; the
- argument of -I is mandatory
-
-2005-09-21 James Youngman <jay@gnu.org>
-
- * xargs/xargs.1, xargs/xargs.c: Clarified the -E option
-
-2005-09-20 James Youngman <jay@gnu.org>
-
- * NEWS, configure.in, doc/find.texi, xargs/xargs.1, xargs/xargs.c:
- Documentation clarification: -L and -I take a mandatory argument;
- -l and -i do not
-
-2005-09-17 James Youngman <jay@gnu.org>
-
- * xargs/xargs.c:
- Fixed Savannah bug #14550 - if environment is too large to allow
- exec() to work, we cannot even use "xargs --help".
-
- * find/find.1:
- Avoid the use of -perm +mode, using -perm /mode instead. From comment
- by Andreas Metzler (though I didn't read the patch).
-
- * ChangeLog, doc/find.texi, find/find.1, xargs/xargs.1:
- Typo fix from A Costa (tiny change)
-
- * NEWS: Corrections for find manual page - symbolic permissions.
-
- * find/find.1:
- Corrected an inaccuracy in the EXAMPLES section - in symbolic modes,
- 'o' stands for 'others' and 'u' stands for 'user' (i.e. the owner).
-
-2005-09-17 A Costa <agcosta@gis.net> (tiny change)
-
- docs/find.texi: Fixed typo
- find/find.1: Fixed typo
- xargs/xargs.1: Fixed typo
-
-2005-09-17 James Youngman <jay@gnu.org>
-
- * NEWS: Corrections for find manual page - symbolic permissions.
-
- * find/find.1:
- Corrected an inaccuracy in the EXAMPLES section - in symbolic modes,
- 'o' stands for 'others' and 'u' stands for 'user' (i.e. the owner).
-
-2005-09-06 James Youngman <jay@gnu.org>
-
- * xargs/xargs.c: Typo in "IEEE" in a comment.
-
-2005-09-04 James Youngman <jay@gnu.org>
-
- * find/defs.h, find/find.c, find/parser.c, find/pred.c,
- Work around compilation failure with GCC 4 and AIX 5.1, in which
- open is #defined to open64
-
- * po/be.po, ca.po, da.po, de.po, el.po, eo.po, es.po, et.po, fi.po,
- findutils.pot, fr.po, ga.po, gl.po, hr.po, hu.po, id.po, it.po,
- ja.po, ko.po, lg.po, ms.po, nl.po, pl.po, pt.po, pt_BR.po, ro.po,
- ru.po, rw.po, sk.po, sl.po, sr.po, sv.po, tr.po, vi.po, zh_CN.po,
- zh_TW.po: Work around compilation failure with GCC 4 and AIX 5.1,
- in which open is #defined to open64
-
-2005-09-03 James Youngman <jay@gnu.org>
-
- * find/testsuite/find.gnu/quit.exp: Fixed Savannah bug#14390, by
- avoiding an accidental assumption in quit.exp that directory
- entries are returned by readir() in any particular order
-
- * NEWS, configure.in, doc/find.texi, xargs/testsuite/Makefile.am,
- xargs/testsuite/inputs/helloworld.xi,
- xargs/testsuite/xargs.gnu/delim-o.exp,
- xargs/testsuite/xargs.gnu/delim-o.xo, xargs/xargs.1,
- xargs/xargs.c: Added the --delimiter option to xargs, resolving
- Savannah support request sr #102914
-
- * ChangeLog, NEWS, configure.in: Released findutils-4.2.25
-
- * po/sr.po, sv.po, tr.po, vi.po, zh_CN.po, zh_TW.po, sl.po, be.po,
- ca.po, da.po, de.po, el.po, eo.po, es.po, et.po, fi.po,
- findutils.pot, fr.po, ga.po, gl.po, hr.po, hu.po, id.po, it.po,
- ja.po, ko.po, lg.po, ms.po, nl.po, pl.po, pt.po, pt_BR.po, ro.po,
- ru.po, rw.po, sk.po: Did update-po
-
-2005-09-02 James Youngman <jay@gnu.org>
-
- * doc/find.texi, find/find.1:
- Improved documentation in response to Savannah bug #14376
-
-2005-09-01 James Youngman <jay@gnu.org>
-
- * po/ChangeLog, ChangeLog: Updated with recent changes.
-
- * locate/locate.c: Removed unused struct stringbuf.soffs.
-
- * doc/find.texi: Typo fix from Jim Meyering (trivial change)
-
-2005-09-01 Jim Meyering <jim@meyering.net>
-
- * locate/locate.c (struct stringbuf) [soffs]: Remove unused member.
- (locate): Remove initialization, too.
-
-2005-09-01 James Youngman <jay@gnu.org>
-
- * doc/find.texi: Typo fix from Jim Meyering (trivial change)
-
-2005-08-30 James Youngman <jay@gnu.org>
-
- * find/defs.h, find/find.c, find/fstype.c, find/pred.c:
- Attempted fix for compilation when AFS is #defined
-
-2005-08-24 James Youngman <jay@gnu.org>
-
- * po/sl.po: Updated from Translation Project
-
-2005-08-13 James Youngman <jay@gnu.org>
-
- * find/find.1: Remind the user to quote the pattern argument to -iname.
-
-2005-08-12 James Youngman <jay@gnu.org>
-
- * NEWS: Corrected typo.
-
-2005-08-11 James Youngman <jay@gnu.org>
-
- * po/fr.po: Updated French translation and added new PO file zh_TW.po
- for Chinese (traditional)
-
-2005-08-09 James Youngman <jay@gnu.org>
-
- * NEWS: Indicate that regexprops.texi is built on Cygin now that
- Savannah bug #14025 has been fixed.
-
- * lib/Makefile.am, lib/regexprops.c: Fixed compilation failure on
- Cygwin - Savannah Bug #14025 (tiny change, three lines), reported
- and fixed by Eric Blake
-
- * find/testsuite/Makefile.am,
- find/testsuite/find.posix/sv-bug-14070.exp,
- find/testsuite/find.posix/sv-bug-14070.xo: Added new test case for
- SourceForge bug #14070
-
- * find/testsuite/find.posix/sv-bug-14070.exp,
- find/testsuite/find.posix/sv-bug-14070.xo: New file.
-
- * find/defs.h, find/ftsfind.c, find/pred.c, find/util.c:
- Ensure we can still build with --enable-debug
-
- * find/testsuite/config/unix.exp,
- find/testsuite/find.gnu/execdir-one.exp,
- find/testsuite/find.gnu/execdir-root-only.exp,
- find/testsuite/find.gnu/sv-bug-12230.exp: If . is on $PATH,
- indicate that the -execdir tests cannot be carried out, as opposed
- to indicating that those tests fail
-
-2005-08-07 James Youngman <jay@gnu.org>
-
- * NEWS: Indicated that some test suite files have been renamed.
-
- * xargs/testsuite/Makefile.am, xargs/testsuite/inputs/eof.xi,
- xargs/testsuite/inputs/eof1.xi,
- xargs/testsuite/xargs.sysv/eof.exp,
- xargs/testsuite/xargs.sysv/eof.xo,
- xargs/testsuite/xargs.sysv/eof1.exp,
- xargs/testsuite/xargs.sysv/eof1.xo,
- xargs/testsuite/xargs.posix/lc_l2.exp,
- xargs/testsuite/xargs.posix/lc_l2.xo,
- xargs/testsuite/xargs.sysv/l2.exp,
- xargs/testsuite/xargs.sysv/l2.xo,
- xargs/testsuite/xargs.sysv/lc_l2.exp,
- xargs/testsuite/xargs.sysv/lc_l2.xo,
- xargs/testsuite/xargs.posix/L2.exp,
- xargs/testsuite/xargs.posix/l2.exp,
- xargs/testsuite/xargs.posix/L2.xo,
- xargs/testsuite/xargs.posix/l2.xo,
- xargs/testsuite/xargs.posix/uc_L2.exp,
- xargs/testsuite/xargs.posix/uc_L2.xo: Work around problems with
- CVS clients on case-insentitive operating systems
-
- * debian/Changelog: Removed Changelog file since changelog is the
- one we should be using and having both files upsets Cygwin
- systems which cannot tell the dirrerence between changelog and
- Changelog
-
- * find/ftsfind.c:
- If DEBUG is defined, show the symbolic names fro fts_info values.
-
- * find/ftsfind.c: Added additional diagnostics.
-
-2005-08-02 James Youngman <jay@gnu.org>
-
- * po/tr.po, vi.po:
- Updated Vietnamese and Turkish translations from Translation Project
-
- * po/sl.po, sr.po, sv.po, tr.po, vi.po, zh_CN.po, be.po, ca.po, da.po, de.po, el.po, eo.po, es.po, fi.po, findutils.pot, fr.po, ga.po, gl.po, hr.po, hu.po, id.po, it.po, ja.po, ko.po, lg.po, ms.po, pl.po, pt.po, pt_BR.po, ru.po, rw.po:
- Did update-po
-
- * po/et.po, sk.po, ro.po:
- Updated Romanian, Slovak and Estonian translations from Translation Project
-
-2005-08-01 James Youngman <jay@gnu.org>
-
- * ABOUT-NLS, INSTALL, Makefile.am, configure.in, depcomp,
- doc/texinfo.tex, install-sh, missing, mkinstalldirs: By adding the
- missing AM_GNU_GETTEXT_VERSION call, allowed autopoint to update
- those files of which it has updated copies.
-
- * po/Makevars.template, po/Makefile.in.in, po/findutils.pot:
- Using AM_GNU_GETTEXT_VERSION, allowed gettext to update the infrastructure
-
- * po/Rules-quot, po/boldquot.sed, po/en@boldquot.header, po/en@quot.header, po/insert-header.sin, po/quot.sed:
- Files added by autopoint now that we are using AM_GNU_GETTEXT_VERSION
-
- * find/testsuite/Makefile.am: Added find.gnu./perm-slash.{exp,xo}.
-
- * po/nl.po: Updated Dutch translation from Translation Project
-
- * po/ga.po: Updated Irish translation from the Translation Project
-
- * po/da.po: Updated Danish translation from the Translation Project
-
- * po/ca.po: Updated Catalan translation from Translation Project
-
-2005-07-31 James Youngman <jay@gnu.org>
-
- * find/testsuite/excuses.txt: We now have tests for -perm.
-
- * NEWS, configure.in, find/parser.c,
- find/testsuite/find.gnu/perm-slash.exp,
- find/testsuite/find.gnu/perm-slash.xo: Fixed bug which caused find
- -perm /440 to be treated the same as find -perm 440
-
- * find/testsuite/Makefile.am:
- Generic tests for -perm -NNN and -perm NNN
-
- * find/testsuite/excuses.txt: New file - list of test cases that
- still need to be written, along with excuses why they haven't been
- done yet
-
- * find/testsuite/find.posix/perm-vanilla.exp,
- find/testsuite/find.posix/perm-vanilla.xo: Generic tests for -perm
- -NNN and -perm NNN
-
- * find/testsuite/find.gnu/inum.exp:
- Ensure that the test would fail if -inum just always returned true
-
- * find/testsuite/Makefile.am, find/testsuite/find.gnu/ilname.exp,
- find/testsuite/find.gnu/ilname.xo,
- find/testsuite/find.gnu/inum.exp, find/testsuite/find.gnu/inum.xo,
- find/testsuite/find.gnu/lname.exp,
- find/testsuite/find.gnu/lname.xo,
- find/testsuite/find.gnu/xtype.exp,
- find/testsuite/find.gnu/xtype.xo,
- find/testsuite/find.posix/links.exp,
- find/testsuite/find.posix/links.xo: New test cases for -ilname,
- -inum, -lname, -xtype
-
- * find/testsuite/Makefile.am, find/testsuite/find.gnu/delete.exp,
- find/testsuite/find.gnu/delete.xo,
- find/testsuite/find.gnu/iregex1.exp,
- find/testsuite/find.gnu/iregex1.xo,
- find/testsuite/find.gnu/regex1.exp,
- find/testsuite/find.gnu/regex1.xo,
- find/testsuite/find.gnu/regex2.exp,
- find/testsuite/find.gnu/regex2.xo,
- find/testsuite/find.gnu/samefile-copy.exp,
- find/testsuite/find.gnu/samefile-copy.xo,
- find/testsuite/find.gnu/samefile-link.exp,
- find/testsuite/find.gnu/samefile-link.xo,
- find/testsuite/find.gnu/samefile-same.exp,
- find/testsuite/find.gnu/samefile-same.xo,
- find/testsuite/find.gnu/samefile-symlink.exp,
- find/testsuite/find.gnu/samefile-symlink.xo: Further test cases
-
- * find/find.1: Indicate that -delete implies -depth (find.texi
- already mentioned this).
-
- * find/testsuite/Makefile.am:
- Brought the list of .exp and .xo files in Makefile.am into sync with
- the actual contents of the CVS repository.
-
- * find/testsuite/Makefile.am, find/testsuite/find.gnu/depth-d.exp,
- find/testsuite/find.gnu/depth-d.xo,
- find/testsuite/find.gnu/empty.exp,
- find/testsuite/find.gnu/empty.xo,
- find/testsuite/find.gnu/execdir-one.exp,
- find/testsuite/find.gnu/execdir-one.xo,
- find/testsuite/find.gnu/false.exp,
- find/testsuite/find.gnu/false.xo,
- find/testsuite/find.gnu/follow-basic.exp,
- find/testsuite/find.gnu/follow-basic.xo,
- find/testsuite/find.gnu/gnu-or.exp,
- find/testsuite/find.gnu/gnu-or.xo,
- find/testsuite/find.gnu/gnuand.exp,
- find/testsuite/find.gnu/gnuand.xo,
- find/testsuite/find.gnu/gnunot.exp,
- find/testsuite/find.gnu/gnunot.xo,
- find/testsuite/find.gnu/iname.exp,
- find/testsuite/find.gnu/iname.xo,
- find/testsuite/find.gnu/ipath.exp,
- find/testsuite/find.gnu/ipath.xo,
- find/testsuite/find.gnu/iwholename.exp,
- find/testsuite/find.gnu/iwholename.xo,
- find/testsuite/find.gnu/path.exp, find/testsuite/find.gnu/path.xo,
- find/testsuite/find.gnu/print0.exp,
- find/testsuite/find.gnu/print0.xo,
- find/testsuite/find.gnu/quit.exp, find/testsuite/find.gnu/quit.xo,
- find/testsuite/find.gnu/true.exp, find/testsuite/find.gnu/true.xo,
- find/testsuite/find.gnu/wholename.exp,
- find/testsuite/find.gnu/wholename.xo,
- find/testsuite/find.posix/and.exp,
- find/testsuite/find.posix/and.xo,
- find/testsuite/find.posix/exec-one.exp,
- find/testsuite/find.posix/exec-one.xo,
- find/testsuite/find.posix/grouping.exp,
- find/testsuite/find.posix/grouping.xo,
- find/testsuite/find.posix/name.exp,
- find/testsuite/find.posix/name.xo,
- find/testsuite/find.posix/posixnot.exp,
- find/testsuite/find.posix/posixnot.xo,
- find/testsuite/find.posix/prune.exp,
- find/testsuite/find.posix/prune.xo: Added new test cases for many
- of the actions and tests of find
-
- * find/find.c (default_prints):
- not a static function, so do not declare it as one.
-
- * m4/withfts.m4: Fixed underquoted definition of FIND_WITH_FTS.
- [this change is currently on a branch only]
-
-2005-07-30 James Youngman <jay@gnu.org>
-
- * find/finddata.c, find/ftsfind.c, find/parser.c, find/pred.c,
- find/util.c, m4/Makefile.am, m4/withfts.m4: Initial attempt to
- convert find to use gnulib's fts()
- [this change is currently on a branch only]
-
- * find/finddata.c, find/ftsfind.c, m4/withfts.m4: New file.
- [this change is currently on a branch only]
-
- * NEWS, configure.in, find/Makefile.am, find/defs.h, find/find.c,
- import-gnulib.sh: Initial attempt to convert find to use gnulib's
- fts() [this change is currently on a branch only]
-
-2005-07-29 James Youngman <jay@gnu.org>
-
- * NEWS, configure.in
- Prepared for the release of findutils-4.2.24
-
- * ChangeLog: Updated with recent changes.
-
- * NEWS, find/find.1, doc/find.texi:
- Indicate that -ok and -okdir redirect stdin from /dev/null.
-
- * NEWS: Explain the directory link count change more throroughly.
-
- * NEWS: Fixed bug #13973.
-
- * find/pred.c (pred_fprintf): Fix Savannah bug #13973: Modify the
- handling of -printf %Y so that it no longer modifies stat_buf
-
- * find/testsuite/find.gnu/printf-symlink.exp,
- find/testsuite/find.gnu/printf-symlink.xo: Detect Savannah bug
- #13973: pollution of stat_buf by the %Y directive (trivial change
- from Andreas Metzler)
-
- * INSTALL, depcomp, doc/texinfo.tex, install-sh, missing, mkinstalldirs:
- Updated auxilliary files from the automake-1.9 distribution
-
- * configure.in:
- Introduce new Automake conditional, CROSS_COMPILING, true when we are corss compiling
-
- * find/find.c:
- If we decline to follow a symbolic link due to the safety check, issue a more self-explanatory warning message
-
- * lib/Makefile.am: Don't build regexprops if we are cross compiling
-
- * doc/Makefile.am:
- Depend on the regex.h file rather than the 'regexprops' binary,
- because the header file will always exist even if we are doing "make
- dist". Otherwise "make distcheck" fails because it tries to rebuild
- find.info while the source-directory is read-only.
-
-2005-07-28 James Youngman <jay@gnu.org>
-
- * find/find.1:
- Say "other users" rather than "rest of the world" when talking about
- Unix permissions. Fixes Savannah bug #4246.
-
-2005-07-27 James Youngman <jay@gnu.org>
-
- * xargs/testsuite/Makefile.am: Added new test case 'childfail.exp'.
-
- * doc/find.texi:
- Updated the description of the safe-dir-change operation to reflect
- what find now does on systems that lack O_NOFOLLOW.
-
- * NEWS, find/parser.c: Indicate in the output of find --version if
- the leaf optimisation is enabled or not
-
- * find/find.c: Fixed typo.
-
- * find/find.c: If the link count of a directory starts off less
- than two, disable the leaf optimisation for this directory.
-
-2005-07-26 James Youngman <jay@gnu.org>
-
- * lib/regexprops.c: Further small corrections from Karl.
-
- * doc/find.texi:
- Reordered the sections in the manual to put the "Common Tasks" and
- "Worked Examples" chapters together.
-
- * configure.in, find/find.c: Allow the leaf optimisation to be
- disabled by default with the configure option
- --disable-leaf-optimisation
-
- * find/find.c: Removed old code for antuqie version of savedir().
-
- * lib/regextype.c: Put the syntaxes in alphabetical order.
-
- * lib/regexprops.c: Karl made some more readability suggestions.
-
-2005-07-24 James Youngman <jay@gnu.org>
-
- * doc/Makefile.am: If the regexprops program has changed we should
- re-run it, since it will probably now produce different output
-
- * lib/regextype.h:
- Allow the caller to detect if one regex type is identical to another.
-
- * configure.in:
- Define the preprocessor macro FINDUTILS for that code int he lib/
- directory can be slightly more reusable.
-
- * lib/regextype.c:
- Allow the caller to detect if one regex type is identical to another.
-
- * lib/regexprops.c:
- Made Texinfo style corrections suggested by Karl Berry.
-
-2005-07-22 James Youngman <jay@gnu.org>
-
- * xargs/testsuite/xargs.posix/childfail.exp, xargs/xargs.c: Fix
- Savannah bug #13878, in which xargs deals incorrectly with child
- failure, returning 0 when it should return 123
-
-2005-07-17 James Youngman <jay@gnu.org>
-
- * find/find.1: (tiny change) Corrections by Greg Wooledge
-
-2005-07-16 James Youngman <jay@gnu.org>
-
- * doc/find.texi: Updates following comments by Dave Gilbert.
-
- * NEWS: Corrected a typo.
-
- * doc/find.texi:
- Added in the example about updating an aggregate timestamp file.
-
-2005-07-15 James Youngman <jay@gnu.org>
-
- * po/da.po: Updated Danish translation from translation project
-
-2005-07-14 James Youngman <jay@gnu.org>
-
- * NEWS, doc/Makefile.am, doc/find.texi, lib/Makefile.am,
- lib/regexprops.c, lib/regextype.c, lib/regextype.h: Added
- --regextype and -regextype options to locate and find
- respectively, and documented these
-
- * doc/find.texi: We use GNU Emacs regexps by default now.
-
- * doc/find.texi:
- We require GNU sort in order for locate to handle newlines correctly,
- not just GNU find.
-
-2005-07-10 James Youngman <jay@gnu.org>
-
- * doc/find.texi:
- Applied several documentation improvement patches from Aaron Hawley
-
- * ChangeLog, NEWS: Updated with recent changes.
-
- * NEWS: Recent gnulib changed have fixed -iregex
-
- * doc/find.texi, xargs/xargs.1:
- Tiny patch from Andreas Metzler: xargs -I is like xargs -i, but the latter is deprecated
-
-2005-07-06 James Youngman <jay@gnu.org>
-
- * find/defs.h, find/find.c, find/parser.c, find/pred.c:
- Fixed Savannah bug #13650; programs run by -exec cannot read stdin
-
-2005-07-04 James Youngman <jay@gnu.org>
-
- * NEWS: *** empty log message ***
-
- * doc/find.texi:
- Added a "Worked Examples" section. It currently only contains a
- (long) example about deleting files.
-
- * .cvsignore: Some extra stuff to ignore.
-
-2005-07-03 James Youngman <jay@gnu.org>
-
- * find/Makefile.am: Don't need regexprops.c really...
-
- * lib/regextype.c, lib/regextype.h:
- New files for selecting regex type based on a keyword
-
- * locate/locate.1: Documented the fact that we now use Emacs-style
- regexps, not POSIX EREs, for compatibility with find -regex.
-
- * lib/Makefile.am, locate/locate.c, doc/find.texi,
- find/Makefile.am, find/defs.h, find/find.1, find/find.c,
- find/parser.c: Fixed Savannah bug #13495: find now uses
- Emacs-style regexps by default
-
-2005-07-02 James Youngman <jay@gnu.org>
-
- * configure.in, find/defs.h, find/fstype.c, find/parser.c,
- intl/dcigettext.c, lib/buildcmd.c, lib/listfile.c,
- lib/savedirinfo.c, locate/locate.c, xargs/xargs.c: Assume unistd.h
- is present - avoid using HAVE_UNISTD_H
-
-2005-07-01 Jim Meyering <jim@meyering.net>
-
- With `-fprint F' or `-fprintf F', don't write diagnostics
- to F when stderr is closed.
-
- * find/parser.c: Include "stdio-safer.h".
- (open_output_file): Use fopen_safer, not fopen.
- * import-gnulib.sh (findutils_modules): Add stdio-safer.
-
-2005-07-01 James Youngman <jay@gnu.org>
-
- * doc/find.texi:
- Aaron pointed out a potentially-confusing sentence. I fixed it.
-
- * find/defs.h, find/find.1, find/find.c, find/parser.c,
- find/pred.c, find/util.c: Allow consistency-checking of the
- predicates, checking for example that actions all have side
- effects
-
-2005-06-29 James Youngman <jay@gnu.org>
-
- * doc/find.texi: Applied patch from Aaron Hawley (Savannah patch
- #3751: Typos and small suggestions to find.texi)
-
-2005-06-27 James Youngman <jay@gnu.org>
-
- * ChangeLog, locate/locate.c: Applied patch from Bas Van Gompel to
- move match counting into a (new) visitor function
-
- * NEWS, configure.in: No longer 4.2.23, as we're moving on now
-
-2005-06-24 Bas van Gompel <patch-findutils.buzz@bavag.tmfweb.nl>
-
- * locate/locate.c (visit_count, visit_limit): New functions.
- (locate): Use visit_limit or visit_count. Simplify main loop.
- (main) Bail out early when limit is reached.
-
-2005-06-20 James Youngman <jay@gnu.org>
-
- * xargs/xargs.c:
- Removed some code which had already been disabled via the preprocessor.
-
-2005-06-19 Dmitry V. Levin <ldv@altlinux.org>
-
- * lib/savedirinfo.c: Fix two compilation warnings (which would
- prevent compilation if "-Wall -Werror" is in effect).
-
-2005-06-19 James Youngman <jay@gnu.org>
-
- * ChangeLog: Indicate that we made (are making) a release.
-
- * ChangeLog, NEWS, configure.in: Preparing to release 4.2.23
-
- * doc/find.texi: Fixed Texinfo syntax error in previous change
-
- * doc/find.texi, xargs/xargs.1:
- Document the fact that the -i and -L options are currently
- incompatible (Savannah bug 13041).
-
- * locate/updatedb.1, locate/updatedb.sh: Fix Savannah bug 13411 -
- reject trailing slashes in updatedb's --prunepaths, bacsue these
- will never be matched
-
- * NEWS: Released findutils-4.2.23.
-
- * doc/find.texi, xargs/xargs.1:
- Document the fact that the -i and -L options are currently
- incompatible (Savannah bug 13041).
-
- * locate/updatedb.1, locate/updatedb.sh: Fix Savannah bug 13411 -
- reject trailing slashes in updatedb's --prunepaths, because these
- will never be matched.
-
-2005-06-18 James Youngman <jay@gnu.org>
-
- * po/ga.po, tr.po: Updated Irish and Turkish translations.
-
- * po/pl.po: Did update-po
-
- * po/pl.po:
- Updated Polish translation file from the Translation Project
-
- * po/ca.po, da.po, de.po, el.po, eo.po, es.po, et.po, fi.po, findutils.pot, fr.po, ga.po, gl.po, hr.po, hu.po, id.po, it.po, ja.po, ko.po, lg.po, ms.po, nl.po, pl.po, pt.po, pt_BR.po, ro.po, ru.po, rw.po, sk.po, sl.po, sr.po, sv.po, tr.po, vi.po, zh_CN.po, be.po:
- Did update-po
-
-2005-06-18 Martin Buchholz (trivial patch applied by James Youngman)
-
- * find/defs.h, find/find.c, find/parser.c, doc/find.texi: Fix
- typos/spelling errors (mostly in source code comments).
-
-2005-06-18 Dmitry V. Levin <ldv@altlinux.org>
-
- Additional documentation tweaks for -execdir/-okdir actions.
- * find/parser.c (parse_help): Mention -execdir and -ordir options.
- * doc/find.texi, find/find.1: Additionally document new options.
-
-2005-06-12 Bas van Gompel <patch-findutils.buzz@bavag.tmfweb.nl>
-
- * locate/locate.c: Implement --all (-A).
-
- * NEWS, doc/find.texi, locate/locate.1: Document locate --all (-A)
-
-2005-06-12 James Youngman <jay@gnu.org>
-
- * find/find.c, NEWS:
- Savannah bug #13381 (Debian bug 313081): if we have O_NOFOLLOW,
- safely_chdir() does not need to call stat(). However, process_dir()
- used to rely on using that stat information. To work around this
- problem, there is now an output parameter in safely_chdir() which
- indicates if the stat buffer is valid.
- This bug has possible security implications.
-
- * find/find.1, doc/find.texi:
- Applied patch from Andreas Metzler, improving the wording for the
- documentation of the %k and %b format directives. This patch does
- not require a copyright assignment as it consists of several
- copies of the same small wording change.
-
-2005-06-11 James Youngman <jay@gnu.org>
-
- * find/find.1: Corrected spelling error 'writeable' to 'writable'.
-
- * find/find.1, locate/locate.1:
- Fixed Savannah bug #13363, typos in manpages (trivial change)
-
-2005-06-10 James Youngman <jay@gnu.org>
-
- * find/find.c, lib/savedirinfo.c, lib/savedirinfo.h: Switch to a
- new scheme for saving directory entry data which is extensible to
- allow additional data to be saved.
-
-2005-06-09 James Youngman <jay@gnu.org>
-
- * locate/testsuite/config/unix.exp:
- Use the new normalize_dir procedure throughout.
-
- * locate/testsuite/config/unix.exp: Move the normalisation into a
- procedure. Don't rely on the "file normalize" command being
- available (it's new in Tcl 8.4).
-
-2005-06-08 James Youngman <jay@gnu.org>
-
- * ChangeLog, NEWS, configure.in: Updated for recent changes
-
- * doc/find.texi:
- Explain that you should put the argument of -name in quotes.
-
- * find/find.1:
- Added a new "NON-BUGS" section pointing out things that look like bugs
- but are caused by mistakes or misunderstandings.
-
- * doc/find.texi, locate/locate.1: Applied Bas van Gompel's patch
- which allows the database to be read from stdin.
-
- * locate/locate.c:
- Read the database in by using the "visitor" pattern. Modified file
- header comment to indicate that we no longer use the efficient
- algorith described in ;login:. Emit an error message if the
- LOCATE_PATH variable implies that we should read stdin twice.
- Most of this code is from Bas van Gompel.
-
- * AUTHORS: Credit Bas van Gompel for his work on locate.
-
- * lib/printquoted.h: Appled patch from Bas - fixing compiler warning.
-
-2005-06-07 James Youngman <jay@gnu.org>
-
- * ChangeLog, NEWS, configure.in: Updates prior to release
-
- * config.rpath: Added file required for 'make dist'
-
- * po/be.po, po/ca.po, po/da.po, po/de.po, po/el.po, po/eo.po,
- po/es.po, po/et.po, po/fi.po, po/findutils.pot, po/fr.po,
- po/ga.po, po/gl.po, po/hr.po, po/hu.po, po/id.po, po/it.po,
- po/ja.po, po/ko.po, po/lg.po, po/ms.po, po/nl.po, po/pl.po,
- po/pt.po, po/pt_BR.po, po/ro.po, po/ru.po, po/rw.po, po/sk.po,
- po/sl.po, po/sr.po, po/sv.po, po/tr.po, po/vi.po, po/zh_CN.po:
- updated the po files for release
-
- * xargs/testsuite/Makefile.am:
- Added in all the test files from Dmitry V. Levin.
-
-2005-06-08 Bas van Gompel <patch-findutils.buzz@bavag.tmfweb.nl>
-
- * NEWS, locate/locate.1, doc/find.texi: Document usage of `-'
- to refer to stdin in database-path for locate.
- * locate/locate.c: Change prototype for visitors and processors
- throughout. Move reading the database and generating base_name
- into visitors. Allow `-' to refer to stdin in database-path.
-
- * lib/printquoted.h: Include stdio.h.
-
-2005-06-07 James Youngman <jay@gnu.org>
-
- * COPYING, debian/copyright, depcomp, doc/texinfo.tex,
- find/defs.h, find/find.c, find/fstype.c, find/parser.c,
- find/pred.c, find/testsuite/config/unix.exp, find/tree.c,
- find/util.c, import-gnulib.sh, intl/Makefile.in,
- intl/bindtextdom.c, intl/config.charset, intl/dcgettext.c,
- intl/dcigettext.c, intl/dcngettext.c, intl/dgettext.c,
- intl/dngettext.c, intl/explodename.c, intl/finddomain.c,
- intl/gettext.c, intl/gettext.h, intl/gettextP.h,
- intl/hash-string.h, intl/intl-compat.c, intl/l10nflist.c,
- intl/libgettext.h, intl/libgnuintl.h, intl/loadinfo.h,
- intl/loadmsgcat.c, intl/localcharset.c, intl/locale.alias,
- intl/localealias.c, intl/ngettext.c, intl/plural.c, intl/plural.y,
- intl/ref-add.sin, intl/ref-del.sin, intl/textdomain.c,
- lib/buildcmd.c, lib/buildcmd.h, lib/extendbuf.c, lib/extendbuf.h,
- lib/forcefindlib.c, lib/listfile.c, lib/listfile.h,
- lib/modetype.h, lib/nextelem.c, lib/nextelem.h, lib/printquoted.c,
- lib/printquoted.h, lib/qmark.c, lib/savedirinfo.c,
- lib/savedirinfo.h, lib/strspn.c, lib/wait.h, lib/waitpid.c,
- locate/bigram.c, locate/code.c, locate/frcode.c, locate/locate.c,
- locate/locatedb.h, locate/testsuite/config/unix.exp,
- locate/updatedb.sh, missing, po/fetch-po-files,
- xargs/testsuite/config/unix.exp, xargs/xargs.c:
- Updated the FSF's postal address
-
- * ChangeLog: Corrected Bas's email address.
-
- * locate/locate.c: Updated copyright years.
-
-2005-06-07 Bas van Gompel <patch-findutils.buzz@bavag.tmfweb.nl>
-
- * locate/locate.c: Fold case once, only when needed.
-
-2005-06-07 James Youngman <jay@gnu.org>
-
- * NEWS: Updated with recent changes.
-
- * mdate-sh: Use the mdate-sh from automake
-
- * find/parser.c, find/pred.c, find/tree.c, find/util.c,
- lib/Makefile.am, lib/forcefindlib.c, lib/listfile.c,
- lib/listfile.h, locate/code.c, locate/locate.c, find/defs.h,
- find/find.c: Fix Savannah bug #13324: Fix compiler warnings for
- GCC-3.4
-
- * locate/locate.c:
- Fixed Savannah bug #13325: Quoting of output filenames in locate
- should match find.
-
- * find/parser.c:
- Fixed Savannah bug #13319: C9X-ism in parser.c (declaration after
- statements).
-
- * find/pred.c, lib/Makefile.am, lib/listfile.c, lib/nextelem.c,
- lib/printquoted.c, lib/printquoted.h, lib/qmark.c, NEWS,
- doc/find.texi, find/defs.h, find/find.1, find/parser.c: Fixed
- Savannah bug #13303, find should filter out non-printable
- characters if outputting to tty
-
-2005-05-30 James Youngman <jay@gnu.org>
-
- * locate/locate.c: rename new_locate() to locate() since
- old_locate() has gone the way of the dodo.
-
-2005-05-29 Bas van Gompel <patch-findutils.buzz@bavag.tmfweb.nl>
-
- Add a ``--print'' (``-p'') option. (to cancel side-effects of -c/-S)
- Allow ``--statistics'' in combination with non-options.
- * doc/find.texi: Add documentation for locate --print (-p), and the
- use of non-options with --statistics.
- * locate/locate.1: ditto.
- * locate/locate.c: Read each database only once.
-
-2005-05-23 Paul Eggert <eggert@cs.ucla.edu>
-
- Adjust to recent gnulib changes.
- * import-gnulib.sh: Get config.rpath from gnulib/build-aux,
- not gnulib/config.
- * find/parser.c (parse_perm): Ignore umask when parsing
- symbolic permissions. Adjust to new modechange API.
-
-2005-05-16 James Youngman <jay@gnu.org>
-
- * find/find.c, find/parser.c, find/pred.c, find/tree.c:
- Trivial change: don't use i18n support for debug-only messages
-
- * ChangeLog: Added ChangeLog entry crediting Dmitry
-
-2005-05-09 James Youngman <jay@gnu.org>
-
- * find/parser.c:
- The previous change fixed Savannah bug #12999. This change doesn't do
- anything, it's only intended to be a place to record the Savannah bug
- ID we've just fixed.
-
- * find/parser.c:
- Oops. Initialise the variable which indicates which regex syntax to
- use. We use POSIX basic regular expressions.
-
- * find/parser.c:
- Suggestion by Ed Avis: point out that "-name foo/bar" will almost
- always evaluate to false. Suggest to the user what alternatives they
- might find useful.
-
-2005-05-02 James Youngman <jay@gnu.org>
-
- * AUTHORS:
- Added Dimitry (his new test suite contribution required a copyright
- assignment).
-
-2005-05-03 Dmitry V. Levin
-
- * Added xargs test suite tests by Dmitry V. Levin, together with
- bugfixes which ensure that the tests pass.
-
-2005-04-18 James Youngman <jay@gnu.org>
-
- * Added test suite tests for Bas van Gompel's changes.
-
-2005-04-18 Bas van Gompel <patch-findutils.buzz@bavag.tmfweb.nl>
-
- * doc/find.texi: Document locate --non-existing (-E).
- * locate/locate.1: Ditto.
- * locate/locate.c: Implement --non-existing (-E).
-
-2005-04-04 James Youngman <jay@gnu.org>
-
- * configure.in, import-gnulib.sh:
- We no longer need gnulib/m4/Makefile.am
-
- * po/vi.po: Updated Vietnamese translation
-
- * locate/updatedb.sh:
- Savannah bug #12491: Only use the "-s" option to "su" if it is
- supported.
-
-2005-04-01 James Youngman <jay@gnu.org>
-
- * locate/locate.1, locate/updatedb.1, xargs/xargs.1: Trivial
- change from A Costa <agcosta@gis.net>, fixing typos in manual
- pages for xargs, locate and updatedb; fixes Savannah bug #12500,
- Debian bug #301934
-
-2005-03-22 James Youngman <jay@gnu.org>
-
- * import-gnulib.sh: Include the new gnulib module stat-macros
-
- * configure.in:
- CVS code is (will shortly be) no longer identical to the 4.2.20 release
-
-2005-03-17 James Youngman <jay@gnu.org>
-
- * configure.in: Preprare for release of 4.2.20.
-
- * NEWS: Updated prior to release of 4.2.20.
-
- * ChangeLog: Updated with recent changes.
-
- * THANKS: Thank Bas van Gompel, but only once.
-
- * THANKS: Thank Bas van Gompel and Aaron S. Hawley.
-
- * po/vi.po: Updated Vietnamese PO file
-
-2005-03-10 James Youngman <jay@gnu.org>
-
- * po/nl.po: Updated Dutch PO file
-
-2005-03-08 Bas van Gompel <patch-findutils.buzz@bavag.tmfweb.nl>
-
- * import-gnulib.sh: Re-enable creation of gnulib/m4/Makefile.am.
-
-2005-03-07 James Youngman <jay@gnu.org>
-
- * Released findutils-4.2.19.
-
- * find/testsuite/find.posix/sizes.exp:
- Use 2>/dev/null instead of 2>&1, because Tcl understands the former
- but not the latter.
-
- * find/testsuite/Makefile.am: Also distribute sv-bug-12181.xo.
-
- * find/testsuite/Makefile.am: Distribute sv-bug-12181.
-
- * find/testsuite/Makefile.am: Distribute sv-bug-12230.
-
- * NEWS: Updated with new news.
-
- * ChangeLog: Brought up to date.
-
- * lib/buildcmd.c, find/testsuite/find.gnu/sv-bug-12230.exp: Fixed
- Savannah bug #12230, in which '-exec echo == {} +' is always run,
- even if there were no matched files.
-
-2005-03-06 James Youngman <jay@gnu.org>
-
- * ChangeLog: Added latest changes.
-
- * po/pt.po, configure.in: Added Portuguese translation
-
-2005-03-04 James Youngman <jay@gnu.org>
-
- * configure.in: Modernized the way we call AC_INIT and
- AM_INIT_AUTOMAKE
-
- * locate/locate.c, find/pred.c, find/find.c:
- Eliminated some compiler warnings
-
- * find/pred.c: Clarified the meaning of a comment.
-
- * find/testsuite/Makefile.am: Added sizes.exp, sizes.xo.
-
- * find/testsuite/find.posix/sizes.xo,
- find/testsuite/find.posix/sizes.exp: Added tests for -size
- predicate
-
-2005-03-03 James Youngman <jay@gnu.org>
-
- * find/find.c:
- safely_chdir_lstat(): if we didn't end up in the right place, and then
- fchdir() fails, we can't return to the directory we started in.
- Therefore, issue a fatal error message and exit.
-
-2005-03-01 James Youngman <jay@gnu.org>
-
- * find/find.c, find/testsuite/find.posix/sv-bug-12181.exp,
- find/testsuite/find.posix/sv-bug-12181.xo: Fixed SourceForge bug
- 12181 (find -H symlink-to-dir reports 'Too many Symbolic links')
- and bug 12044 (find still hangs on dead NFS filesystems on
- Solaris)
-
-2005-02-28 James Youngman <jay@gnu.org>
-
- * doc/find.texi: Typo: O_NOFOLLOW, not O_FOLLOW
-
- * import-gnulib.sh:
- Suggestion from Martin Buchholz; unset CDPATH to prevent "cd" echoing
- the new directory.
-
-2005-02-27 James Youngman <jay@gnu.org>
-
- * README: Indicate how the reader can verify the release.
-
-2005-02-26 James Youngman <jay@gnu.org>
-
- * po/sk.po, po/sl.po, po/sr.po, po/sv.po, po/tr.po, po/vi.po,
- po/zh_CN.po, po/be.po, po/ca.po, po/da.po, po/de.po, po/el.po,
- po/eo.po, po/es.po, po/et.po, po/fi.po, po/findutils.pot,
- po/fr.po, po/gl.po, po/hr.po, po/hu.po, po/id.po, po/it.po,
- po/ja.po, po/ko.po, po/lg.po, po/ms.po, po/nl.po, po/pl.po,
- po/pt_BR.po, po/ro.po, po/ru.po: Added new Vietnamese translation
-
- * configure.in: Added new Vietnamese translation.
-
-2005-02-25 James Youngman <jay@gnu.org>
-
- * po/ga.po: Updated Irish po file
-
-2005-02-23 James Youngman <jay@gnu.org>
-
- * Makefile.am: Fix Savannah bug #12064 - 'make distclean' deletes
- regex.c but should not.
-
- * find/testsuite/Makefile.am,
- find/testsuite/find.gnu/printf-h.exp,
- find/testsuite/find.gnu/printf-h.xo: Added test case for Savannah
- bug #12085 (-printf %h).
-
- * NEWS, doc/find.texi, find/find.1, find/pred.c:
- %h now expands to '.' instead of nothing.
-
-2005-02-22 James Youngman <jay@gnu.org>
-
- * find/find.c:
- Fixed Savannah bug #12099 (misinterpretation of system versions
- leading to possible incorrect disabling of O_NOFOLLOW). Reported by
- Dmitry V. Levin.
-
- * find/pred.c:
- For the %h format, don't bail out early as the format might contain
- something else too.
-
-2005-02-21 James Youngman <jay@gnu.org>
-
- * find/find.c: Fixed accidental C99 dependency.
-
-2005-02-20 James Youngman <jay@gnu.org>
-
- * po/be.po, po/ca.po, po/da.po, po/de.po, po/el.po, po/eo.po,
- po/es.po, po/et.po, po/fi.po, po/findutils.pot, po/fr.po,
- po/ga.po, po/gl.po, po/hr.po, po/hu.po, po/id.po, po/it.po,
- po/ja.po, po/ko.po, po/lg.po, po/ms.po, po/nl.po, po/pl.po,
- po/pt_BR.po, po/ro.po, po/ru.po, po/sk.po, po/sl.po, po/sr.po,
- po/sv.po, po/tr.po, po/zh_CN.po: Updated italian translation
-
- * doc/find.texi: Corrected a typo.
-
- * find/find.c:
- Read the mounted device list afer parsing the command line, so that
- for example "find --version" still works (in response to Savannah bug
- #12044).
-
- * configure.in: We've moved on from findutils-4.2.18.
-
-2005-02-19 James Youngman <jay@gnu.org>
-
- * NEWS: Corrected the summary of the "find -depth" bug.
-
-2005-02-16 James Youngman <jay@gnu.org>
-
- * NEWS, configure.in: Prepared for release of 4.2.18.
-
- * ChangeLog: Updated prior to release of 4.2.18.
-
- * find/testsuite/Makefile.am:
- Distribute the test cases for the recent "find -depth" bug.
-
- * find/testsuite/find.posix/depth1.exp, find/testsuite/find.posix/depth1.xo:
- Added test case for find -depth bug reported by Joseph S. Myers
-
- * find/find.c:
- If -depth is in effect, processing of the subdirectories invalidates
- the information in 'state'. Therefore once we get around to
- processing the predicates, restore the information that we keep in
- 'state' and in 'stat_buf'.
-
-2005-02-15 James Youngman <jay@gnu.org>
-
- * ChangeLog: Updated with recent changes
-
- * find/find.1:
- Emphasise that -L causes find to recurse into subdirectories pointed
- to by symbolic links.
-
- * find/find.1:
- Patch to find.1 from Aaron Hawley <Aaron.Hawley@uvm.edu>:
-
- * Notes about -H actually apply to -L.
- * Said paragraph is duplicated two paragraphs later.
- * Typos: nno, ibmue, surrpounding
-
-2005-02-15 Aaron Hawley <Aaron.Hawley@uvm.edu>
-
- * find/find.1: Notes about -H actually apply to -L. Said
- paragraph is duplicated two paragraphs later. Also typos: nno,
- ibmue, surrpounding
-
-2005-02-13 James Youngman <jay@gnu.org>
-
- * find/find.1: Miscellaneous small clarifications and improvements.
-
- * doc/find.texi: Added Info nodes and menus under "Changing the
- Current Working Directory" so that it doesn't generate such a huge
- Info page.
-
- * find/find.c: Parenthesise #if defined(...).
-
-2005-02-13 Dmitry V. Levin <ldv@altlinux.org>
-
- * find/find.c: remove test code snippet (time(NULL) was used to
- place a marker for spotting with strace(), but was not actually
- needed).
-
- * find/find.c (safely_chdir_nofollow): must not fall back on
- safely_chdir_lstat() because that will expose it to race condition
- exploits, making it pointless.
-
- * find/find.c (safely_chdir_lstat): Move
- complete_pending_execdirs() up into safely_chdir(), because we
- need to do that in either case.
-
-2005-02-12 James Youngman <jay@gnu.org>
-
- * configure.in, doc/find.texi, find/defs.h, find/find.c,
- find/parser.c: Fix for Savannah bug #11879, that
- init_mounted_dev_list() causes find to hang on systems which are
- clients to dead NFS servers
-
-2005-02-10 James Youngman <jay@gnu.org>
-
- * doc/find.texi: Talk about the problem where find will not work
- if you have a filesystem mounted from an unresponsive NFS server.
-
-2005-02-09 James Youngman <jay@gnu.org>
-
- * find/find.1: Indicate that $TZ affects from printf-format
- results, and add extra cross-references in the SEE ALSO section.
-
-2005-02-08 James Youngman <jay@gnu.org>
-
- * xargs/testsuite/Makefile.am: Distribute the .xe files also.
-
- * Makefile.am: Check that we have the right number of .xe files in
- the distribution also.
-
- * ChangeLog, NEWS, configure.in
- Preparing to release findutils-4.2.17
-
-2005-02-07 James Youngman <jay@gnu.org>
-
- * find/testsuite/config/unix.exp: Re-sort the .xo file using the
- calling user's locale, because our 'pre-sorted' .so output file
- may not be sorted with the same collating order as 'sort' used to
- order the output of "find. Bug spotted by Vin Shelton and Dimitry
- V. Levin.
-
- * find/testsuite/Makefile.am:
- New test, find/testsuite/find.gnu/follow-arg-parent-symlink.exp.
-
- * find/testsuite/find.gnu/follow-arg-parent-symlink.exp,
- find/testsuite/find.gnu/follow-arg-parent-symlink.xo, find/find.c:
- Fix for starting point /foo/bar/baz where bar is a symlink but baz
- is not - we should chdir into bar there even if it is a symbolic
- link
-
-2005-02-07 James Youngman <jay@gnu.org>
-
- * find/testsuite/Makefile.am:
- New test, find/testsuite/find.gnu/follow-arg-parent-symlink.exp.
-
- * find/testsuite/find.gnu/follow-arg-parent-symlink.exp,
- find/testsuite/find.gnu/follow-arg-parent-symlink.xo, find/find.c:
- Fix for starting point /foo/bar/baz where bar is a symlink but baz
- is not - we should chdir into bar there even if it is a symbolic
- link
-
-2005-02-06 James Youngman <jay@gnu.org>
-
- * doc/find.texi:
- -size: Clarification - -size gives a result consistent with 'wc -c'
- for example.
-
- * Makefile.am, find/testsuite/Makefile.am,
- find/testsuite/find.gnu/execdir-root-only.exp,
- find/testsuite/find.gnu/execdir-root-only.xo,
- locate/testsuite/Makefile.am, xargs/testsuite/Makefile.am:
- dist-hook: Ensure that we distribute all the .po files and all the
- testsuite files
-
- * po/pl.po: Updated Polish translation from TP website
-
-2005-02-05 Dmitry V. Levin <ldv@altlinux.org>
-
- * find/parser.c, find/pred.c: Additional tweaks for
- -execdir/-okdir actions.
-
- * find/parser.c (new_insert_exec_ok): Disable ignore_readdir_race
- for -execdir/-okdir.
-
- * find/pred.c (pred_execdir, pred_okdir): Use state.rel_pathname
- instead of basename(pathname). Do not add "./" prefix for
- absolute pathnames.
-
- * find/find.c (process_top_path): Treat "/" similarly to ".".
-
- * xargs/testsuite/xargs.posix/savannah-11865.exp,
- xargs/testsuite/xargs.posix/savannah-11865.xo, xargs/xargs.c:
- Fixed Savannah bug #11866 (not resetting number of used chars in
- the command buffer) - reported by Dimitry V. Levin
-
-2005-02-05 James Youngman <jay@gnu.org>
-
- * THANKS:
- Added thanks for Dimitry - has produced many patches, bugfixes and
- suggestions.
-
- * find/pred.c:
- Fixed Savannah bug #11866: typo in pred_okdir() renders it useless
-
- * find/pred.c:
- Savannah bug #11861: undefined symbol 'basename' on IRIX 5.3
-
- * NEWS, configure.in, po/be.po, po/ca.po, po/el.po, po/eo.po,
- po/fi.po, po/ga.po, po/hr.po, po/hu.po, po/ja.po, po/lg.po,
- po/ms.po, po/ro.po, po/sl.po, po/sr.po, po/zh_CN.po: Added new
- translations
-
- * ChangeLog: Updated from CVS prior to release of 4.2.16.
-
- * po/ChangeLog: Updated from CVS.
-
- * NEWS, configure.in: Preparing to release 4.2.16
-
- * po/da.po, po/de.po, po/es.po, po/et.po, po/findutils.pot,
- po/fr.po, po/gl.po, po/id.po, po/it.po, po/ko.po, po/nl.po,
- po/pl.po, po/pt_BR.po, po/ru.po, po/sk.po, po/sl.po, po/sv.po,
- po/tr.po: make update-po prior to 'make distcheck'
-
- * po/fetch-po-files: This is the first version we actually used.
-
- * find/find.c: process_top_path() fixed compilation warning.
-
- * find/find.c: process_top_path(): avoid processing this item if
- we can't chdir to the basename of the named file.
-
- * lib/Makefile.am: Always build forcefindlib.c
-
- * locate/locate.c: Say 'base name' rather than 'basename' in comments
-
- * find/pred.c, find/find.c: process_top_path(): Proper bugfix for
- correct handling of items at depth 0 (i.e. specified on the
- command line) - do an extra chdir to ensure that we're in the
- directory containing the item before calling process_path().
- Hnece also undo the previous 'quick fix' for the same problem
-
- * doc/find.texi:
- -execdir no longer has to treat anything as special, even at depth 0.
-
-2005-02-03 James Youngman <jay@gnu.org>
-
- * doc/find.texi, find/pred.c: When state.curdepth is 0, our
- working directory is not the directory containing the file we are
- processing.
-
-2005-02-02 James Youngman <jay@gnu.org>
-
- * find/pred.c:
- To allow compilation on cygwin, use base_name(), not basename().
-
- * po/tr.po: Updated Turkish translation from TP
-
- * po/ro.po: Updated Romanian translation from TP
-
- * po/da.po, po/et.po: Updated translations from MT project website
-
-2005-02-01 James Youngman <jay@gnu.org>
-
- * ChangeLog: Updated from CVS log.
-
-2005-01-31 James Youngman <jay@gnu.org>
-
- * find/find.c, lib/nextelem.c, lib/nextelem.h, locate/code.c,
- locate/frcode.c, locate/testsuite/config/unix.exp,
- xargs/testsuite/config/unix.exp, xargs/xargs.c: Updated/corrected
- the email address for David MacKenzie, one of the original authors
- of findutils
-
- * doc/Makefile.am: The HTML version of the manual generated for
- the GNU project website has each node in a separate file, not each
- chapter in a separate file; adjust filenames accordingly
-
- * find/parser.c, find/pred.c, lib/savedirinfo.c:
- Removed some unused variables (patch from Dmitry V. Levin)
-
- * find/find.c:
- Patch from Dmitry V. Levin <ldv@altlinux.org>: Add subfs to the list
- of filesystems which are likely to be automounted.
-
- * m4/findlib.m4: Corrected typo (pointed out by Dmitry V. Levin).
-
- * find/testsuite/config/unix.exp,
- find/testsuite/find.gnu/name-period.xo,
- find/testsuite/find.gnu/posix-dflt.xo,
- find/testsuite/find.gnu/posix-h.xo,
- find/testsuite/find.gnu/posix-l.xo,
- find/testsuite/find.gnu/printf.exp,
- find/testsuite/find.gnu/printf.xo: Systems differ in the order in
- which filenames are returned by readdir. Hence sort the output of
- 'find' before comparing against the expected-output file. We
- therefore also have the lines in the .xo files ready-sorted.
-
- * po/ca.po: Updated from Translation Project
-
- * po/ChangeLog: Updated from CVS logs.
-
- * po/de.po, es.po, et.po, fr.po, gl.po, id.po, it.po, ko.po, nl.po,
- pl.po, pt_BR.po, ru.po, sk.po, sv.po, tr.po, da.po: Ran update-po
-
- * po/be.po, ca.po, el.po, eo.po, fi.po, hr.po, hu.po, ja.po, lg.po,
- ms.po, ro.po, sl.po, sr.po, zh_CN.po: Added new translation files
- from the Translation Project web site
-
- * po/da.po, de.po, es.po, et.po, fr.po, ga.po, gl.po, id.po, it.po,
- ko.po, nl.po, pl.po, pt_BR.po, ru.po, sk.po, sv.po, tr.po: Updated
- .po files from the Translation Project site
-
-2005-01-30 James Youngman <jay@gnu.org>
-
- * doc/Makefile.am:
- Added rules for extra targets that we buld to update the web site.
-
-2005-01-29 James Youngman <jay@gnu.org>
-
- * configure.in: No longer version 4.2.15 - we've changed the manual.
-
- * doc/find.texi:
- Clarified the txt about adding extra tests with post-processing via
- xargs, and recommend -execdir instead for security reasons.
-
- * doc/find.texi: Patch from Karl Berry:
- - more entries for the dir file
- - use @copying so the copyright ends up in the HTML etc. output.
- (This is the only really important change.)
- - put @contents after the title page, for conventional toc location.
- - use @ifnottex to wrap the Top node instead of @ifinfo, for the sake of
- HTML output, etc.
-
- * NEWS, configure.in, po/da.po, po/de.po, po/es.po, po/et.po,
- po/findutils.pot, po/fr.po, po/gl.po, po/id.po, po/it.po,
- po/ko.po, po/nl.po, po/pl.po, po/pt_BR.po, po/ru.po, po/sk.po,
- po/sv.po, po/tr.po: Prepared to release findutils-4.2.15
-
- * ChangeLog: Updated from CVS log.
-
-2005-01-28 James Youngman <jay@gnu.org>
-
- * configure.in:
- Make --enable-d_type-optimization and --enable-d_type-optimisation
- both work.
-
- * configure.in: Assume --enable-d_type-optimisation by default
-
- * find/parser.c: Indicate which features are enabled/disabled
-
- * locate/testsuite/config/unix.exp:
- Clean up the files left behind by the locate_textonly test
-
-2005-01-27 James Youngman <jay@gnu.org>
-
- * doc/find.texi: Documented --regex.
-
- * NEWS, locate/locate.1, locate/locate.c, locate/testsuite/Makefile.am, locate/testsuite/config/unix.exp, locate/testsuite/locate.gnu/regex1.exp:
- Implemented locate --regex - but needs documenting in Texinfo manual.
-
-2005-01-25 James Youngman <jay@gnu.org>
-
- * configure.in: Bumped version no.
-
- * doc/find.texi:
- Document --mmap and --stdio as being synonyms of -m and -s.
-
- * locate/locate.1:
- Document --mmap and --stdio as synonyms of -m and -s.
-
- * locate/locate.c:
- Document -m and -s (both no-ops) in the usage message.
-
- * doc/find.texi, locate/locate.1: Document -m and -s as no-ops.
-
- * ChangeLog: Updated for release of findutils-4.2.14.
-
- * NEWS, configure.in, po/da.po, po/de.po, po/es.po, po/et.po, po/findutils.pot, po/fr.po, po/gl.po, po/id.po, po/it.po, po/ko.po, po/nl.po, po/pl.po, po/pt_BR.po, po/ru.po, po/sk.po, po/sv.po, po/tr.po:
- Preparing to release findutils-4.2.14
-
-2005-01-25 James Youngman <jay@gnu.org>
-
- * NEWS, configure.in, po/da.po, po/de.po, po/es.po, po/et.po,
- po/findutils.pot, po/fr.po, po/gl.po, po/id.po, po/it.po,
- po/ko.po, po/nl.po, po/pl.po, po/pt_BR.po, po/ru.po, po/sk.po,
- po/sv.po, po/tr.po: Preparing to release findutils-4.2.14
-
-2005-01-24 James Youngman <jay@gnu.org>
-
- * Makefile.am: Work around the fact that automake-1.7 actually
- works, and correctly distributes regex.c; hence dist-hook should
- only copy gnulib/lib/regex.c if this has not already been done.
-
- * find/defs.h, find/find.c, find/pred.c,
- find/testsuite/Makefile.am,
- find/testsuite/find.gnu/printf-symlink.exp,
- find/testsuite/find.gnu/printf-symlink.xo,
- find/testsuite/find.gnu/xtype-symlink.exp,
- find/testsuite/find.gnu/xtype-symlink.xo: Fixes for -xtype and
- -printf %Y, which had been the wrong way around.
-
- * NEWS: Avoid including the find.gnu subdirectory in the
- distributed file more than once
-
- * locate/locate.c:
- Move the printing of the statistics into a new function, print_stats()
-
- * find/testsuite/Makefile.am: Avoid including the find.gnu
- subdirectory in the distributed file more than once
-
- * import-gnulib.sh:
- We need the regex module anyway, to allow compilation on Solaris
-
-2005-01-23 James Youngman <jay@gnu.org>
-
- * configure.in:
- Invoke gl_INCLUDED_REGEX directly to ensure successful compilation on
- systems like Solaris, which lacks those functions in libc (fixes GNU
- Savannah bug #11710).
-
- * locate/locate.1: -S is a synonym for --statistics
-
- * doc/find.texi: Documented the new -H, -L and -P options.
-
- * locate/locate.1, locate/locate.c: Implement options -L
- (default), -H and -P, which mean the same things as for find,
- except for the fact that the default is -L rather than -P
-
- * find/find.1: Corrected definition of the exit status for -quit.
-
- * find/find.c, find/pred.c: If DEBUG_STAT is set, issue a debug
- message when we call chdir() so that we can figure out what is
- actually being stat()ed
-
- * locate/updatedb.sh:
- Removed spurious newline from help message (bug report from Karl
- Berry).
-
- * po/da.po, po/de.po, po/es.po, po/et.po, po/findutils.pot,
- po/fr.po, po/gl.po, po/id.po, po/it.po, po/ko.po, po/nl.po,
- po/pl.po, po/pt_BR.po, po/ru.po, po/sk.po, po/sv.po, po/tr.po,
- Makefile.am, NEWS, configure.in, find/defs.h, find/find.c,
- find/parser.c, find/pred.c, find/tree.c, find/util.c,
- import-gnulib.sh, lib/savedirinfo.c: Merged the d_type
- optimisation code; this is disabled by default, and can be enabled
- with 'configure --enable-d_type-optimisation'
-
- * NEWS:
- Updated optimisation NEWS item to indicate the effect on runtime.
-
-2005-01-22 James Youngman <jay@gnu.org>
-
- * NEWS, configure.in: Prepare for release of findutils-4.2.12
-
- * ChangeLog: Brought up to date with recent changes.
-
- * Makefile.am, import-gnulib.sh, po/Makefile.in.in, po/Makevars,
- po/da.po, po/de.po, po/es.po, po/et.po, po/findutils.pot,
- po/fr.po, po/gl.po, po/id.po, po/it.po, po/ko.po, po/nl.po,
- po/pl.po, po/pt_BR.po, po/remove-potcdate.sin, po/ru.po, po/sk.po,
- po/sv.po, po/tr.po: Switch to using the gnulib gettext module, to
- ensure that 'make distcheck' works with current xgettext,
- autoconf, etc.
-
- * find/testsuite/config/unix.exp:
- Oops, we do need to clean up after all.
-
-2005-01-21 James Youngman <jay@gnu.org>
-
- * xargs/testsuite/Makefile.am: Added name of missing input file.
-
- * find/testsuite/Makefile.am:
- Distribute a few files that we had forgotten about
-
- * xargs/testsuite/Makefile.am: Added some missing files.
-
- * lib/Makefile.am: Also need buildcmd.h.
-
- * xargs/testsuite/Makefile.am: Fixed a typo.
-
- * NEWS: Indicate the d_type performance improvement
-
-2005-01-18 James Youngman <jay@gnu.org>
-
- * lib/savedirinfo.h: Added on d_type_optimisation also
-
- * lib/savedirinfo.c: Added on branch d_type_optimisation also.
-
- * find/pred.c: Added assert that we actually know the file type by
- the time pred_type() is called
-
- * find/find.c: Always initialise state.have_stat = false when
- starting to work with a new file
-
-2005-01-17 James Youngman <jay@gnu.org>
-
- * ChangeLog: Brought up to date with recent changes.
-
- * NEWS: Documented the changes so far.
-
- * find/testsuite/find.gnu/exec-many-rtn-success.xo:
- Expected output for exec-many-rtn-success.exp
-
- * find/find.1:
- Indicate that -quit still ensures that pending commands are invoked
-
- * doc/find.texi:
- Indicate that -quit still causes partial command lines to be invoked,
- but there are some types of fatal error which leave such commands
- uninvoked.
-
- * find/defs.h, find/find.c, find/pred.c, find/testsuite/Makefile.am, find/testsuite/config/unix.exp:
- Fixed savannah bug #11625 Wrong return status for -exec ... \; when command fails; also execute any pending commands when doing -quit
-
- * find/testsuite/find.gnu/exec-many-rtn-failure.exp, find/testsuite/find.gnu/exec-many-rtn-failure.xo, find/testsuite/find.gnu/exec-many-rtn-success.exp, find/testsuite/find.gnu/exec-one-rtn-fail.exp, find/testsuite/find.gnu/exec-one-rtn-fail.xo, find/testsuite/find.gnu/exec-one-rtn-success.exp, find/testsuite/find.gnu/exec-one-rtn-success.xo:
- Various test cases for succeeding and failing forms of -exec \; and -exec {} +
-
- * find/pred.c: "-exec ... {} +" always returns "true".
-
- * configure.in, find/defs.h, find/find.c, find/parser.c, find/pred.c, find/tree.c, find/util.c:
- Implemented d_type optimisation but not working correctly, so currently disabled
-
- * lib/savedirinfo.h, lib/savedirinfo.c:
- Initial implementation (temporarily disabled).
-
- * lib/Makefile.am: Resolved merge conflict.
-
- * lib/Makefile.am:
- Make sure nextelem.h is included in the list of sources.
-
- * find/parser.c, lib/nextelem.c, lib/nextelem.h, locate/locate.c:
- Use prototypes for next_element() to make sure it is called correctly.
-
-2005-01-16 James Youngman <jay@gnu.org>
-
- * find/find.c, find/pred.c:
- When completing incomplete multiple execs, use 'eval_tree' not 'predicates'
-
- * lib/buildcmd.c:
- Oops, initialise state->cmd_initial_argv_chars to zero.
-
- * find/find.1:
- Document the way that -execdir and -okdir will refuse to wqork if ">"
- is on $PATH. Also document -okdir in the manpage.
-
- * find/parser.c:
- -execdir and -okdir are insecure if $PATH includes the current
- directory, and so they refuse to work if the user has done that.
-
- * find/pred.c:
- Oops; for -exec ... {} +, pass arguments to bc_push_arg() in the right
- order. Problem spotted by Geoff Clare.
-
- * TODO: Removed items which have now been done.
-
- * lib/buildcmd.c: Tidied up formatting of arg list for bc_do_insert
-
-2005-01-15 James Youngman <jay@gnu.org>
-
- * find/testsuite/find.gnu/printf.exp, find/testsuite/find.gnu/printf.xo:
- Added extra tests for more printf formats; patch by Andreas Metzler
-
- * locate/locate.c:
- Ensure that the new long options have a relevang short option too.
- Also bring usage message into line with the options actually
- supported. Thanks to Bas van Gompel for noticing this defect.
-
- * locate/locate.1:
- Escape "-" in SYNOPSIS. Thanks to Bas van Gompel for noticing this
- defect.
-
- * ChangeLog: Fixed typos.
-
- * doc/find.texi:
- Documented -execdir, and the "+" variants of -exec and -execdir.
-
- * find/find.1: Documented -execdir.
-
- * xargs/xargs.c:
- Updated to bring into line with bc_*() interface changes
-
- * ChangeLog: Updated with recent changes.
-
- * find/defs.h, find/parser.c, find/pred.c, lib/buildcmd.c, lib/buildcmd.h:
- Implemented -execdir and -okdir
-
- * find/defs.h, find/find.c, find/fstype.c, find/parser.c, find/pred.c, lib/buildcmd.c, lib/buildcmd.h, xargs/xargs.c:
- First working version of -exec ...+
-
-2005-01-09 James Youngman <jay@gnu.org>
-
- * find/defs.h, find/find.c, find/parser.c, find/pred.c, lib/buildcmd.c, lib/buildcmd.h, xargs/xargs.c:
- Initial implementation of -exec ..{} +, but currently disabled since not yet working
-
-2005-01-08 James Youngman <jay@gnu.org>
-
- * find/find.c: Fixed typo in comment.
-
- * find/defs.h, find/find.c, find/parser.c, find/pred.c:
- We now understand but do not implement -execdir (a *BSD invention, and a very useful security enhancement) and -okdir (the obvious companion to it)
-
- * locate/bigram.c, locate/code.c, locate/frcode.c, locate/locate.c, xargs/xargs.c:
- The GNU coding standard requires a space between the function name and
- its parenthesised argument list.
-
- * find/defs.h:
- Understand the -exec ... {} \+ construction (for multiple
- replacement). No support yet.
-
- * locate/locate.1:
- Indicate that empty elements in the dbpath are treated as synonyms for
- the default database.
-
- * locate/locate.c:
- Support empty elements in the dbpath as synonyms for the default
- database. These colons can be leading, trailing or in the middle of
- the string. We no longer com,plain if the user does this.
-
- * lib/nextelem.c:
- If curdir_ok is 0 and an element is empty, return "" instead of NULL
- so that the caller knows to keep calling us.
-
- * find/find.c, find/pred.c, import-gnulib.sh, locate/bigram.c, locate/code.c, locate/frcode.c, locate/locate.c, xargs/xargs.c:
- Savannah bug 11517: find, xargs, locate, etc. should not hide write failures; patch from Jim Meyering
-
- * po/da.po, po/de.po, po/es.po, po/et.po, po/findutils.pot, po/fr.po, po/gl.po, po/id.po, po/it.po, po/ko.po, po/nl.po, po/pl.po, po/pt_BR.po, po/ru.po, po/sk.po, po/sv.po, po/tr.po:
- changed .pot creation date
-
- * THANKS, AUTHORS: Take into account the FSF copyright-assignments list
-
- * doc/find.texi:
- If -quit is used, the exit value can be nonzero if errors have occurred.
-
- * find/find.1:
- Removed incorrect comment about -H, -P and -follow in HISTORY.
-
-2005-01-07 James Youngman <jay@gnu.org>
-
- * lib/Makefile.am, lib/buildcmd.c, lib/buildcmd.h, xargs/xargs.c:
- Refactored xargs to use an external library function from the new file buildcmd.c
-
- * configure.in: no longer the same as the released 4.2.11 version
-
-2005-01-06 James Youngman <jay@gnu.org>
-
- * xargs/testsuite/inputs/lines.xi, xargs/testsuite/xargs.posix/l2.exp, xargs/testsuite/Makefile.am:
- Tests for the -L option
-
- * xargs/testsuite/config/unix.exp: When a test fails, show the diffs
-
- * xargs/testsuite/xargs.posix/l2.exp, xargs/testsuite/xargs.posix/l2.xo:
- tests for the -l option
-
- * xargs/testsuite/Makefile.am: Added extra test files
-
- * xargs/testsuite/xargs.sysv/trace.exp, xargs/testsuite/xargs.sysv/trace.xe, xargs/testsuite/xargs.sysv/trace.xo:
- Added tests for the -t option
-
- * xargs/testsuite/config/unix.exp, xargs/testsuite/inputs/foobar.xi, xargs/testsuite/xargs.gnu/r.exp, xargs/testsuite/xargs.gnu/r.xo, xargs/xargs.1:
- Use a blanks-only input file for cases where there is supposed to be no output
-
- * xargs/testsuite/inputs/blank.xi: Initial version.
-
- * xargs/xargs.1:
- Corrected a typo; also indicate that it's impossible to use xargs
- securely due to the race condition.
-
-2005-01-05 James Youngman <jay@gnu.org>
-
- * find/parser.c:
- Fixed Savannah bug 11495: fallthrough from -printf format processing
- from 'n' case to 'd' case.
-
-2005-01-03 James Youngman <jay@gnu.org>
-
- * doc/find.texi:
- Oops. Had duplicated an entire section. Fortunately this was after
- @bye, so there was no adverse effect.
-
- * NEWS: locate -b.
-
- * doc/find.texi, locate/locate.1: document locate -S
-
- * configure.in, doc/find.texi, locate/locate.1, locate/locate.c:
- Support locate -b as a synonym for locate --basename
-
- * po/da.po, po/de.po, po/es.po, po/et.po, po/findutils.pot, po/fr.po, po/gl.po, po/id.po, po/it.po, po/ko.po, po/nl.po, po/pl.po, po/pt_BR.po, po/ru.po, po/sk.po, po/sv.po, po/tr.po:
- distcheck
-
- * find/testsuite/config/unix.exp:
- Clean up (delete) find.out at at the end of the test.
-
- * NEWS, doc/find.texi, find/defs.h, find/find.1, find/find.c, find/parser.c, find/pred.c:
- Implemented the -samefile test for find
-
-2005-01-02 James Youngman <jay@gnu.org>
-
- * ChangeLog: Updated with recent changes.
-
- * NEWS:
- Bas van Gompel: two-line patch to locate.c to make locate's -i and -w
- options work if -e is in use.
-
- * THANKS: Added Bas van Gompel.
-
- * locate/locate.c:
- Bas van Gompel: (visit_exists) when testing for the existence of the
- file, check the real filename [printname], not the case-converted
- filename [testname]. Really these argument names are badly chosen.
-
- * find/find.1, doc/find.texi:
- Improved the documentation for -perm, with plenty of examples,
- following a comment by Dan Jacobson that the comment "Symbolic modes
- use mode 0 as a point of departure" is baffling and unhelpful.
-
- * locate/locate.c:
- Suggestion and patch from Bas van Gompel: (new_locate): Fix display of
- negative compression ratios.
-
-2004-12-31 James Youngman <jay@gnu.org>
-
- * NEWS: Brought up to date with recent changes
-
- * doc/find.texi:
- Don't need to nest the "race conditions with..." sections so deeply.
-
- * doc/find.texi: Corrected some spelling errors.
-
- * doc/find.texi: Added new "Security Considerations" chapter.
-
-2004-12-23 James Youngman <jay@gnu.org>
-
- * locate/locate.c:
- Applied bugfixes from Bas van Gompel <patch-findutils.buzz@bavag.tmfweb.nl>.
- (lc_strcpy): Zero-terminate result.
- (add_visitor): Update lastinspector.
- (visit_substring_match_casefold): fix off-by-one error.
- (new_locate): Move visit_exists down to improve performance.
- (new_locate): Don't fold case when getting stats.
-
-2004-12-19 James Youngman <jay@gnu.org>
-
- * doc/find.texi:
- Indicate that "cd /; find tmp -wholename /tmp" will never match anything.
-
- * doc/find.texi: Documented locate --statistics.
-
- * locate/locate.1: Documented the --statistics option.
-
- * locate/locate.c: Added support for the -S option.
-
-2004-12-12 James Youngman <jay@gnu.org>
-
- * NEWS: Added a summary of the changes so far.
-
- * find/tree.c: Made some of the error messages more self-explanatory
-
- * find/pred.c: Print pointers with %p, not %x.
-
- * find/find.c: Moved option data into struct options.
-
- * find/find.1: clarifications
-
- * find/testsuite/find.gnu/comma.exp:
- Limit the amount of searching with maxdepth.
-
- * doc/find.texi: clearer description of how -prune works
-
- * ChangeLog: Removed duplicate entry.
-
- * configure.in, find/defs.h, find/find.c, find/fstype.c, find/parser.c, find/pred.c, find/tree.c, find/util.c:
- Separated ariables representing current state from variable representing option information
-
-2004-12-11 James Youngman <jay@gnu.org>
-
- * find/parser.c: Readability improvement to the usage message.
-
- * find/find.c: Oops. Fixed unmatched #endif.
-
- * find/testsuite/find.gnu/printf.exp, find/testsuite/find.gnu/printf.xo, THANKS, configure.in, find/testsuite/Makefile.am, find/testsuite/config/unix.exp:
- Fixed Savannah bug #11280
-
- * find/find.c:
- Remember to set path_length and curdepth in process_top_path().
-
-2004-12-07 James Youngman <jay@gnu.org>
-
- * find/fstype.c: Use xstat() not stat() to examine things.
-
- * find/find.c: Explain why #ifdef EOVERFLOW.
-
- * find/find.c: EOVERFLOW is not defined on UNICOS.
-
- * NEWS: Corrected typo.
-
-2004-12-06 James Youngman <jay@gnu.org>
-
- * ChangeLog: Brought up to date.
-
- * NEWS, configure.in: releasing 4.2.10
-
- * po/da.po, po/de.po, po/es.po, po/et.po, po/findutils.pot, po/fr.po, po/gl.po, po/id.po, po/it.po, po/ko.po, po/nl.po, po/pl.po, po/pt_BR.po, po/ru.po, po/sk.po, po/sv.po, po/tr.po:
- distcheck
-
- * ChangeLog: Updated prior to release of finsutils-4.2.10.
-
- * import-gnulib.sh, find/fstype.c:
- Use gnulib's mountlist module instead of grokking it ourselves.
-
- * configure.in:
- Removed all the out-of-date cruft for grokking getmntent().
-
- * xargs/xargs.c:
- Added the -I and -L options; also -E takes an argument which is not optional.
-
-2004-12-05 James Youngman <jay@gnu.org>
-
- * README, configure.in, find/defs.h, find/find.c, find/parser.c, find/pred.c, find/tree.c:
- Allow debug output to be turned on or off by saying --enable-debug on the configure command line
-
- * README:
- Removed disparaging (it is now, it probably wasn't then) comment about
- the production-readiness of Automake.
-
- * README: Qualify remarks about POSIX compliance.
-
- * NEWS, configure.in: Preparation for release 4.2.9
-
- * po/da.po, po/de.po, po/es.po, po/et.po, po/findutils.pot, po/fr.po, po/gl.po, po/id.po, po/it.po, po/ko.po, po/nl.po, po/pl.po, po/pt_BR.po, po/ru.po, po/sk.po, po/sv.po, po/tr.po:
- distcheck
-
- * ChangeLog: Brought up to date.
-
- * find/find.c:
- Avoid duplicate error message when we cannot chdir() into a subdirectory.
-
- * THANKS: Added recent thankees.
-
- * NEWS:
- Brought up to date with respect to the current set of fixed bugs.
-
- * NEWS, xargs/xargs.1, xargs/xargs.c:
- Implemented POSIX options -L, -I and -E
-
-2004-12-03 James Youngman <jay@gnu.org>
-
- * find/parser.c:
- -xdev is an option, not a test. Fixes Savannah bug 11192.
-
- * find/find.1, xargs/xargs.1:
- Escape dashes with a backslash (for fix Savannah bug 11189).
-
-2004-11-27 James Youngman <jay@gnu.org>
-
- * find/find.c:
- More use of safely_chdir(). Also bugfix: -L should imply -noleaf. Be more careful about when xstat should fall back on lstat() when stat() fails.
-
- * find/find.1: "necessary" only has one "C".
-
- * find/find.1:
- If stat() fails with ELOOP, we issue a diagnostic message.
-
-2004-11-26 James Youngman <jay@gnu.org>
-
- * find/find.c: Removed some unused code.
-
- * Makefile.am: Don't do anything in the 'intl' subdirectory
-
- * find/find.c:
- Enhanced safely_chdir() to the point where the test suite passes, and report infinite loops in the directory hierarchy
-
- * find/defs.h:
- belt and braces; ensure that SYMLINK_NEVER_DEREF has value zero
-
- * find/find.1:
- Describe our strategy for detecting and reporting infinite loops
-
-2004-11-24 James Youngman <jay@gnu.org>
-
- * doc/find.texi:
- Updated the discussion of th error messages for findutils-4.2.8.
-
- * configure.in: Next version will be 4.2.9...
-
- * find/find.c:
- Don't issue a warning if we notice the mounting of a filesystem that's
- likely just to be an automounter.
-
- * doc/find.texi, find/find.1:
- Explain how rounding is performed for -atime and friends.
-
- * xargs/xargs.c:
- Once we collect enough arguments (for the value specified by the -n
- option) to do an exec(), do it immediaely instead of waiting for the
- next one to arrive. This fixes Savannah bug #7340.
-
- * ChangeLog, configure.in, NEWS: Prepare to release 4.2.8.
-
- * NEWS: Updates for 4.2.8.
-
- * configure.in: check for sys/types.h
-
- * find/find.c:
- If wd_sanity_check() discovers that the mount table has changed, remember the updated device number and inode so that we also consider these to be valid on the way back up.
-
- * find/defs.h:
- Declarations of xmalloc() and friends belong in xalloc.h, not in defs.h
-
- * find/parser.c: avoid signed/unsigned warning, and #include xalloc.h
-
- * find/fstype.c:
- Changed to alloc get_mounted_devices() to compile on Solaris
-
- * README-CVS:
- Automake requires GNU m4, so point out that the reader needs that.
-
- * find/defs.h, find/find.c, find/fstype.c:
- When wd_sanity_check() fails, enumerate the mounted devices, rather than the mounted filesystem names
-
- * NEWS: prepare for 4.2.8
-
- * configure.in:
- Look for some Solaris headers which are used by get_mounted_devices()
-
- * lib/Makefile.am: don't build savedirtypes yet
-
- * po/da.po, po/de.po, po/es.po, po/et.po, po/findutils.pot, po/fr.po, po/gl.po, po/id.po, po/it.po, po/ko.po, po/nl.po, po/pl.po, po/pt_BR.po, po/ru.po, po/sk.po, po/sv.po, po/tr.po:
- updated po files
-
- * m4/nullsort.m4:
- Avoid suprious output of the test data when the tests fail.
-
-2004-11-21 James Youngman <jay@gnu.org>
-
- * po/da.po, po/de.po, po/es.po, po/et.po, po/findutils.pot, po/fr.po, po/gl.po, po/id.po, po/it.po, po/ko.po, po/nl.po, po/pl.po, po/pt_BR.po, po/ru.po, po/sk.po, po/sv.po, po/tr.po:
- Messages changed again
-
- * ChangeLog, configure.in: Preparing to release 4.2.7.
-
- * NEWS: Updated for release of 4.2.7.
-
- * import-gnulib.sh: Also need canonicalize module.
-
- * find/find.c:
- When checking to see if a filesystem has changed state, use an
- absolute pathname.
-
- * configure.in:
- No need to pause to allow James to view his handiwork, it (allegedly)
- works now.
-
- * configure.in:
- Oops. Check for setlocale() to re-enable the i18n support which was
- accidentally disabled in 4.2.5.
-
- * find/find.c:
- Check to see if the new directory is a transitioned mount point by
- using its ABSOLUTE name, if we can figure it out.
-
- * doc/find.texi:
- Added guidance on some of the error messages. Not the most common
- ones, but the ones where the user might most benefit from some handy
- hints or an explanation of what is going on.
-
- * find/pred.c:
- Actually emit an error message if we fail to stat a symlink (for
- reasons other than nonexistence of the link and infinite loop).
-
- * doc/texinfo.tex: Updated texinfo.tex
-
- * NEWS, configure.in, find/find.c, find/fstype.c:
- Enable the 'Warning: filesystem XXX has recently been mounted' check on Solaris, which prevents it exiting fatally when traversing an automount mount point
-
- * po/da.po, po/de.po, po/es.po, po/et.po, po/findutils.pot, po/fr.po, po/gl.po, po/id.po, po/it.po, po/ko.po, po/nl.po, po/pl.po, po/pt_BR.po, po/ru.po, po/sk.po, po/sv.po, po/tr.po:
- messages changed again
-
- * NEWS: Implemented xargs --arg-file.
-
- * doc/find.texi, xargs/xargs.1, xargs/xargs.c, NEWS:
- Implemented xargs --arg-file
-
- * find/find.c:
- Where a filesystem was recently (un)mounted, try togive its full name
-
- * configure.in:
- Try to avoid requesting -lsun if we don't seem to need it (e.g. on
- UNICOS where it is not present and trying to link against it produces
- a warning).
-
- * find/defs.h, lib/modetype.h: Guard against multiple inclusion
-
- * find/fstype.c:
- We now need <mntent.h> even if we are not using getmntent() to figure
- out the type of a filesystem, because wd_sanity_check() needs to
- enumerate the system mount points.
-
- * configure.in: Next release will be 4.2.7.
-
- * find/fstype.c:
- get_mounted_filesystems() should use getmntent() if that function is
- present, rather than just if configure didn't find anything better for
- filesystem_type_uncached() to use than that.
-
- * find/parser.c:
- If -delete is the only action on a file, don't assume the default
- -print action too.
-
- * ChangeLog, configure.in, po/da.po, po/de.po, po/es.po, po/et.po, po/findutils.pot, po/fr.po, po/gl.po, po/id.po, po/it.po, po/ko.po, po/nl.po, po/pl.po, po/pt_BR.po, po/ru.po, po/sk.po, po/sv.po, po/tr.po:
- Preparation to release findutils-4.2.6.
-
- * find/Makefile.am, xargs/Makefile.am:
- Enable checking of support for --version and --help
-
- * locate/Makefile.am:
- Con't check command-line options for frcode, code or bigram
-
- * locate/code.c: Support --version and --help.
-
- * ChangeLog: *** empty log message ***
-
- * find/defs.h, find/find.c, find/fstype.c, lib/Makefile.am, lib/extendbuf.c, lib/extendbuf.h, NEWS:
- Avoid fatal error if automount mounts a filesystem on a directory because we chdir()ed into it
-
- * configure.in: Next release will be 4.2.6.
-
- * find/find.1:
- Indicate that the '-' flag does work for most fields. Also provide
- an example of using the comma operator to traverse the filesystem just
- once but search for more than one thing.
-
- * doc/find.texi: Indicate that the '-' flag does work for most fields.
-
-2004-11-19 James Youngman <jay@gnu.org>
-
- * configure.in: releaseing findutils-4.2.5
-
- * find/testsuite/Makefile.am, locate/testsuite/Makefile.am, xargs/testsuite/Makefile.am:
- If a directory has no Makefile.am, omit it from the parent's DIST_SUBDIRS - automake-1.9 requires this
-
- * po/da.po, po/de.po, po/es.po, po/et.po, po/findutils.pot, po/fr.po, po/gl.po, po/id.po, po/it.po, po/ko.po, po/nl.po, po/pl.po, po/pt_BR.po, po/ru.po, po/sk.po, po/sv.po, po/tr.po:
- updated by make distcheck
-
- * ChangeLog, NEWS: Updated for release 4.2.5.
-
- * find/find.1, doc/find.texi:
- Tell the reader that format flags may not work as they expect.
-
- * configure.in:
- Use the correct name for the macro gl_AC_TYPE_LONG_LONG (not
- jm_AC_TYPE_LONG_LONG).
-
-2004-11-15 James Youngman <jay@gnu.org>
-
- * import-gnulib.sh:
- Avoid test -e because not all systems are POSIX-compliant (bug
- #11005). Also don't need regex module any more if we're not building
- in intl.
-
- * Makefile.am, configure.in:
- These days gnulib likes to include 'libintl.h' which our very old intl/ directory lacks. For the moment, disable use of the internal intl/ directory
-
- * doc/find.texi:
- Use @ref not @xref for a reference at the beginning of a sentence.
-
- * intl/Makefile.in:
- Make sure gnulib.lib is on the #include path (Savannah bug #11002)
-
- * locate/locate.c:
- Use base_name instead of basename - fixes Savannah bug 11003.
-
- * configure.in, find/defs.h, find/find.c, find/parser.c, find/pred.c, locate/bigram.c, locate/locate.c:
- Don't need banner to emphasise the location of the call to jy_SORTZ
-
-2004-11-12 James Youngman <jay@gnu.org>
-
- * NEWS, doc/find.texi, find/defs.h, find/find.1, find/find.c, find/parser.c, find/pred.c, find/testsuite/find.gnu/posix-dflt.exp, find/testsuite/find.gnu/posix-dflt.xo, find/testsuite/find.gnu/posix-h.exp, find/testsuite/find.gnu/posix-h.xo, find/testsuite/find.gnu/posix-l.exp, find/testsuite/find.gnu/posix-l.xo, find/util.c:
- Implemented BSD option -P and also the correct default behaviour of find with respect to symlinks if neither -L nor -H is specified [i.e. same as -P]
-
-2004-11-11 James Youngman <jay@gnu.org>
-
- * NEWS, doc/find.texi, find/defs.h, find/find.1, find/find.c, find/parser.c:
- Implemented -H and -L options.
-
- * find/util.c: Added in the -H and -L options on the usage message.
-
-2004-11-10 James Youngman <jay@gnu.org>
-
- * doc/find.texi, find/find.1, find/parser.c, find/pred.c:
- Implemented %M and %A+ format specifiers
-
- * doc/find.texi, find/find.1, find/parser.c, find/pred.c:
- Documented the fact that only %d and %m format specifiers honour the various formatting flags
-
- * xargs/xargs.c:
- Get the right number of bytes in a Kilobyte (hint: it's not 1048; that
- was a typo, honest :)
-
- * po/pl.po: Applied Polish translations
-
-2004-11-08 James Youngman <jay@gnu.org>
-
- * po/da.po, po/de.po, po/es.po, po/et.po, po/findutils.pot, po/fr.po, po/gl.po, po/id.po, po/it.po, po/ko.po, po/nl.po, po/pl.po, po/pt_BR.po, po/ru.po, po/sk.po, po/sv.po, po/tr.po:
- distcheck changed the po files again
-
- * locate/Makefile.am:
- Make install-data-hook honour the setting of DESTDIR so that "make
- DESTDIR=/tmp/foo install" works and puts localstater in the right
- place.
-
- * configure.in: We're now working on findutils-4.2.5.
-
- * doc/find.texi, xargs/xargs.1:
- Point out that xargs -i only splits input items at newlines
-
- * ChangeLog: Indicate that we released 4.2.4.
-
- * ChangeLog: Updated for release 4.2.4
-
- * NEWS, configure.in: Prepare for release of 4.2.4.
-
- * NEWS: Brought up to date with latest changes.
-
- * NEWS, doc/find.texi, find/defs.h, find/find.1, find/find.c, find/parser.c, po/da.po, po/de.po, po/es.po, po/findutils.pot, po/gl.po, po/id.po, po/ko.po, po/pl.po, po/pt_BR.po, po/ru.po, po/sv.po:
- Turn warning messages off by default if stdin is not a tty; allow these to be controlled explicitly by options -warn and -nowarn
-
- * po/et.po, po/it.po: Updated translation files
-
- * po/sk.po: New translation file
-
- * po/fr.po, po/nl.po, po/tr.po: Updated translation files
-
- * configure.in: Added Slovak (sk) language.
-
- * xargs/xargs.c:
- Enforcing a lower limit on the value specified by -s makes the test
- suite fail. Removed that lower limit.
-
- * locate/Makefile.am: Oops, multilocate doesn't exist yet.
-
- * NEWS: *** empty log message ***
-
- * doc/find.texi, locate/updatedb.1, locate/updatedb.sh:
- Added option --findoptions to updatedb
-
- * locate/Makefile.am, locate/locatedb.5, locate/updatedb.1, xargs/xargs.1:
- Fixed section numbers in manpage titles and cross-references
-
- * NEWS, doc/find.texi, xargs/xargs.1, xargs/xargs.c:
- Increased the default argument length and improved POSIX compliance of the handling of out-of-range values for the -s option
-
-2004-11-07 James Youngman <jay@gnu.org>
-
- * m4/Makefile.am:
- Added in the extra files we need to distribute, nullsort.m4
- order-bad.bin order-good.bin
-
- * doc/find.texi: Documented locate's --limit option
-
- * locate/locate.1, locate/locate.c:
- Implmented --limit and corrected the implementation of the -i option.
-
-2004-11-06 James Youngman <jay@gnu.org>
-
- * NEWS, doc/find.texi, locate/locate.1:
- Documented --wholename and --basename and updated the NEWS file
-
- * README-CVS:
- Give the autogen commands in a form that you can usefully cut and paste into a shell
-
- * NEWS: Options --null and --count) for locate
-
- * lib/nextelem.c:
- Don't return '.' for an empty path element, because the path we are splitting may not be intended to contain directories
-
- * configure.in: we're working on findutils-4.2.4 now
-
- * locate/Makefile.am: Substitute @SORT_SUPPORTS_Z@
-
- * doc/find.texi:
- Documented new locate option --null and newline handling
-
- * locate/locate.1, locate/locate.c:
- New locate options --null, --wholename, --basename, --count
-
- * locate/frcode.c, locate/updatedb.1, locate/updatedb.sh:
- correctly handle newlines in the file names
-
- * configure.in: Determine if sort -z works
-
- * m4/nullsort.m4, m4/order-bad.bin, m4/order-good.bin:
- jy_SORTZ: a macro to determine if the system has a sort command with a working -z option
-
-2004-11-01 James Youngman <jay@gnu.org>
-
- * NEWS: Fixed "find -printf '%H\n'".
-
- * find/find.c:
- Avoid segfault if -printf %H is used where the matched file was the default, unspecified starting point, the current directory
-
-2004-10-31 James Youngman <jay@gnu.org>
-
- * find/find.1, find/parser.c: NetBSD also supports -d.
-
- * find/find.1, doc/find.texi:
- Documented the behaviour of -daystart and -follow in more detail
-
- * find/parser.c: Corrected the usage message.
-
- * find/parser.c:
- When deciding whether to issue a warning about options following
- non-options, ignore any options whose position affects the tests
- (i.e. -daystart and -follow).
-
- * find/parser.c: -daystart is a positional option like -follow.
-
- * find/parser.c:
- Issue a warning message if an option is specified after a test or an
- action (because the user might have believed that the behaviour of the
- option is in some way conditional on the preceding tests).
-
- * locate/updatedb.sh:
- Oops; removed some test code that I shouldn't have checked in.
-
- * locate/updatedb.sh:
- Indicate that the old locate database format will shortly be unsupported.
-
- * doc/find.texi:
- Use @direntry instead of hard-coding START-INFO-DIR-ENTRY inside @ifinfo.
-
- * locate/updatedb.1: Updated default location of locatedb file.
-
- * README-alpha:
- Updated to give correct FTP location and to not talk about "test"
- versions of automake, which are no longer required.
-
- * locate/updatedb.sh:
- Incorporated the default list of filesystems to avoid from the Debian
- package. Also added /afs and /sfs to the default pruned paths.
-
- * configure.in: Released findutils 4.2.3
-
- * po/da.po, po/de.po, po/es.po, po/et.po, po/findutils.pot, po/fr.po, po/gl.po, po/id.po, po/it.po, po/ko.po, po/nl.po, po/pl.po, po/pt_BR.po, po/ru.po, po/sv.po, po/tr.po:
- did make distcheck, which updates these files
-
- * find/defs.h, find/fstype.c:
- Use const qualifier in arguments to filesystem_type() to allow callers with const variables to use them
-
- * ChangeLog: Updated.
-
- * NEWS: Added new news.
-
- * find/find.c:
- Extra diagnositcs for the case where we have the error "%s changed
- during execution of %s" - that is when we chdir back to the parent
- directory only to find that it has changed.
-
-2004-10-30 James Youngman <jay@gnu.org>
-
- * .cvsignore, NEWS, doc/find.texi, find/defs.h, find/find.1, find/parser.c, find/pred.c:
- Implemented the -quit action
-
- * NEWS, doc/find.texi, find/find.1, find/parser.c, find/pred.c:
- Refactored time handling routines in preparation for support of absolute timestamp comparison predicates
-
- * locate/locate.c:
- Applied Savannah patch #2952 ("getline off-by-one bugfix").
-
- * NEWS, doc/find.texi, find/defs.h, find/find.1, find/parser.c, find/pred.c:
- Added -delete action (Savannah patch #3454 with additions)
-
- * locate/locate.c:
- Applied Savannah patch #2692 (allowing get_short to process negative integers).
-
- * find/find.c:
- If we are iossuing an error message because $FIND_BLOCK_SIZE is set,
- ignore the setting of errno.
-
- * find/parser.c: More fixes for pedantic compiler warnings
-
- * NEWS, find/parser.c, find/tree.c: Eliminated some compiler warnings
-
- * find/find.c, find/parser.c, find/pred.c:
- Various fixes for compiler warninga sbout unreachable code or unused function arguments
-
- * intl/plural.y: Silence compiler warning about unused argument.
-
- * locate/testsuite/Makefile.am:
- Subdirectory "inputs" does not exist, so remove it from DIST_SUBDIRS.
-
- * locate/locate.c:
- Corrected the explanation of why we have to use no parentheses around
- the String argument to the N_ macro in its expansion.
-
- * configure.in: Nextr release is 4.2.3.
-
- * configure.in: IOndicate this is no longer the pristine release.
-
- * NEWS:
- Oops, comments for release 4.2.0 should have said 20480 bytes, not 2480.
-
- * lib/listfile.c:
- The -ls predicate should not truncate usernames. Fixes Savannah bug #10800.
-
- * find/fstype.c, locate/locate.c:
- Fixes for Savannah bug #3727 (Intel icc compilation errors).
-
-2004-10-25 James Youngman <jay@gnu.org>
-
- * doc/find.texi, find/find.1, find/parser.c, find/pred.c:
- Support -printf %D, which prints the device number of the containing filesystem
-
- * locate/updatedb.sh:
- Avoid confusion between James Woods and James Youngman, by using the
- disambiguating surname.
-
- * find/parser.c: Use RE_ICASE instead of re->translate.
-
- * configure.in, find/parser.c, find/pred.c, xargs/xargs.c:
- No need to #define _GNU_SOURCE if we use gl_INIT.
-
-2004-10-24 James Youngman <jay@gnu.org>
-
- * ChangeLog: Prepared to release findutils-4.2.2.
-
- * ChangeLog, NEWS, po/da.po, po/de.po, po/es.po, po/et.po, po/findutils.pot, po/fr.po, po/gl.po, po/id.po, po/it.po, po/ko.po, po/nl.po, po/pl.po, po/pt_BR.po, po/ru.po, po/sv.po, po/tr.po:
- Updates prior to release of 4.2.2
-
- * NEWS: Updated with news for findutils-4.2.2.
-
- * find/testsuite/config/unix.exp, lib/forcefindlib.c, lib/listfile.c, lib/modetype.h, lib/nextelem.c, locate/bigram.c, locate/code.c, locate/frcode.c, locate/locate.c, locate/locatedb.h, locate/testsuite/config/unix.exp, locate/updatedb.sh, xargs/testsuite/config/unix.exp, xargs/xargs.c, NEWS, find/defs.h, find/find.c, find/fstype.c, find/parser.c, find/pred.c, find/tree.c, find/util.c, import-gnulib.sh:
- Corrected typo in the address of the FSF office
-
- * lib/strspn.c: Updated FSF address.
-
- * m4/.cvsignore: 'cvs status' should ignore Makefile.in
-
- * m4/Makefile.am, Makefile.am, NEWS, README-CVS, configure.in, doc/texinfo.tex, find/defs.h, find/fstype.c, find/parser.c, find/pred.c, import-gnulib.sh, intl/bindtextdom.c, intl/dcgettext.c, intl/dcigettext.c, intl/dcngettext.c, intl/dgettext.c, intl/dngettext.c, intl/explodename.c, intl/finddomain.c, intl/gettext.c, intl/intl-compat.c, intl/l10nflist.c, intl/loadmsgcat.c, intl/localcharset.c, intl/localealias.c, intl/ngettext.c, intl/plural.y, intl/textdomain.c, lib/Makefile.am, lib/forcefindlib.c, lib/listfile.c, lib/nextelem.c, lib/strspn.c, lib/waitpid.c, locate/bigram.c, locate/code.c, locate/frcode.c, locate/locate.c, m4/findlib.m4, po/da.po, po/de.po, po/es.po, po/et.po, po/findutils.pot, po/fr.po, po/gl.po, po/id.po, po/it.po, po/ko.po, po/nl.po, po/pl.po, po/pt_BR.po, po/ru.po, po/sv.po, po/tr.po, xargs/xargs.c:
- Use gnulib-tool --import to import the gnulib code, rather than the odd way we were doing it before
-
- * find/find.c, find/fstype.c, find/parser.c, find/pred.c, find/tree.c, find/util.c, locate/code.c, locate/locate.c, xargs/xargs.c:
- Work round an apparent compiler bug in HP-UX 11.23 for
- ia64
-
- * locate/locate.c:
- Work around what appears to be a C compiler bug in HP-UX 11.23 for
- ia64.
-
- * INSTALL, depcomp, install-sh, missing, mkinstalldirs:
- Updated from automake
-
- * locate/bigram.c, locate/code.c, locate/frcode.c, locate/locate.c, xargs/xargs.c, find/find.c:
- Avoid use of exit() within main, to silence warnings about unreachable code
-
-2004-10-22 James Youngman <jay@gnu.org>
-
- * doc/find.texi: Syntax corrections.
-
- * doc/find.texi: Indicate that "-exec {}+" is not yet supported.
-
- * find/find.1: Indicate that "{}+" is not yet supported.
-
- * find/testsuite/find.gnu/name-period.xo, find/testsuite/find.gnu/name-period.exp, find/find.1, doc/find.texi:
- The -name predicate must allow '*' to match '.foo' as demanded by IEEE
- Std 1003.2-1992 Interpretation #126.
-
- * find/pred.c:
- Remove use of FNM_PERIOD for -name as demanded by IEEE Std 1003.2-1992
- Interpretation #126
-
- * find/parser.c: Fix for compilation (on AIX 4.3) with GCC 2.x.
-
- * xargs/xargs.c:
- Changed the erorr message issued when there is an unmatched quote to
- point out that the user might have wanted to use the -0 option instead.
-
-2004-10-17 James Youngman <jay@gnu.org>
-
- * configure.in:
- Define intmax_t if it is not already defined - allows parser.c to compile on AIX 4.3
-
- * configure.in:
- Adjust version number to indicate that this s/w has moved on since the
- 4.2.1 release.
-
- * configure.in: preparing to release 4.2.1
-
- * ChangeLog: updated with current changes
-
- * README-CVS: Updated to go with newer version of gnulib.
-
- * po/da.po, po/de.po, po/es.po, po/et.po, po/findutils.pot, po/fr.po, po/gl.po, po/id.po, po/it.po, po/ko.po, po/nl.po, po/pl.po, po/pt_BR.po, po/ru.po, po/sv.po, po/tr.po:
- preparation for release
-
- * NEWS: Mention the changes to "trap".
-
- * NEWS: Brought up to date.
-
- * import-gnulib.sh:
- Use xalloc-die module from gnulib, since that has now been split out
-
- * find/parser.c:
- Check fnmatch() when other predicates that rely on fnmatch() are used.
-
- * find/parser.c: bug #10701: find needs fnmatch sanitycheck on startup
-
-2004-10-16 James Youngman <jay@gnu.org>
-
- * import-gnulib.sh:
- Switch to requirement for GNU fnmatch because it supports FNM_CASEFOLD.
-
- * locate/updatedb.sh:
- Bug #9465: use of signal numbers for 'trap' is deprecated. Should use
- names instead. See
- http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html,
- which indicates that support for signal numbers is optional, while
- support for signal names is mandatory.
-
- * configure.in:
- Indicate that this is the CVS version (once again) now that findutils
- 4.2.0 has been released.
-
- * ChangeLog, configure.in, po/da.po, po/de.po, po/es.po, po/et.po, po/findutils.pot, po/fr.po, po/gl.po, po/id.po, po/it.po, po/ko.po, po/nl.po, po/pl.po, po/pt_BR.po, po/ru.po, po/sv.po, po/tr.po:
- findutils 4.1.20 check-in for tagging
-
-2004-10-02 James Youngman <jay@gnu.org>
-
- * po/Makefile.in.in:
- Search in $(top_srcdir) for mkinstalldirs, since that's where we keep it.
-
- * NEWS: Brought up to date, organised more clearly, and tidied up.
-
- * NEWS: brought up to date with recent changes
-
- * locate/testsuite/config/unix.exp, locate/testsuite/locate.gnu/ignore_case1.exp, locate/testsuite/locate.gnu/ignore_case3.exp, locate/updatedb.sh:
- Added new option --changecwd to updatedb so that the 'cd /' which it does can be compatible with the requirements of the test suite. Specifically, the test suite relies on being able to use relative pathnames
-
- * find/pred.c:
- Fixed usage of human_readable() in '%k' format specifier to fix a bug
- reported by Dmitry V. Levin (arguments to human_readable() were
- specified in the wrong order, which resulted in a floating-point
- error).
-
-2004-08-08 James Youngman <jay@gnu.org>
-
- * locate/updatedb.sh:
- cd to / to avoid inability to examine the current directory if we're
- invoked via cron (and hence in root's home directory for example).
-
- * doc/find.texi, find/find.1:
- Deprecate -path and -ipath in favour of -wholename and -iwholename
-
- * find/parser.c:
- As per RMS's suggestion, deprecate -path and -ipath in favour of
- -wholename and -iwholename.
-
- * locate/locate.c:
- Fixed Savannah bug #9923, in which get_short() returns large positive
- ints when it should be returning negative shorts.
-
- * xargs/xargs.1:
- Applied documentation improvements suggested by Dan Jacobson
- <jidanni@jidanni.org>.
-
- * xargs/xargs.c:
- Don't check size_of_environment against arg_max since that causes the
- test suite to fail.
-
- * xargs/xargs.1, xargs/xargs.c: Better documentation for the -i option
-
-2004-05-03 James Youngman <jay@gnu.org>
-
- * find/find.1:
- document the various suffixes for -size and also the new
- option -ignore_readdir_race
-
- * locate/locate.c:
- Fixes Savannah bug #8623 (failure to check consistency of data
- read from locate database)
-
- * locate/updatedb.sh:
- Resolves Savannah bug 4380, that updatedb generates an empty
- database if one of the commands fails
-
- * NEWS: Talk about -ignore_readdir_race
-
- * doc/find.texi:
- Documented -ignore_readdir_race and -noignore_readdir_race
-
- * find/find.c:
- -ignore_readdir_race should have no effect if the reason for the
- failure of stat(2) was anything other than ENOENT.
-
- * find/defs.h, find/find.c, find/parser.c:
- Fixed Savannah bug 4391 (readdir race condition leading to
- spurious error messages)
-
-2004-04-24 James Youngman <jay@gnu.org>
-
- * README-CVS: Corrected the instructions for getting gnulib via CVS.
-
-2004-04-13 James Youngman <jay@gnu.org>
-
- * doc/find.texi:
- Actioned Savannah bug #8558 (find complains when it tries to recurse
- into directories that it had removed).
-
-2004-03-13 James Youngman <jay@gnu.org>
-
- * ChangeLog: Updated from checkin comments.
-
- * find/find.c:
- Oops, there is no access to the predicate name table if DEBUG is
- not #defined.
-
- * find/parser.c:
- Detect arithmetic overflow (poorly) in insert_time(), which diagnoses
- the failure to handle large arguments to -mtime. The existing code
- does careful computation and then bungs the value into a time_t, which
- ruins all our careful effort. The new code is not a great
- improvement. We just check the result to detect overflow, rather than
- actually avoiding the overflow.
-
- * find/find.c:
- Fixed Debian bug #185202 by checking for any trailing predicates after
- the top-level invocation of get_expr() has done its work.
-
- * locate/locate.1, xargs/xargs.1:
- Fixed Debian bug 175372, inappropriate 'L' suffixes on manual
- page section indicators
-
- * find/find.1:
- Removed "L" suffixes from manual page section indicators, to fix
- Debian bug 175372.
-
- * debian/updatedb.conf:
- Updated with list of filesystems from current Debian release. This
- includes devfs, for example.
-
- * xargs/xargs.1:
- Modified documentation of "-s" option to take into account the fix for
- Debian bug #176201.
-
- * xargs/xargs.c:
- Fixed Debian bug #176201, "xargs enviroment size limited to 20k", by
- reading a patch offered by Bob Proulx and implementing something
- substantially similar myself.
-
-2004-01-03 James Youngman <jay@gnu.org>
-
- * xargs/xargs.c:
- Indicate that prep_child_for_exec() fixes Savannah bug #3992.
-
- * xargs/xargs.c:
- Attach the stdin of xargs' child process to /dev/null so that if it
- tries to read from its stdin it doesn't consume any of the list of
- files that xargs is trying to use.
-
- * find/find.1:
- Documented that the -regex option follows Gnulib's re_match()
- implementation.
-
- * NEWS, locate/locate.c: Applied Savannah patch 2108
-
- * xargs/xargs.c: Applied Savannah patch 1500
-
- * find/find.1, doc/find.texi:
- Improved the documentation for the %k and %b format specifiers to
- -printf (Savannah bug #5034). Also pointed out that this handling is
- different to that used by the "b" and "k" suffixes with "-size".
-
- * find/find.1: Improved the documentation for %k (Savannah bug #5034).
-
- * find/find.1:
- Improved the documentation for -print0 in the manpage, fixing Debian
- bug 111143.
-
- * README-CVS, find/pred.c, lib/listfile.c:
- Brought up-to-date with change in gnulib's human.c - we no longer
- use human_readable_inexact(), because it is no longer provided.
-
-2003-08-08 James Youngman <jay@gnu.org>
-
- * find/find.1:
- Documented the fact that -printf also supports the '\0' escape code.
- Added "STANDARDS CONFORMANCE" section.
-
-2003-08-02 James Youngman <jay@gnu.org>
-
- * find/find.1:
- Explain that braces are not special when performing filename matching
- with -name.
-
- * find/find.1:
- added example of the use of -exec to the EXAMPLES section
-
- * find/fstype.c, locate/locate.c:
- Savannah bug #4295 - implicit declarations of ctype.h functions
-
- * locate/locate.c:
- Savannah bug #4279 - missing newline on locate help message
-
- * find/find.1, xargs/xargs.1:
- Improved discussion of the -print0 option of find and the -0 option of xargs
-
-2003-06-26 James Youngman <jay@gnu.org>
-
- * import-gnulib.sh:
- Remove reference to nonexistent module "basename" ("dirname" exists
- and we already use that).
-
-2003-06-21 James Youngman <jay@gnu.org>
-
- * doc/find.texi:
- Indicate that xargs stops immediately if a command exits with status 255
-
- * xargs/xargs.1:
- Document the fact that xargs exits immediately with an error message
- if the command it executes exits with a status of 255.
-
-2003-06-18 James Youngman <jay@gnu.org>
-
- * find/find.1:
- Indicate that -fls and friends always create their output file
-
-2003-06-16 James Youngman <jay@gnu.org>
-
- * ChangeLog, find/find.1, locate/locate.1, locate/locatedb.5, locate/updatedb.1, xargs/xargs.1:
- Added BUGS section to manual pages. This section includes information about known bugs and how to report new bugs.
-
- * AUTHORS: Identify the current maintainer.
-
- * TODO: Removed the TODO items which have now been done.
-
- * THANKS: Added Bruno Haible and Bob Proulx.
-
- * xargs/xargs.c: xargs/xargs.c (DO_MULTIBYTE): New macro.
- (mbstrstr): New function.
- (do_insert): Use it instead of strstr.
-
- * config.guess, config.sub:
- Use config.guess and config.sub from automake
-
- * find/fstype.c:
- Bruno Haible: (fstype_to_string) Don't define this function if
- HAVE_F_FSTYPENAME_IN_STATFS is defined.
-
- * configure.in:
- Bruno Haible: Prefer the 4.4BSD API (if present) to the 4.3BSD API,
- because some 4.4BSD systems have <mntent.h> but no /etc/mtab file.
-
- * doc/find.texi, find/find.1:
- Applied patch 1498 (documenting the backslash escape sequence)
-
- * locate/updatedb.sh: Applied (my own version of) Savannah patch 1601.
-
- * doc/find.texi:
- Applied Savannah patch #1547 (document the fact that printf
- field-width specifiers are supported).
-
- * xargs/xargs.c:
- Applied Savannah patch #1499 (adds final newline to usage message).
-
-2003-06-14 James Youngman <jay@gnu.org>
-
- * NEWS, configure.in:
- Updated version number to 4.2.0-CVS [not ready for release yet]
-
- * configure.in, doc/.cvsignore, doc/Makefile.in, find/.cvsignore, find/Makefile.am, find/Makefile.in, find/defs.h, find/find.c, find/fstype.c, find/parser.c, find/pred.c, find/testsuite/.cvsignore, find/testsuite/Makefile.in, find/testsuite/config/unix.exp, find/tree.c, find/util.c, import-gnulib.sh, intl/bindtextdom.c, intl/dcgettext.c, intl/dcigettext.c, intl/dcngettext.c, intl/dgettext.c, intl/dngettext.c, intl/explodename.c, intl/finddomain.c, intl/gettext.c, intl/intl-compat.c, intl/l10nflist.c, intl/loadmsgcat.c, intl/localcharset.c, intl/localealias.c, intl/ngettext.c, intl/plural.y, intl/textdomain.c, lib/.cvsignore
- also need stpcpy (e.g. for Solaris)
-
- * intl/dcigettext.c:
- plural_lookup: don't use a variable called "index", because we may
- have done "#define strchr index", in which case using a variable
- called index will prevent us calling strchr(p, ch) in the same scope.
-
- * find/defs.h, find/find.c, find/fstype.c, find/parser.c, find/pred.c, find/testsuite/config/unix.exp, find/tree.c, find/util.c, import-gnulib.sh, lib/Makefile.am, lib/listfile.c, lib/modetype.h, lib/nextelem.c, locate/bigram.c, locate/code.c, locate/frcode.c, locate/locate.c, locate/locatedb.h, locate/testsuite/config/unix.exp, locate/updatedb.sh, xargs/testsuite/config/unix.exp, xargs/xargs.c:
- Updated copyright years and the address of the FSF
-
- * aclocal.m4, config.h.in, configure:
- Removed files that are generated from other files (e.g. configure)
-
- * NEWS: Updated NEWS file for 4.1.20.
-
- * configure.in, lib/Makefile.am, po/POTFILES.in, po/da.po, po/de.po, po/es.po, po/et.po, po/findutils.pot, po/fr.po, po/gl.po, po/id.po, po/it.po, po/ko.po, po/nl.po, po/pl.po, po/pt_BR.po, po/ru.po, po/sv.po, po/tr.po:
- Updates to the i18n files to ensure that 'make dist' succeeds
-
- * lib/posix/.cvsignore, lib/posix/Makefile.am,
- lib/posix/Makefile.in, lib/posix/regex.h, lib/strftime.c,
- lib/strncasecmp.c, lib/strspn.c, lib/strstr.c, lib/strtol.c,
- lib/strtoul.c, lib/strtoull.c, lib/strtoumax.c, lib/wait.h,
- lib/waitpid.c, lib/xalloc.h, lib/xgetcwd.c, lib/xmalloc.c,
- lib/xstat.in, lib/xstrdup.c, lib/xstrtol.c, lib/xstrtol.h,
- lib/xstrtoul.c, lib/xstrtoul.h, lib/xstrtoumax.c, lib/yesno.c,
- locate/Makefile.am, locate/Makefile.in, locate/locate.c,
- locate/testsuite/Makefile.in, m4/.cvsignore, m4/ChangeLog,
- m4/Makefile.am, m4/Makefile.am.in, m4/Makefile.in, m4/README,
- m4/afs.m4, m4/assert.m4, m4/c-bs-a.m4, m4/check-decl.m4,
- m4/codeset.m4, m4/d-ino.m4, m4/d-type.m4, m4/error.m4,
- m4/fnmatch.m4, m4/fnmatchcase.m4, m4/fstypename.m4, m4/getline.m4,
- m4/gettext.m4, m4/glibc.m4, m4/glibc21.m4, m4/iconv.m4,
- m4/inttypes_h.m4, m4/isc-posix.m4, m4/jm-glibc-io.m4,
- m4/jm-macros.m4, m4/jm-mktime.m4, m4/lcmessage.m4, m4/libintl.m4,
- m4/link-follow.m4, m4/ls-mntd-fs.m4, m4/lstat-slash.m4,
- m4/lstat.m4, m4/malloc.m4, m4/mbstate_t.m4, m4/memcmp.m4,
- m4/prereq.m4, m4/progtest.m4, m4/readdir.m4, m4/realloc.m4,
- m4/regex.m4, m4/st_dm_mode.m4, m4/st_mtim.m4, m4/stat.m4,
- m4/strerror_r.m4, m4/strftime.m4, m4/timespec.m4, m4/uintmax_t.m4,
- m4/ulonglong.m4, m4/xstrtoumax.m4, xargs/Makefile.am,
- xargs/Makefile.in, xargs/testsuite/Makefile.in,
- find/testsuite/Makefile.in, lib/.cvsignore, lib/Makefile.am,
- lib/Makefile.in, lib/alloca.c, lib/ansi2knr.1, lib/ansi2knr.c,
- lib/argmatch.c, lib/argmatch.h, lib/basename.c, lib/basename.h,
- lib/dirname.c, lib/dirname.h, lib/error.c, lib/error.h,
- lib/fileblocks.c, lib/filemode.c, lib/filemode.h, lib/fnmatch.c,
- lib/fnmatch.h, lib/getline.c, lib/getline.h, lib/getopt.c,
- lib/getopt.h, lib/getopt1.c, lib/human.c, lib/human.h,
- lib/idcache.c, lib/malloc.c, lib/memcmp.c, lib/memcpy.c,
- lib/memset.c, lib/mktime.c, lib/modechange.c, lib/modechange.h,
- lib/pathmax.h, lib/quotearg.c, lib/quotearg.h, lib/realloc.c,
- lib/regex.c, lib/regex.h, lib/rpmatch.c, lib/savedir.c,
- lib/savedir.h, lib/stpcpy.c, lib/strcasecmp.c, lib/strdup.c,
- find/Makefile.am, find/Makefile.in, find/find.c, find/pred.c:
- Updated to work with current version of gnulib
-
- * import-gnulib.sh: New file.
-
- * config.h.in, configure, configure.in, doc/Makefile.in, import-gnulib.sh:
- Updated to work with current version of gnulib
-
- * README-CVS: New file.
-
- * Makefile.am, Makefile.in, README-CVS, aclocal.m4:
- Updated to work with current version of gnulib
-
-2003-05-26 James Youngman <jay@gnu.org>
-
- * po/pl.po, pt_BR.po, ru.po, sv.po, tr.po, da.po, de.po, es.po,
- et.po, findutils.pot, fr.po, gl.po, id.po, it.po, ko.po, nl.po:
- Changes to allow compilation on non-GNU systems (i.e. for the
- macros that gnulib decides to #define to be effective)
-
-2003-05-24 James Youngman <jay@gnu.org>
-
- * po/da.po, de.po, es.po, et.po, findutils.pot, fr.po, gl.po,
- id.po, it.po, ko.po, nl.po, pl.po, pt_BR.po, ru.po, sv.po, tr.po:
- also need stpcpy (e.g. for Solaris)
-
- * po/POTFILES.in, da.po, de.po, es.po, et.po, findutils.pot, fr.po,
- gl.po, id.po, it.po, ko.po, nl.po, pl.po, pt_BR.po, ru.po, sv.po,
- tr.po: Updates to the i18n files to ensure that 'make dist'
- succeeds
-
-2001-06-09 Kevin Dalley <kevin@seti.org>
-
- * intl/plural.c:
- Changes the location of bison.simple after running bison on local
- machine
-
- * ChangeLog: *** empty log message ***
-
- * Makefile.in, aclocal.m4, config.h.in, configure,
- doc/Makefile.in, find/Makefile.in, find/testsuite/Makefile.in,
- lib/Makefile.in, lib/posix/Makefile.in, locate/Makefile.in,
- locate/testsuite/Makefile.in, m4/Makefile.in, xargs/Makefile.in,
- xargs/testsuite/Makefile.in: Updates mostly from gettext-0.10.38
-
- * ABOUT-NLS: * ABOUT-NLS: updated from gettext-0.10.38.
-
- * configure.in: * configure.in: add tr to ALL_LINGUAS.
-
- * intl/config.charset, intl/dcigettext.c, intl/dcngettext.c,
- intl/dngettext.c, intl/libgnuintl.h, intl/localcharset.c,
- intl/locale.alias, intl/ngettext.c, intl/plural.y,
- intl/ref-add.sin, intl/ref-del.sin: updated from gettext-0.10.38
-
- * intl/cat-compat.c, intl/linux-msg.sed, intl/po2tbl.sed.in,
- intl/xopen-msg.sed, m4/ChangeLog: *** empty log message ***
-
- * m4/jm-macros.m4:
- * jm-macros.m4 (jm_MACROS): remove jm_ICONV, which is replaced by
- AM_ICONV, which is imported from gettext-0.10.38. removed
- jm_GLIBC21, which is required in AM_GNU_GETTEXT, which is
- imported from gettext-0.10.38.
-
- * po/stamp-cat-id: * stamp-cat-id: Remove file.
-
- * po/Makefile.in.in: * Makefile.in.in: Upgrade to gettext-0.10.38.
-
- * po/ChangeLog: * cat-id-tbl.c: Remove file.
-
- * po/de.po, po/es.po, po/et.po, po/fr.po:
- * fr.po, et.po, es.po, de.po: updated translations to
- findutils-4.1.7.
-
- * po/tr.po: * tr.po: New Turkish translation.
-
- * m4/ChangeLog: *** empty log message ***
-
- * intl/dgettext.c, intl/explodename.c, intl/finddomain.c,
- intl/gettext.c, intl/gettext.h, intl/gettextP.h,
- intl/hash-string.h, intl/intl-compat.c, intl/l10nflist.c,
- intl/libgettext.h, intl/loadinfo.h, intl/loadmsgcat.c,
- intl/localealias.c, intl/plural.c, intl/textdomain.c,
- intl/ChangeLog, intl/Makefile.in, intl/VERSION,
- intl/bindtextdom.c, intl/dcgettext.c: Updated from gettext-0.10.38
-
- * m4/Makefile.am:
- reflects addition of codeset.m4 from gettext-0.10.38, automatically
- generated.
-
- * m4/codeset.m4, m4/gettext.m4, m4/glibc21.m4, m4/iconv.m4,
- m4/isc-posix.m4, m4/lcmessage.m4, m4/progtest.m4: *
- progtest.m4, lcmessage.m4, isc-posix.m4, iconv.m4,
- glibc21.m4, gettext.m4, codeset.m4: updated from
- gettext-0.10.38.
-
- * ChangeLog: *** empty log message ***
-
- * THANKS: added "Gerrit P. Haase" <gerrit.haase@t-online.de>
-
- * m4/ChangeLog, locate/testsuite/.cvsignore,
- xargs/testsuite/.cvsignore, config.h.in, configure, aclocal.m4,
- doc/.cvsignore: *** empty log message ***
-
- * m4/jm-macros.m4: * jm-macros.m4 (jm_MACROS): add jm_FSTYPENAME
-
- * doc/Makefile.in: *** empty log message ***
-
- * doc/Makefile.am:
- * doc/Makefile.am (MOSTLYCLEANFILES): add find.cps, which is
- created by dvips. This should be taken care of by automake, but
- the code is commented out.
-
-2001-06-09 Kevin Dalley <kevin@seti.org>
-
- * ABOUT-NLS: updated from gettext-0.10.38.
-
- * configure.in: add tr to ALL_LINGUAS.
-
- * doc/Makefile.am (MOSTLYCLEANFILES): add find.cps, which is
- created by dvips. This should be taken care of by automake, but
- the code is commented out.
-
- * po/stamp-cat-id: * stamp-cat-id: Remove file.
-
- * po/Makefile.in.in: * Makefile.in.in: Upgrade to gettext-0.10.38.
-
- * po/ChangeLog: * cat-id-tbl.c: Remove file.
-
- * po/de.po, es.po, et.po, fr.po:
- * po/fr.po, et.po, es.po, de.po: updated translations to
- findutils-4.1.7.
-
- * po/tr.po: * tr.po: New Turkish translation.
-
-2001-06-05 Kevin Dalley <kevin@seti.org>
-
- * locate/updatedb.sh: replace "whoami" with "id -u" when testing
- for root.
-
-2001-06-04 Kevin Dalley <kevin@seti.org>
-
- * locate/testsuite/Makefile.am (DIST_SUBDIRS): remove second
- instance of DIST_SUBDIRS.
-
- * locate/Makefile.am (install-data-hook): changed install target
- to install-data-hook, which still installs other files.
-
- * doc/Makefile.am (MOSTLYCLEANFILES): added find.cps, which should
- probably be handled by automake.
-
- * doc/mdate-sh: removed file in doc directory. It now exists only
- in top_srcdir, but this changed required a patch to automake.
-
-2001-06-01 gettextize <bug-gnu-utils@gnu.org>
-
- * Makefile.in.in: Upgrade to gettext-0.10.38.
- * cat-id-tbl.c: Remove file.
- * stamp-cat-id: Remove file.
-
-2001-05-20 Kevin Dalley <kevin@seti.org>
-
- * Version 4.1.7
-
- * lib/Makefile.am (EXTRA_DIST): add strcasecmp.c
-
- * find/testsuite/Makefile.am (EXTRA_DIST): new tests:
- find.gnu/name-opt.exp find.gnu/perm.exp find.gnu/perm.xo
- find.gnu/prune-default-print.exp find.gnu/prune-default-print.xo
-
- * configure.in: update to 4.1.7
-
- * config.sub, config.guess: upgraded to recent versions of
- config.sub and config.guess.
-
- * locate/updatedb.sh: Add space to "#! /bin/sh"
-
- * configure.in: Add id to ALL_LINGUAS
-
- * lib/Makefile.am (EXTRA_DIST): getline.[ch] added
- (libfind_a_SOURCES): getline.[ch] removed since getline.c is not
- always needed.
-
- * po/da.po, de.po, es.po, et.po, fr.po, gl.po, id.po, it.po, ko.po,
- nl.po, pl.po, pt_BR.po, ru.po, sv.po: updated to reflect changes
- in source code.
-
- * po/id.po: New translation for Indonesia.
-
-2001-05-20 Lionel CONS <lionel.cons@cern.ch>
-
- * find/find.c: Fixed security holes. 1. There is a race
- condition between the lstat() to detect a symbolic link and the
- actual chdir(). 2. An attacker can move directories while find
- is _inside_ so that chdir(..) goes out of the intended file tree.
-
- * lib/modetype.h: support for Solaris door files is added.
-
- * lib/filemode.c: S_ISDOOR is undef'ed if STAT_MACROS_BROKEN
-
- * find/pred.c (pred_type): -D option (for Solaris door files) is
- added.
-
- * find/parser.c (insert_type): -D option (for Solaris door files)
- is added.
-
- * find/find.1: -D option (for Solaris door files) is documented
-
- * doc/find.texi (Type): -D option (for Solaris door files) is
- documented
-
-2001-05-02 Kevin Dalley <kevin@seti.org>
-
- * configure.in: Change AC_CHECK_MEMBERS to conform to new
- autoconf. Add Danish.
-
-2001-04-28 Kevin Dalley <kevind@rahul.net>
-
- * po/sv.po, ru.po, pt_BR.po, pl.po, nl.po, ko.po, it.po, gl.po,
- fr.po, et.po, es.po, de.po, findutils.pot: new translations, and
- new source code to translate.
-
- * po/da.po: new Danish translation.
-
-2001-01-20 Kevin Dalley <kevin@seti.org>
-
- * doc/find.texi (Adding Tests): Place space in "#! /bin/sh".
-
- * find/testsuite/find.gnu/prune-default-print.xo,
- find/testsuite/find.gnu/prune-default-print.exp: test for "find
- . -prune" which passes after changes. Also see name-opt.exp.
-
- * find/util.c (get_new_pred):
- * find/tree.c (set_new_parent):
- * find/parser.c (various parse functions):
- * find/find.c (main):
- (default_prints): new function
- * find/defs.h (struct predicate): added no_default_print
- side_effects are no separated from no_default_print. predicates
- which cause side effects should not be reordered (optimized).
- predicates which cause printing should have printing turned off.
- Printing statements also cause side effects.
-
-2000-10-29 Bruno Haible <haible@ilog.fr>
-
- * locate/code.c (main), doc/find.texi: improve handling of
- non-ASCII characters used old format.
-
-2000-10-21 Paul Eggert <eggert@twinsun.com>
-
- If open + fchdir fails, fall back on xgetcwd + chdir.
- The old code tested for this at compile-time,
- but SunOS 4.1.4 fchdir can fail at run-time.
-
- * find/defs.h (fchdir): Define to -1 if not available.
- * find/defs.h (starting_dir, starting_desc):
- Always declare. starting_dir now points to const.
- * find/find.c (starting_dir, starting_desc): Likewise.
- * find/find.c (starting_dir):
- Now "." if starting_desc is nonnegative, for benefit of diagnostics.
- (main, process_top_path, process_dir):
- If open + fchdir fails, fall back on xgetcwd + chdir.
- * find/pred.c (launch): Likewise.
-
-2000-10-20 Kevin Dalley <kevin@seti.org>
-
- * xargs/xargs.c, locate/updatedb.sh, locate/locate.c (usage),
- find/parser.c (parse_help): add bug reporting address to help
-
-2000-10-13 Kevin Dalley <kevin@seti.org>
-
- * depcomp, lib/depcomp: depcomp moved from lib to .
-
- * po/sv.po, ru.po, pt_BR.po, pl.po, nl.po, ko.po, it.po, gl.po,
- fr.po, findutils.pot, et.po, es.po, de.po: updated after addition
- of lib/rpmatch.c
-
-2000-10-11 Kevin Dalley <kevind@rahul.net>
-
- * Version 4.1.6
-
- * locate/testsuite/config/unix.exp: set PRUNEFS to "" for the
- testsuite.
-
-2000-10-10 Bruno Haible <haible@ilog.fr>
-
- * lib/Makefile.am (libfind_a_SOURCES): added yesno.c
-
- * lib/yesno.c, lib/rpmatch.c: new files.
-
- * find/pred.c: use function yesno().
-
-2000-10-10 Kevin Dalley <kevind@rahul.net>
-
- * locate/testsuite/Makefile.am: Added missing \ at end of
- EXTRA_DIST lines.
-
- * locate/testsuite/locate.gnu/ignore_case3.xo,
- locate/testsuite/locate.gnu/ignore_case3.exp,
- locate/testsuite/locate.gnu/ignore_case2.exp,
- locate/testsuite/locate.gnu/ignore_case1.xo,
- locate/testsuite/locate.gnu/ignore_case1.exp: place locatedb
- inside tmp directory, add subdir directory under tmp.
-
- * locate/testsuite/config/unix.exp: clean up tmp after test is
- finished.
-
-2000-10-10 Kevin Dalley <kevind@rahul.net>
-
- * locate/testsuite/config/unix.exp (Repository):
-
- * po/POTFILES.in: added lib/rpmatch.c
-
-2000-10-09 Kevin Dalley <kevind@rahul.net>
-
- * lib/fnmatch.c, lib/fnmatch.h: reverted to older version of
- fnmatch which works with Solaris.
-
- * locate/testsuite/config/unix.exp: dejagnu unix.exp
-
- * xargs/testsuite/config/unix.exp: remove temporary file
-
- * xargs/xargs.c: spelling correction
-
- * m4/prereq.m4: updated and changed some macros
-
- * m4/jm-macros.m4: replaced jm_FUNC_FNMATCH with
- kd_FUNC_FNMATCH_CASE_REPL
-
- * m4/timespec.m4, m4/strerror_r.m4, m4/mbstate_t.m4,
- m4/largefile.m4, m4/gettext.m4, m4/fnmatchcase.m4, m4/d-type.m4,
- m4/d-ino.m4, m4/c-bs-a.m4: new m4 macros.
-
- * m4/Makefile.am: add fnmatchcase.m4 and mbstate_t.m4
-
- * locate/testsuite/locate.gnu/ignore_case3.xo,
- locate/testsuite/locate.gnu/ignore_case3.exp,
- locate/testsuite/locate.gnu/ignore_case2.xo,
- locate/testsuite/locate.gnu/ignore_case2.exp,
- locate/testsuite/locate.gnu/ignore_case1.xo,
- locate/testsuite/locate.gnu/ignore_case1.exp,
- locate/testsuite/config/unix.exp: tests related to "--ignore-case"
- option.
-
- * locate/testsuite/locate.gnu: testsuite directory
-
- * locate/testsuite/Makefile.am (Repository):
-
- * locate/testsuite: add directory for locate testsuite
-
- * po/findutils.pot: updated file
-
- * po/sv.po, po/ru.po, po/pt_BR.po, po/pl.po, po/nl.po, po/ko.po,
- po/it.po, po/gl.po, po/fr.po, po/et.po, po/es.po, po/de.po:
- updated various po files.
-
- * locate/updatedb.sh: export TMPDIR, which is used by child
- processes.
-
- * locate/locate.1, locate/locate.c: add "--ignore-case" option.
-
- * locate/Makefile.am: add testsuite subdirectory
-
- * find/testsuite/find.gnu/perm.xo,
- find/testsuite/find.gnu/perm.exp,
- find/testsuite/find.gnu/name-opt.xo,
- find/testsuite/find.gnu/name-opt.exp: added test suites
-
- * configure.in: add locate/testsuite/Makefile
-
- * doc/find.info*: removed from repository
-
- * doc/find.texi: add documentation for "-i" option.
-
- * aclocal.m4: removed from repository, as it is generated.
-
- * find/pred.c: fixes problem with "find -perm -0100".
-
- * lib/lstat.c, lib/stat.c: removed from repository. These files
- are generated from lib/xstat.in.
-
-2000-08-24 Kevin Dalley <kevind@rahul.net>
-
- * doc/find.texi (Invoking xargs): changed @var{-s} to @samp{-s}.
-
-2000-05-13 Kevin Dalley <kevind@rahul.net>
-
- * find/tree.c (opt_expr): move iname and ipath to the front of the
- list of arguments.
-
- * doc/find.texi (Directories): changed wording for "-prune".
-
- * find/parser.c (parse_prune): set side_effects to true, to
- prevent prune from being moved in opt_expr.
-
-2000-04-12 Kevin Dalley <kevind@rahul.net>
-
- * doc/find.texi, doc/permi.texi: fix spellings, add LocalWords.
-
- * lib/Makefile.am: put getline.c back into libfind_a_SOURCES,
- since getstr is needed.
-
- * Version 4.1.5
-
- * po/POTFILES.in: updated list of files, updated po files.
-
-
-2000-04-02 Paul Eggert <eggert@twinsun.com>
-
- Add support for large files, and port to Solaris 8 and earlier
- versions.
-
- * lib/human.c (getenv): Depend on NEED_GETENV_DECL, not
- HAVE_DECL_GETENV.
-
- * lib/strftime.c (my_strftime): Make sure we call the system
- strftime, not ourselves, when invoking the underlying strftime.
-
- * m4/check-decl.m4 (jm_CHECK_DECLS): Remove memchr, nanosleep.
-
- * m4/jm-macros.m4 (jm_MACROS): Don't check for utime.h. Do not
- require jm_BISON, jm_CHECK_TYPE_STRUCT_UTIMBUF, jm_FUNC_LCHOWN,
- jm_FUNC_CHOWN, jm_FUNC_NANOSLEEP, jm_FUNC_GROUP_MEMBER,
- jm_FUNC_PUTENV, jm_FUNC_GETGROUPS, AM_FUNC_GETLOADAVG,
- jm_SYS_PROC_UPTIME, jm_FUNC_FTRUNCATE, jm_FUNC_UTIME. Do not
- replace strcasecmp, dup2, gethostname, getusershell, stime,
- strcspn, strpbrk, euidaccess, mkdir, rmdir, rpmatch, strndup,
- strverscmp, memchr, memmove. Do not check for declaration of
- lchown. Remove invocations of AM_FUNC_OBSTACK, AM_FUNC_STRTOD,
- POW_LIBM, jm_LANGINFO_CODESET, jm_ICONV. Remove df tests.
- (jm_CHECK_ALL_TYPES): Include <sys/stat.h> when checking for
- struct stat.st_blksize.
-
- * m4/strftime.m4 (jm_FUNC_GNU_STRFTIME): Set environment variable
- in shell rather than using putenv, which isn't portable.
-
- * COPYING, lib/alloca.c, lib/dirname.c, lib/error.c,
- lib/savedir.c, lib/strstr.c, m4/check-decl.m4, m4/d-ino.m4,
- m4/d-type.m4, m4/getline.m4, m4/jm-glibc-io.m4, m4/jm-macros.m4,
- m4/jm-mktime.m4, m4/ls-mntd-fs.m4, m4/memcmp.m4, m4/prereq.m4,
- m4/readdir.m4, m4/regex.m4, m4/strftime.m4, m4/uintmax_t.m4: Sync
- to latest version from sh-utils-2.0g.
-
- * config.guess, config.sub, lib/argmatch.c, lib/argmatch.h,
- lib/human.c, lib/human.h, lib/memcpy.c, lib/quotearg.c,
- lib/quotearg.h, lib/strtoull.c, lib/strtoumax.c,
- lib/xstrtoumax.c, m4/c-bs-a.m4, m4/gettext.m4,
- m4/largefile.m4, m4/lcmessage.m4, m4/link-follow.m4,
- m4/progtest.m4, m4/strerror_r.m4, m4/timespec.m4,
- m4/xstrtoumax.m4: New files, taken from sh-utils-2.0g.
-
- * lib/ansi2knr.1, lib/ansi2knr.c, lib/basename.c, lib/getopt.h,
- lib/fnmatch.c, lib/fnmatch.h, lib/modechange.c: Sync to latest
- unreleased version of GNU tar (between 1.13.17 and 1.13.18).
-
- * lib/basename.h, lib/waitpid.c: New files, taken from same
- version of GNU tar.
-
- * lib/regex.c, lib/regex.h: Sync to GNU grep 2.4.2.
-
- * lib/posix/Makefile.am, lib/posix/regex.h: New files, taken from
- GNU grep 2.4.2.
-
- * lib/strftime.c: Sync to textutils 2.0e.
-
- * acconfig.h, depcomp, lib/strcasecmp.c, m4/check-type.m4,
- m4/const.m4, m4/decl.m4, m4/lfs.m4, m4/mktime.m4, m4/perl.m4,
- m4/putenv.m4, m4/uptime.m4, m4/utimbuf.m4, m4/utime.m4,
- m4/utimes.m4: Remove these files; no longer needed.
-
- * configure.in (AC_CANONICAL_HOST, AC_SYS_LARGEFILE,
- jm_AC_TYPE_UINTMAX_T): Add.
- (CACHE_IDS, FSTYPE_STATVFS, FSTYPE_USG_STATFS, FSTYPE_AIX_STATFS,
- FSTYPE_MNTENT, FSTYPE_STATFS, FSTYPE_GETMNT): Add comment, so that
- we don't need acconfig.h.
- (AC_CHECK_TYPE): Add ssize_t.
- (AC_REPLACE_FUNCS): Add waitpid.
- (AC_CHECK_FUNCS): Remove basename.
- (AC_FUNC_MKTIME): Remove.
- (LIBOBJS): Add no-ops to work around automake 1.4 bug.
- (AC_OUTPUT): Add lib/posix/Makefile.
-
- * find/defs.h: Include <config.h>, <sys/types.h>, <sys/stat.h>,
- <stdio.h>, <limits.h>, <inttypes.h>. All includers changed to not
- include these files, and to include "defs.h" first (since config.h
- must be included first).
- (CHAR_BIT, S_ISUID, S_ISGID, S_ISVTX, S_IRUSR, S_IWUSR, S_IXUSR,
- S_IRGRP, S_IWGRP, S_IXGRP, S_IROTH, S_IWOTH, S_IXOTH, MOD_WXUSR,
- MODE_R, MODE_RW, MODE_RWX, MODE_ALL): New macros.
- (enum permissions_type): New enum.
- (struct long_val.negative): New member.
- (struct long_val.l_val): Now uintmax_t, not unsigned long.
- (struct size_val.size): Likewise.
- (struct perm_val): New type.
- (struct predicate.perm): Now struct perm_val, not unsigned long.
- (struct predicate.type): Now mode_t, not unsigned long.
- (list_file): New parameters current_time, output_block_size.
- All callers changed.
- (savedir, basename): Remove decls.
- (output_block_size, start_time): New extern vars.
-
- * find/find.c: Include <human.h>, <savedir.h>.
- (output_block_size, start_time): New vars.
- (main): Initialize them. No need to check for negative st_size,
- since savedir now does it for us.
-
- * find/fstype.c: Include "dirname.h".
- (xatoi): Remove.
- (filesystem_type_uncached): Use xstrtoumax instead of xatoi.
-
- * find/parser.c: Include "xstrtol.h".
- (get_num_days, get_num, parse_amin, parse_cmin, parse_mmin,
- parse_size, parse_used, insert_time, insert_num): Compute using
- uintmax_t, not unsigned long.
- (parse_amin, parse_cmin, parse_mmin, parse_used, insert_time):
- Keep track of whether time was negative before converting it to an
- unsigned type.
- (parse_daystart): Don't assume that localtime succeeds; e.g. it
- can fail with 64-bit time_t and 32-bit tm_year.
- (parse_perm, insert_type): Compute using mode_t, not unsigned
- long.
- (insert_type): Use symbolic constants like MODE_ALL instead of
- traditional ones like 07777. Set new kind member to indicate
- permissions type, instead of using unportable magic numbers.
- (make_segment): We will use human_readable to convert most numeric
- values, so simplify the cases.
- (get_num_days): Write in terms of get_num, to avoid duplicated
- code.
- (insert_time, insert_num): When debugging, convert large values to
- uintmax_t and output with %ju.
- (get_num): Use xstrtoumax to do the real work.
-
- * find/pred.c: Include "basename.h", "human.h".
- (DEV_BSIZE, ST_BLKSIZE, ST_NBLOCKSIZE): New macros, taken from
- fileutils.
- (ST_NBLOCKS): Replace with fileutils defn.
- (MAX): New macro.
- (ctime_format): New function.
- (pred_fprintf, format_date): Use human_readable to output large
- numbers portably.
- (pred_fprintf): Use ctime_format to output ctime-style dates. Use
- base_name to compute the base name of a path. With %m, output the
- mode portably using traditional numbers, even if the host uses
- some other numbering scheme.
- (pred_iname, pred_name): basename -> base_name.
- (pred_perm): Use new kind member to deduce permissions type,
- instead of relying on magic numbers.
- (pred_size): Compute using uintmax_t, not unsigned long. Avoid
- overflow if file size is near the maximum.
- (pred_type): Compute using mode_t, not unsigned long.
- (launch): Use waitpid, not wait. Check for EINTR.
- (format_date): Don't assume that localtime succeeds.
-
- * find/util.c (basename): Remove; we now use base_name.
-
- * lib/Makefile.am (SUBDIRS): New macro.
- (libfind_a_SOURCES): Add argmatch.h, argmatch.c, basename.h,
- basename.c, human.c, human.h, quotearg.c, quotearg.h, xstrtoumax.c.
- Remove error.h, error.c, getline.c.
- (EXTRA_DIST): Add mktime.c, regex.c.
-
- * lib/listfile.c: Include "human.h".
- (alloca): Declare, or include appropriate files to declare.
- (DEV_BSIZE, ST_NBLKSIZE, ST_NBLOCKS, ST_NBLOCKSIZE): New macros.
- (convert_blocks): Remove.
- (list_file): New current_time and output_block_size args.
- Revamp quite a bit, to handle large numbers correctly
- and to match GNU ls behavior more closely.
-
- * m4/Makefile.am (EXTRA_DIST): Add c-bs-a.m4, gettext.m4,
- largefile.m4, lcmessage.m4, link-follow.m4, progtest.m4,
- strerror_r.m4, xstrtoumax.m4. Remove check-type.m4, const.m4,
- decl.m4, lfs.m4, mktime.m4, perl.m4, putenv.m4, timespec.m4,
- uptime.m4, utimbuf.m4, utime.m4, utimes.m4.
-
- * xargs/xargs.c (wait_for_proc): Retry wait if it fails with
- errno == EINTR.
-
-2000-04-05 Kevin Dalley <kevind@rahul.net>
-
- * xargs/Makefile.am: add ansi2knr
-
- * xargs/xargs.c: add macros PARAMS rather than P_. Add
- prototypes.
-
- * po/POTFILES: new file listing all POFILES.
-
- * m4/gl.po, m4/et.po: new files
-
- * m4/Makefile.am.in: updated file
-
- * m4: update directory
-
- * locate/Makefile.am: create updatedb from updatedb.sh
-
- * locate/updatedb.sh, locate/updatedb.in: removed file. Replaced
- by updatedb.sh
-
- * locate/frcode.c, locate/code.c, locate/bigram.c: add macros
- PARAMS rather than P_. Add prototypes.
-
- * lib/xstat.in: new file
-
- * lib/Makefile.am: update to latest versions of library files.
-
- * find/testsuite/Makefile.am: add CLEANFILES
-
- * find/util.c: remove definition of basename
-
- * find/util.c, find/tree.c, find/pred.c, find/parser.c,
- find/fstype.c, find/find.c, find/defs.h: add macros PARAMS rather
- than P_, for consistency, change to prototypes
-
- * find/Makefile.am: Add prototypes and ansi2knr
-
- * configure.in: add Galition and Estonian languages.
- Miscellaneous other fixes.
-
-
-2000-03-11 Kevin Dalley <kevind@rahul.net>
-
- * lib/basename.c: Add file from libit.
- * lib/Makefile.am (libfind_a_SOURCES): add basename.c since it is
- no longer replaceable.
-
- * find/util.c: Remove definition of basename, which is now in
- lib/basename.c (as base_name).
- * find/pred.c: Use base_name, not basename.
- * find/defs.h: Likewise.
-
- * configure.in : Don't replace basename. Now we use only
- base_name.
-
-2000-02-26 Kevin Dalley <kevind@rahul.net>
-
- * Version 4.1.4
-
- * lib/strtoul.c: added to distribution
-
- * configure.in: added strtoul to AC_REPLACE_FUNCS
-
- * configure.in: added jm_CHECK_ALL_TYPE
-
-2000-02-23 Kevin Dalley <kevind@rahul.net>
-
- * po/ChangeLog: removed, merged with top-level ChangeLog.
-
- * po/de.po: new version of German file.
-
- * po/gl.po, po/et.po: new languages, Estonian and Galician.
-
- * locate/updatedb.sh (PRUNEFS): enclose paths in quotes
-
-2000-02-17 Kevin Dalley <kevind@rahul.net>
-
- * po/it.po: new version of Italian file.
-
- * locate/updatedb.sh (prunefs_exp): have sed statement use '*'
- rather than the often unsupported '+'.
-
-2000-02-13 Kevin Dalley <kevind@rahul.net>
-
- * configure.in: removed AC_ARG_PROGRAM, which is already in
- AM_INIT_AUTOMAKE.
-
- * locate/Makefile.am (updatedb), locate/updatedb.sh: add
- transforms of find, frcode, bigram, and code back into
- updatedb.sh, which were accidentally removed.
-
-2000-02-12 Kevin Dalley <kevind@rahul.net>
-
- * lib/wait.h: updated address.
-
-2000-01-26 Kevin Dalley <kevind@rahul.net>
-
- * Version 4.1.3
-
- * acconfig.h: added internationalization.
-
- * intl/*: copied from tar-1.13.17.
-
- * locate/Makefile.am, locate/locate.c, locate/code.c:
- internationalized file.
-
- * locate/frcode.c, locate/bigram.c: include headers from ../lib
- directory.
-
- * xargs/Makefile.am, xargs/xargs.c: internationalized directory.
-
-2000-01-26 Kevin Dalley <kevind@rahul.net>
-
- * po/POTFILES.in: added list of files with translatable strings.
-
- * de.po, es.po, fr.po, it.po, ko.po, nl.po, pl.po, pt_BR.po,
- ru.po, sv.po: New, slightly out of date, files imported from the
- Translation Project: http://www.iro.umontreal.ca/contrib/po/HTML/,
- German, Spanish, French, Italian, Korean, Dutch, Polish, Brazilian
- Portuguese.
-
-
-2000-01-24 Kevin Dalley <kevind@rahul.net>
-
- * lib/xmalloc.c, lib/regex.c, lib/getopt.c: internationalization
- works with current version of gettext.
-
- * lib/getline.h : added declaration of getstr.
- * lib/Makefile.am (libfind_a_SOURCES): added getline.[ch] to
- standard compilation. Added internationalization.
- * find/Makefile.am (INCLUDES): corrected -I options for building
- in other directories.
- (LDADD): changes for internationalization.
-
- * configure.in (ALL_LINGUAS): added internationalization.
- getline.c is always compiled and linked, because of getstr.
- AM_GNU_GETTEXT
-
- * Makefile.am:
- (DISTCLEANFILES): added intl/libintl.h
- (AUTOMAKE_OPTIONS): added gnits to AUTOMAKE_OPTIONS
- (SUBDIRS): added intl and po
-
- * acconfig.h: added internationalization values
-
- * THANKS: added thanks file for gnits compatibility.
-
-2000-01-22 Kevin Dalley <kevind@rahul.net>
-
- * added intl directory.
- * created po directory and added existing po files from
- http://www.iro.umontreal.ca/contrib/po/HTML
-
- * Added internationalization, only with slightly out of date po
- files for many locales.
-
-2000-01-18 Kevin Dalley <kevind@rahul.net>
-
- * Version 4.1.2
-
- * locate/Makefile.am: remove creation of updatedb, since it is now
- made by configure
-
- * configure.in: updatedb is now created by configure.
-
- * xargs/Makefile.am: added testsuite to xargs directory
-
- * locate/updatedb.in: updatedb is now created by configure
-
- * locate/frcode.c, locate/code.c, locate/bigram.c: change return
- from main to int. Replace getstr with getline, where possible.
-
- * locate/Makefile.am: place frcode, code, bigram in
- libexec_PROGRAMS
-
- * lib/xstrdup.c, lib/xmalloc.c, lib/xgetcwd.c, lib/xalloc.h,
- lib/strtol.c, lib/strstr.c, lib/strftime.c, lib/strdup.c,
- lib/stpcpy.c, lib/stat.c, lib/savedir.h, lib/savedir.c,
- lib/regex.h, lib/regex.c, lib/realloc.c, lib/pathmax.h,
- lib/modechange.h, lib/modechange.c, lib/mktime.c, lib/memset.c,
- lib/memcmp.c, lib/malloc.c, lib/lstat.c, lib/idcache.c,
- lib/getopt1.c, lib/getopt.c, lib/getopt.h, lib/getline.c,
- lib/getline.h, lib/fnmatch.c, lib/fnmatch.h, lib/filemode.c,
- lib/filemode.h, lib/fileblocks.c, lib/error.c, lib/error.h,
- lib/dirname.c, lib/alloca.c: updated to newer version of file from
- fileutils.
-
- * find/version.c: version number is now automatically generated by
- configure.
-
- * find/fstype.c (filesystem_type_uncached): fixes bug described as
- follows: When 'find' looks for a fstype, it parses the /etc/mtab
- until it finds the good line. But, if there is, before the good
- line, a line whose mountpoint is unreachable, it fails.
-
- * doc/texinfo.tex: updated to newer version
-
- * doc/find.texi: added version.texi, fixed a few documentation bugs.
-
- * configure.in: new m4 features.
-
- * Makefile.am: moved testsuite to below corresponding directories
- find and xargs.
-
- * acconfig.h: updated to match new m4 files.
-
- * m4: added m4 directory, largely borrowed from Jim Meyering's
- fileutils.
-
-2000-01-17 Kevin Dalley <kevind@rahul.net>
-
- * doc/find.texi (Multiple Files): placed missing xargs in examples
-
- * find/testsuite/find.gnu/depth.exp: added find tests to test
- "-depth" bug.
-
- * doc/find.texi: include version.texi for automatic determination
- of version number, update bug report email address to
- bug-findutils@gnu.org.
- (Combining Primaries With Operators): add indices for " ,", "()",
- "-a", "-o", etc.
-
-2000-01-17 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
-
- * find/tree.c (opt_expr): Never rearrange the arguments of the
- comma operator, since it is not commutative. Remove useless
- assignment.2
-
-2000-01-17 Jonathan R. Ferro <jferro@corwin.ece.cmu.edu>
-
- * find/find.c (process_path): fix problem with "-depth" which is
- tested in depth.exp test.
-
-1999-08-15 Kevin Dalley <Kevin Dalley <kevin@seti.org>>
-
- * find/fstype.c (filesystem_type_uncached): a stat failure with
- EACCESS will ignore this file system keep on looking. Patch
- suggested by Vincent Danjean <vdanjean@ens-lyon.fr>.
-
-1999-08-15 Mark Kettenis <kettenis@gnu.org>
-
- * xargs/xargs.c (LONG_MAX): Define if necessary.
- (main): If ARG_MAX is -1 (that is sysconf
- (_SC_ARG_MAX) returns -1) the system does not impose a limit. In
- that case, use LONG_MAX as the limit.
-
-1999-08-15 Kevin Dalley <Kevin Dalley <kevind@rahul.net>
-
- * find/version.c: version string is now set by config.h
-
-1999-08-08 Kevin Dalley <kevin@seti.org>
-
- * Version 4.1.1
-
- * README-alpha: added alpha README file
-
- * find/defs.h: move lstat declarations into defs.h
-
- * xargs/Makefile.am, testsuite/Makefile.am, locate/Makefile.am,
- lib/Makefile.am, find/Makefile.am, doc/Makefile.am, configure.in,
- Makefile.am: update for automake-1.4
-
-1999-08-02 Kevin Dalley <kevind@rahul.net>
-
- * AUTHORS: added file listing AUTHORS
-
- * lib/Makefile.am: modified code for EXTRA sources
-
-1999-01-30 Kevin Dalley <kevind@rahul.net>
-
- * added const to declaration of basename, which should satisfy
- Linux as well as Hurd (fixes bug #31325).
-
-1998-12-04 Kevin Dalley <kevind@rahul.net>
-
- * lib/nextelem.c: removed declaration of strdup and free, which
- meets GNU coding standards and allows compilation on more
- platforms.
-
- * find.texi: corrected explanation of -amin option which described
- hours instead of minutes
-
-1998-09-26 Kevin Dalley <kevind@rahul.net>
-
- * lib/getline.c: fix getstr so that it correctly handles long file
- paths
-
-1998-09-20 Kevin Dalley <kevind@rahul.net>
-
- * removed more function declarations to meet GNU coding standards
-
-1998-08-30 Kevin Dalley <kevind@rahul.net>
-
- * lib/nextelem.c: removed declaration of strdup and free, which
- meets GNU coding standards and allow compilation on sparc
-
- * corrected explanation of -amin option which described hours
- instead of minutes
-
-1998-02-27 Kevin Dalley <kevind@rahul.net>
-
- * locate/locate.c: add --existing option to locate, which only
- prints the names of files which still exist
-
-1998-02-08 Kevin Dalley <kevind@rahul.net>
-
- * locate/locate.c: corrected get_short so that it correctly
- returns negative numbers.
-
- * remove declarations of various string functions. Removing the
- declarations almost matches the GNU Coding Standards.
-
-1997-03-03 Kevin Dalley <kevind@rahul.net>
-
- * xargs/xargs.c: xargs fixed to prevent occasional core dumping.
-
-1997-01-11 Kevin Dalley <kevind@rahul.net>
-
- * locate/updatedb.sh: add --localuser option to updatedb, which
- allows find to be run as nobody, while allowing database file to
- be created as root, change suggested by
- <Bernd_Eckenfels@Wittumstrasse13.76646Bruchsal.de>
-
-1996-12-28 Kevin Dalley <kevind@rahul.net>
- * added PRUNEFS as variable in updatedb and --prunefs as option to
- updatedb
-
-1996-05-27 Kevin Dalley <kevind@rahul.net>
-
- * updatedb.sh: when NETPATHS is used, only su to NETUSER if whoami
- is root
-1996-04-27 Kevin Dalley <kevind@rahul.net>
-
- * lib/getline.c (getstr): verify that nchars_avail is *really*
- greater than 0; set *n to a large enough number, stops some core
- dumping
-
Thu Nov 3 09:23:33 1994 David J. MacKenzie <djm@duality.gnu.ai.mit.edu>
* Version 4.1.
@@ -6414,7 +25,7 @@ Tue Oct 25 16:09:04 1994 David J. MacKenzie <djm@duality.gnu.ai.mit.edu>
Flack.
* find/parser.c (insert_fprintf): Warn about unrecognized \ and %
- sequences.
+ sequences.
Tue Oct 18 00:03:10 1994 David J. MacKenzie <djm@duality.gnu.ai.mit.edu>
@@ -6447,11 +58,11 @@ Fri Oct 7 12:33:24 1994 David MacKenzie <djm@geech.gnu.ai.mit.edu>
Wed Oct 5 11:23:09 1994 David MacKenzie <djm@geech.gnu.ai.mit.edu>
- * xargs/xargs.c (main, read_line, read_string, do_exec): Pass
+ * xargs/xargs.c (main, read_line, read_string, do_exec): Pass
along the lengths of the args.
(main): Calculate length of replace_pat.
(push_arg, do_insert): Use those lengths instead of calculating
- them.
+ them.
Tue Oct 4 10:02:05 1994 David MacKenzie <djm@churchy.gnu.ai.mit.edu>
@@ -6470,7 +81,7 @@ Sat Oct 1 17:43:13 1994 David MacKenzie <djm@geech.gnu.ai.mit.edu>
* find/pred.c (launch): Use pid_t.
* xargs/xargs.c (EOF_STR): Define and use.
- [__STDC__]: Declare xrealloc and xmalloc using void *.
+ [__STDC__]: Delcare xrealloc and xmalloc using void *.
* find/defs.h: Likewise.
* find/defs.h: Only declare stpcpy if !HAVE_STPCPY.
@@ -6634,7 +245,7 @@ Mon Jun 28 00:18:52 1993 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu)
otherwise unknown.
* parser.c (parse_size): Recognize b and w suffixes for dd
- compatibility.
+ compatibility.
* code.c (puthalfword): New function.
(main): Call it.
@@ -6756,7 +367,242 @@ Tue Mar 23 13:18:08 1993 David J. MacKenzie (djm@kropotkin.gnu.ai.mit.edu)
Fri Dec 11 08:17:07 1992 Jim Meyering (meyering@comco.com)
* defs.h: Remove dcl of process_path.
- * find.c: Put dcl of p
+ * find.c: Put dcl of process_path here. Make a few functions
+ and file-scope variables static.
+ * parser.c, tree.c: Declare most functions static.
+
+ * locate.c: Use `required_argument' macro in dcl of longopts.
+ * bigram.c, code.c, locate.c, xargs.c: Make most functions and
+ file-scope variables static.
+
+ * parser.c, xargs.c: Guard ctype.h macros with isascii.
+
+ * find.c: Add declarations for opt_expr and mark_stat.
+ * tree.c (set_new_parent): Add empty default clause to enum swicth.
+ * locate.c (main): Parenthesize for gcc -Wall.
+ * xargs.c (push_arg): Parenthesize for gcc -Wall.
+
+Tue Nov 24 08:04:36 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
+
+ * find.c, fstype.c, parser.c, pred.c, util.c, listfile.c,
+ nextelem.c, xargs.c, bigram.c, code.c, locate.c: Use
+ HAVE_STRING_H, not USG.
+
+ * pred.c: Use SYSDIR and NDIR instead of USG.
+ Define direct as dirent, not vice-versa.
+
+Fri Oct 9 02:15:17 1992 David J. MacKenzie (djm@kropotkin.gnu.ai.mit.edu)
+
+ * xargs.c (main): Set orig_arg_max before possibly cutting
+ down arg_max.
+
+Thu Sep 10 19:25:35 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * parser.c: Always declare getgrent and getpwent.
+
+Mon Aug 24 12:54:16 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * xargs.c: Include sys/types.h before unistd.h. Use ARG_MAX
+ if it's defined.
+ * find.c, nextelem.c: Add missing decls.
+ From bde@runx.oz.au (Bruce Evans).
+
+Thu Jul 23 15:06:07 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * Version 3.7.
+
+Tue Jul 14 00:16:52 1992 David J. MacKenzie (djm@apple-gunkies.gnu.ai.mit.edu)
+
+ * pathmax.h: New file.
+ * bigram.c, code.c, locate.c: Use it. Use xmalloc instead of malloc.
+
+Sat Jul 11 22:31:46 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * nextelem.c: New file.
+ * locate.c (main): Use it to support a database path.
+
+Fri Jul 3 02:12:09 1992 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu)
+
+ * listfile.c, pred.c: Change FOO_MISSING to HAVE_FOO.
+
+ * parser.c [_POSIX_SOURCE]: Define endpwent and endgrent as empty.
+ * listfile.c [!HAVE_ST_RDEV]: Print blanks.
+ From Jeffrey Siegal (jbs@congruent.com).
+
+ * locate.c (locate): Check for EOF at top of loop, not middle.
+ * updatedb.sh: Remove duplication hack.
+ From Jay Plett.
+
+Wed Jun 10 15:04:23 1992 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu)
+
+ * pred.c (pred_amin, pred_atime, pred_cmin, pred_ctime,
+ pred_mmin, pred_mtime, pred_used): Cast l_val to time_t before
+ comparing it to a time_t. From fpm@crash.cts.com (Frank Maclachlan).
+
+ * locate.c (locate): Take the database path as an arg.
+ (main): Take an option to specify the database path.
+ (usage): New function.
+
+ * updatedb.sh: Don't read from and write to the file-list file
+ in the same statement.
+
+Thu Jun 4 15:27:07 1992 David J. MacKenzie (djm@geech.gnu.ai.mit.edu)
+
+ * Version 3.6.
+
+Wed May 20 00:05:13 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
+
+ * xargs.c: Include sys/param.h before limits.h, not after.
+
+ * listfile.c: If we include a header file specifically to get
+ major et al., assume we have them.
+
+Tue May 12 01:09:33 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
+
+ * locate.c (locate): Don't give fnmatch FNM_PERIOD (it's useless).
+
+ * parser.c (parse_path): New function.
+ * pred.c (pred_path): New function.
+ * tree.c (opt_expr): Move -path like -name.
+
+ * updatedb.sh: Duplicate the last entry in the file list so it
+ doesn't get ignored.
+
+Mon May 11 22:24:40 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
+
+ * updatedb.sh: Allow many vars to be overridden in the environment.
+
+ * locate.c, updatedb.sh: FCODES -> LOCATE_DB.
+
+Wed Apr 22 15:24:00 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
+
+ * updatedb.sh: Use binprefix when calling find.
+
+ * locate.c (locate): Use LOCATE_DB environ variable if set.
+
+ * find.c (scan_directory): Allow for dirs having negative
+ st_size (NFS mount points on VAX 4.3BSD+NFS).
+ From metcalf@catfish.lcs.mit.edu (Chris Metcalf).
+
+Sat Apr 18 15:42:52 1992 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu)
+
+ * fstype.c: Rename FS_* to FSTYPE_*. Support Dynix's
+ name for the mount table.
+
+Sun Mar 8 23:21:25 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * listfile.c (list_file): Allow a slop factor for deciding what
+ is in the future.
+
+Tue Feb 25 16:24:15 1992 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu)
+
+ * Version 3.5.
+
+Sat Feb 22 08:43:01 1992 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu)
+
+ * tree.c (set_new_parent): Initialize need_stat field.
+
+ * defs.h (struct predicate): Define p_name unconditionally.
+
+Fri Feb 21 15:28:43 1992 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu)
+
+ * tree.c (opt_expr): Preserve expression precedence when
+ rearranging expression tree.
+ (set_new_parent): New function.
+ (mark_stat): Set need_stat whether or not it's been set
+ earlier in the expression.
+ All from Tim Wood.
+
+Mon Feb 17 10:20:38 1992 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * updatedb.sh: Use current value of TMPDIR if already set.
+ From Dana Jacobsen (jacobsd@cs.orst.edu).
+
+ * pred.c: Include pwd.h and grp.h after unistd.h, not before.
+ Apparently needed on ISC 2.2. From Juha Takala <jta@piuha.sah.vtt.fi>.
+
+Thu Feb 13 10:52:31 1992 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * modetype.h: Don't define S_IFMT, because doing so breaks pred_type
+ on plain POSIX.1 systems.
+
+Sat Feb 8 00:58:13 1992 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * Version 3.4.
+
+Fri Feb 7 21:35:58 1992 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * defs.h: Don't declare process_path.
+ * find.c [DEBUG_STAT] (debug_stat): New function.
+ (main) [DEBUG_STAT]: Call it.
+ (process_path): Return a value.
+ (scan_directory): Count number of subdirs seen so far.
+ * parser.c (pred_and, pred_close, pred_comma, pred_negate,
+ pred_open, pred_or): Don't need stat.
+ * util.c (get_new_pred_chk_op): Implicit AND doesn't need stat.
+
+Fri Jan 17 21:51:18 1992 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * Version 3.3.
+
+Tue Dec 24 02:16:49 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * wait.h, listfile.c, xargs.c, bigram.c, code.c, locate.c:
+ Change POSIX ifdefs to HAVE_UNISTD_H and _POSIX_VERSION.
+
+Wed Dec 18 16:37:17 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * listfile.c: Use MAJOR_IN_MKDEV and MAJOR_IN_SYSMACROS to
+ find major and minor.
+
+ * code.c, bigram.c, locate.c, xargs.c: Use LIMITS_H_MISSING
+ instead of LIMITS_MISSING.
+
+Sat Dec 7 06:13:26 1991 David J. MacKenzie (djm at frob.eng.umd.edu)
+
+ * parser.c (parse_prune): No stat needed for prune.
+ (insert_fprintf, make_segment): Possibly no stat needed,
+ depending on which information is printed.
+
+ * xargs.c (usage): Document long-named options as starting
+ with -- instead of +.
+
+ * parser.c [!POSIX]: Declare getgrent and getpwent.
+
+ * fstype.c (filesystem_type): Only check MNTTYPE_IGNORE if
+ it's defined. From Rainer Orth.
+
+ * Add leaf node optimization suggested by Matthew Farwell
+ <dylan@ibmpcug.co.uk>. Add -noleaf option to disable it.
+ Adapt parts of Tim Wood's work to current sources.
+ * find.c (scan_directory): New function, from code in process_path.
+ (process_path): Take an arg indicating whether the pathname
+ is a leaf non-directory, instead of a redundant current level.
+ * parser.c (parse_noleaf): New function.
+ (parse_print, parse_name, etc.): Set need_stat = false.
+
+Wed Nov 2 13:34:32 1990 Tim Wood at home (tim at axolotl.UUCP)
+
+ * pred.c: Call stat() if an AND, OR or NOT node tells you to.
+ * find.c: Limit calls to stat().
+
+Wed Oct 3 17:30:39 1990 Tim Wood at home (tim at axolotl.UUCP)
+
+ * tree.c (opt_expr): New function to rearrange predicates within
+ a conjunction/disjunction so that non-inode (-name, -regex) ones
+ are executed first.
+ * pred.c: Make some supporting tree structure changes for opt_expr().
+
+Sat Dec 7 00:36:06 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * xargs.c (do_exec): Simplify test for which exit
+ status to use if exec fails.
+
+Fri Dec 6 18:24:06 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * listfile.c (list_file): POSIX_ME_HARDER -> POSIXLY_CORRECT.
+
+Thu 24 Oct 1991 21:33:21 Jim Meyering (meyering at churchy.gnu.ai.mit.edu)
* pred.c (pred_fprintf): Don't print "\n" unless it's in the
format string.
@@ -6766,8 +612,6 @@ Mon Oct 21 22:30:35 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* defs.h, parser.c, pred.c: Rename some types that conflict
with reserved POSIX.1 namespace (ended in _t).
-
-
Thu Oct 17 22:39:06 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* xargs.c: Don't determine memory.h based on POSIX, which
@@ -6962,7 +806,7 @@ Wed Dec 26 03:25:51 1990 David J. MacKenzie (djm at apple-gunkies)
on more kinds of systems, incl. POSIX.
* pred.c, listfile.c, xargs.c: Get some decls from unistd.h,
- if available.
+ if available.
* find.c, defs.h: Make `cur_day_start' a time_t, not long.
@@ -7036,7 +880,7 @@ Mon Nov 12 02:54:00 1990 David J. MacKenzie (djm at apple-gunkies)
* pred.c (pred_fstype): Free old fs type.
- * fstype.c, pred.c (pred_fstype), parser.c (parse_fstype):
+ * fstype.c, pred.c (pred_fstype), parser.c (parse_fstype):
Reread the file system type info. every time a filesystem
mount point is crossed, to allow for automounting.
@@ -7056,10 +900,10 @@ Thu Nov 8 11:52:22 1990 David J. MacKenzie (djm at apple-gunkies)
getpwuid and getgrgid. Use them.
* listfile.c: If not _POSIX_SOURCE, define S_ISDIR and
- S_ISBLK. Use them.
+ S_ISBLK. Use them.
* find.c: Use S_ISDIR instead of S_IFDIR, and define if not
- _POSIX_SOURCE.
+ _POSIX_SOURCE.
* Makefile: Define AR and RANLIB and pass to child makes.
lib/Makefile: Use them.
@@ -7070,7 +914,7 @@ Mon Nov 5 00:02:01 1990 David J. MacKenzie (djm at apple-gunkies)
* find.c (process_path): For -xdev, process filesystem
mountpoints (but don't descend them), instead of skipping them
- entirely.
+ entirely.
* find.c, parser.c, defs.h: Add -follow predicate.
@@ -7229,7 +1073,7 @@ Sun Jun 17 13:54:09 1990 David J. MacKenzie (djm at apple-gunkies)
* Makefile: Make fastfind a separate program.
* find.c (main): Print correct message if a predicate arg is
- missing.
+ missing.
* parser.c (insert_exec_ok): Make args that start with a ';' but
contain other characters not terminate the command.
@@ -7316,7 +1160,7 @@ Thu May 17 02:07:44 1990 David J. MacKenzie (djm at abyss)
* fastfind.c: New file.
* find.c (main): Call fastfind if given only 1 arg.
- * util.c (usage): Update message.
+ * util.c (usage): Update message.
* lib/{Makefile,updatedb.sh,bigram.c,code.c}: New files.
* Makefile: Add 'all' and 'install' targets.
@@ -7331,7 +1175,7 @@ Mon May 14 00:09:35 1990 David J. MacKenzie (djm at abyss)
(process_path): Take an arg determining whether this call is
the root of a tree. Use lstat instead of stat. If
stay_on_filesystem, don't process a dir on a different
- filesystem.
+ filesystem.
* parser.c (parse_newer): Use lstat instead of stat. Is this right?
(parse_xdev): Set stay_on_filesystem.
@@ -7357,7 +1201,7 @@ Mon May 14 00:09:35 1990 David J. MacKenzie (djm at abyss)
Sun May 13 17:45:09 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
* Replace fprintf, simple_error, and mem_error with error and
- usage.
+ usage.
* Fix string header includes for USG.
diff --git a/INSTALL b/INSTALL
index 23e5f25d..0338fbce 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,43 +1,27 @@
-Installation Instructions
-*************************
-
-Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free
-Software Foundation, Inc.
-
-This file is free documentation; the Free Software Foundation gives
-unlimited permission to copy, distribute and modify it.
-
Basic Installation
==================
-These are generic installation instructions.
+ These are generic installation instructions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
-you can run in the future to recreate the current configuration, and a
-file `config.log' containing compiler output (useful mainly for
-debugging `configure').
-
- It can also use an optional file (typically called `config.cache'
-and enabled with `--cache-file=config.cache' or simply `-C') that saves
-the results of its tests to speed up reconfiguring. (Caching is
-disabled by default to prevent problems with accidental use of stale
-cache files.)
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
-be considered for the next release. If you are using the cache, and at
-some point `config.cache' contains results you don't want to keep, you
-may remove or edit it.
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
- The file `configure.ac' (or `configure.in') is used to create
-`configure' by a program called `autoconf'. You only need
-`configure.ac' if you want to change it or regenerate `configure' using
-a newer version of `autoconf'.
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
The simplest way to compile this package is:
@@ -59,64 +43,48 @@ The simplest way to compile this package is:
documentation.
5. You can remove the program binaries and object files from the
- source code directory by typing `make clean'. To also remove the
- files that `configure' created (so you can compile the package for
- a different kind of computer), type `make distclean'. There is
- also a `make maintainer-clean' target, but that is intended mainly
- for the package's developers. If you use it, you may have to get
- all sorts of other programs in order to regenerate files that came
- with the distribution.
+ source directory by typing `make clean'. To also remove the files
+ that `configure' created (so you can compile the package for a
+ different kind of computer), type `make distclean'.
Compilers and Options
=====================
-Some systems require unusual options for compilation or linking that the
-`configure' script does not know about. Run `./configure --help' for
-details on some of the pertinent environment variables.
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
- You can give `configure' initial values for configuration parameters
-by setting variables in the command line or in the environment. Here
-is an example:
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
- ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+Using a Different Build Directory
+=================================
- *Note Defining Variables::, for more details.
-
-Compiling For Multiple Architectures
-====================================
-
-You can compile the package for more than one kind of computer at the
-same time, by placing the object files for each architecture in their
-own directory. To do this, you must use a version of `make' that
-supports the `VPATH' variable, such as GNU `make'. `cd' to the
-directory where you want the object files and executables to go and run
-the `configure' script. `configure' automatically checks for the
-source code in the directory that `configure' is in and in `..'.
-
- If you have to use a `make' that does not support the `VPATH'
-variable, you have to compile the package for one architecture at a
-time in the source code directory. After you have installed the
-package for one architecture, use `make distclean' before reconfiguring
-for another architecture.
+ You can compile the package in a different directory from the one
+containing the source code. Doing so allows you to compile it on more
+than one kind of computer at the same time. To do this, you must use a
+version of `make' that supports the `VPATH' variable, such as GNU
+`make'. `cd' to the directory where you want the object files and
+executables to go and run the `configure' script. `configure'
+automatically checks for the source code in the directory that
+`configure' is in and in `..'.
Installation Names
==================
-By default, `make install' installs the package's commands under
-`/usr/local/bin', include files under `/usr/local/include', etc. You
-can specify an installation prefix other than `/usr/local' by giving
-`configure' the option `--prefix=PREFIX'.
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
-pass the option `--exec-prefix=PREFIX' to `configure', the package uses
-PREFIX as the prefix for installing programs and libraries.
-Documentation and other data files still use the regular prefix.
-
- In addition, if you use an unusual directory layout you can give
-options like `--bindir=DIR' to specify different values for particular
-kinds of files. Run `configure --help' for a list of the directories
-you can set and what kinds of files go in them.
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
@@ -125,7 +93,7 @@ option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
-Some packages pay attention to `--enable-FEATURE' options to
+ Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
@@ -140,97 +108,60 @@ you can use the `configure' options `--x-includes=DIR' and
Specifying the System Type
==========================
-There may be some features `configure' cannot figure out automatically,
-but needs to determine by the type of machine the package will run on.
-Usually, assuming the package is built to be run on the _same_
-architectures, `configure' can figure that out, but if it prints a
-message saying it cannot guess the machine type, give it the
-`--build=TYPE' option. TYPE can either be a short name for the system
-type, such as `sun4', or a canonical name which has the form:
-
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
CPU-COMPANY-SYSTEM
-where SYSTEM can have one of these forms:
-
- OS KERNEL-OS
-
- See the file `config.sub' for the possible values of each field. If
+See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
-need to know the machine type.
-
- If you are _building_ compiler tools for cross-compiling, you should
-use the option `--target=TYPE' to select the type of system they will
-produce code for.
+need to know the host type.
- If you want to _use_ a cross compiler, that generates code for a
-platform different from the build platform, you should specify the
-"host" platform (i.e., that on which the generated programs will
-eventually be run) with `--host=TYPE'.
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
Sharing Defaults
================
-If you want to set default values for `configure' scripts to share, you
-can create a site shell script called `config.site' that gives default
-values for variables like `CC', `cache_file', and `prefix'.
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
-Defining Variables
+Operation Controls
==================
-Variables not defined in a site shell script can be set in the
-environment passed to `configure'. However, some packages may run
-configure again during the build, and the customized values of these
-variables may be lost. In order to avoid this problem, you should set
-them in the `configure' command line, using `VAR=value'. For example:
-
- ./configure CC=/usr/local2/bin/gcc
-
-causes the specified `gcc' to be used as the C compiler (unless it is
-overridden in the site shell script). Here is a another example:
-
- /bin/bash ./configure CONFIG_SHELL=/bin/bash
+ `configure' recognizes the following options to control how it
+operates.
-Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent
-configuration-related scripts to be executed by `/bin/bash'.
-
-`configure' Invocation
-======================
-
-`configure' recognizes the following options to control how it operates.
+`--cache-file=FILE'
+ Save the results of the tests in FILE instead of `config.cache'.
+ Set FILE to `/dev/null' to disable caching, for debugging
+ `configure'.
`--help'
-`-h'
Print a summary of the options to `configure', and exit.
-`--version'
-`-V'
- Print the version of Autoconf used to generate the `configure'
- script, and exit.
-
-`--cache-file=FILE'
- Enable the cache: use and save the results of the tests in FILE,
- traditionally `config.cache'. FILE defaults to `/dev/null' to
- disable caching.
-
-`--config-cache'
-`-C'
- Alias for `--cache-file=config.cache'.
-
`--quiet'
`--silent'
`-q'
- Do not print messages saying which checks are being made. To
- suppress all normal output, redirect it to `/dev/null' (any error
- messages will still be shown).
+ Do not print messages saying which checks are being made.
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
-`configure' also accepts some other, not widely useful, options. Run
-`configure --help' for more details.
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
diff --git a/Makefile.am b/Makefile.am
index 63bc3882..3063ab11 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,70 +1,6 @@
-AUTOMAKE_OPTIONS=gnits
-# readme-alpha
+DIST_OTHER = COPYING ChangeLog TODO install-sh config.h.in stamp-h.in
+SUBDIRS = lib find xargs locate doc testsuite
+CONFIG_HEADER = config.h
-EXTRA_DIST = COPYING ChangeLog TODO config.h.in stamp-h.in \
- THANKS import-gnulib.sh import-gnulib.config
-# "tests" is the gnulib unit test dir.
-SUBDIRS = gnulib tests build-aux lib find xargs locate doc po m4
-
-ACLOCAL_AMFLAGS = -I gnulib/m4 -I m4
-
-TESTFILE_SUFFIXES = .exp .xo .xe .xi
-
-# CONFIG_CLEAN_FILES = gnulib/lib/regex.c
-
-
-# DISTCLEANFILES = intl/libintl.h
-
-dist-hook: jy-regex-fix findutils-check-pofiles findutils-check-testfiles
-
-
-## regex.c seems to get left out if I use automake-1.9 but not
-## if I use automake-1.7. Hence dist-hook has to be able to
-## copy regex.c into the relevant (read-only) directory if it
-## is not already there, but needs to avoid doing so if the
-## file is already in place. Ugh.
-##
-## This problem appears not to apply to Automake-1.10, but since
-## gnulib only requires Automake-1.9.6, we should support that.
-## Therefore we probably can't remove this kludge yet.
-##
-## -- James Youngman <jay@gnu.org>
-##
-jy-regex-fix:
- if test -f $(distdir)/gnulib/lib/regex.c ; then \
- echo regex.c is already in place. Great. ; \
- else \
- echo Making $(distdir)/gnulib/lib writable ... ; \
- chmod +w $(distdir)/gnulib/lib ; \
- echo Copying $(srcdir)/gnulib/lib/regex.c to $(distdir)/gnulib/lib ; \
- cp $(srcdir)/gnulib/lib/regex.c $(distdir)/gnulib/lib/regex.c ; \
- fi
-# ls -ld $(srcdir)/gnulib/lib/regex.c $(distdir)/gnulib/lib
-
-## Check that we actually shipped all the .po files. If this rule fails,
-## check ALL_LINGUAS in configure.in against the po files in the source
-## directory (their names, not their contents)
-findutils-check-pofiles:
- @echo ; echo Checking to see if we distributed the full set of .po files
- distcount=`ls $(distdir)/po/*.po | wc -l` ; srccount=`ls $(srcdir)/po/*.po | wc -l` ; test $$distcount -eq $$srccount || ( echo FAILED: Please check the value of ALL_LINGUAS in configure.in against the actual set of ".po" files >&2 ; false )
- @echo All .po files distributed OK.
-
-## Check that we actually shipped all the test files that exist in the source.
-## runtest will run all the .exp files it finds, and so if we don't ship all
-## of them, there will be some tests which people using the CVS code will be
-## running, but people using the source distribution will not.
-findutils-check-testfiles:
- @echo
- $(AUXDIR)/check-testfiles.sh "$(distdir)" "$(srcdir)" $(TESTFILE_SUFFIXES)
-
-
-findutils-check-smells:
- find $(srcdir) \( -path $(srcdir)/autom4te.cache -o \
- -path $(srcdir)/gnulib-git -o \
- -name .git -o \
- \( -type d -name CVS \) \
- \) -prune -o \
- \( -type f -o -type l \) \
- \! \( -name '*~' -o -name '*.xo' -o -name '*.xi' \) \
- -print0 | \
- xargs -0 python $(AUXDIR)/src-sniff.py
+distname:
+ echo findutils-`sed -e '/version_string/!d' -e 's/[^0-9.]*\([0-9.]*\).*/\1/' -e q find/version.c` > $@
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 00000000..5d0bda0b
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,140 @@
+# Makefile.in generated automatically by automake from Makefile.am.
+# Copyright (C) 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = $(exec_prefix)/bin
+sbindir = $(exec_prefix)/sbin
+libexecdir = $(exec_prefix)/libexec
+datadir = $(prefix)/share
+sysconfdir = $(prefix)/etc
+sharedstatedir = $(prefix)/com
+localstatedir = $(prefix)/var
+libdir = $(exec_prefix)/lib
+infodir = $(prefix)/info
+mandir = $(prefix)/man
+includedir = $(prefix)/include
+oldincludedir = /usr/include
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+transform = @program_transform_name@
+
+ALL = ${PROGRAMS} ${LIBPROGRAMS} ${SCRIPTS} ${LIBSCRIPTS} ${LIBFILES}
+ACCONFIG = acconfig.h
+SOURCES =
+DIST_CONF = Makefile.am Makefile.in README INSTALL NEWS \
+ configure configure.in ${ACLOCAL} ${ACCONFIG} ${CONFIG_TOP} \
+ ${CONFIG_BOT} mkinstalldirs
+DIST_FILES = $(DIST_CONF) $(SOURCES) $(TEXINFOS) $(INFOS) $(MANS) $(DIST_OTHER)
+
+DIST_OTHER = COPYING ChangeLog TODO install-sh config.h.in stamp-h.in
+SUBDIRS = lib find xargs locate doc testsuite
+CONFIG_HEADER = config.h
+
+all:: ${ALL}
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+
+@SET_MAKE@
+
+all install install-info uninstall check tags TAGS info dvi::
+ for subdir in $(SUBDIRS); do \
+ echo making $@ in $$subdir ; \
+ (cd $$subdir; $(MAKE) $@); \
+ done
+
+mostlyclean: mostlyclean-recursive mostlyclean-local
+
+clean: clean-recursive clean-local
+
+distclean: distclean-recursive
+ $(MAKE) distclean-local
+
+realclean: realclean-recursive
+ $(MAKE) realclean-local
+
+mostlyclean-recursive clean-recursive distclean-recursive realclean-recursive:
+ for subdir in $(SUBDIRS); do \
+ (cd $$subdir; $(MAKE) `echo $@ | sed s/-recursive//`); \
+ done
+
+mostlyclean-local:
+
+clean-local: mostlyclean-local
+
+distclean-local: clean-local
+ rm -f Makefile config.cache config.log config.status
+ rm -f ${CONFIG_HEADER} stamp-h
+
+realclean-local: distclean-local
+
+# For an explanation of the following Makefile rules, see node
+# `Automatic Remaking' in GNU Autoconf documentation.
+Makefile: Makefile.in config.status
+ CONFIG_FILES=$@ CONFIG_HEADERS= ./config.status
+config.status: configure
+ ./config.status --recheck
+${srcdir}/configure: configure.in ${ACLOCAL}
+ cd $(srcdir); autoconf
+
+${CONFIG_HEADER}: stamp-h
+stamp-h: ${CONFIG_HEADER}.in config.status
+ CONFIG_FILES= CONFIG_HEADERS=${CONFIG_HEADER} ./config.status
+${srcdir}/${CONFIG_HEADER}.in: stamp-h.in
+${srcdir}/stamp-h.in: configure.in ${ACLOCAL} ${ACCONFIG} ${CONFIG_TOP} ${CONFIG_BOT}
+ cd $(srcdir); autoheader
+ date > $(srcdir)/stamp-h.in
+
+dist: $(DIST_FILES) $(DIST_DIRS) distname
+ rm -rf `cat distname`; mkdir `cat distname`
+ @for file in $(DIST_FILES); do \
+ echo linking $$file; \
+ ln $(srcdir)/$$file `cat distname`/$$file || \
+ { echo copying $$file instead; cp -p $(srcdir)/$$file `cat distname`/$$file;}; \
+ done
+ for subdir in $(SUBDIRS); do \
+ (cd $$subdir; $(MAKE) subdir=$$subdir $@); done
+ chmod -R a+r `cat distname`
+ tar -chozf `cat distname`.tar.gz `cat distname`
+ rm -rf `cat distname` distname
+
+check dvi info install uninstall::
+
+tags:: TAGS
+
+TAGS::
+ cd $(srcdir); etags $(SOURCES)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
+
+distname:
+ echo findutils-`sed -e '/version_string/!d' -e 's/[^0-9.]*\([0-9.]*\).*/\1/' -e q find/version.c` > $@
diff --git a/NEWS b/NEWS
index 70d91e6c..c047834a 100644
--- a/NEWS
+++ b/NEWS
@@ -1,1400 +1,51 @@
-GNU findutils NEWS - User visible changes. -*- outline -*- (allout)
+Major changes in release 4.1:
-* Major changes in release 4.3.14-CVS
-
-** Documentation Fixes
-
-#20873: Indicate that * matches / and leading dot in filenames for
-"find -path".
-
-* Major changes in release 4.3.13, 2008-02-14
-
-** Bug Fixes
-
-#22057: Actually rename the old locate database to the new one
-atomically, instead of just claiming the rename is atomic in a
-comment.
-
-#22056: -Xtime tests are off by one second (e.g. rm -f x; touch x;
-find x -mtime 0 should print x).
-
-#21960: xargs should collect the exit status of child processes even if
-the total count of unreaped children has not yet reached the maximum
-allowed.
-
-** Documentation Fixes
-
-Documented various useful techniques with invoking "sh -c" from
-xargs in the Texinfo documentation.
-
-** Translations
-
-Updated the German, Irish, Dutch, Polish and Vietnamese translations.
-
-
-* Major changes in release 4.3.12, 2007-12-19
-
-** Bug Fixes
-
-#15384: Find misbehaves when parent directory is not readable.
-
-** Documentation Fixes
-
-More examples in the xargs manual page, including a portable analogue
-for BSD's "xargs -o".
-
-** Translations
-
-Updated translations: Polish, Dutch, Portuguese, Swedish, Vietnamese.
-
-
-* Major changes in release 4.3.11, 2007-12-02
-
-** Functional changes
-
-When the POSIXLY_CORRECT environment variable is set, "find -perm
-+a+w" is rejected as invalid. Some other similar mode strings
-starting with '+' which are not valid in POSIX are also rejected.
-
-The -prune action now always evaluates as true (this is also a
-bugfix).
-
-
-** Bug Fixes
-
-#21568: Switch to checking the gnulib code out with native git, not
-CVS. This affects mainly those who check findutils code out of CVS.
-This is not the first time this bug has been fixed (the previous fix
-used "cvs update -D", which git-cvspserver silently does not
-support).
-
-#21039: Setting the POSIXLY_CORRECT environment variable now turns off
-warnings by default, because POSIX requires that only diagnostic
-messages (and -ok prompts) are printed on STDERR, and diagnostic
-messages must also result in a nonzero exit status.
-
-#20970: Trailing slash on directory arguments breaks -name. "find
-foo/ -name foo" now correctly matches foo and printf foo/. See POSIX
-interp http://www.opengroup.org/austin/interps/uploads/40/14959/AI-186.txt
-
-#20865: Using both -delete and -prune without explicitly using -depth
-is now an error. Traditionally, -delete has always turned -depth on
-anyway, so this is not a functional change. However, using -depth
-(implicitly or explicitly) makes -prune a no-op. This change is
-intended to avoid nasty surprises for people who test with
-"-print" and then change it to "-delete" when they are happy.
-
-#20803: POSIX requires that -prune always returns true. Previously it
-returned false when -depth was in effect and true otherwise.
-
-#20802: If -delete fails, find's exit status will now be non-zero.
-However, find still skips trying to delete ".".
-
-** Documentation Fixes
-#21635: Some of the documentation files had missing copying
-conditions. The missing files now have copying headers, and these
-are compatible with each other (GNU FDL 1.2).
-
-#21634: No copy of FDL 1.2 included with the source code
-
-#21633: Missing copyright/license header in some documentation.
-
-#21628: find -perm /000 matches all files rather than none, since
-findutils-4.3.3. The Texinfo documentation is now consistent with the
-manual page on this point.
-
-#21270: Formatting fixes to the xargs.1 manual page, including making
-options bold instead of italic and making OPTIONS a section header
-rather than a subsection.
-
-* Major changes in release 4.3.10, 2007-11-13
-
-** Bug Fixes
-
-#21568: findutils gnulib code does not match the date in
-import-gnulib.config. We now check out the gnulib code via
-git-cvs-pserver.
-
-* Major changes in release 4.3.9, 2007-11-11
-
-** Licensing
-
-Findutils version 4.3.9 is released under version 3 of the GNU General
-Public License.
-
-** Bug Fixes
-
-#20834: Avoid segmentation violation for -execdir when $PATH is
-unset. Assume that the PATH is safe in this situation.
-
-#20310: configure uses hosts's support status for "sort -z" when
-generating the updatedb script for use on the target. This is
-inappropriate when cross-compiling, so avoid doing that.
-
-#20263: Compilation fix for DEC Alpha OSF/1 cc, which forbids the
-ordering comparison of function pointers.
-
-#20139: find -[acm]time -N (wrongly) includes files from N days ago,
-as well as (correctly) from less than N days ago.
-
-#20273: When xargs is successful without consuming all of stdin (for
-example, with the -E option), and stdin is seekable, xargs now
-correctly restores the file position, even on platforms where exit()
-does not follow the POSIX rules of doing likewise. Likewise for find
-(for example, with the -ok action).
-
-#20547: The version information printed by find, xargs, locate,
-updatedb, frcode and code now complies with the GNU Project's coding
-standards.
-
-#20662: Avoid memory leak in find -name and other places affected by
-gnulib dirname module. The leak had been present since 4.3.1.
-
-#20751: Avoid memory corruption in find -ls that has been present
-since 4.3.1.
-
-#20871: Assertion failure introduced in 4.3.3, when oldfind is invoked
-in a directory where the parent directory lacks search permission.
-
-** Enhancements
-
-#20594: Allow fine-tuning of the default argument size used by xargs
-and find at ./configure time.
-
-#20688: The warning printed by -name or -iname when the pattern to
-match contains a slash can now be silenced by -nowarn. This warning
-was originally introduced unconditionally in 4.2.21.
-
-Translation of locate --limit problems is improved.
-
-POSIX will standardise -path, so the documentation no longer claims
-that -wholename is the 'canonical' test, and -ipath no longer
-generates a warning.
-
-** Documentation Fixes
-
-Point out more explicitly that the subsecond timestamp support
-introduced by findutils-4.3.3 introduces a change in the format of
-several fields.
-
-Also explain that when reporting a bug, you should check the most
-recent findutils release first.
-
-Introduced doc/find-maint.texi, a maintenance manual for findutils.
-
-Added an extra worked example for find (copying a subset of files).
-
-The locate command's manual page now has a HISTORY section.
-
-#20951: Very bad/unclear/confusing documentation of security checks in
-find -execdir
-
-#20865: Better documentation on the fact that -delete implies -depth
-and that -delete interacts badly with -prune.
-
-#20552: Fixed typos, formatting and section ordering issues in the
-find manual page.
-
-#20529: removed spurious 'o' in description of "xargs -a" in
-doc/find.texi.
-
-#20232: The --max-database-age option of locate was added in release
-4.3.3, but this file (NEWS) did not previously mention this fact.
-
-** Translations
-
-Updated Dutch translation.
-
-
-* Major changes in release 4.3.8, 2007-06-12
-
-** Bug Fixes
-
-#20157: Avoid segfault in locate when run as root. This is caused by
-a buffer overrun, but at this time no exploit mechanism is known.
-
-* Major changes in release 4.3.7, 2007-06-09
-
-** Functional changes
-
-Locate can now read old-format locate databases generated on machines
-with a different byte order. It does this by guessing the byte order,
-so the result is not completely reliable. If you need to share
-databases between machines of different architectures, you should use
-the LOCATE02 format (which has other advantages, as explained in the
-documentation).
-
-** Security Fixes
-
-#20014: Findutils-4.3.7 includes a patch for a potential security
-problem in locate. When locate read an old-format database, it read
-file names into a fixed-length buffer allocated on the heap without
-checking for overflow. Although overflowing a heap buffer is often
-somewhat safer than overflowing a buffer on the stack, this bug still
-has potential security implications.
-
-This bug also affected the following previous findutils releases:
-
- - All releases prior to 4.2.31
- - Findutils 4.3.0 to 4.3.6.
-
-This bug has been assigned CVE number CVE-2007-2452.
-
-** Bug Fixes
-
-#20128: Fix compilation error of find/tree.c on AIX with GCC.
-
-#20005: Tests -mtime -n and -mtime +n incorrectly treated like -mtime n.
-
-#19983: include_next causes compilation failure in findutils 4.3.6 on
-non-GCC compilers
-
-#19981: Don't call setgroups if the function isn't available. This
-fixes Savannah bug# 19981.
-
-#19980: Don't use the functions putw() or getw() since these are not
-in current POSIX. Use the gnulib version of wcwidth() where the
-system does not provide it.
-
-#19979: Compilation errors on BeOS
-
-#19970: Cannot cast from pointer to bool using gnulib's <stdbool.h>
-
-#19967: Use of __attribute((__noreturn__)) makes compilation fail with
-some non-GCC compilers
-
-#19966: find should link against -lm for modf() and fabs()
-
-#19965: Compilation failure on OSF/1 4.0; non-declaration of uintmax_t
-
-#19948: Assertion failure O_NOFOLLOW != 0 on IRIX 6.5
-
-#19871: Typos in find.1
-
-#19596: Fixed this bug again, this time in the Texinfo manual (the
-discussion should compare %b with %s/512, not %s/1024).
-
-#19416: _FORTIFY_SOURCE warn_unused_result warnings
-
-* Major changes in release 4.3.6, 2007-05-21
-
-** Bug Fixes
-
-#19948: Fixed an assertion failure on IRIX 6.5 (O_NOFOLLOW is defined
-to 0 there).
-
-#19923: Fixed an array overrun in groups[] array of 'locate' when run by
-or as root. This bug appears not to be exploitable. If locate is not
-installed setuid, the bug is not exploitable. For setuid
-installations, it is concievable that there could be an information
-leak if the user uses the -d option or the -e option, though the
-maintainer has been unable to provoke this on an x86 system.
-
-#19871: Spurious .R directives in manpage produced error messages from
-GNU troff. This is now fixed (they are corrected to .B).
-
-#19416: The result of I/O operations in print-related actions is now
-checked, and failures are reported. Any failure will cause find's
-exit status to be nonzero. The predicate itself will continue to
-return true.
-
-** Compilation Fixes
-
-A variety of changes were made to allow compilation to succeed on
-non-GNU systems.
-
-#19983: Now compiles on DEC C V5.9-005 on Digital UNIX V4.0 (or at
-least, should).
-
-#19970: Compile correctly on C89 systems where the "_Bool" type is not
-provided, taking into account the limitations of the gnulib
-replacement for stdbool.h.
-
-#19967: Build successfully with C compilers that don't support the GCC
- construct __attribute__((__noreturn__)).
-
-#19966: Findutils should now build on systems which have the modf()
-and fabs() functions in the maths library, -lm. This includes some
-versions of HP-UX and Solaris.
-
-#19965: Fixed a compilation failure on OSF/1 4.0 (no definition of the
-type uintmax_t).
-
-
-* Major changes in release 4.3.5, 2007-05-05
-
-** Functional changes
-
-Updatedb can now support he generation of file name databases which
-are compatible with slocate. For some time, GNU locate has been able
-to read these.
-
-The /proc filesystem is excluded from the locate database (by
-default; change PRUNEPATHS to modify this behaviour).
-
-** Bug Fixes
-
-#19806: The -samefile predicate might get fooled by inode reuse. We
-now hold open a file descriptor on the reference file to prevent this.
-
-#19768: Better detection of corrupted old-style locate databases
-(e.g. if the database is too short to include a complete bigram
-table).
-
-#19766: The frcode and code programs now detect write errors more
-reliably.
-
-#19371: Fix compilation failure on systems which #define open to
-open64 (and similarly with the close system call). This fixes
-Savannah bug #19371, affecting AIX 5.3.
-
-#19658: When cross-compiling, "make clean" no longer deletes the
-generated file doc/regexprops.texi, because there is no way to
-regenerate it.
-
-#19391: When xargs knows that the system's actual exec limit is larger
-than the compiled-in ARG_MAX, use the system's limit without
-generating an assertion failure.
-
-#18203: A duplicate report of bug #17478.
-
-#17478: Error messages from find can garble the console.
-
-#16378: Assertion failure if stat() returns 00000 as the mode
-of a file. This apparently can happen occasionally with broken NFS
-servers.
-
-#11668: FreeBSD extensions for time specification are now
-implemented. In fact, these were included in findutils-4.3.3. The
-change was listed as a functional change (whcih it is) and this bug
-report was not mentioned.
-
-** Documentation Fixes
-
-The locatedb.5 manpage now documents the (default) LOCATE02 format
-more clearly, and also documents the slocate database format.
-
-The maximum and default values applying to the -s option of xargs are
-now documented more clearly in the manual page.
-
-* Major changes in release 4.3.4, 2007-04-21
-
-** Bug Fixes
-
-#19634: Test suite now passes (again) if "." is on your $PATH.
-
-#19619: Findutils builds once again on Cygwin.
-
-#19617: Nonexistent start points are (once again) diagnosed in
-ftsfind. This bug affected only findutils-4.3.3.
-
-#19616: Fix leaf optimisation and loop detection (which were
-unreliable in findutils 4.3.3). This bug affected only
-findutils-4.3.3.
-
-#19615: find --version no longer claims to be using FTS_CWDFD when it
-isn't. This bug affected only findutils-4.3.3.
-
-#19613: "find -L . -type f" no longer causes an assertion failure when
-it encounters a symbolic link loop. This bug affected only
-findutils-4.3.3.
-
-#19605: Issue an error message (and later return nonzero exit status)
- if a symbolic link loop was encountered during directory traversal.
-
-#19484: bigram.c and code.c fail if the first pathname recorded begins
-with a space
-
-#19483: Inconsistent option highlighting in updatedb manpage
-
-#18414: Tests for "find -readable" are skipped for the superuser, as
- on some systems (e.g. Cygwin with an Administrative user) users can
- read mode-000 files.
-
-** Translations
-
-Findutils 4.3.4 includes a translation for the Ukranian language.
-
-
-* Major changes in release 4.3.3, 2007-04-15
-
-Fiundutils-4.3.3 was released on 2007-04-15.
-
-** Bug Fixes
-
-#19596: Correct the comparison in the find manpage between %b and %s
-(the divisor is 512 not 1024).
-
-#18714: In the POSIX locale, vertical tabs and form feeds are not
-field separators.
-
-#18713: Quoted but empty arguments which occur last on an xargs input
-line are no longer ignored, but instead produce an empty argument.
-
-#18554: Documented the construct -exec sh -c 'foo "$@" bar' {} +
-
-#18466: we now avoid this bug by limiting "-execdir ...+"
-to just one argument for the time being. There is a performance
-penalty for doing this. We hope to make a better fix in a later
-release.
-
-#18384: excess bracket in xargs --help
-
-#18320: Zero bytes in input should give warning
-
-#17437: Corrected the handling of X in symbolic permissions (such
-as-u+w,a+X). This change actually occurred in findutils-4.3.2, but
-the NEWS file for that release didn't mention it.
-
-#17396: find -mtime -atime -ctime does not support fractional part
-(see "Functional changes" below)
-
-#14748: find -perm /zzz gives wrong result when zzz evaluates to an
- all-zero mask
-
-#14535: correctly support case-folding in locate (that is, "locate
--i") for multibyte character environments such as UTF-8. Previously,
-if your search string contained a character which was outside the
-single-byte-encoding range for UTF-8 for example, then the
-case-folding behaviour failed to work and only exact matches would be
-returned.
-
-
-
-** Functional changes
-
-The -printf action (and similar related actions) now support %S,
-which is a measurement of the sparseness of a file.
-
-The test "-perm /000" now matches all files instead of no files. For
-over a year find has been issuing warning messages indicating that
-this change will happen. We now issue a warning indicating that the
-change has already happened (in 4.3.x only, there is no plan to make
-this change in the 4.2.x series).
-
-The tests -newer, -anewer, -cnewer, -mtime, -atime, -ctime, -amin,
--cmin, -mmin and -used now support sub-second timestamps, including
-the ability to specify times with non-integer arguments.
-
-The -printf format specifiers also support sub-second timestamps:
- atime ctime mtime
- %a %c %t
- %AS %CS %TS
- %AT %CT %TT
- %A+ %C+ %T+
- %AX %CX %TX
-
-
-The new test -newerXY supports comparison between status times for
-files. One of the status times for a file being considered (denoted
-X) is checked against a reference time (denoted Y) for the file whose
-name id the argument. X and Y can be:
-
- a Access time
- B Birth time (st_birthtime, currently unsupported)
- c Change time
- m Modification time
- t Valid only for the reference time; instead of comparison
- against a file status time, the argument is a time string.
- Not yet supported.
-
-For example, -newermm is equivalent to -newer, and -neweram is true if
-the file being considered was accessed more recently than the
-reference file was modified. The -newerXY test supports subsecond
-timestamps where these are available. The X=B variant is not yet
-implemented.
-
-If you configure the source code and then run the tests with "make
-check", the test suite fails rather than defaulting to testing the
-system binaries.
-
-A new option, --max-database-age, has been added to locate.
-
-
-* Major changes in release 4.3.2, 2006-11-25
-
-** Bug Fixes
-
-#18222: find -printf '%H %P' once again prints the right result if
-more than one start point was given on the command line.
-
-#17782: find -execdir now correctly puts the prefix "./" before the
-expansion of "{}" rather than at the start of the argument it appears
-in. Please note that if you use the -exec or -execdir actions with a
-shell, then you may be vulnerable to shell code injection attacks, so
-don't do that. It's not a security defect in find - you should not be
-passing untrusted data (such as file names chosen by other people) to
-the shell.
-
-#17490: find -regex generated a segfault in findutils-4.3.1, but this
- is fixed in findutils-4.3.2.
-
-#17477: find -printf '%' (that is, where the format has a trailing %)
-now generates an error message.
-
-#17372: The fts-based find executable (the default configuration uses
-fts) is now much faster when -maxdepth is used on filesystems with
-high fanouts.
-
-#15531: The -prune action now behaves correctly when applied to a file.
-
-** Functional changes
-
-The slocate database format is now supported. Preliminary changes
-intended to eventually allow setuid operation of locate have also been
-made. For the moment, please don't install GNU locate as a
-set-user-ID program (except for testing purposes; if you do so, please
-make sure that untrusted users cannot execute the set-user-ID locate
-program).
-
-Use of an slocate database which was built with a nonzero security
-mode (at the moment, GNU updatedb will not do this) forces locate's
-"-e" option to be turned on, which has an effect on the "-S" option
-which is probably surprising for most users.
-
-
-** Documentation Fixes
-
-The global effect of options (other than -daystart and -follow) is now
-explained more clearly in the manual page. Savannah bug #15360.
-
-
-* Major changes in release 4.3.1, 2006-08-06
-
-** Bug Fixes
-
-Find now follows POSIX rules for determining where directories end and
-expressions start. This means that "find \(1 \!2 \, \)" now searches
-in the four named directories, rather than trying to parse an
-expression. (Savannah bug #15235).
-
-You now get a more helpful error message when you use command lines
-which have missing expressions, such as
- find . ( )
- find . !
- find . -a
- find . \( -not \)
- find . \( -true -a
-
-Savannah bug #15800: If find finds more subdirectories within a parent
-directory than it previously expected to based on the link count of
-the parent, the resulting error message now gives the correct
-directory name (previously an error message was issued but it
-specified the wrong directory).
-
-Savannah bug #16738: "find .... -exec ... {} +" now works if you have
-a large environment and many files must be passed to the -exec
-action. The same problem affected the -execdir action, though since
-the number of files in a given directory will normally be smaller, the
-problem was worse for -exec.
-
-Savannah bug #16579: Updatedb now works if it is running as a user
-whose login shell is not actually a shell.
-
-There have also been a number of documentation improvements (includng
-Savannah bug #16269).
-
-** Functional changes
-
-For find, debug output can now be enabled at runtime with the -D
-option. This causes the printing of various sorts of information
-about find's internal state and progress.
-
-The find option -nowarn cannot itself produce a warning (this used to
-happen with commands like "find . -name quux -nowarn -print").
-
-** Performance Enhancements
-
-Find now has a rudimentary cost-based optimiser. It has an idea of
-the basic cost of each test (i.e. that -name is very cheap while -size
-is more expensive). It re-orders tests bearing in mind the cost of
-each test and its likely success. Predicates with side effects (for
-example -delete or -exec) are not reordered. The optimiser is not
-yet enabled by default, but the new option -O controls the query
-optimisation level. To see this in action, try
- find -D opt -O3 . -type f -o -type c -o -size 555 -name Z
-and compare the optimised query with:
- find -D opt -O3 . -size 555 -o -type c -o -type f -name Z
-and
- find -D opt . -size 555 -o -type c -o -type f -name Z
-
-Over time, as optimisations are proven to be robust and correct, they
-will be moved to lower optimisation levels. Some optimisations have
-always been performed by find (for example -name is always done early
-if possible).
-
-** Translations
-
-Findutils 4.3.1 includes updated translations for the following
-languages:
- Vietnamese, Belarusian, Catalan, Danish, German, Greek, Esperanto,
- Spanish, Estonian, Finnish, French, Irish, Galician, Croatian, Hungarian,
- Indonesian, Italian, Japanese, Korean, Luganda, Malay, Dutch, Polish,
- Portuguese, Brazilian Portuguese, Romanian, Russian, Kinyarwanda,
- Slovak, Slovenian, Serbian, Swedish, Turkish, Chinese (simplified),
- Chinese (traditional), Bulgarian
-
-* Major changes in release 4.3.0, 2005-12-12
-
-The 4.3.x release series are currently 'development' releases. Please
-test it, but think carefully before installing it in a production
-system. New features in findutils-4.3.x are under development; they
-may change or go away.
-
-All changes up to and including findutils-4.2.27 are included in this
-release. In addition the following changes are new in this release:
-
-** Functional Changes
-
-By default, find now uses the fts() function to search the file
-system. The use of fts greatly increases find's ability to search
-extremely deep directory hierarchites.
-
-You can tell that the version of find you are using uses FTS, because
-the output of "find --version" will include the word "FTS".
-
-Currently two binaries for 'find' are built. The configure option
---without-fts can be used to select whether 'find' uses fts:
-
- With fts Without fts
-default configuration find oldfind
-configure --with-fts find oldfind
-configure --without-fts ftsfind find
-
-New tests, -readable, -writable, -executable. These check that a file
-can be read, written or executed respectively.
-
-* Major changes in release 4.2.27, 2005-12-06
-
-** Warnings of Future Changes
-
-The test -perm /000 currently matches no files, but for greater
-consistency with -perm -000, this will be changed to match all files;
-this change will probably be made in early 2006. Meanwhile, a warning
-message is given if you do this.
-
-** Bug Fixes
-
-If xargs is invoked with many short arguments on PPC systems running
-the Linux kernel, we no longer get an "argument list too long" error
-from the operating system.
-
-Fixed a bug in the test suite which caused it to spuriously fail on
-systems where ARG_MAX is different to the value used by the Linux
-kernel on 32-bit x86-architecture systems.
-
-On systems running the Linux kernel, "find -printf %F" no longer
-produces the wrong answer for files on filesystems that have been
-remounted elsewhere using "mount --bind". (Savannah bug #14921).
-
-** Documentation Changes
-
-Following some extensive and detailed review comments from Aaron
-Hawley, the material in the manual pages and the Texinfo manual are
-now synchronised.
-
-The %M format specifier of "find -printf" is now documented, although
-it has existed since release 4.2.5.
-
-The 'find' manual page now correctly documents the fact that -regex
-defaults to using Emacs-style regular expressions (though this can be
-changed).
-
-* Major changes in release 4.2.26, 2005-11-19
-
-** Public Service Announcements
-
-I'd like to point out a second time that the interpretation of '-perm
-+mode' has changed to be more POSIX-compliant. If you want the old
-behaviour of the GNU extension you should use '-perm /mode'. See the
-NEWS entry for findutils version 4.2.21 for details.
-
-** Functional Changes
-
-The xargs command now supports a new option (--delimiter) which allows
-input items to be separated by characters other than null and
-whitespace. This resolves Savannah support request sr #102914.
-
-Sometimes find needs to read the /etc/mtab file (or perform the
-equivalent operation on systems not using /etc/mtab). If this
-information is needed but not available, find now exits with an error
-message non-zero status. If the information is not needed, find will
-not spuriously fail.
-
-A new xargs option --delimiter allows the input delimiter to be
-changed (previously \0 was the only choice unless you use the -L
-option, which changes other semantics too).
-
-** Bug Fixes
-
-If the environment size is too large to allow xargs to operate
-normally, 'xargs --help' still works (now).
-
-If the input to xargs is a large number of very short options (for
-example, one character each), earlier versions of xargs would fail
-with 'Argument list too long'. However, since this is precisely the
-problem that xargs was invented to solve, this is a bug. Hence on
-those systems we now correctly use a shorter command line. This
-problem particularly affected 64-bit Linux systems because of the
-larger size of pointers, although 32-bit Linux systems were also
-affected (albeit for longer command lines). In theory the same
-problem could affect 'find -exec {} +', but that's much less likely
-(even so, the bug is fixed there too).
-
-Bugfix for an unusual failure mode (Savannah bug #14842) where an
-attempt to allocate more space for directory contents succeeds but is
-incorrectly diagnosed as a failure. The likelihood of you
-experiencing this depends on your architecture, operating system and
-resource limits. This failure has been observed in a directory
-containing 35396 entries.
-
-** Documentation Changes
-
-The EXAMPLES section of the find manual page now correctly describes
-the symbolic and octal modes for the -perm test.
-
-The documentation and "--help" usage information for the -L, -l, -I
-and -i options have been clarified (but the behaviour has not changed).
-
-The documentation now explains more clearly what happens when you use
-"-L -type l".
-
-* Major changes in release 4.2.25, 2005-09-03
-
-** Bug Fixes
-
-find -perm /440 (which should succeed if a file is readable by its
-owner or group) now works. Previously there was a bug which caused
-this to be treated as "find -perm 440".
-
-Some files in the xargs test suite have been renamed to avoid problems
-on operating systems whoch cannot distinguish filenames on the basis
-of upper/lower case distinctions.
-
-The software now builds on Cygwin, including the generated file
-regexprops.texi.
-
-Findutils should now build once again on systems supporting AFS, but
-this support has not recently been fully tested. Findutils should
-also (once again) build on Cygwin.
-
-** Other Changes
-
-The test suite for find is now much more extensive.
-
-* Major changes in release 4.2.24, 2005-07-29
-
-** Documentation Changes
-
-The manual now includes a "Worked Examples" section which talks about
-the various ways in which findutils can be used to perform common
-tasks, and why some of these alternatives are better than others.
-
-The -I option of xargs (which is required by the POSIX standard) is
-now documented.
-
-We now document the fact that find ensures that commands run by -ok
-and -okdir don't steal find's input. Find does this by redirecting
-the command's standard input from stdin.
-
-Many documentation readability enhancements and proofreading fixes
-were contributed by Aaron Hawley.
-
-** Functional Changes
-
-*** Functional changes in locate
-
-The "--regex" option of locate now assumes the regular expression to
-be in the same syntax as is used in GNU Emacs, though this can be
-changed with the new option --regextype. This is a change from the
-existing behaviour (which was to use POSIX Basic Regular Expressions).
-Since this feature is releatively new anyway, I though it was more
-useful to have compatibility between regular expression handling in
-find and locate than to maintain the short-lived previous behaviour of
-locate.
-
-The locate program now also supports a "--regextype" long option which
-controls which regular expression syntax is understood by locate.
-This is a long option and has no single-letter 'short option'
-equivalent.
-
-*** Functional changes in find
-
-The regular expression syntax understood by "find" can be changed with
-the -regextype option; this option is positional, meaning that you can
-have several tests, each using a distinct syntax (this is not
-recommended practice however).
-
-The default regular expression syntax is substantially the same as
-that recognised by GNU Emacs, except for the fact that "." will match
-a newline.
-
-The leaf optimisation can be disabled with the configure option
-"--disable-leaf-optimisation", which is equivalent to specifying
-"-noleaf" on all find command lines. This is useful for systems
-having filesystems which do not provide traditional Unix behaviour for
-the link count on directories (for example Cygwin and the Solaris 9
-HSFS implementation).
-
-** Bug Fixes
-
-*** Bug Fixes for find
-
-The -iregex test now works once again on systems that lack
-re_search() (that is, systems on which findutils needs to use the
-gnulib version of this function).
-
-find -regex now once again uses GNU Emacs-compatible regular
-expressions.
-
-If invoked with stderr closed, the -fprint and -fprintf actions now no
-longer cause error messages to be sent into the output file.
-
-If the link count of a directory is less that two, the leaf
-optimisation is now disabled for that directory. This should allow
-searching of non-Unix filesystems to be more reliable on systems that
-don't take the trouble to make their filesystems look like traditional
-Unix filesystems. Some filesystems don't even take the trouble to
-have a link count of less than two and for these, -noleaf is still
-required unless --disable-leaf-optimisation was used at configure time.
-
-The "%Y" directive for the -printf action now no longer changes find's
-idea of the mode of the file, so this means among other things that
-"-printf %Y %y" now works properly. This is Savannah bug #13973.
-
-* Major changes in release 4.2.23, 2005-06-19
-
-** Documentation Changes
-
-The -L and -I options of xargs are currently incompatible (but should
-not be).
-
-Improved the documentation for -execdir and -okdir.
-
-** Functional Changes to updatedb
-
-File names ending in "/" which are specified as an argument to
---prunepaths (or in $PRUNEPATHS) don't work, so we now issue an error
-message if the user tries to do that. The obvious exception of course
-is "/" which does work and is not rejected.
-
-
-* Major changes in release 4.2.22, 2005-06-12
-
-** Security Fixes
-
-If a directory entry searched with "find -L" is a symbolic link to
-".", we no longer loop indefinitely. This problem affected find
-versions 4.2.19, 4.2.20 and 4.2.21. This problem allows users to make
-"find" loop indefinitely. This is in effect a denial of service and
-could be used to prevent updates to the locate database or to defeat
-file security checks based on find. However, it should be noted that
-you should not use "find -L" in security-sensitive scenarios.
-
-** Other Bug Fixes
-
-None in this release.
-
-** Functional Changes to locate
-
-A locate database can now be supplied on stdin, using '-' as a element
-of the database-path. If more than one database-path element is '-',
-later instances are ignored.
-
-A new option to locate, '--all' ('-A') causes matches to be limited to
-entries which match all given patterns, not entries which match
-one or more patterns.
-
-** Documentation Changes
-
-Some typos in the manual pages have been fixed. Various parts of the
-manual now point out that it is good practice to quote the argument of
-"-name". The manpage now has a "NON-BUGS" section which explains some
-symptoms that look like bugs but aren't. The explanations of the "%k"
-and "%b" directives to "find -printf" have been imrpoved.
-
-
-* Major changes in release 4.2.21, 2005-06-07
-** Functional Changes to find
-
-The GNU extension "find ... -perm +MODE" has been withdrawn because it
-is incompatible with POSIX in obscure cases like "find ... -perm ++r".
-Use the new syntax "find ... -perm /MODE" instead. Old usages will
-still continue to work, so long as they don't conflict with POSIX.
-
-If the output is going to a terminal, the -print, -fprint, -printf and
--fprintf actions now quote "unusual" characters to prevent unwanted
-effects on the terminal. See "Unusual Characters in File Names" for
-further details. There is no change to the behaviour when the output
-is not going to a terminal. The locate program does the same thing,
-unless the -0 option is in effect (in which case the filenames are
-printed as-is).
-
-** Functional Changes to locate
-
-The locate command will now read each locate database at most once.
-This means that if you are using multiple databases and are searching
-for more than one name, the results will now be printed in a different
-order (and if you specified a small limit with --limit, you may get a
-different set of results).
-
-A new option '--print' for locate causes it to print the matching
-results even if the '--count' or '--statistics' option is in effect.
-
-** Bug Fixes
-find /blah/blah/blah -depth -empty now works once again.
-
-The -regex and -iregex tests of find now correctly accept POSIX Basic
-Regular Expressions. (Savannah bug #12999)
-
-The updatedb program now works on systems where "su" does not support
-the "-s" option, for example Solaris.
-
-* Major changes in release 4.2.20, 2005-03-17
-** Internationalization and Localization
-Updated Vietnamese and Dutch translations.
-
-** Bug Fixes
-Minor bugfix affecting only those who compile from the CVS repository,
-as opposed to those who compile from the source releases.
-
-* Major changes in release 4.2.19, 2005-03-07
-** Bug Fixes
-
-find should now no longer hang on systems which lack the O_NOFOLLOW
-flag to open(2) and which are clients of an unresponsive NFS server
-(Savannah bug #12044).
-
-We now avoid inappropriately failing for "find -L foo" or "find -H
-foo" if foo is a symbolic link (Savannah bug #12181). Previously we
-used to fail with the error message "Too many levels of symbolic
-links".
-
-"find . -false -exec foo {} +" no longer runs an extra instance of foo
-when find exits (Savannah bug #12230).
-
-If the chdir() safety check fails but we can no longer get back to
-where we started, exit with an explanatory (fatal) error message.
-This does not happen on GNU/Linux and FreeBSD because the safety check
-is not needed (the security problem the safety check protects against
-is prevented in a cleaner way on those systems).
-
-"make distclean" no longer deletes regex.c (which "make all" needs).
-
-** Functionality Changes
-"find -printf "%h\n" will now print "." for files in the current directory.
-Previously it printed nothing (but there was a bug in the %h
-implementation anyway). This fixes Savannah bug #12085.
-
-Should now build (again) on non-C99-compliant systems.
-
-** Documentation enhancements
-Fixed some typos and clarified wording in "Working with automounters".
-
-** Internationalization and Localization
-New Vietnamese message translation.
-
-* Major changes in release 4.2.18, 2005-02-16
-** Bug Fixes
-*** "find -depth" was missing out non-leaf directories when they contain
- non-directories. This affected findutils releases 4.2.15,
- 4.2.16 and 4.2.17, but the bug is now fixed.
-*** Find no longer hangs on systems which are clients of unresponsive
- NFS servers.
-** Documentation improvements
-*** Improvements and corrections to the find.1 manpage, including corrections to the descriptions of -H and -L.
-
-* Major changes in release 4.2.17, 2005-02-08
-** Bug Fixes
-*** bug #11861 undefined symbol "basename" on IRIX 5.3
-*** bug #11865 xargs -i regression (as compared to findutils-4.2.12)
-*** bug #11866 Typo in pred_okdir renders it useless (affecting 4.2.16 only)
-*** patch #3723 fix recent process_top_path change (for -execdir on /)
-*** Fixing bug #11866 and applying patch #3723 made -execdir work much better.
-*** find bar/baz/ugh now works again if baz is a symbolic link (broken
- in 4.2.15).
-
-* Major changes in release 4.2.16, 2005-02-05
-** Functionality Changes
-*** Updated the message catalogues for the translated messages.
-*** The subfs filesystem is now treated the same as the autofs
- filesystem is.
-*** New translations: Belarusian, Catalan, Greek, Esperanto,
- Finnish, Irish, Croatian, Hungarian, Japanese, Luganda,
- Malay, Romanian, Slovenian, Serbian, Chinese (simplified).
-
-** Bug Fixes
-*** The -execdir action now works correctly for files named on the
- command line.
-
-* Major changes in release 4.2.15, 2005-01-29
-** Functionality Changes
-*** locate now supports matching regular expression (--regex).
-*** --enable-d_type-optimization (introduced in findutils 4.2.13) is now turned on by default.
-
-* Major changes in release 4.2.14, 2005-01-25
-** Functionality Changes
-*** New options -L, -P, -H for locate. The work in the same was as the same options for find.
-** Bug Fixes
-*** Don't include the "findutils/find/testsuite/find.gnu" subdirectory in the
- distributed tar file more than once.
-*** Should now build on Solaris once again.
-*** -xtype and -printf %Y now work correctly for symbolic links once again
-** Documentation improvements
-*** All options for "locate" are now documented
-
-* Major changes in release 4.2.13, 2005-01-23
-** Performance Enhancements
-*** On Linux and some other systems, a large performance improvement,
- because we can eliminate many of the calls to lstat() (in extreme
- cases, 99% of them). Limited testing shows a 2x speedup on NFS
- filesystems. Other systems which can make use of this enhancement
- include Mac OS X and *BSD.
-
-* Major changes in release 4.2.12, 2005-01-22
-** Functionality Changes
-*** find is now POSIX-compliant, as far as I know.
-*** -exec ... {} + now works.
-*** New actions -execdir and -okdir which are like -exec and -ok but more secure.
-*** "locate -w" is now a synonym for "locate --wholepath".
-*** An empty path entry in the locate database path (for example "::" in
- $LOCATE_PATH or in the argument to "locate -d") is taken to mean
- the default database, whose name is hard-coded in locate.
-** Bug Fixes
-*** If find or xargs cannot write to stdout, for example because
- output is redirected to a file and the disk is full, the
- relevant program will return a non-zero exit status.
-
-* Major changes in release 4.2.11, 2004-12-12
-** Bug Fixes
-*** Compilation fix for systems without EOVERFLOW.
-*** More helpful error message if you make a mistake with (, ), -o or -a.
-** Functionality Changes
-*** If you have unclosed parentheses on the find command line,
- or any of a number of similar problems, find will now produce
- a more helpful error message.
-*** locate -b is now a synonym for locate --basename
-*** locate now supports a --statistics (or -S) option, which prints some
- statistics about the locate databases.
-*** Implemented the -samefile option.
-** Documentation improvements
-*** New chapter in the manual, "Security Considerations".
-*** Better documentation for -prune (Mainly thanks to Stepan Kasal)
-** Bug Fixes
-*** locate's options -i and -w now work with the -e option (previously a bug
- prevented this).
-
-* Major changes in release 4.2.10, 2004-12-06
-** Bug Fixes
-*** Portability fix for fstype.c: should now compile on UNICOS, and possibly
- also produce useful results on BeOS and Dolphin, perhaps other
- systems too.
-
-* Major changes in release 4.2.9, 2004-12-05
-** Functionality Changes
-*** xargs no longer treats a line containing only an underscore as a logical end-of-file. To obtain the behaviour that was previously the default, use "-E_".
-*** xargs now supports the POSIX options -E, -I and -L. These are synonyms
- for the existing options -e, -i and -l, but the latter three are
- now deprecated.
-** Bug Fixes
-*** xargs -n NUM now invokes a command as soon as it has NUM arguments.
- Previously, it waited until NUM+1 items had been read, and then
- invoked the command with NUM arguments, saving the remaining one
- for next time.
-*** If "find -L" discovers a symbolic link loop, an error message is issued.
-*** If you specify a directory on the find command line, but -prune
- is applied to it, find will no longer chdir() into it anyway.
-** Documentation improvements
-*** The precise interpretation of the arguments to the -atime, -ctime
- and similar tests in find has been documented more clearly.
-
-* Major changes in release 4.2.8, 2004-11-24
-*** Bugfix to the findutils 4.2.7 automount handling on Solaris. This
- worked to some extent in findutils-4.2.7, but is much improved in
- findutils-4.2.8.
-
-* Major changes in release 4.2.7, 2004-11-21
-** Functionality Changes
-*** xargs can now read a list of arguments from a named file, allowing
- the invoked program to use the same stdin as xargs started with
- (for example ``xargs --arg-file=todo emacs'').
-** Documentation improvements
-*** The Texinfo manual now has an extra chapter, "Error Messages". Most
- error messages are self-explanatory, but some of the ones which
- are not are explained in this chapter.
-** Bug Fixes
-*** Avoid trying to link against -lsun on UNICOS, which doesn't need it or
- have it.
-*** Bugfix to the findutils 4.2.6 automount handling (which hadn't been enabled
- on Solaris).
-*** Reenabled internationalisation support (which had been accidentally
- disabled in findutils-4.2.5).
-
-* Major changes in release 4.2.6, 2004-11-21
-** Bug Fixes
-*** find now copes rather better when a directory appears to change just as
- it is about to start examining it, which happens with automount.
- This is because automount mounts filesystems as you change
- directory into them. This should resolve Savannah bugs #3998,
- #9043.
-
-* Major changes in release 4.2.5, 2004-11-11
-** Functionality Changes
-*** The POSIX options -H and -L are supported. These control whether or not
- find will follow symbolic links.
-*** The BSD option -P is also now supported (though in any case
- it is the default).
-** Documentation improvements
-*** Better documentation for "xargs -i".
-** Bug Fixes
-*** "make install" now respects DESTDIR when generating localstatedir.
- (this is only relevant if you are installing to some location
- other than the one that you indictaed when you ran "configure").
-*** Compatible with automake versions 1.8 and 1.9.
-*** Build problems on UNICOS now fixed, though the linker will still generate
- warnings because we try to link with the nonexistent library
- "-lsun". Edit $(LIBS) to work around this problem.
-
-* Major changes in release 4.2.4, 2004-11-08
-** Functionality Changes
-*** If your system sort command has a working "-z" option, updatedb will
- now correctly handle newline characters in filenames (as will
- locate).
-*** xargs now uses 128Kb of command line by default (less if the system
- doesn't support that much).
-*** If you specify a 'find' option after non-option, a warning message
- is now issued. Options should be specified immediately after the
- list of paths to search. These warnings are enabled if you
- specify the -warn option, or if stdin is a tty. They are diabled
- by the use of the -nowarn option.
-*** Like find, the locate program now supports an option --null (short form -0)
- which changes the result separator from newline to NULL.
-*** Locate supports the option -c (long form --count) which suppresses normal
- output but prints on stdout the number of results produced (like
- grep -c).
-*** Locate supports the option -l (long form --limit) which limits the
- number of results. This is useful if you only want to find out if
- there are copies of a certain file on the system, but don't want
- to wait for the entire locate database to be searched.
-*** Locate now has an option --basename which forces the specified pattern to
- be matched against the basename of the entries in the locate
- database, rather than the whole name. The default behaviour
- (matching against the whole name of the file including all the
- parent directory names) corresponds to the option --wholename.
-*** updatedb has a new option, --findoptions, that can be used to
- pass extra options through to the find command that it uses.
-** Bug Fixes
-*** "find -printf '%H\n'" now works (rather than segfaulting) on
- systems that have non-writable string constants.
-*** Better POSIX compliance for the -s option to xargs (out of range
- values should just result in bounding to the correct range, not an
- error, so now we just print a warning message and adjust the
- value).
-*** Corrected section numbers of manual page cross-references
-
-* Major changes in release 4.2.3, 2004-10-30
-** Functionality Changes
-*** Added new action -delete which deletes things that find matches.
-*** Added new action -quit which causes find to exit immediately.
-*** A new format directive '%D' for "find -printf" prints the device number.
-*** The -ls predicate no longer truncates user or group names.
-*** Added new option "-d" which is a synonym for "-depth" for compatibility
- with Mac OS, OpenBSD and FreeBSD. This option is already
- deprecated since the POSIX standard specifies "-depth".
-*** Added two new format specifiers to the -printf action; these are
- %y and %Y. They indicate the type of the file as a single letter;
- these are the same latters as are used by the "-type" test.
-*** If a parent directory changes during the execution of find,
- the error message we issue identifies the nature of the change
- (for example the previous and current inode numbers of the
- directory we've just returned out of).
-** Other Changes
-*** Non-functional code changes to silence compiler warnings.
-
-* Major changes in release 4.2.2, 2004-10-24
-** Documentation improvements
-*** "find ... -exec {}+" is not yet supported.
-** Bug Fixes
-*** Fixed compilation problems on Solaris, RedHat EL AS 2.1, Irix, AIX
-*** Work around possible compiler bug on HP-UX 11.23 for ia64
-*** The built-in internationalisation support now works again.
-** Other Changes
-*** We now import the gnulib source in the way it is intended to be used,
- which means among other things that we only have one config.h file
- now.
-*** Functions which findutils requires but which are not present in
- gnulib are now defined in "libfind.a". This is in the lib
- directory, while gnulib is in the gnulib subdirectory.
-*** Fixed a typo in the address of the FSF in many of the file headers.
-
-* Major changes in release 4.2.1, 2004-10-17
-** Bug Fixes
-*** 'find -name \*bar now matches .foobar, because the POSIX standard
- requires it, as explained at
- http://standards.ieee.org/reading/ieee/interp/1003-2-92_int/pasc-1003.2-126.html
-
-* Major changes in release 4.2.1, 2004-10-17
-** Bug Fixes
-*** find -iname now works correctly on systems that have an fnmatch() function
- that does not support FNM_CASEFOLD
-*** updatedb now uses signal names for "trap" instead of numbers,
- as per bug #9465 (see http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html)
-*** Better support for systems lacking intmax_t
-** Other Changes
-**** findutils now uses a newer version of gnulib (dated 2004-10-17).
-
-* Major changes in release 4.2.0, 2003-06-14
-** Functionality Changes
-*** xargs now works better when the environment variables are very extensive.
- The xargs command used to run into difficulties if the environment
- data contained more than 20480 bytes.
-*** New options -wholename and -iwholename
- As per the GNU Projecvt coding standard, These are preferred over
- the -path and -ipath options. Using -ipath now generates a warning,
- though -path does not (since HPUX also offers -path).
-*** The environment variable FIND_BLOCK_SIZE is now ignored.
-*** New option "-ignore_readdir_race"
- silences an error messages which would otherwise occur if a file is removed
- after find has read it from the directory using readdir(), but before
- find stats the file. There is also an option
- -noignore_readdir_race which has the opposite effect.
-** Documentation improvements
-*** The -size option of find is now documented in more detail
-*** POSIX compliance and GNU extensions
- The find manual page also now includes a section
- which describes the relationship between the features of GNU
- find and the POSIX standard. Some other small improvements
- to the find and xargs manual pages have been made.
-*** The argument to the -fprintf directive is now better documented.
- The escape code '\0' for the `-printf' predicate of find is now
- documented, and the documentation for the %k and %b specifiers
- has been improved.
-*** xargs -i is now more clearly documented.
-** Bug Fixes
-*** locate 'pa*d' will now find /etc/passwd (if it exists, of course)
-*** xargs standard input is not inherited by child processes
- If the command invoked by xargs reads from its standard input,
- it now gets nothing, as opposed to stealing data from the
- list of files that xargs is trying to read.
-*** Better support for 64-bit systems.
-*** The command "xargs -i -n1" now works as one might expect,
- I think this is a strange thing to want to do.
-*** Arguments to find -mtime that are too large are now diagnosed
- Previously, this just used to cause find just to do the wrong thing.
-*** updatedb is now somewhat more robust
- The updatedb shell script now does not generate an empty
- database if it fails.
-*** Sanity-check on some data read from locatedb
- Locate now detects some types of file corruption in the
- locate database.
-*** The %k format specifier for -fprintf now works
- This was broken in 4.1.20.
-
-* Major changes in release 4.1.20, 2003-06-14:
-** New maintainer, James Youngman <jay@gnu.org>
-** As far as I know, this is the first release after 4.1.7, but I've left
- a gap just in case.
-** We now use an "imported" version of gnulib, rather than including
- a copy of the gnulib code in our CVS repository. There are no
- differences in the build instructions, though (unless you are
- building directly from CVS, in which case please read the file
- README-CVS).
-** There are no (deliberate) functional changes in version 4.1.20.
-
-* Major changes in release 4.1.7, 2001-05-20:
-fix problem so that default "-print" is added when "-prune" is used.
-security fixes related to directories changing while find is executing.
-
-* Major changes in release 4.1.6, 2000-10-10:
-correct bug in prune.
-added --ignore-case option for locate
-
-* Major changes in release 4.1.5, 2000-04-12:
-Add support for large files
-
-* Major changes in release 4.1.4, 2000-02-26:
-bug fixes, more up-to-date languages.
-
-* Major changes in release 4.1.3, 2000-01-27:
-added internationalization and localization.
-
-* Major changes in release 4.1.2, 2000-01-18:
-None.
-
-* Major changes in release 4.1.1, 1999-08-8:
-attempt at successful compilation on many platforms after years of neglect
- "--existing" option added to locate "--prunefs" option added to updatedb
-
-* Major changes in release 4.1, 1994-11-3:
-
-** Distribution renamed to findutils.
-** updatedb is now a user command, installed in $exec_prefix/bin
+* Distribution renamed to findutils.
+* updatedb is now a user command, installed in $exec_prefix/bin
instead of $exec_prefix/libexec.
-** A few problems in Makefiles and testsuite corrected.
+* A few problems in Makefiles and testsuite corrected.
-* Major changes in release 4.0, 1994-11-2:
+Major changes in release 4.0:
-** Documentation:
-*** Texinfo manual.
-*** Man page for updatedb.
-*** Man page for the locate database formats.
+* Documentation:
+** Texinfo manual.
+** Man page for updatedb.
+** Man page for the locate database formats.
-** find:
-*** Takes less CPU time on long paths, because it uses chdir to descend
+* find:
+** Takes less CPU time on long paths, because it uses chdir to descend
trees, so it does fewer inode lookups.
-*** Does not get trapped in symbolic link loops when -follow is given.
-*** Supports "-fstype afs" if you have /afs and /usr/afsws/include
+** Does not get trapped in symbolic link loops when -follow is given.
+** Supports "-fstype afs" if you have /afs and /usr/afsws/include
and you configure using the --with-afs option.
-*** New action -fls FILE; like -ls but writes to FILE.
+** New action -fls FILE; like -ls but writes to FILE.
-** locate:
-*** Supports a new database format, which is 8-bit clean and
- allows machines with different byte orderings and integer sizes to
+* locate:
+** Supports a new database format, which is 8-bit clean and
+ allows machines with diffent byte orderings and integer sizes to
share the databases. The new locate can also detect and read the
old database format automatically. The new databases are typically
30% or more larger than the old ones (due to allowing all 8 bits in
file names). Search times are approximately the same, or faster on
some systems.
-*** Warns if a file name database is more than 8 days old.
+** Warns if a file name database is more than 8 days old.
-** updatedb:
-*** Takes command-line options.
+* updatedb:
+** Takes command-line options.
-** xargs:
-*** Performance improved 10-20%.
-*** The EOF string is not used when -0 is given.
-*** Now has a test suite. Some minor bugs fixed as a result.
+* xargs:
+** Performance improved 10-20%.
+** The EOF string is not used when -0 is given.
+** Now has a test suite. Some minor bugs fixed as a result.
-* Major changes in release 3.8, 1993-03-29:
+Major changes in release 3.8:
-** case insensitive versions of -lname, -name, -path, -regex:
+* case insensitive versions of -lname, -name, -path, -regex:
-ilname, -iname, -ipath, -iregex
-** %F directive for -printf, -fprintf to print file system type
-
-* Major changes in release 3.7:
-
-** locate can search multiple databases
-** locate has an option to specify the database path
-** updatedb no longer goes into an infinite loop with some versions of tail
+* %F directive for -printf, -fprintf to print file system type
-* No NEWS was kept for earlier releases. Known release dates include:
-** release 3.2, 1991-08-28
-** release 3.1, 1991-08-21
-** release 3.0, 1991-08-21
-** release 2.2, 1991-04-05
-** release 2.1, 1991-01-01
-** release 2.0, 1990-11-20
-** release 1.2, 1990-07-03
-** release 1.1, 1990-06-24
-** release 1.0, 1990-06-22
-** beginning of findutils history, 1987-02-21
-
- --//--
-This is used by Emacs' spell checker ispell.el:
-
-LocalWords: ansi knr strftime xargs updatedb sh fnmatch hin strcpy
-LocalWords: lib getstr getline frcode bigram texi depcomp automake
-LocalWords: strncasecmp strcasecmp LIBOBJS FUNC prunefs allout libexec
-LocalWords: testsuite Texinfo chdir inode fstype afs fls ls EOF lname
-LocalWords: regex ilname iname ipath iregex printf fprintf
+Major changes in release 3.7:
+* locate can search multiple databases
+* locate has an option to specify the database path
+* updatedb no longer goes into an infinite loop with some versions of tail
diff --git a/README b/README
index ec5d312e..beff1408 100644
--- a/README
+++ b/README
@@ -1,21 +1,12 @@
This package contains the GNU find, xargs, and locate programs. find
-and xargs comply with POSIX 1003.2, as far as I know (with the
-exception of the "+" modifier for the "-exec" action, which isn't
-implemented yet). They also support a large number of additional
-options, some borrowed from Unix and some unique to GNU.
+and xargs comply with POSIX 1003.2, as far as I know. They also
+support some additional options, some borrowed from Unix and some
+unique to GNU.
See the file NEWS for a list of major changes in the current release.
See the file INSTALL for compilation and installation instructions.
-To verify the GPG signature of the release, you will need the public
-key of the findutils maintainer. You can download this from
-ftp://ftp.gnu.org/gnu/gnu-keyring.gpg. Alternatively, you could query
-a PGP keyserver, but you will need to use one that can cope with
-subkeys containing photos. Many older key servers cannot do this. I
-use subkeys.pgp.net. I think that one works. See also the
-"Downloading" section of http://www.gnu.org/software/findutils/.
-
Special configure options:
--with-afs
@@ -30,20 +21,6 @@ getpwuid or getgrgid when needed. Speeds up -nouser and -nogroup
unless you are running NIS or Hesiod, which make password and group
calls very expensive.
---enable-debug
- Produce output on the standard error output indicating what find is
-doing. This information includes details about how the command line
-has been parsed and what files have been stat()ed. This output is
-normally interesting only to the maintainer, and so is off by default.
-
-DEFAULT_ARG_SIZE=<value>
- If this environment variable is defined to a numeric expression
-during configure, it determines the default argument size limits used
-by xargs without -s, and by find, when spawning child processes.
-Otherwise, the default is set at 128 kibibytes. If the system cannot
-support the default limit, the system's limit will be used instead.
-
-
To gain speed, GNU find avoids statting files whenever possible.
It does this by:
1. Checking the number of links to directories and not statting files
@@ -62,5 +39,9 @@ searching has been moved to a separate program, `locate'; the same
thing has been done in 4.4BSD. If you use locate, you should run the
included `updatedb' script from cron periodically (typically nightly).
+The `Makefile.am' files are used by an experimental program called
+AutoMake that is under development. It's not ready for general use
+yet, so don't worry about them.
+
Mail suggestions and bug reports for these programs to
-bug-findutils@gnu.org.
+bug-gnu-utils@prep.ai.mit.edu.
diff --git a/TODO b/TODO
index 9dd54685..1dff5860 100644
--- a/TODO
+++ b/TODO
@@ -1,53 +1,5 @@
--*-outline-*-
-* -fstype core dumps on sparc-sun-sunos4.1.3_U1 with gcc-2.95.2
-This is on foxtrot.rahul.net. dbx does not work on compiled find.
-Perhaps gcc is installed incorrectly. "find / -fstype ufs" core dumps
-quickly. cc works correctly.
+To do:
-* Speed of locate without "-i" option needs to be increased.
+Eliminate unnecessary strcpy calls in xargs.
-* Internationalization
-** updatedb.sh should be internationalized
-
-* Eliminate unnecessary strcpy calls in xargs.
-
-* man pages for frcode, bigram, and code
-Perhaps a better description in texi pages as well.
-
-* Add option for find to sort output in lexical order for use for updatedb
-olarsac@airfrance.fr (Olivier) made the following suggestion:
-
-As I was running thru the code looking for the bug I wondered why the updatedb
-has to use sort...
-why not add an option to find that sorts the output in lexical order?
-my point is:
-- sort on a big list is costly (here we do locate on big big file system)
-- find may (in theory) sort incrementally very easily by sorting only the current
-directory entries before recursion
-
-
-* large file problems
-depcomp gets added by automake
-
-* investigate _LIBC when used with TOLOWER and TOUPPER
-_LIBC is used to determine whether TOLOWER should check isupper first.
-Is there something better to check? Alternatively, can tolower be
-checked at run time to determine whether isupper should be called first.
-
-* BeOS problems with multibyte
-Bruno Haible reported problems with BeOS.
-
-* Include example of use of updatedb in documentation.
-Use something close to the Debian daily cron job.
-
-* Supply example for time range commands for find.
-
- --//--
-This is used by Emacs' spell checker ispell.el:
-
-LocalWords: strftime xargs updatedb sh strcpy
-LocalWords: lib frcode bigram texi depcomp automake
-LocalWords: LIBOBJS FUNC findutils
-LocalWords: LIBC TOLOWER TOUPPER tolower isupper
-LocalWords: Debian cron
-LocalWords: Haible BeOS
+Use mode_t and AC_TYPE_MODE_T.
diff --git a/acconfig.h b/acconfig.h
new file mode 100644
index 00000000..e9d4a969
--- /dev/null
+++ b/acconfig.h
@@ -0,0 +1,36 @@
+/* Entries for config.h.in that aren't automatically generated. */
+
+/* Define if you have the Andrew File System. */
+#undef AFS
+
+/* Define If you want find -nouser and -nogroup to make tables of
+ used UIDs and GIDs at startup instead of using getpwuid or
+ getgrgid when needed. Speeds up -nouser and -nogroup unless you
+ are running NIS or Hesiod, which make password and group calls
+ very expensive. */
+#undef CACHE_IDS
+
+/* Define to use SVR4 statvfs to get filesystem type. */
+#undef FSTYPE_STATVFS
+
+/* Define to use SVR3.2 statfs to get filesystem type. */
+#undef FSTYPE_USG_STATFS
+
+/* Define to use AIX3 statfs to get filesystem type. */
+#undef FSTYPE_AIX_STATFS
+
+/* Define to use 4.3BSD getmntent to get filesystem type. */
+#undef FSTYPE_MNTENT
+
+/* Define to use 4.4BSD and OSF1 statfs to get filesystem type. */
+#undef FSTYPE_STATFS
+
+/* Define to use Ultrix getmnt to get filesystem type. */
+#undef FSTYPE_GETMNT
+
+/* Define to `unsigned long' if <sys/types.h> doesn't define. */
+#undef dev_t
+
+/* Define to `unsigned long' if <sys/types.h> doesn't define. */
+#undef ino_t
+
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 00000000..bf72e536
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,171 @@
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+
+/* Define if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+#undef _ALL_SOURCE
+#endif
+
+/* Define if using alloca.c. */
+#undef C_ALLOCA
+
+/* Define if the closedir function returns void instead of int. */
+#undef CLOSEDIR_VOID
+
+/* Define to empty if the keyword does not work. */
+#undef const
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+ This function is required for alloca.c support on those systems. */
+#undef CRAY_STACKSEG_END
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef gid_t
+
+/* Define if you have alloca, as a function or macro. */
+#undef HAVE_ALLOCA
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
+#undef HAVE_ALLOCA_H
+
+/* Define if you don't have vprintf but do have _doprnt. */
+#undef HAVE_DOPRNT
+
+/* Define if you have the getmntent function. */
+#undef HAVE_GETMNTENT
+
+/* Define if your struct stat has st_blocks. */
+#undef HAVE_ST_BLOCKS
+
+/* Define if your struct stat has st_rdev. */
+#undef HAVE_ST_RDEV
+
+/* Define if you have the strftime function. */
+#undef HAVE_STRFTIME
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define if your struct tm has tm_zone. */
+#undef HAVE_TM_ZONE
+
+/* Define if you don't have tm_zone but do have the external array
+ tzname. */
+#undef HAVE_TZNAME
+
+/* Define if you have the vprintf function. */
+#undef HAVE_VPRINTF
+
+/* Define if major, minor, and makedev are declared in <mkdev.h>. */
+#undef MAJOR_IN_MKDEV
+
+/* Define if major, minor, and makedev are declared in <sysmacros.h>. */
+#undef MAJOR_IN_SYSMACROS
+
+/* Define if on MINIX. */
+#undef _MINIX
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef pid_t
+
+/* Define if the system does not provide POSIX.1 features except
+ with this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define if you need to in order for stat and other things to work. */
+#undef _POSIX_SOURCE
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+#undef size_t
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+#undef STACK_DIRECTION
+
+/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */
+#undef STAT_MACROS_BROKEN
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if your <sys/time.h> declares struct tm. */
+#undef TM_IN_SYS_TIME
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef uid_t
+
+/* Define if you have the Andrew File System. */
+#undef AFS
+
+/* Define If you want find -nouser and -nogroup to make tables of
+ used UIDs and GIDs at startup instead of using getpwuid or
+ getgrgid when needed. Speeds up -nouser and -nogroup unless you
+ are running NIS or Hesiod, which make password and group calls
+ very expensive. */
+#undef CACHE_IDS
+
+/* Define to use SVR4 statvfs to get filesystem type. */
+#undef FSTYPE_STATVFS
+
+/* Define to use SVR3.2 statfs to get filesystem type. */
+#undef FSTYPE_USG_STATFS
+
+/* Define to use AIX3 statfs to get filesystem type. */
+#undef FSTYPE_AIX_STATFS
+
+/* Define to use 4.3BSD getmntent to get filesystem type. */
+#undef FSTYPE_MNTENT
+
+/* Define to use 4.4BSD and OSF1 statfs to get filesystem type. */
+#undef FSTYPE_STATFS
+
+/* Define to use Ultrix getmnt to get filesystem type. */
+#undef FSTYPE_GETMNT
+
+/* Define to `unsigned long' if <sys/types.h> doesn't define. */
+#undef dev_t
+
+/* Define to `unsigned long' if <sys/types.h> doesn't define. */
+#undef ino_t
+
+/* Define if you have the fchdir function. */
+#undef HAVE_FCHDIR
+
+/* Define if you have the getcwd function. */
+#undef HAVE_GETCWD
+
+/* Define if you have the strerror function. */
+#undef HAVE_STRERROR
+
+/* Define if you have the <dirent.h> header file. */
+#undef HAVE_DIRENT_H
+
+/* Define if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* Define if you have the <ndir.h> header file. */
+#undef HAVE_NDIR_H
+
+/* Define if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define if you have the <sys/dir.h> header file. */
+#undef HAVE_SYS_DIR_H
+
+/* Define if you have the <sys/ndir.h> header file. */
+#undef HAVE_SYS_NDIR_H
+
+/* Define if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the sun library (-lsun). */
+#undef HAVE_LIBSUN
diff --git a/configure b/configure
new file mode 100755
index 00000000..73838939
--- /dev/null
+++ b/configure
@@ -0,0 +1,2774 @@
+#!/bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.1
+# Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+ --enable-id-cache cache all UIDs & GIDs; avoid if using NIS or Hesiod"
+ac_help="$ac_help
+ --with-afs support -fstype afs"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Initialize some other variables.
+subdirs=
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -build | --build | --buil | --bui | --bu | --b)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=* | --b=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=PREFIX install architecture-dependent files in PREFIX
+ [same as prefix]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM run sed PROGRAM on installed program names
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+--enable and --with options recognized:$ac_help
+EOF
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.1"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 unused; standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 unused; some systems may open it to /dev/tty
+# 4 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 4>/dev/null
+else
+ exec 4>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=find/pred.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} $CFLAGS $CPPFLAGS conftest.$ac_ext -c 1>&5 2>&5'
+ac_link='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext -o conftest $LIBS 1>&5 2>&5'
+
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+
+# Check whether --enable-id-cache or --disable-id-cache was given.
+enableval="$enable_id_cache"
+if test -n "$enableval"; then
+ cat >> confdefs.h <<\EOF
+#define CACHE_IDS 1
+EOF
+
+fi
+
+# Check whether --with-afs or --without-afs was given.
+withval="$with_afs"
+if test -n "$withval"; then
+ cat >> confdefs.h <<\EOF
+#define AFS 1
+EOF
+
+ CPPFLAGS="$CPPFLAGS -I/usr/afsws/include"
+ LIBS="$LIBS -L/usr/afsws/lib -L/usr/afsws/lib/afs -lsys -lrx -llwp"
+fi
+
+if test "$program_transform_name" = s,x,x,; then
+ program_transform_name=
+else
+ # Double any \ or $.
+ echo 's,\\,\\\\,g; s,\$,$$,g' > conftestsed
+ program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+ rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+ program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_CC" && ac_cv_prog_CC="cc"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&4
+else
+ echo "$ac_t""no" 1>&4
+fi
+
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if ${CC-cc} -E conftest.c 2>&5 | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+echo "$ac_t""$ac_cv_prog_gcc" 1>&4
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+ if test "${CFLAGS+set}" != set; then
+ echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_prog_gcc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_gcc_g=yes
+else
+ ac_cv_prog_gcc_g=no
+fi
+rm -f conftest*
+
+fi
+ echo "$ac_t""$ac_cv_prog_gcc_g" 1>&4
+ if test $ac_cv_prog_gcc_g = yes; then
+ CFLAGS="-g -O"
+ else
+ CFLAGS="-O"
+ fi
+ fi
+else
+ GCC=
+ test "${CFLAGS+set}" = set || CFLAGS="-g"
+fi
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&4
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '${'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 533 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 547 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+fi
+CPP="$ac_cv_prog_CPP"
+echo "$ac_t""$CPP" 1>&4
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&4
+if test -z "$INSTALL"; then
+if eval "test \"`echo '${'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ case "$ac_dir" in
+ ''|.|/etc|/usr/sbin|/usr/etc|/sbin|/usr/afsws/bin|/usr/ucb) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ for ac_prog in ginstall installbsd scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ # OSF/1 installbsd also uses dspmsg, but is usable.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_ifs"
+ # As a last resort, use the slow shell script.
+ test -z "$ac_cv_path_install" && ac_cv_path_install="$ac_install_sh"
+fi
+ INSTALL="$ac_cv_path_install"
+fi
+echo "$ac_t""$INSTALL" 1>&4
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_RANLIB="ranlib"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+ echo "$ac_t""$RANLIB" 1>&4
+else
+ echo "$ac_t""no" 1>&4
+fi
+
+echo $ac_n "checking whether ${MAKE-make} sets \$MAKE""... $ac_c" 1>&4
+set dummy ${MAKE-make}; ac_make=$2
+if eval "test \"`echo '${'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftestmake <<\EOF
+all:
+ @echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ SET_MAKE=
+else
+ echo "$ac_t""no" 1>&4
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+echo $ac_n "checking for AIX""... $ac_c" 1>&4
+cat > conftest.$ac_ext <<EOF
+#line 697 "configure"
+#include "confdefs.h"
+#ifdef _AIX
+ yes
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "yes" >/dev/null 2>&1; then
+ rm -rf conftest*
+ echo "$ac_t""yes" 1>&4; cat >> confdefs.h <<\EOF
+#define _ALL_SOURCE 1
+EOF
+
+else
+ rm -rf conftest*
+ echo "$ac_t""no" 1>&4
+fi
+rm -f conftest*
+
+
+ac_safe=`echo "minix/config.h" | tr './\055' '___'`
+echo $ac_n "checking for minix/config.h""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 724 "configure"
+#include "confdefs.h"
+#include <minix/config.h>
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ MINIX=yes
+else
+ echo "$ac_t""no" 1>&4
+MINIX=
+fi
+
+if test "$MINIX" = yes; then
+ cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define _POSIX_1_SOURCE 2
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define _MINIX 1
+EOF
+
+fi
+
+echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&4
+if test -d /etc/conf/kconfig.d &&
+ grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1
+then
+ echo "$ac_t""yes" 1>&4
+ ISC=yes # If later tests want to check for ISC.
+ cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+ if test "$GCC" = yes; then
+ CC="$CC -posix"
+ else
+ CC="$CC -Xp"
+ fi
+else
+ echo "$ac_t""no" 1>&4
+ ISC=
+fi
+
+
+echo $ac_n "checking for -lsun""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_lib_sun'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ ac_save_LIBS="$LIBS"
+LIBS="$LIBS -lsun "
+cat > conftest.$ac_ext <<EOF
+#line 791 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+getpwnam()
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ eval "ac_cv_lib_sun=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_lib_sun=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'sun`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ ac_tr_lib=HAVE_LIB`echo sun | tr '[a-z]' '[A-Z]'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="$LIBS -lsun"
+
+else
+ echo "$ac_t""no" 1>&4
+fi
+
+
+for ac_hdr in fcntl.h string.h limits.h unistd.h
+do
+ac_safe=`echo "$ac_hdr" | tr './\055' '___'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 832 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ ac_tr_hdr=HAVE_`echo $ac_hdr | tr '[a-z]./\055' '[A-Z]___'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&4
+fi
+done
+
+# If we cannot run a trivial program, we must be cross compiling.
+echo $ac_n "checking whether cross-compiling""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_c_cross'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_cross=yes
+else
+cat > conftest.$ac_ext <<EOF
+#line 869 "configure"
+#include "confdefs.h"
+main(){return(0);}
+EOF
+eval $ac_link
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ ac_cv_c_cross=no
+else
+ ac_cv_c_cross=yes
+fi
+fi
+rm -fr conftest*
+fi
+cross_compiling=$ac_cv_c_cross
+echo "$ac_t""$ac_cv_c_cross" 1>&4
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_header_stdc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 890 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_header_stdc=yes
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 912 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 930 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+ ac_cv_header_stdc=no
+else
+cat > conftest.$ac_ext <<EOF
+#line 951 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+eval $ac_link
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+fi
+rm -fr conftest*
+fi
+fi
+echo "$ac_t""$ac_cv_header_stdc" 1>&4
+if test $ac_cv_header_stdc = yes; then
+ cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+echo $ac_n "checking whether sys/types.h defines makedev""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_header_sys_types_h_makedev'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 985 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+int main() { return 0; }
+int t() {
+return makedev(0, 0);
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ ac_cv_header_sys_types_h_makedev=yes
+else
+ rm -rf conftest*
+ ac_cv_header_sys_types_h_makedev=no
+fi
+rm -f conftest*
+
+
+fi
+echo "$ac_t""$ac_cv_header_sys_types_h_makedev" 1>&4
+
+if test $ac_cv_header_sys_types_h_makedev = no; then
+ac_safe=`echo "sys/mkdev.h" | tr './\055' '___'`
+echo $ac_n "checking for sys/mkdev.h""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1013 "configure"
+#include "confdefs.h"
+#include <sys/mkdev.h>
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ cat >> confdefs.h <<\EOF
+#define MAJOR_IN_MKDEV 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&4
+fi
+
+
+ if test $ac_cv_header_sys_mkdev_h = no; then
+ac_safe=`echo "sys/sysmacros.h" | tr './\055' '___'`
+echo $ac_n "checking for sys/sysmacros.h""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1047 "configure"
+#include "confdefs.h"
+#include <sys/sysmacros.h>
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ cat >> confdefs.h <<\EOF
+#define MAJOR_IN_SYSMACROS 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&4
+fi
+
+ fi
+fi
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
+do
+ac_safe=`echo "$ac_hdr" | tr './\055' '___'`
+echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1085 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_hdr>
+int main() { return 0; }
+int t() {
+DIR *dirp = 0;
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+ eval "ac_cv_header_dirent_$ac_safe=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_header_dirent_$ac_safe=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ ac_tr_hdr=HAVE_`echo $ac_hdr | tr '[a-z]./\055' '[A-Z]___'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ ac_header_dirent=$ac_hdr; break
+else
+ echo "$ac_t""no" 1>&4
+fi
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+echo $ac_n "checking for -ldir""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_lib_dir'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ ac_save_LIBS="$LIBS"
+LIBS="$LIBS -ldir "
+cat > conftest.$ac_ext <<EOF
+#line 1124 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+opendir()
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ eval "ac_cv_lib_dir=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_lib_dir=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'dir`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ LIBS="$LIBS -ldir"
+else
+ echo "$ac_t""no" 1>&4
+fi
+
+else
+echo $ac_n "checking for -lx""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_lib_x'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ ac_save_LIBS="$LIBS"
+LIBS="$LIBS -lx "
+cat > conftest.$ac_ext <<EOF
+#line 1158 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+opendir()
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ eval "ac_cv_lib_x=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_lib_x=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'x`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ LIBS="$LIBS -lx"
+else
+ echo "$ac_t""no" 1>&4
+fi
+
+fi
+
+echo $ac_n "checking whether stat file-mode macros are broken""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_header_stat_broken'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1191 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef S_ISBLK
+# if S_ISBLK (S_IFDIR)
+You lose.
+# endif
+# ifdef S_IFCHR
+# if S_ISBLK (S_IFCHR)
+You lose.
+# endif
+# endif
+#endif
+
+#ifdef S_ISLNK
+# if S_ISLNK (S_IFREG)
+You lose.
+# endif
+#endif
+
+#ifdef S_ISSOCK
+# if S_ISSOCK (S_IFREG)
+You lose.
+# endif
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "You lose" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_header_stat_broken=yes
+else
+ rm -rf conftest*
+ ac_cv_header_stat_broken=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_header_stat_broken" 1>&4
+if test $ac_cv_header_stat_broken = yes; then
+ cat >> confdefs.h <<\EOF
+#define STAT_MACROS_BROKEN 1
+EOF
+
+fi
+
+echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_header_sys_wait_h'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1243 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+int main() { return 0; }
+int t() {
+int s;
+wait (&s);
+s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+ ac_cv_header_sys_wait_h=yes
+else
+ rm -rf conftest*
+ ac_cv_header_sys_wait_h=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&4
+if test $ac_cv_header_sys_wait_h = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SYS_WAIT_H 1
+EOF
+
+fi
+
+
+echo $ac_n "checking how to get filesystem type""... $ac_c" 1>&4
+fstype=no
+# The order of these tests is important.
+cat > conftest.$ac_ext <<EOF
+#line 1283 "configure"
+#include "confdefs.h"
+#include <sys/statvfs.h>
+#include <sys/fstyp.h>
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ cat >> confdefs.h <<\EOF
+#define FSTYPE_STATVFS 1
+EOF
+ fstype=SVR4
+else
+ echo "$ac_err" >&5
+fi
+rm -f conftest*
+if test $fstype = no; then
+cat > conftest.$ac_ext <<EOF
+#line 1302 "configure"
+#include "confdefs.h"
+#include <sys/statfs.h>
+#include <sys/fstyp.h>
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ cat >> confdefs.h <<\EOF
+#define FSTYPE_USG_STATFS 1
+EOF
+ fstype=SVR3
+else
+ echo "$ac_err" >&5
+fi
+rm -f conftest*
+fi
+if test $fstype = no; then
+cat > conftest.$ac_ext <<EOF
+#line 1322 "configure"
+#include "confdefs.h"
+#include <sys/statfs.h>
+#include <sys/vmount.h>
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ cat >> confdefs.h <<\EOF
+#define FSTYPE_AIX_STATFS 1
+EOF
+ fstype=AIX
+else
+ echo "$ac_err" >&5
+fi
+rm -f conftest*
+fi
+if test $fstype = no; then
+cat > conftest.$ac_ext <<EOF
+#line 1342 "configure"
+#include "confdefs.h"
+#include <mntent.h>
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ cat >> confdefs.h <<\EOF
+#define FSTYPE_MNTENT 1
+EOF
+ fstype=4.3BSD
+else
+ echo "$ac_err" >&5
+fi
+rm -f conftest*
+fi
+if test $fstype = no; then
+cat > conftest.$ac_ext <<EOF
+#line 1361 "configure"
+#include "confdefs.h"
+#include <sys/mount.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "f_type;" >/dev/null 2>&1; then
+ rm -rf conftest*
+ cat >> confdefs.h <<\EOF
+#define FSTYPE_STATFS 1
+EOF
+ fstype=4.4BSD/OSF1
+fi
+rm -f conftest*
+
+fi
+if test $fstype = no; then
+cat > conftest.$ac_ext <<EOF
+#line 1378 "configure"
+#include "confdefs.h"
+#include <sys/mount.h>
+#include <sys/fs_types.h>
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ cat >> confdefs.h <<\EOF
+#define FSTYPE_GETMNT 1
+EOF
+ fstype=Ultrix
+else
+ echo "$ac_err" >&5
+fi
+rm -f conftest*
+fi
+echo "$ac_t""$fstype" 1>&4
+
+
+echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_type_uid_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1404 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "uid_t" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_uid_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_uid_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_uid_t" 1>&4
+if test $ac_cv_type_uid_t = no; then
+ cat >> confdefs.h <<\EOF
+#define uid_t int
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define gid_t int
+EOF
+
+fi
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_type_size_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1436 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "size_t" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_size_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_size_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_size_t" 1>&4
+if test $ac_cv_type_size_t = no; then
+ cat >> confdefs.h <<\EOF
+#define size_t unsigned
+EOF
+
+fi
+
+echo $ac_n "checking for pid_t""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_type_pid_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1467 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "pid_t" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_pid_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_pid_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_pid_t" 1>&4
+if test $ac_cv_type_pid_t = no; then
+ cat >> confdefs.h <<\EOF
+#define pid_t int
+EOF
+
+fi
+
+echo $ac_n "checking for ino_t""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_type_ino_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1498 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "ino_t" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_ino_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_ino_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_ino_t" 1>&4
+if test $ac_cv_type_ino_t = no; then
+ cat >> confdefs.h <<\EOF
+#define ino_t unsigned long
+EOF
+
+fi
+
+echo $ac_n "checking for dev_t""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_type_dev_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1529 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "dev_t" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_dev_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_dev_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_dev_t" 1>&4
+if test $ac_cv_type_dev_t = no; then
+ cat >> confdefs.h <<\EOF
+#define dev_t unsigned long
+EOF
+
+fi
+
+echo $ac_n "checking for st_blocks in struct stat""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_struct_st_blocks'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1560 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+int main() { return 0; }
+int t() {
+struct stat s; s.st_blocks;
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+ ac_cv_struct_st_blocks=yes
+else
+ rm -rf conftest*
+ ac_cv_struct_st_blocks=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_struct_st_blocks" 1>&4
+if test $ac_cv_struct_st_blocks = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_ST_BLOCKS 1
+EOF
+
+else
+ LIBOBJS="$LIBOBJS fileblocks.o"
+fi
+
+echo $ac_n "checking for st_rdev in struct stat""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_struct_st_rdev'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1594 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+int main() { return 0; }
+int t() {
+struct stat s; s.st_rdev;
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+ ac_cv_struct_st_rdev=yes
+else
+ rm -rf conftest*
+ ac_cv_struct_st_rdev=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_struct_st_rdev" 1>&4
+if test $ac_cv_struct_st_rdev = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_ST_RDEV 1
+EOF
+
+fi
+
+echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_struct_tm'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1626 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <time.h>
+int main() { return 0; }
+int t() {
+struct tm *tp; tp->tm_sec;
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+ ac_cv_struct_tm=time.h
+else
+ rm -rf conftest*
+ ac_cv_struct_tm=sys/time.h
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_struct_tm" 1>&4
+if test $ac_cv_struct_tm = sys/time.h; then
+ cat >> confdefs.h <<\EOF
+#define TM_IN_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking for tm_zone in struct tm""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_struct_tm_zone'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1658 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_cv_struct_tm>
+int main() { return 0; }
+int t() {
+struct tm tm; tm.tm_zone;
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+ ac_cv_struct_tm_zone=yes
+else
+ rm -rf conftest*
+ ac_cv_struct_tm_zone=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_struct_tm_zone" 1>&4
+if test "$ac_cv_struct_tm_zone" = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_TM_ZONE 1
+EOF
+
+else
+ echo $ac_n "checking for tzname""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_var_tzname'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1689 "configure"
+#include "confdefs.h"
+#include <time.h>
+#ifndef tzname /* For SGI. */
+extern char *tzname[]; /* RS6000 and others reject char **tzname. */
+#endif
+int main() { return 0; }
+int t() {
+atoi(*tzname);
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ ac_cv_var_tzname=yes
+else
+ rm -rf conftest*
+ ac_cv_var_tzname=no
+fi
+rm -f conftest*
+
+fi
+ echo "$ac_t""$ac_cv_var_tzname" 1>&4
+ if test $ac_cv_var_tzname = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_TZNAME 1
+EOF
+
+ fi
+fi
+
+echo $ac_n "checking for working const""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_c_const'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1724 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+
+/* Ultrix mips cc rejects this. */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this. */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this. */
+struct point {int x, y;};
+static struct point const zero;
+/* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in an arm
+ of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+}
+
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+ ac_cv_c_const=yes
+else
+ rm -rf conftest*
+ ac_cv_c_const=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_c_const" 1>&4
+if test $ac_cv_c_const = no; then
+ cat >> confdefs.h <<\EOF
+#define const
+EOF
+
+fi
+
+
+
+for ac_func in memcmp memset mktime stpcpy strdup strftime strspn strstr strtol
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1801 "configure"
+#include "confdefs.h"
+#include <ctype.h> /* Arbitrary system header to define __stub macros. */
+/* Override any gcc2 internal prototype to avoid an error. */
+char $ac_func();
+
+int main() { return 0; }
+int t() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ :
+else
+ echo "$ac_t""no" 1>&4
+LIBOBJS="$LIBOBJS ${ac_func}.o"
+fi
+
+done
+
+for ac_func in fchdir getcwd strerror
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1848 "configure"
+#include "confdefs.h"
+#include <ctype.h> /* Arbitrary system header to define __stub macros. */
+/* Override any gcc2 internal prototype to avoid an error. */
+char $ac_func();
+
+int main() { return 0; }
+int t() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ ac_tr_func=HAVE_`echo $ac_func | tr '[a-z]' '[A-Z]'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&4
+fi
+done
+
+# strftime is in -lintl on SCO UNIX.
+echo $ac_n "checking for -lintl""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_lib_intl'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ ac_save_LIBS="$LIBS"
+LIBS="$LIBS -lintl "
+cat > conftest.$ac_ext <<EOF
+#line 1898 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+strftime()
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ eval "ac_cv_lib_intl=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_lib_intl=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'intl`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ LIBS="$LIBS -lintl"
+else
+ echo "$ac_t""no" 1>&4
+fi
+
+echo $ac_n "checking for strftime""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_func_strftime'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1929 "configure"
+#include "confdefs.h"
+#include <ctype.h> /* Arbitrary system header to define __stub macros. */
+/* Override any gcc2 internal prototype to avoid an error. */
+char strftime();
+
+int main() { return 0; }
+int t() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_strftime) || defined (__stub___strftime)
+choke me
+#else
+strftime();
+#endif
+
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ eval "ac_cv_func_strftime=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_func_strftime=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_func_'strftime`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ cat >> confdefs.h <<\EOF
+#define HAVE_STRFTIME 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&4
+fi
+
+echo $ac_n "checking for vprintf""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_func_vprintf'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1974 "configure"
+#include "confdefs.h"
+#include <ctype.h> /* Arbitrary system header to define __stub macros. */
+/* Override any gcc2 internal prototype to avoid an error. */
+char vprintf();
+
+int main() { return 0; }
+int t() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_vprintf) || defined (__stub___vprintf)
+choke me
+#else
+vprintf();
+#endif
+
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ eval "ac_cv_func_vprintf=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_func_vprintf=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ cat >> confdefs.h <<\EOF
+#define HAVE_VPRINTF 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&4
+fi
+
+if test "$ac_cv_func_vprintf" != yes; then
+echo $ac_n "checking for _doprnt""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_func__doprnt'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2020 "configure"
+#include "confdefs.h"
+#include <ctype.h> /* Arbitrary system header to define __stub macros. */
+/* Override any gcc2 internal prototype to avoid an error. */
+char _doprnt();
+
+int main() { return 0; }
+int t() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub__doprnt) || defined (__stub____doprnt)
+choke me
+#else
+_doprnt();
+#endif
+
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ eval "ac_cv_func__doprnt=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_func__doprnt=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ cat >> confdefs.h <<\EOF
+#define HAVE_DOPRNT 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&4
+fi
+
+fi
+
+# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+# for constant arguments. Useless!
+echo $ac_n "checking for working alloca.h""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_header_alloca_h'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2069 "configure"
+#include "confdefs.h"
+#include <alloca.h>
+int main() { return 0; }
+int t() {
+char *p = alloca(2 * sizeof(int));
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ ac_cv_header_alloca_h=yes
+else
+ rm -rf conftest*
+ ac_cv_header_alloca_h=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_header_alloca_h" 1>&4
+if test $ac_cv_header_alloca_h = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA_H 1
+EOF
+
+fi
+
+echo $ac_n "checking for alloca""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_func_alloca'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2100 "configure"
+#include "confdefs.h"
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# if HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# ifdef _AIX
+ #pragma alloca
+# else
+# ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+# endif
+# endif
+# endif
+#endif
+
+int main() { return 0; }
+int t() {
+char *p = (char *) alloca(1);
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ ac_cv_func_alloca=yes
+else
+ rm -rf conftest*
+ ac_cv_func_alloca=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_func_alloca" 1>&4
+if test $ac_cv_func_alloca = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA 1
+EOF
+
+fi
+
+if test $ac_cv_func_alloca = no; then
+ # The SVR3 libPW and SVR4 libucb both contain incompatible functions
+ # that cause trouble. Some versions do not even contain alloca or
+ # contain a buggy version. If you still want to use their alloca,
+ # use ar to extract alloca.o from them instead of compiling alloca.c.
+ ALLOCA=alloca.o
+ cat >> confdefs.h <<\EOF
+#define C_ALLOCA 1
+EOF
+
+
+echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_os_cray'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2158 "configure"
+#include "confdefs.h"
+#if defined(CRAY) && ! defined(CRAY2)
+webecray
+#else
+wenotbecray
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "webecray" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_os_cray=yes
+else
+ rm -rf conftest*
+ ac_cv_os_cray=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_os_cray" 1>&4
+if test $ac_cv_os_cray = yes; then
+echo $ac_n "checking for _getb67""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_func__getb67'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2185 "configure"
+#include "confdefs.h"
+#include <ctype.h> /* Arbitrary system header to define __stub macros. */
+/* Override any gcc2 internal prototype to avoid an error. */
+char _getb67();
+
+int main() { return 0; }
+int t() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub__getb67) || defined (__stub____getb67)
+choke me
+#else
+_getb67();
+#endif
+
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ eval "ac_cv_func__getb67=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_func__getb67=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_func_'_getb67`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ cat >> confdefs.h <<\EOF
+#define CRAY_STACKSEG_END _getb67
+EOF
+
+else
+ echo "$ac_t""no" 1>&4
+echo $ac_n "checking for GETB67""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_func_GETB67'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2228 "configure"
+#include "confdefs.h"
+#include <ctype.h> /* Arbitrary system header to define __stub macros. */
+/* Override any gcc2 internal prototype to avoid an error. */
+char GETB67();
+
+int main() { return 0; }
+int t() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_GETB67) || defined (__stub___GETB67)
+choke me
+#else
+GETB67();
+#endif
+
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ eval "ac_cv_func_GETB67=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_func_GETB67=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_func_'GETB67`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ cat >> confdefs.h <<\EOF
+#define CRAY_STACKSEG_END GETB67
+EOF
+
+else
+ echo "$ac_t""no" 1>&4
+echo $ac_n "checking for getb67""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_func_getb67'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2271 "configure"
+#include "confdefs.h"
+#include <ctype.h> /* Arbitrary system header to define __stub macros. */
+/* Override any gcc2 internal prototype to avoid an error. */
+char getb67();
+
+int main() { return 0; }
+int t() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_getb67) || defined (__stub___getb67)
+choke me
+#else
+getb67();
+#endif
+
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ eval "ac_cv_func_getb67=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_func_getb67=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_func_'getb67`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ cat >> confdefs.h <<\EOF
+#define CRAY_STACKSEG_END getb67
+EOF
+
+else
+ echo "$ac_t""no" 1>&4
+fi
+
+fi
+
+fi
+
+fi
+
+echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_c_stack_direction'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_c_stack_direction=0
+else
+cat > conftest.$ac_ext <<EOF
+#line 2325 "configure"
+#include "confdefs.h"
+find_stack_direction ()
+{
+ static char *addr = 0;
+ auto char dummy;
+ if (addr == 0)
+ {
+ addr = &dummy;
+ return find_stack_direction ();
+ }
+ else
+ return (&dummy > addr) ? 1 : -1;
+}
+main ()
+{
+ exit (find_stack_direction() < 0);
+}
+EOF
+eval $ac_link
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ ac_cv_c_stack_direction=1
+else
+ ac_cv_c_stack_direction=-1
+fi
+fi
+rm -fr conftest*
+fi
+echo "$ac_t""$ac_cv_c_stack_direction" 1>&4
+cat >> confdefs.h <<EOF
+#define STACK_DIRECTION $ac_cv_c_stack_direction
+EOF
+
+fi
+
+# getmntent is in -lsun on Irix 4, -lseq on Dynix/PTX.
+echo $ac_n "checking for -lsun""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_lib_sun'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ ac_save_LIBS="$LIBS"
+LIBS="$LIBS -lsun "
+cat > conftest.$ac_ext <<EOF
+#line 2368 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+getmntent()
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ eval "ac_cv_lib_sun=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_lib_sun=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'sun`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ LIBS="$LIBS -lsun"
+else
+ echo "$ac_t""no" 1>&4
+echo $ac_n "checking for -lseq""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_lib_seq'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ ac_save_LIBS="$LIBS"
+LIBS="$LIBS -lseq "
+cat > conftest.$ac_ext <<EOF
+#line 2399 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+getmntent()
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ eval "ac_cv_lib_seq=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_lib_seq=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'seq`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ LIBS="$LIBS -lseq"
+else
+ echo "$ac_t""no" 1>&4
+fi
+
+fi
+
+echo $ac_n "checking for getmntent""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_func_getmntent'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2432 "configure"
+#include "confdefs.h"
+#include <ctype.h> /* Arbitrary system header to define __stub macros. */
+/* Override any gcc2 internal prototype to avoid an error. */
+char getmntent();
+
+int main() { return 0; }
+int t() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_getmntent) || defined (__stub___getmntent)
+choke me
+#else
+getmntent();
+#endif
+
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ eval "ac_cv_func_getmntent=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_func_getmntent=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_func_'getmntent`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ cat >> confdefs.h <<\EOF
+#define HAVE_GETMNTENT 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&4
+fi
+
+echo $ac_n "checking whether closedir returns void""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_func_closedir_void'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+cat > conftest.$ac_ext <<EOF
+#line 2480 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_header_dirent>
+int closedir(); main() { exit(closedir(opendir(".")) != 0); }
+EOF
+eval $ac_link
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ ac_cv_func_closedir_void=no
+else
+ ac_cv_func_closedir_void=yes
+fi
+fi
+rm -fr conftest*
+fi
+echo "$ac_t""$ac_cv_func_closedir_void" 1>&4
+if test $ac_cv_func_closedir_void = yes; then
+ cat >> confdefs.h <<\EOF
+#define CLOSEDIR_VOID 1
+EOF
+
+fi
+
+
+trap '' 1 2 15
+if test -w $cache_file; then
+echo "updating cache $cache_file"
+cat > $cache_file <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# Ultrix sh set writes to stderr and can't be redirected directly.
+(set) 2>&1 |
+ sed -n "s/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/: \${\1='\2'}/p" \
+ >> $cache_file
+else
+echo "not updating unwritable cache $cache_file"
+fi
+
+trap 'rm -fr conftest* confdefs* core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#!/bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.1"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr Makefile lib/Makefile find/Makefile xargs/Makefile \
+locate/Makefile doc/Makefile testsuite/Makefile config.h conftest*; exit 1' 1 2 15
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g$/%g/' > conftest.subs <<\CEOF
+$ac_vpsub
+$extrasub
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@INCLUDES@%$INCLUDES%g
+s%@CC@%$CC%g
+s%@CPP@%$CPP%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@RANLIB@%$RANLIB%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@LIBOBJS@%$LIBOBJS%g
+s%@ALLOCA@%$ALLOCA%g
+
+CEOF
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile lib/Makefile find/Makefile xargs/Makefile \
+locate/Makefile doc/Makefile testsuite/Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust relative srcdir, etc. for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/$ac_dir"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ case "$ac_given_INSTALL" in
+ [/$]*) INSTALL="$ac_given_INSTALL" ;;
+ *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+ esac
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" -f conftest.subs $ac_given_srcdir/$ac_file_in > $ac_file
+fi; done
+rm -f conftest.subs
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+CONFIG_HEADERS=${CONFIG_HEADERS-"config.h"}
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ cp $ac_given_srcdir/$ac_file_in conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h. And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) \(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+# Maximum number of lines to put in a single here document.
+ac_max_here_lines=12
+
+rm -f conftest.tail
+while :
+do
+ ac_lines=`grep -c . conftest.vals`
+ # grep -c gives empty output for an empty file on some AIX systems.
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ # Write a limited-size here document to conftest.frag.
+ echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+ echo 'CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+ rm -f conftest.vals
+ mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+
+date > stamp-h
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS
+
diff --git a/configure.in b/configure.in
new file mode 100644
index 00000000..ae56fba9
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,89 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(find/pred.c)
+AC_CONFIG_HEADER(config.h)
+
+AC_SUBST(INCLUDES)dnl
+AC_ARG_ENABLE(id-cache,
+[ --enable-id-cache cache all UIDs & GIDs; avoid if using NIS or Hesiod],
+ AC_DEFINE(CACHE_IDS))
+AC_ARG_WITH(afs,
+[ --with-afs support -fstype afs],
+[ AC_DEFINE(AFS)
+ CPPFLAGS="$CPPFLAGS -I/usr/afsws/include"
+ LIBS="$LIBS -L/usr/afsws/lib -L/usr/afsws/lib/afs -lsys -lrx -llwp"])
+AC_ARG_PROGRAM
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_RANLIB
+AC_PROG_MAKE_SET
+
+dnl Try to get a POSIX.1 environment.
+AC_AIX
+AC_MINIX
+AC_ISC_POSIX
+
+dnl Checks for libraries.
+AC_CHECK_LIB(sun, getpwnam)
+
+dnl Checks for header files.
+AC_CHECK_HEADERS(fcntl.h string.h limits.h unistd.h)
+AC_HEADER_STDC
+AC_HEADER_MAJOR
+AC_HEADER_DIRENT
+AC_HEADER_STAT
+AC_HEADER_SYS_WAIT
+
+AC_MSG_CHECKING(how to get filesystem type)
+fstype=no
+# The order of these tests is important.
+AC_TRY_CPP([#include <sys/statvfs.h>
+#include <sys/fstyp.h>], AC_DEFINE(FSTYPE_STATVFS) fstype=SVR4)
+if test $fstype = no; then
+AC_TRY_CPP([#include <sys/statfs.h>
+#include <sys/fstyp.h>], AC_DEFINE(FSTYPE_USG_STATFS) fstype=SVR3)
+fi
+if test $fstype = no; then
+AC_TRY_CPP([#include <sys/statfs.h>
+#include <sys/vmount.h>], AC_DEFINE(FSTYPE_AIX_STATFS) fstype=AIX)
+fi
+if test $fstype = no; then
+AC_TRY_CPP([#include <mntent.h>], AC_DEFINE(FSTYPE_MNTENT) fstype=4.3BSD)
+fi
+if test $fstype = no; then
+AC_EGREP_HEADER(f_type;, sys/mount.h, AC_DEFINE(FSTYPE_STATFS) fstype=4.4BSD/OSF1)
+fi
+if test $fstype = no; then
+AC_TRY_CPP([#include <sys/mount.h>
+#include <sys/fs_types.h>], AC_DEFINE(FSTYPE_GETMNT) fstype=Ultrix)
+fi
+AC_MSG_RESULT($fstype)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+
+AC_TYPE_UID_T
+AC_TYPE_SIZE_T
+AC_TYPE_PID_T
+AC_CHECK_TYPE(ino_t, unsigned long)
+AC_CHECK_TYPE(dev_t, unsigned long)
+AC_STRUCT_ST_BLOCKS
+AC_STRUCT_ST_RDEV
+AC_STRUCT_TM
+AC_STRUCT_TIMEZONE
+AC_C_CONST
+
+dnl Checks for library functions.
+
+AC_REPLACE_FUNCS(memcmp memset mktime stpcpy strdup strftime strspn strstr strtol)
+AC_CHECK_FUNCS(fchdir getcwd strerror)
+AC_FUNC_STRFTIME
+AC_FUNC_VPRINTF
+AC_FUNC_ALLOCA
+AC_FUNC_GETMNTENT
+AC_FUNC_CLOSEDIR_VOID
+
+AC_OUTPUT(Makefile lib/Makefile find/Makefile xargs/Makefile \
+locate/Makefile doc/Makefile testsuite/Makefile,
+ date > stamp-h)
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 2e085531..8fb12971 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -1,75 +1,4 @@
-info_TEXINFOS = find.texi find-maint.texi
-find_TEXINFOS = perm.texi getdate.texi regexprops.texi fdl.texi
-find_maint_TEXINFOS = fdl.texi
-MOSTLYCLEANFILES = find.cps
-CLEANFILES = find.txt find_mono.html findutils.texi_html_node.tar.gz
+TEXINFOS = find.texi
+DIST_OTHER = perm.texi texinfo.tex
-# To build regexprops.texi, we need to build the regexprops program and
-# run it on the host. If we are cross compiling, we may not have a native
-# binary. When this is the case, we use a workaround; don't delete the
-# file for 'make clean'. This fixes Savannah bug #19658.
-if !CROSS_COMPILING
-CLEANFILES += regexprops.texi regexprops-generic.texi
-endif
-
-MAKEINFOTXT = $(MAKEINFO) --plaintext
-
-find.txt: find.texi $(srcdir)/version.texi $(find_TEXINFOS)
-
-# find.txt is a file which we need to know how to build
-# because it gets put on the www.gnu.org website.
-# This rule is derived from the .texi.html rule.
-.texi.txt:
- rm -rf $(@:.txt=.tmp)
- if $(MAKEINFOTXT) $(AM_MAKEINFOTXTFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
- -o $(@:.txt=.tmp) $<; \
- then \
- rm -rf $@; \
- if test ! -d $(@:.txt=.tmp) && test -d $(@:.txt=); then \
- mv $(@:.txt=) $@; else mv $(@:.txt=.tmp) $@; fi; \
- else \
- if test ! -d $(@:.txt=.tmp) && test -d $(@:.txt=); then \
- rm -rf $(@:.txt=); else rm -Rf $(@:.txt=.tmp) $@; fi; \
- exit 1; \
- fi
-
-
-# find_mono.html is a file which we need to know how to build
-# because it gets put on the www.gnu.org website.
-# This rule is derived from the generic .texi.html rule.
-find_mono.html: find.texi
- rm -rf $(@:.html=.htp)
- if $(MAKEINFOHTML) --no-split $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
- -o $(@:.html=.htp) $<; \
- then \
- rm -rf $@; \
- if test ! -d $(@:.html=.htp) && test -d $(@:.html=); then \
- mv $(@:.html=) $@; else mv $(@:.html=.htp) $@; fi; \
- else \
- if test ! -d $(@:.html=.htp) && test -d $(@:.html=); then \
- rm -rf $(@:.html=); else rm -Rf $(@:.html=.htp) $@; fi; \
- exit 1; \
- fi
-
-
-# findutils.texi_html_node.tar.gz is a file which we need to know
-# how to build because it gets put on the www.gnu.org website.
-# This rule depends on GNU tar, but it's principally used
-# by the maintainer, and we don't need to build the file
-# for "make all" or "make install" (or even "make check").
-findutils.texi_html_node.tar.gz: find.html
- tar zcf $@ $<
-
-if CROSS_COMPILING
-regexprops.texi regexprops-generic.texi: ../gnulib/lib/regex.h
- echo "WARNING: $? is newer than $@ but $@ cannot be rebuilt because we are cross-compiling. Continuing anyway." >&2
-else
-regexprops.texi: ../gnulib/lib/regex.h ../lib/regexprops.c
- cd ../lib && $(MAKE) $(AM_MAKEFLAGS) regexprops$(EXEEXT)
- ../lib/regexprops$(EXEEXT) "Regular Expressions" findutils > $@
- rm ../lib/regexprops$(EXEEXT)
-regexprops-generic.texi: ../gnulib/lib/regex.h ../lib/regexprops.c
- cd ../lib && $(MAKE) $(AM_MAKEFLAGS) regexprops$(EXEEXT)
- ../lib/regexprops$(EXEEXT) "Regular Expressions" generic > $@
- rm ../lib/regexprops$(EXEEXT)
-endif
+find.info find.dvi: perm.texi
diff --git a/doc/Makefile.in b/doc/Makefile.in
new file mode 100644
index 00000000..fcaa8f04
--- /dev/null
+++ b/doc/Makefile.in
@@ -0,0 +1,121 @@
+# Makefile.in generated automatically by automake from Makefile.am.
+# Copyright (C) 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = $(exec_prefix)/bin
+sbindir = $(exec_prefix)/sbin
+libexecdir = $(exec_prefix)/libexec
+datadir = $(prefix)/share
+sysconfdir = $(prefix)/etc
+sharedstatedir = $(prefix)/com
+localstatedir = $(prefix)/var
+libdir = $(exec_prefix)/lib
+infodir = $(prefix)/info
+mandir = $(prefix)/man
+includedir = $(prefix)/include
+oldincludedir = /usr/include
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+transform = @program_transform_name@
+
+ALL = ${PROGRAMS} ${LIBPROGRAMS} ${SCRIPTS} ${LIBSCRIPTS} ${LIBFILES}
+MAKEINFO = makeinfo
+TEXI2DVI = texi2dvi
+
+TEXFILES = *.aux *.cp *.cps *.dvi *.fn *.fns *.ky *.log *.pg *.toc *.tp *.vr
+
+INFOS = find.info*
+INFO_DEPS = find.info
+DVIS = find.dvi
+SOURCES =
+DIST_CONF = Makefile.am Makefile.in
+DIST_FILES = $(DIST_CONF) $(SOURCES) $(TEXINFOS) $(INFOS) $(MANS) $(DIST_OTHER)
+
+TEXINFOS = find.texi
+DIST_OTHER = perm.texi texinfo.tex
+
+all:: ${ALL}
+
+.SUFFIXES: .texi .info .dvi
+
+.texi.info:
+ $(MAKEINFO) -I$(srcdir) $<
+
+.texi.dvi:
+ TEXINPUTS=$(srcdir):$$TEXINPUTS $(TEXI2DVI) $<
+
+info:: $(INFO_DEPS)
+
+dvi:: $(DVIS)
+
+install:: install-info
+
+install-info: $(INFO_DEPS)
+ $(top_srcdir)/mkinstalldirs $(infodir)
+ cd $(srcdir); for file in *.info*; do \
+ $(INSTALL_DATA) $$file $(infodir)/$$file; \
+ done
+
+uninstall:: uninstall-info
+
+uninstall-info:
+ cd $(srcdir); for file in *.info*; do \
+ rm -f $(infodir)/$$file; \
+ done
+
+mostlyclean:
+ rm -f *.o core
+
+clean: mostlyclean
+ rm -f $(PROGRAMS) $(LIBPROGRAMS) $(LIBFILES) $(TEXFILES) $(CLEANFILES)
+
+distclean: clean
+ rm -f Makefile *.tab.c $(DISTCLEANFILES)
+ rm -f config.cache config.log config.status ${CONFIG_HEADER} stamp-h
+
+realclean: distclean
+ rm -f TAGS $(INFOS)
+
+dist: $(DIST_FILES) $(DIST_DIRS)
+ -mkdir ../`cat ../distname`/$(subdir)
+ @for file in $(DIST_FILES); do \
+ echo linking $$file; \
+ ln $(srcdir)/$$file ../`cat ../distname`/$(subdir)/$$file || \
+ { echo copying $$file instead; cp -p $(srcdir)/$$file ../`cat ../distname`/$(subdir)/$$file;}; \
+ done
+
+check dvi info install uninstall::
+
+tags:: TAGS
+
+TAGS::
+ cd $(srcdir); etags $(SOURCES)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
+
+find.info find.dvi: perm.texi
diff --git a/doc/find.info b/doc/find.info
new file mode 100644
index 00000000..c8acfbaf
--- /dev/null
+++ b/doc/find.info
@@ -0,0 +1,113 @@
+This is Info file find.info, produced by Makeinfo-1.55 from the input
+file find.texi.
+
+START-INFO-DIR-ENTRY
+* Finding Files: (find). Listing and operating on files
+ that match certain criteria.
+END-INFO-DIR-ENTRY
+
+ This file documents the GNU utilities for finding files that match
+certain criteria and performing various operations on them.
+
+ Copyright (C) 1994 Free Software Foundation, Inc.
+
+ Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+ Permission is granted to copy and distribute modified versions of
+this manual under the conditions for verbatim copying, provided that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+ Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be stated in a
+translation approved by the Foundation.
+
+
+Indirect:
+find.info-1: 1097
+find.info-2: 50752
+
+Tag Table:
+(Indirect)
+Node: Top1097
+Node: Introduction1909
+Node: Scope3080
+Node: Overview5000
+Node: find Expressions6758
+Node: Finding Files8379
+Node: Name8845
+Node: Base Name Patterns9469
+Node: Full Name Patterns10008
+Node: Fast Full Name Search10993
+Node: Shell Pattern Matching13148
+Node: Links14989
+Node: Symbolic Links15419
+Node: Hard Links16367
+Node: Time17403
+Node: Age Ranges17918
+Node: Comparing Timestamps18851
+Node: Size20130
+Node: Type20945
+Node: Owner21757
+Node: Permissions22570
+Node: Contents23255
+Node: Directories24423
+Node: Filesystems26897
+Node: Combining Primaries With Operators28169
+Node: Actions29470
+Node: Print File Name30017
+Node: Print File Information30621
+Node: Escapes32856
+Node: Format Directives33516
+Node: Name Directives34214
+Node: Ownership Directives34745
+Node: Size Directives35170
+Node: Location Directives35466
+Node: Time Directives36018
+Node: Time Formats36886
+Node: Time Components37313
+Node: Date Components37806
+Node: Combined Time Formats38616
+Node: Run Commands39100
+Node: Single File39453
+Node: Multiple Files40303
+Node: Unsafe File Name Handling42106
+Node: Safe File Name Handling43656
+Node: Limiting Command Size44342
+Node: Interspersing File Names46097
+Node: Querying47158
+Node: Adding Tests48074
+Node: Common Tasks50336
+Node: Viewing And Editing50752
+Node: Archiving51263
+Node: Cleaning Up52895
+Node: Strange File Names54456
+Node: Fixing Permissions56086
+Node: Classifying Files56645
+Node: Databases57363
+Node: Database Locations57977
+Node: Database Formats59501
+Node: New Database Format60152
+Node: Sample Database61714
+Node: Old Database Format62353
+Node: File Permissions64083
+Node: Mode Structure64651
+Node: Symbolic Modes66779
+Node: Setting Permissions67777
+Node: Copying Permissions70314
+Node: Changing Special Permissions71115
+Node: Conditional Executability72951
+Node: Multiple Changes73568
+Node: Umask and Protection75216
+Node: Numeric Modes76305
+Node: Reference78135
+Node: Invoking find78433
+Node: Invoking locate79480
+Node: Invoking updatedb80163
+Node: Invoking xargs80932
+Node: Primary Index84002
+
+End Tag Table
diff --git a/doc/find.info-1 b/doc/find.info-1
new file mode 100644
index 00000000..dc78df66
--- /dev/null
+++ b/doc/find.info-1
@@ -0,0 +1,1581 @@
+This is Info file find.info, produced by Makeinfo-1.55 from the input
+file find.texi.
+
+START-INFO-DIR-ENTRY
+* Finding Files: (find). Listing and operating on files
+ that match certain criteria.
+END-INFO-DIR-ENTRY
+
+ This file documents the GNU utilities for finding files that match
+certain criteria and performing various operations on them.
+
+ Copyright (C) 1994 Free Software Foundation, Inc.
+
+ Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+ Permission is granted to copy and distribute modified versions of
+this manual under the conditions for verbatim copying, provided that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+ Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be stated in a
+translation approved by the Foundation.
+
+
+File: find.info, Node: Top, Next: Introduction, Up: (dir)
+
+ This file documents the GNU utilities for finding files that match
+certain criteria and performing various actions on them. This is
+edition 1.1, for `find' version 4.1.
+
+* Menu:
+
+* Introduction:: Summary of the tasks this manual describes.
+* Finding Files:: Finding files that match certain criteria.
+* Actions:: Doing things to files you have found.
+* Common Tasks:: Solutions to common real-world problems.
+* Databases:: Maintaining file name databases.
+* File Permissions:: How to control access to files.
+* Reference:: Summary of how to invoke the programs.
+* Primary Index:: The components of `find' expressions.
+
+
+File: find.info, Node: Introduction, Next: Finding Files, Prev: Top, Up: Top
+
+Introduction
+************
+
+ This manual shows how to find files that meet criteria you specify,
+and how to perform various actions on the files that you find. The
+principal programs that you use to perform these tasks are `find',
+`locate', and `xargs'. Some of the examples in this manual use
+capabilities specific to the GNU versions of those programs.
+
+ GNU `find' was originally written by Eric Decker, with enhancements
+by David MacKenzie, Jay Plett, and Tim Wood. GNU `xargs' was
+originally written by Mike Rendell, with enhancements by David
+MacKenzie. GNU `locate' and its associated utilities were originally
+written by James Woods, with enhancements by David MacKenzie. The idea
+for `find -print0' and `xargs -0' came from Dan Bernstein. Many other
+people have contributed bug fixes, small improvements, and helpful
+suggestions. Thanks!
+
+ Mail suggestions and bug reports for these programs to
+`bug-gnu-utils@prep.ai.mit.edu'. Please include the version number,
+which you can get by running `find --version'.
+
+* Menu:
+
+* Scope::
+* Overview::
+* find Expressions::
+
+
+File: find.info, Node: Scope, Next: Overview, Up: Introduction
+
+Scope
+=====
+
+ For brevity, the word "file" in this manual means a regular file, a
+directory, a symbolic link, or any other kind of node that has a
+directory entry. A directory entry is also called a "file name". A
+file name may contain some, all, or none of the directories in a path
+that leads to the file. These are all examples of what this manual
+calls "file names":
+
+ parser.c
+ README
+ ./budget/may-94.sc
+ fred/.cshrc
+ /usr/local/include/termcap.h
+
+ A "directory tree" is a directory and the files it contains, all of
+its subdirectories and the files they contain, etc. It can also be a
+single non-directory file.
+
+ These programs enable you to find the files in one or more directory
+trees that:
+
+ * have names that contain certain text or match a certain pattern;
+
+ * are links to certain files;
+
+ * were last used during a certain period of time;
+
+ * are within a certain size range;
+
+ * are of a certain type (regular file, directory, symbolic link,
+ etc.);
+
+ * are owned by a certain user or group;
+
+ * have certain access permissions;
+
+ * contain text that matches a certain pattern;
+
+ * are within a certain depth in the directory tree;
+
+ * or some combination of the above.
+
+ Once you have found the files you're looking for (or files that are
+potentially the ones you're looking for), you can do more to them than
+simply list their names. You can get any combination of the files'
+attributes, or process the files in many ways, either individually or in
+groups of various sizes. Actions that you might want to perform on the
+files you have found include, but are not limited to:
+
+ * view or edit
+
+ * store in an archive
+
+ * remove or rename
+
+ * change access permissions
+
+ * classify into groups
+
+ This manual describes how to perform each of those tasks, and more.
+
+
+File: find.info, Node: Overview, Next: find Expressions, Prev: Scope, Up: Introduction
+
+Overview
+========
+
+ The principal programs used for making lists of files that match
+given criteria and running commands on them are `find', `locate', and
+`xargs'. An additional command, `updatedb', is used by system
+administrators to create databases for `locate' to use.
+
+ `find' searches for files in a directory hierarchy and prints
+information about the files it found. It is run like this:
+
+ find [FILE...] [EXPRESSION]
+
+Here is a typical use of `find'. This example prints the names of all
+files in the directory tree rooted in `/usr/src' whose name ends with
+`.c' and that are larger than 100 Kilobytes.
+ find /usr/src -name '*.c' -size +100k -print
+
+ `locate' searches special file name databases for file names that
+match patterns. The system administrator runs the `updatedb' program
+to create the databases. `locate' is run like this:
+
+ locate [OPTION...] PATTERN...
+
+This example prints the names of all files in the default file name
+database whose name ends with `Makefile' or `makefile'. Which file
+names are stored in the database depends on how the system
+administrator ran `updatedb'.
+ locate '*[Mm]akefile'
+
+ The name `xargs', pronounced EX-args, means "combine arguments."
+`xargs' builds and executes command lines by gathering together
+arguments it reads on the standard input. Most often, these arguments
+are lists of file names generated by `find'. `xargs' is run like this:
+
+ xargs [OPTION...] [COMMAND [INITIAL-ARGUMENTS]]
+
+The following command searches the files listed in the file `file-list'
+and prints all of the lines in them that contain the word `typedef'.
+ xargs grep typedef < file-list
+
+
+File: find.info, Node: find Expressions, Prev: Overview, Up: Introduction
+
+`find' Expressions
+==================
+
+ The expression that `find' uses to select files consists of one or
+more "primaries", each of which is a separate command line argument to
+`find'. `find' evaluates the expression each time it processes a file.
+An expression can contain any of the following types of primaries:
+
+"options"
+ affect overall operation rather than the processing of a specific
+ file;
+
+"tests"
+ return a true or false value, depending on the file's attributes;
+
+"actions"
+ have side effects and return a true or false value; and
+
+"operators"
+ connect the other arguments and affect when and whether they are
+ evaluated.
+
+ You can omit the operator between two primaries; it defaults to
+`-and'. *Note Combining Primaries With Operators::, for ways to
+connect primaries into more complex expressions. If the expression
+contains no actions other than `-prune', `-print' is performed on all
+files for which the entire expression is true (*note Print File
+Name::.).
+
+ Options take effect immediately, rather than being evaluated for each
+file when their place in the expression is reached. Therefore, for
+clarity, it is best to place them at the beginning of the expression.
+
+ Many of the primaries take arguments, which immediately follow them
+in the next command line argument to `find'. Some arguments are file
+names, patterns, or other strings; others are numbers. Numeric
+arguments can be specified as
+
+`+N'
+ for greater than N,
+
+`-N'
+ for less than N,
+
+`N'
+ for exactly N.
+
+
+File: find.info, Node: Finding Files, Next: Actions, Prev: Introduction, Up: Top
+
+Finding Files
+*************
+
+ By default, `find' prints to the standard output the names of the
+files that match the given criteria. *Note Actions::, for how to get
+more information about the matching files.
+
+* Menu:
+
+* Name::
+* Links::
+* Time::
+* Size::
+* Type::
+* Owner::
+* Permissions::
+* Contents::
+* Directories::
+* Filesystems::
+* Combining Primaries With Operators::
+
+
+File: find.info, Node: Name, Next: Links, Up: Finding Files
+
+Name
+====
+
+ Here are ways to search for files whose name matches a certain
+pattern. *Note Shell Pattern Matching::, for a description of the
+PATTERN arguments to these tests.
+
+ Each of these tests has a case-sensitive version and a
+case-insensitive version, whose name begins with `i'. In a
+case-insensitive comparison, the patterns `fo*' and `F??' match the
+file names `Foo', `FOO', `foo', `fOo', etc.
+
+* Menu:
+
+* Base Name Patterns::
+* Full Name Patterns::
+* Fast Full Name Search::
+* Shell Pattern Matching:: Wildcards used by these programs.
+
+
+File: find.info, Node: Base Name Patterns, Next: Full Name Patterns, Up: Name
+
+Base Name Patterns
+------------------
+
+ - Test: -name PATTERN
+ - Test: -iname PATTERN
+ True if the base of the file name (the path with the leading
+ directories removed) matches shell pattern PATTERN. For `-iname',
+ the match is case-insensitive. To ignore a whole directory tree,
+ use `-prune' (*note Directories::.). As an example, to find
+ Texinfo source files in `/usr/local/doc':
+
+ find /usr/local/doc -name '*.texi'
+
+
+File: find.info, Node: Full Name Patterns, Next: Fast Full Name Search, Prev: Base Name Patterns, Up: Name
+
+Full Name Patterns
+------------------
+
+ - Test: -path PATTERN
+ - Test: -ipath PATTERN
+ True if the entire file name, starting with the command line
+ argument under which the file was found, matches shell pattern
+ PATTERN. For `-ipath', the match is case-insensitive. To ignore
+ a whole directory tree, use `-prune' rather than checking every
+ file in the tree (*note Directories::.).
+
+ - Test: -regex EXPR
+ - Test: -iregex EXPR
+ True if the entire file name matches regular expression EXPR.
+ This is a match on the whole path, not a search. For example, to
+ match a file named `./fubar3', you can use the regular expression
+ `.*bar.' or `.*b.*3', but not `b.*r3'. *Note Syntax of Regular
+ Expressions: (emacs)Regexps, for a description of the syntax of
+ regular expressions. For `-iregex', the match is case-insensitive.
+
+
+File: find.info, Node: Fast Full Name Search, Next: Shell Pattern Matching, Prev: Full Name Patterns, Up: Name
+
+Fast Full Name Search
+---------------------
+
+ To search for files by name without having to actually scan the
+directories on the disk (which can be slow), you can use the `locate'
+program. For each shell pattern you give it, `locate' searches one or
+more databases of file names and displays the file names that contain
+the pattern. *Note Shell Pattern Matching::, for details about shell
+patterns.
+
+ If a pattern is a plain string--it contains no
+metacharacters--`locate' displays all file names in the database that
+contain that string. If a pattern contains metacharacters, `locate'
+only displays file names that match the pattern exactly. As a result,
+patterns that contain metacharacters should usually begin with a `*',
+and will most often end with one as well. The exceptions are patterns
+that are intended to explicitly match the beginning or end of a file
+name.
+
+ The command
+ locate PATTERN
+
+ is almost equivalent to
+ find DIRECTORIES -name PATTERN
+
+ where DIRECTORIES are the directories for which the file name
+databases contain information. The differences are that the `locate'
+information might be out of date, and that `locate' handles wildcards
+in the pattern slightly differently than `find' (*note Shell Pattern
+Matching::.).
+
+ The file name databases contain lists of files that were on the
+system when the databases were last updated. The system administrator
+can choose the file name of the default database, the frequency with
+which the databases are updated, and the directories for which they
+contain entries.
+
+ Here is how to select which file name databases `locate' searches.
+The default is system-dependent.
+
+`--database=PATH'
+`-d PATH'
+ Instead of searching the default file name database, search the
+ file name databases in PATH, which is a colon-separated list of
+ database file names. You can also use the environment variable
+ `LOCATE_PATH' to set the list of database files to search. The
+ option overrides the environment variable if both are used.
+
+
+File: find.info, Node: Shell Pattern Matching, Prev: Fast Full Name Search, Up: Name
+
+Shell Pattern Matching
+----------------------
+
+ `find' and `locate' can compare file names, or parts of file names,
+to shell patterns. A "shell pattern" is a string that may contain the
+following special characters, which are known as "wildcards" or
+"metacharacters".
+
+ You must quote patterns that contain metacharacters to prevent the
+shell from expanding them itself. Double and single quotes both work;
+so does escaping with a backslash.
+
+`*'
+ Matches any zero or more characters.
+
+`?'
+ Matches any one character.
+
+`[STRING]'
+ Matches exactly one character that is a member of the string
+ STRING. This is called a "character class". As a shorthand,
+ STRING may contain ranges, which consist of two characters with a
+ dash between them. For example, the class `[a-z0-9_]' matches a
+ lowercase letter, a number, or an underscore. You can negate a
+ class by placing a `!' or `^' immediately after the opening
+ bracket. Thus, `[^A-Z@]' matches any character except an
+ uppercase letter or an at sign.
+
+`\'
+ Removes the special meaning of the character that follows it. This
+ works even in character classes.
+
+ In the `find' tests that do shell pattern matching (`-name',
+`-path', etc.), wildcards in the pattern do not match a `.' at the
+beginning of a file name. This is not the case for `locate'. Thus,
+`find -name '*macs'' does not match a file named `.emacs', but `locate
+'*macs'' does.
+
+ Slash characters have no special significance in the shell pattern
+matching that `find' and `locate' do, unlike in the shell, in which
+wildcards do not match them. Therefore, a pattern `foo*bar' can match
+a file name `foo3/bar', and a pattern `./sr*sc' can match a file name
+`./src/misc'.
+
+
+File: find.info, Node: Links, Next: Time, Prev: Name, Up: Finding Files
+
+Links
+=====
+
+ There are two ways that files can be linked together. "Symbolic
+links" are a special type of file whose contents are a portion of the
+name of another file. "Hard links" are multiple directory entries for
+one file; the file names all have the same index node ("inode") number
+on the disk.
+
+* Menu:
+
+* Symbolic Links::
+* Hard Links::
+
+
+File: find.info, Node: Symbolic Links, Next: Hard Links, Up: Links
+
+Symbolic Links
+--------------
+
+ - Test: -lname PATTERN
+ - Test: -ilname PATTERN
+ True if the file is a symbolic link whose contents match shell
+ pattern PATTERN. For `-ilname', the match is case-insensitive.
+ *Note Shell Pattern Matching::, for details about the PATTERN
+ argument. So, to list any symbolic links to `sysdep.c' in the
+ current directory and its subdirectories, you can do:
+
+ find . -lname '*sysdep.c'
+
+ - Option: -follow
+ Dereference symbolic links. The following differences in behavior
+ occur when this option is given:
+
+ * `find' follows symbolic links to directories when searching
+ directory trees.
+
+ * `-lname' and `-ilname' always return false.
+
+ * `-type' reports the types of the files that symbolic links
+ point to.
+
+ * Implies `-noleaf' (*note Directories::.).
+
+
+File: find.info, Node: Hard Links, Prev: Symbolic Links, Up: Links
+
+Hard Links
+----------
+
+ To find hard links, first get the inode number of the file whose
+links you want to find. You can learn a file's inode number and the
+number of links to it by running `ls -i' or `find -ls'. If the file has
+more than one link, you can search for the other links by passing that
+inode number to `-inum'. Add the `-xdev' option if you are starting
+the search at a directory that has other filesystems mounted on it,
+such as `/usr' on many systems. Doing this saves needless searching,
+since hard links to a file must be on the same filesystem. *Note
+Filesystems::.
+
+ - Test: -inum N
+ File has inode number N.
+
+ You can also search for files that have a certain number of links,
+with `-links'. Directories normally have at least two hard links; their
+`.' entry is the second one. If they have subdirectories, each of
+those also has a hard link called `..' to its parent directory.
+
+ - Test: -links N
+ File has N hard links.
+
+
+File: find.info, Node: Time, Next: Size, Prev: Links, Up: Finding Files
+
+Time
+====
+
+ Each file has three time stamps, which record the last time that
+certain operations were performed on the file:
+
+ 1. access (read the file's contents)
+
+ 2. change the status (modify the file or its attributes)
+
+ 3. modify (change the file's contents)
+
+ You can search for files whose time stamps are within a certain age
+range, or compare them to other time stamps.
+
+* Menu:
+
+* Age Ranges::
+* Comparing Timestamps::
+
+
+File: find.info, Node: Age Ranges, Next: Comparing Timestamps, Up: Time
+
+Age Ranges
+----------
+
+ These tests are mainly useful with ranges (`+N' and `-N').
+
+ - Test: -atime N
+ - Test: -ctime N
+ - Test: -mtime N
+ True if the file was last accessed (or its status changed, or it
+ was modified) N*24 hours ago.
+
+ - Test: -amin N
+ - Test: -cmin N
+ - Test: -mmin N
+ True if the file was last accessed (or its status changed, or it
+ was modified) N minutes ago. These tests provide finer
+ granularity of measurement than `-atime' et al. For example, to
+ list files in `/u/bill' that were last read from 2 to 6 hours ago:
+
+ find /u/bill -amin +2 -amin -6
+
+ - Option: -daystart
+ Measure times from the beginning of today rather than from 24
+ hours ago. So, to list the regular files in your home directory
+ that were modified yesterday, do
+
+ find ~ -daystart -type f -mtime 1
+
+
+File: find.info, Node: Comparing Timestamps, Prev: Age Ranges, Up: Time
+
+Comparing Timestamps
+--------------------
+
+ As an alternative to comparing timestamps to the current time, you
+can compare them to another file's timestamp. That file's timestamp
+could be updated by another program when some event occurs. Or you
+could set it to a particular fixed date using the `touch' command. For
+example, to list files in `/usr' modified after February 1 of the
+current year:
+
+ touch -t 02010000 /tmp/stamp$$
+ find /usr -newer /tmp/stamp$$
+ rm -f /tmp/stamp$$
+
+ - Test: -anewer FILE
+ - Test: -cnewer FILE
+ - Test: -newer FILE
+ True if the file was last accessed (or its status changed, or it
+ was modified) more recently than FILE was modified. These tests
+ are affected by `-follow' only if `-follow' comes before them on
+ the command line. *Note Symbolic Links::, for more information on
+ `-follow'. As an example, to list any files modified since
+ `/bin/sh' was last modified:
+
+ find . -newer /bin/sh
+
+ - Test: -used N
+ True if the file was last accessed N days after its status was
+ last changed. Useful for finding files that are not being used,
+ and could perhaps be archived or removed to save disk space.
+
+
+File: find.info, Node: Size, Next: Type, Prev: Time, Up: Finding Files
+
+Size
+====
+
+ - Test: -size N[BCKW]
+ True if the file uses N units of space, rounding up. The units
+ are 512-byte blocks by default, but they can be changed by adding a
+ one-character suffix to N:
+
+ `b'
+ 512-byte blocks
+
+ `c'
+ bytes
+
+ `k'
+ kilobytes (1024 bytes)
+
+ `w'
+ 2-byte words
+
+ The size does not count indirect blocks, but it does count blocks
+ in sparse files that are not actually allocated.
+
+ - Test: -empty
+ True if the file is empty and is either a regular file or a
+ directory. This might make it a good candidate for deletion.
+ This test is useful with `-depth' (*note Directories::.) and
+ `-exec rm -rf '{}' ';'' (*note Single File::.).
+
+
+File: find.info, Node: Type, Next: Owner, Prev: Size, Up: Finding Files
+
+Type
+====
+
+ - Test: -type C
+ True if the file is of type C:
+
+ `b'
+ block (buffered) special
+
+ `c'
+ character (unbuffered) special
+
+ `d'
+ directory
+
+ `p'
+ named pipe (FIFO)
+
+ `f'
+ regular file
+
+ `l'
+ symbolic link
+
+ `s'
+ socket
+
+ - Test: -xtype C
+ The same as `-type' unless the file is a symbolic link. For
+ symbolic links: if `-follow' has not been given, true if the file
+ is a link to a file of type C; if `-follow' has been given, true
+ if C is `l'. In other words, for symbolic links, `-xtype' checks
+ the type of the file that `-type' does not check. *Note Symbolic
+ Links::, for more information on `-follow'.
+
+
+File: find.info, Node: Owner, Next: Permissions, Prev: Type, Up: Finding Files
+
+Owner
+=====
+
+ - Test: -user UNAME
+ - Test: -group GNAME
+ True if the file is owned by user UNAME (belongs to group GNAME).
+ A numeric ID is allowed.
+
+ - Test: -uid N
+ - Test: -gid N
+ True if the file's numeric user ID (group ID) is N. These tests
+ support ranges (`+N' and `-N'), unlike `-user' and `-group'.
+
+ - Test: -nouser
+ - Test: -nogroup
+ True if no user corresponds to the file's numeric user ID (no group
+ corresponds to the numeric group ID). These cases usually mean
+ that the files belonged to users who have since been removed from
+ the system. You probably should change the ownership of such
+ files to an existing user or group, using the `chown' or `chgrp'
+ program.
+
+
+File: find.info, Node: Permissions, Next: Contents, Prev: Owner, Up: Finding Files
+
+Permissions
+===========
+
+ *Note File Permissions::, for information on how file permissions are
+structured and how to specify them.
+
+ - Test: -perm MODE
+ True if the file's permissions are exactly MODE (which can be
+ numeric or symbolic). Symbolic modes use mode 0 as a point of
+ departure. If MODE starts with `-', true if *all* of the
+ permissions set in MODE are set for the file; permissions not set
+ in MODE are ignored. If MODE starts with `+', true if *any* of
+ the permissions set in MODE are set for the file; permissions not
+ set in MODE are ignored.
+
+
+File: find.info, Node: Contents, Next: Directories, Prev: Permissions, Up: Finding Files
+
+Contents
+========
+
+ To search for files based on their contents, you can use the `grep'
+program. For example, to find out which C source files in the current
+directory contain the string `thing', you can do:
+
+ grep -l thing *.[ch]
+
+ If you also want to search for the string in files in subdirectories,
+you can combine `grep' with `find' and `xargs', like this:
+
+ find . -name '*.[ch]' | xargs grep -l thing
+
+ The `-l' option causes `grep' to print only the names of files that
+contain the string, rather than the lines that contain it. The string
+argument (`thing') is actually a regular expression, so it can contain
+metacharacters. This method can be refined a little by using the `-r'
+option to make `xargs' not run `grep' if `find' produces no output, and
+using the `find' action `-print0' and the `xargs' option `-0' to avoid
+misinterpreting files whose names contain spaces:
+
+ find . -name '*.[ch]' -print0 | xargs -r -0 grep -l thing
+
+ For a fuller treatment of finding files whose contents match a
+pattern, see the manual page for `grep'.
+
+
+File: find.info, Node: Directories, Next: Filesystems, Prev: Contents, Up: Finding Files
+
+Directories
+===========
+
+ Here is how to control which directories `find' searches, and how it
+searches them. These two options allow you to process a horizontal
+slice of a directory tree.
+
+ - Option: -maxdepth LEVELS
+ Descend at most LEVELS (a non-negative integer) levels of
+ directories below the command line arguments. `-maxdepth 0' means
+ only apply the tests and actions to the command line arguments.
+
+ - Option: -mindepth LEVELS
+ Do not apply any tests or actions at levels less than LEVELS (a
+ non-negative integer). `-mindepth 1' means process all files
+ except the command line arguments.
+
+ - Option: -depth
+ Process each directory's contents before the directory itself.
+ Doing this is a good idea when producing lists of files to archive
+ with `cpio' or `tar'. If a directory does not have write
+ permission for its owner, its contents can still be restored from
+ the archive since the directory's permissions are restored after
+ its contents.
+
+ - Action: -prune
+ If `-depth' is not given, true; do not descend the current
+ directory. If `-depth' is given, false; no effect. `-prune' only
+ affects tests and actions that come after it in the expression, not
+ those that come before.
+
+ For example, to skip the directory `src/emacs' and all files and
+ directories under it, and print the names of the other files found:
+
+ find . -path './src/emacs' -prune -o -print
+
+ - Option: -noleaf
+ Do not optimize by assuming that directories contain 2 fewer
+ subdirectories than their hard link count. This option is needed
+ when searching filesystems that do not follow the Unix
+ directory-link convention, such as CD-ROM or MS-DOS filesystems or
+ AFS volume mount points. Each directory on a normal Unix
+ filesystem has at least 2 hard links: its name and its `.' entry.
+ Additionally, its subdirectories (if any) each have a `..' entry
+ linked to that directory. When `find' is examining a directory,
+ after it has statted 2 fewer subdirectories than the directory's
+ link count, it knows that the rest of the entries in the directory
+ are non-directories ("leaf" files in the directory tree). If only
+ the files' names need to be examined, there is no need to stat
+ them; this gives a significant increase in search speed.
+
+
+File: find.info, Node: Filesystems, Next: Combining Primaries With Operators, Prev: Directories, Up: Finding Files
+
+Filesystems
+===========
+
+ A "filesystem" is a section of a disk, either on the local host or
+mounted from a remote host over a network. Searching network
+filesystems can be slow, so it is common to make `find' avoid them.
+
+ There are two ways to avoid searching certain filesystems. One way
+is to tell `find' to only search one filesystem:
+
+ - Option: -xdev
+ - Option: -mount
+ Don't descend directories on other filesystems. These options are
+ synonyms.
+
+ The other way is to check the type of filesystem each file is on, and
+not descend directories that are on undesirable filesystem types:
+
+ - Test: -fstype TYPE
+ True if the file is on a filesystem of type TYPE. The valid
+ filesystem types vary among different versions of Unix; an
+ incomplete list of filesystem types that are accepted on some
+ version of Unix or another is:
+ ufs 4.2 4.3 nfs tmp mfs S51K S52K
+ You can use `-printf' with the `%F' directive to see the types of
+ your filesystems. *Note Print File Information::. `-fstype' is
+ usually used with `-prune' to avoid searching remote filesystems
+ (*note Directories::.).
+
+
+File: find.info, Node: Combining Primaries With Operators, Prev: Filesystems, Up: Finding Files
+
+Combining Primaries With Operators
+==================================
+
+ Operators build a complex expression from tests and actions. The
+operators are, in order of decreasing precedence:
+
+`( EXPR )'
+ Force precedence. True if EXPR is true.
+
+`! EXPR'
+`-not EXPR'
+ True if EXPR is false.
+
+`EXPR1 EXPR2'
+`EXPR1 -a EXPR2'
+`EXPR1 -and EXPR2'
+ And; EXPR2 is not evaluated if EXPR1 is false.
+
+`EXPR1 -o EXPR2'
+`EXPR1 -or EXPR2'
+ Or; EXPR2 is not evaluated if EXPR1 is true.
+
+`EXPR1 , EXPR2'
+ List; both EXPR1 and EXPR2 are always evaluated. True if EXPR2 is
+ true. The value of EXPR1 is discarded. This operator lets you do
+ multiple independent operations on one traversal, without
+ depending on whether other operations succeeded.
+
+ `find' searches the directory tree rooted at each file name by
+evaluating the expression from left to right, according to the rules of
+precedence, until the outcome is known (the left hand side is false for
+`-and', true for `-or'), at which point `find' moves on to the next
+file name.
+
+ There are two other tests that can be useful in complex expressions:
+
+ - Test: -true
+ Always true.
+
+ - Test: -false
+ Always false.
+
+
+File: find.info, Node: Actions, Next: Common Tasks, Prev: Finding Files, Up: Top
+
+Actions
+*******
+
+ There are several ways you can print information about the files that
+match the criteria you gave in the `find' expression. You can print
+the information either to the standard output or to a file that you
+name. You can also execute commands that have the file names as
+arguments. You can use those commands as further filters to select
+files.
+
+* Menu:
+
+* Print File Name::
+* Print File Information::
+* Run Commands::
+* Adding Tests::
+
+
+File: find.info, Node: Print File Name, Next: Print File Information, Up: Actions
+
+Print File Name
+===============
+
+ - Action: -print
+ True; print the full file name on the standard output, followed by
+ a newline.
+
+ - Action: -fprint FILE
+ True; print the full file name into file FILE, followed by a
+ newline. If FILE does not exist when `find' is run, it is
+ created; if it does exist, it is truncated to 0 bytes. The file
+ names `/dev/stdout' and `/dev/stderr' are handled specially; they
+ refer to the standard output and standard error output,
+ respectively.
+
+
+File: find.info, Node: Print File Information, Next: Run Commands, Prev: Print File Name, Up: Actions
+
+Print File Information
+======================
+
+ - Action: -ls
+ True; list the current file in `ls -dils' format on the standard
+ output. The output looks like this:
+
+ 204744 17 -rw-r--r-- 1 djm staff 17337 Nov 2 1992 ./lwall-quotes
+
+ The fields are:
+
+ 1. The inode number of the file. *Note Hard Links::, for how to
+ find files based on their inode number.
+
+ 2. the number of blocks in the file. The block counts are of 1K
+ blocks, unless the environment variable `POSIXLY_CORRECT' is
+ set, in which case 512-byte blocks are used. *Note Size::,
+ for how to find files based on their size.
+
+ 3. The file's type and permissions. The type is shown as a dash
+ for a regular file; for other file types, a letter like for
+ `-type' is used (*note Type::.). The permissions are read,
+ write, and execute for the file's owner, its group, and other
+ users, respectively; a dash means the permission is not
+ granted. *Note File Permissions::, for more details about
+ file permissions. *Note Permissions::, for how to find files
+ based on their permissions.
+
+ 4. The number of hard links to the file.
+
+ 5. The user who owns the file.
+
+ 6. The file's group.
+
+ 7. The file's size in bytes.
+
+ 8. The date the file was last modified.
+
+ 9. The file's name. `-ls' quotes non-printable characters in
+ the file names using C-like backslash escapes.
+
+ - Action: -fls FILE
+ True; like `-ls' but write to FILE like `-fprint' (*note Print
+ File Name::.).
+
+ - Action: -printf FORMAT
+ True; print FORMAT on the standard output, interpreting `\'
+ escapes and `%' directives. Field widths and precisions can be
+ specified as with the `printf' C function. Unlike `-print',
+ `-printf' does not add a newline at the end of the string.
+
+ - Action: -fprintf FILE FORMAT
+ True; like `-printf' but write to FILE like `-fprint' (*note Print
+ File Name::.).
+
+* Menu:
+
+* Escapes::
+* Format Directives::
+* Time Formats::
+
+
+File: find.info, Node: Escapes, Next: Format Directives, Up: Print File Information
+
+Escapes
+-------
+
+ The escapes that `-printf' and `-fprintf' recognize are:
+
+`\a'
+ Alarm bell.
+
+`\b'
+ Backspace.
+
+`\c'
+ Stop printing from this format immediately and flush the output.
+
+`\f'
+ Form feed.
+
+`\n'
+ Newline.
+
+`\r'
+ Carriage return.
+
+`\t'
+ Horizontal tab.
+
+`\v'
+ Vertical tab.
+
+`\\'
+ A literal backslash (`\').
+
+ A `\' character followed by any other character is treated as an
+ordinary character, so they both are printed, and a warning message is
+printed to the standard error output (because it was probably a typo).
+
+
+File: find.info, Node: Format Directives, Next: Time Formats, Prev: Escapes, Up: Print File Information
+
+Format Directives
+-----------------
+
+ `-printf' and `-fprintf' support the following format directives to
+print information about the file being processed. Unlike the C
+`printf' function, they do not support field width specifiers.
+
+ `%%' is a literal percent sign. A `%' character followed by any
+other character is discarded (but the other character is printed), and
+a warning message is printed to the standard error output (because it
+was probably a typo).
+
+* Menu:
+
+* Name Directives::
+* Ownership Directives::
+* Size Directives::
+* Location Directives::
+* Time Directives::
+
+
+File: find.info, Node: Name Directives, Next: Ownership Directives, Up: Format Directives
+
+Name Directives
+...............
+
+`%p'
+ File's name.
+
+`%f'
+ File's name with any leading directories removed (only the last
+ element).
+
+`%h'
+ Leading directories of file's name (all but the last element and
+ the slash before it).
+
+`%P'
+ File's name with the name of the command line argument under which
+ it was found removed from the beginning.
+
+`%H'
+ Command line argument under which file was found.
+
+
+File: find.info, Node: Ownership Directives, Next: Size Directives, Prev: Name Directives, Up: Format Directives
+
+Ownership Directives
+....................
+
+`%g'
+ File's group name, or numeric group ID if the group has no name.
+
+`%G'
+ File's numeric group ID.
+
+`%u'
+ File's user name, or numeric user ID if the user has no name.
+
+`%U'
+ File's numeric user ID.
+
+`%m'
+ File's permissions (in octal).
+
+
+File: find.info, Node: Size Directives, Next: Location Directives, Prev: Ownership Directives, Up: Format Directives
+
+Size Directives
+...............
+
+`%k'
+ File's size in 1K blocks (rounded up).
+
+`%b'
+ File's size in 512-byte blocks (rounded up).
+
+`%s'
+ File's size in bytes.
+
+
+File: find.info, Node: Location Directives, Next: Time Directives, Prev: Size Directives, Up: Format Directives
+
+Location Directives
+...................
+
+`%d'
+ File's depth in the directory tree; files named on the command line
+ have a depth of 0.
+
+`%F'
+ Type of the filesystem the file is on; this value can be used for
+ `-fstype' (*note Directories::.).
+
+`%l'
+ Object of symbolic link (empty string if file is not a symbolic
+ link).
+
+`%i'
+ File's inode number (in decimal).
+
+`%n'
+ Number of hard links to file.
+
+
+File: find.info, Node: Time Directives, Prev: Location Directives, Up: Format Directives
+
+Time Directives
+...............
+
+ Some of these directives use the C `ctime' function. Its output
+depends on the current locale, but it typically looks like
+
+ Wed Nov 2 00:42:36 1994
+
+`%a'
+ File's last access time in the format returned by the C `ctime'
+ function.
+
+`%AK'
+ File's last access time in the format specified by K (*note Time
+ Formats::.).
+
+`%c'
+ File's last status change time in the format returned by the C
+ `ctime' function.
+
+`%CK'
+ File's last status change time in the format specified by K (*note
+ Time Formats::.).
+
+`%t'
+ File's last modification time in the format returned by the C
+ `ctime' function.
+
+`%TK'
+ File's last modification time in the format specified by K (*note
+ Time Formats::.).
+
+
+File: find.info, Node: Time Formats, Prev: Format Directives, Up: Print File Information
+
+Time Formats
+------------
+
+ Below are the formats for the directives `%A', `%C', and `%T', which
+print the file's timestamps. Some of these formats might not be
+available on all systems, due to differences in the C `strftime'
+function between systems.
+
+* Menu:
+
+* Time Components::
+* Date Components::
+* Combined Time Formats::
+
+
+File: find.info, Node: Time Components, Next: Date Components, Up: Time Formats
+
+Time Components
+...............
+
+ The following format directives print single components of the time.
+
+`H'
+ hour (00..23)
+
+`I'
+ hour (01..12)
+
+`k'
+ hour ( 0..23)
+
+`l'
+ hour ( 1..12)
+
+`p'
+ locale's AM or PM
+
+`Z'
+ time zone (e.g., EDT), or nothing if no time zone is determinable
+
+`M'
+ minute (00..59)
+
+`S'
+ second (00..61)
+
+`@'
+ seconds since Jan. 1, 1970, 00:00 GMT.
+
+
+File: find.info, Node: Date Components, Next: Combined Time Formats, Prev: Time Components, Up: Time Formats
+
+Date Components
+...............
+
+ The following format directives print single components of the date.
+
+`a'
+ locale's abbreviated weekday name (Sun..Sat)
+
+`A'
+ locale's full weekday name, variable length (Sunday..Saturday)
+
+`b'
+`h'
+ locale's abbreviated month name (Jan..Dec)
+
+`B'
+ locale's full month name, variable length (January..December)
+
+`m'
+ month (01..12)
+
+`d'
+ day of month (01..31)
+
+`w'
+ day of week (0..6)
+
+`j'
+ day of year (001..366)
+
+`U'
+ week number of year with Sunday as first day of week (00..53)
+
+`W'
+ week number of year with Monday as first day of week (00..53)
+
+`Y'
+ year (1970...)
+
+`y'
+ last two digits of year (00..99)
+
+
+File: find.info, Node: Combined Time Formats, Prev: Date Components, Up: Time Formats
+
+Combined Time Formats
+.....................
+
+ The following format directives print combinations of time and date
+components.
+
+`r'
+ time, 12-hour (hh:mm:ss [AP]M)
+
+`T'
+ time, 24-hour (hh:mm:ss)
+
+`X'
+ locale's time representation (H:M:S)
+
+`c'
+ locale's date and time (Sat Nov 04 12:02:33 EST 1989)
+
+`D'
+ date (mm/dd/yy)
+
+`x'
+ locale's date representation (mm/dd/yy)
+
+
+File: find.info, Node: Run Commands, Next: Adding Tests, Prev: Print File Information, Up: Actions
+
+Run Commands
+============
+
+ You can use the list of file names created by `find' or `locate' as
+arguments to other commands. In this way you can perform arbitrary
+actions on the files.
+
+* Menu:
+
+* Single File::
+* Multiple Files::
+* Querying::
+
+
+File: find.info, Node: Single File, Next: Multiple Files, Up: Run Commands
+
+Single File
+-----------
+
+ Here is how to run a command on one file at a time.
+
+ - Action: -exec COMMAND ;
+ Execute COMMAND; true if 0 status is returned. `find' takes all
+ arguments after `-exec' to be part of the command until an
+ argument consisting of `;' is reached. It replaces the string
+ `{}' by the current file name being processed everywhere it occurs
+ in the command. Both of these constructions need to be escaped
+ (with a `\') or quoted to protect them from expansion by the shell.
+ The command is executed in the directory in which `find' was run.
+
+ For example, to compare each C header file in the current
+ directory with the file `/tmp/master':
+
+ find . -name '*.h' -exec diff -u '{}' /tmp/master ';'
+
+
+File: find.info, Node: Multiple Files, Next: Querying, Prev: Single File, Up: Run Commands
+
+Multiple Files
+--------------
+
+ Sometimes you need to process files alone. But when you don't, it
+is faster to run a command on as many files as possible at a time,
+rather than once per file. Doing this saves on the time it takes to
+start up the command each time.
+
+ To run a command on more than one file at once, use the `xargs'
+command, which is invoked like this:
+
+ xargs [OPTION...] [COMMAND [INITIAL-ARGUMENTS]]
+
+ `xargs' reads arguments from the standard input, delimited by blanks
+(which can be protected with double or single quotes or a backslash) or
+newlines. It executes the COMMAND (default is `/bin/echo') one or more
+times with any INITIAL-ARGUMENTS followed by arguments read from
+standard input. Blank lines on the standard input are ignored.
+
+ Instead of blank-delimited names, it is safer to use `find -print0'
+or `find -fprint0' and process the output by giving the `-0' or
+`--null' option to GNU `xargs', GNU `tar', GNU `cpio', or `perl'.
+
+ You can use shell command substitution (backquotes) to process a
+list of arguments, like this:
+
+ grep -l sprintf `find $HOME -name '*.c' -print`
+
+ However, that method produces an error if the length of the `.c'
+file names exceeds the operating system's command-line length limit.
+`xargs' avoids that problem by running the command as many times as
+necessary without exceeding the limit:
+
+ find $HOME -name '*.c' -print | grep -l sprintf
+
+ However, if the command needs to have its standard input be a
+terminal (`less', for example), you have to use the shell command
+substitution method.
+
+* Menu:
+
+* Unsafe File Name Handling::
+* Safe File Name Handling::
+* Limiting Command Size::
+* Interspersing File Names::
+
+
+File: find.info, Node: Unsafe File Name Handling, Next: Safe File Name Handling, Up: Multiple Files
+
+Unsafe File Name Handling
+.........................
+
+ Because file names can contain quotes, backslashes, blank characters,
+and even newlines, it is not safe to process them using `xargs' in its
+default mode of operation. But since most files' names do not contain
+blanks, this problem occurs only infrequently. If you are only
+searching through files that you know have safe names, then you need not
+be concerned about it.
+
+ In many applications, if `xargs' botches processing a file because
+its name contains special characters, some data might be lost. The
+importance of this problem depends on the importance of the data and
+whether anyone notices the loss soon enough to correct it. However,
+here is an extreme example of the problems that using blank-delimited
+names can cause. If the following command is run daily from `cron',
+then any user can remove any file on the system:
+
+ find / -name '#*' -atime +7 -print | xargs rm
+
+ For example, you could do something like this:
+
+ eg$ echo > '#
+ vmunix'
+
+and then `cron' would delete `/vmunix', if it ran `xargs' with `/' as
+its current directory.
+
+ To delete other files, for example `/u/joeuser/.plan', you could do
+this:
+
+ eg$ mkdir '#
+ '
+ eg$ cd '#
+ '
+ eg$ mkdir u u/joeuser u/joeuser/.plan'
+ '
+ eg$ echo > u/joeuser/.plan'
+ /#foo'
+ eg$ cd ..
+ eg$ find . -name '#*' -print | xargs echo
+ ./# ./# /u/joeuser/.plan /#foo
+
+
+File: find.info, Node: Safe File Name Handling, Next: Limiting Command Size, Prev: Unsafe File Name Handling, Up: Multiple Files
+
+Safe File Name Handling
+.......................
+
+ Here is how to make `find' output file names so that they can be
+used by other programs without being mangled or misinterpreted. You can
+process file names generated this way by giving the `-0' or `--null'
+option to GNU `xargs', GNU `tar', GNU `cpio', or `perl'.
+
+ - Action: -print0
+ True; print the full file name on the standard output, followed by
+ a null character.
+
+ - Action: -fprint0 FILE
+ True; like `-print0' but write to FILE like `-fprint' (*note Print
+ File Name::.).
+
+
+File: find.info, Node: Limiting Command Size, Next: Interspersing File Names, Prev: Safe File Name Handling, Up: Multiple Files
+
+Limiting Command Size
+.....................
+
+ `xargs' gives you control over how many arguments it passes to the
+command each time it executes it. By default, it uses up to `ARG_MAX'
+- 2k, or 20k, whichever is smaller, characters per command. It uses as
+many lines and arguments as fit within that limit. The following
+options modify those values.
+
+`--no-run-if-empty'
+`-r'
+ If the standard input does not contain any nonblanks, do not run
+ the command. By default, the command is run once even if there is
+ no input.
+
+`--max-lines[=MAX-LINES]'
+`-l[MAX-LINES]'
+ Use at most MAX-LINES nonblank input lines per command line;
+ MAX-LINES defaults to 1 if omitted. Trailing blanks cause an
+ input line to be logically continued on the next input line, for
+ the purpose of counting the lines. Implies `-x'.
+
+`--max-args=MAX-ARGS'
+`-n MAX-ARGS'
+ Use at most MAX-ARGS arguments per command line. Fewer than
+ MAX-ARGS arguments will be used if the size (see the `-s' option)
+ is exceeded, unless the `-x' option is given, in which case
+ `xargs' will exit.
+
+`--max-chars=MAX-CHARS'
+`-s MAX-CHARS'
+ Use at most MAX-CHARS characters per command line, including the
+ command and initial arguments and the terminating nulls at the
+ ends of the argument strings.
+
+`--max-procs=MAX-PROCS'
+`-P MAX-PROCS'
+ Run up to MAX-PROCS processes at a time; the default is 1. If
+ MAX-PROCS is 0, `xargs' will run as many processes as possible at
+ a time. Use the `-n', `-s', or `-l' option with `-P'; otherwise
+ chances are that the command will be run only once.
+
+
+File: find.info, Node: Interspersing File Names, Prev: Limiting Command Size, Up: Multiple Files
+
+Interspersing File Names
+........................
+
+ `xargs' can insert the name of the file it is processing between
+arguments you give for the command. Unless you also give options to
+limit the command size (*note Limiting Command Size::.), this mode of
+operation is equivalent to `find -exec' (*note Single File::.).
+
+`--replace[=REPLACE-STR]'
+`-i[REPLACE-STR]'
+ Replace occurences of REPLACE-STR in the initial arguments with
+ names read from standard input. Also, unquoted blanks do not
+ terminate arguments. If REPLACE-STR is omitted, it defaults to
+ `{}' (like for `find -exec'). Implies `-x' and `-l 1'. As an
+ example, to sort each file the `bills' directory, leaving the
+ output in that file name with `.sorted' appended, you could do:
+
+ find bills -type f | xargs -iXX sort -o XX.sorted XX
+
+ The equivalent command using `find -exec' is:
+
+ find bills -type f -exec sort -o '{}.sorted' '{}' ';'
+
+
+File: find.info, Node: Querying, Prev: Multiple Files, Up: Run Commands
+
+Querying
+--------
+
+ To ask the user whether to execute a command on a single file, you
+can use the `find' primary `-ok' instead of `-exec':
+
+ - Action: -ok COMMAND ;
+ Like `-exec' (*note Single File::.), but ask the user first (on
+ the standard input); if the response does not start with `y' or
+ `Y', do not run the command, and return false.
+
+ When processing multiple files with a single command, to query the
+user you give `xargs' the following option. When using this option, you
+might find it useful to control the number of files processed per
+invocation of the command (*note Limiting Command Size::.).
+
+`--interactive'
+`-p'
+ Prompt the user about whether to run each command line and read a
+ line from the terminal. Only run the command line if the response
+ starts with `y' or `Y'. Implies `-t'.
+
+
+File: find.info, Node: Adding Tests, Prev: Run Commands, Up: Actions
+
+Adding Tests
+============
+
+ You can test for file attributes that none of the `find' builtin
+tests check. To do this, use `xargs' to run a program that filters a
+list of files printed by `find'. If possible, use `find' builtin tests
+to pare down the list, so the program run by `xargs' has less work to
+do. The tests builtin to `find' will likely run faster than tests that
+other programs perform.
+
+ For example, here is a way to print the names of all of the
+unstripped binaries in the `/usr/local' directory tree. Builtin tests
+avoid running `file' on files that are not regular files or are not
+executable.
+
+ find /usr/local -type f -perm +a=x | xargs file |
+ grep 'not stripped' | cut -d: -f1
+
+The `cut' program removes everything after the file name from the
+output of `file'.
+
+ If you want to place a special test somewhere in the middle of a
+`find' expression, you can use `-exec' to run a program that performs
+the test. Because `-exec' evaluates to the exit status of the executed
+program, you can write a program (which can be a shell script) that
+tests for a special attribute and make it exit with a true (zero) or
+false (non-zero) status. It is a good idea to place such a special
+test *after* the builtin tests, because it starts a new process which
+could be avoided if a builtin test evaluates to false. Use this method
+only when `xargs' is not flexible enough, because starting one or more
+new processes to test each file is slower than using `xargs' to start
+one process that tests many files.
+
+ Here is a shell script called `unstripped' that checks whether its
+argument is an unstripped binary file:
+
+ #!/bin/sh
+ file $1 | grep 'not stripped' > /dev/null
+
+ This script relies on the fact that the shell exits with the status
+of the last program it executed, in this case `grep'. `grep' exits
+with a true status if it found any matches, false if not. Here is an
+example of using the script (assuming it is in your search path). It
+lists the stripped executables in the file `sbins' and the unstripped
+ones in `ubins'.
+
+ find /usr/local -type f -perm +a=x \
+ \( -exec unstripped '{}' \; -fprint ubins -o -fprint sbins \)
+
+
+File: find.info, Node: Common Tasks, Next: Databases, Prev: Actions, Up: Top
+
+Common Tasks
+************
+
+ The sections that follow contain some extended examples that both
+give a good idea of the power of these programs, and show you how to
+solve common real-world problems.
+
+* Menu:
+
+* Viewing And Editing::
+* Archiving::
+* Cleaning Up::
+* Strange File Names::
+* Fixing Permissions::
+* Classifying Files::
+
diff --git a/doc/find.info-2 b/doc/find.info-2
new file mode 100644
index 00000000..4d5a9802
--- /dev/null
+++ b/doc/find.info-2
@@ -0,0 +1,1069 @@
+This is Info file find.info, produced by Makeinfo-1.55 from the input
+file find.texi.
+
+START-INFO-DIR-ENTRY
+* Finding Files: (find). Listing and operating on files
+ that match certain criteria.
+END-INFO-DIR-ENTRY
+
+ This file documents the GNU utilities for finding files that match
+certain criteria and performing various operations on them.
+
+ Copyright (C) 1994 Free Software Foundation, Inc.
+
+ Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+ Permission is granted to copy and distribute modified versions of
+this manual under the conditions for verbatim copying, provided that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+ Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be stated in a
+translation approved by the Foundation.
+
+
+File: find.info, Node: Viewing And Editing, Next: Archiving, Up: Common Tasks
+
+Viewing And Editing
+===================
+
+ To view a list of files that meet certain criteria, simply run your
+file viewing program with the file names as arguments. Shells
+substitute a command enclosed in backquotes with its output, so the
+whole command looks like this:
+
+ less `find /usr/include -name '*.h' | xargs grep -l mode_t`
+
+You can edit those files by giving an editor name instead of a file
+viewing program.
+
+
+File: find.info, Node: Archiving, Next: Cleaning Up, Prev: Viewing And Editing, Up: Common Tasks
+
+Archiving
+=========
+
+ You can pass a list of files produced by `find' to a file archiving
+program. GNU `tar' and `cpio' can both read lists of file names from
+the standard input--either delimited by nulls (the safe way) or by
+blanks (the lazy, risky default way). To use null-delimited names,
+give them the `--null' option. You can store a file archive in a file,
+write it on a tape, or send it over a network to extract on another
+machine.
+
+ One common use of `find' to archive files is to send a list of the
+files in a directory tree to `cpio'. Use `-depth' so if a directory
+does not have write permission for its owner, its contents can still be
+restored from the archive since the directory's permissions are
+restored after its contents. Here is an example of doing this using
+`cpio'; you could use a more complex `find' expression to archive only
+certain files.
+
+ find . -depth -print0 |
+ cpio --create --null --format=crc --file=/dev/nrst0
+
+ You could restore that archive using this command:
+
+ cpio --extract --null --make-dir --unconditional \
+ --preserve --file=/dev/nrst0
+
+ Here are the commands to do the same things using `tar':
+
+ find . -depth -print0 |
+ tar --create --null --files-from=- --file=/dev/nrst0
+
+ tar --extract --null --preserve-perm --same-owner \
+ --file=/dev/nrst0
+
+ Here is an example of copying a directory from one machine to
+another:
+
+ find . -depth -print0 | cpio -0o -Hnewc |
+ rsh OTHER-MACHINE "cd `pwd` && cpio -i0dum"
+
+
+File: find.info, Node: Cleaning Up, Next: Strange File Names, Prev: Archiving, Up: Common Tasks
+
+Cleaning Up
+===========
+
+ This section gives examples of removing unwanted files in various
+situations. Here is a command to remove the CVS backup files created
+when an update requires a merge:
+
+ find . -name '.#*' -print0 | xargs -0r rm -f
+
+ You can run this command to clean out your clutter in `/tmp'. You
+might place it in the file your shell runs when you log out
+(`.bash_logout', `.logout', or `.zlogout', depending on which shell you
+use).
+
+ find /tmp -user $LOGNAME -type f -print0 | xargs -0 -r rm -f
+
+ To remove old Emacs backup and auto-save files, you can use a command
+like the following. It is especially important in this case to use
+null-terminated file names because Emacs packages like the VM mailer
+often create temporary file names with spaces in them, like `#reply to
+David J. MacKenzie<1>#'.
+
+ find ~ \( -name '*~' -o -name '#*#' \) -print0 |
+ xargs --no-run-if-empty --null rm -vf
+
+ Removing old files from `/tmp' is commonly done from `cron':
+
+ find /tmp /var/tmp -not -type d -mtime +3 -print0 |
+ xargs --null --no-run-if-empty rm -f
+
+ find /tmp /var/tmp -depth -mindepth 1 -type d -empty -print0 |
+ xargs --null --no-run-if-empty rmdir
+
+ The second `find' command above uses `-depth' so it cleans out empty
+directories depth-first, hoping that the parents become empty and can
+be removed too. It uses `-mindepth' to avoid removing `/tmp' itself if
+it becomes totally empty.
+
+
+File: find.info, Node: Strange File Names, Next: Fixing Permissions, Prev: Cleaning Up, Up: Common Tasks
+
+Strange File Names
+==================
+
+ `find' can help you remove or rename a file with strange characters
+in its name. People are sometimes stymied by files whose names contain
+characters such as spaces, tabs, control characters, or characters with
+the high bit set. The simplest way to remove such files is:
+
+ rm -i SOME*PATTERN*THAT*MATCHES*THE*PROBLEM*FILE
+
+ `rm' asks you whether to remove each file matching the given
+pattern. If you are using an old shell, this approach might not work if
+the file name contains a character with the high bit set; the shell may
+strip it off. A more reliable way is:
+
+ find . -maxdepth 1 TESTS -ok rm '{}' \;
+
+where TESTS uniquely identify the file. The `-maxdepth 1' option
+prevents `find' from wasting time searching for the file in any
+subdirectories; if there are no subdirectories, you may omit it. A
+good way to uniquely identify the problem file is to figure out its
+inode number; use
+
+ ls -i
+
+ Suppose you have a file whose name contains control characters, and
+you have found that its inode number is 12345. This command prompts
+you for whether to remove it:
+
+ find . -maxdepth 1 -inum 12345 -ok rm -f '{}' \;
+
+ If you don't want to be asked, perhaps because the file name may
+contain a strange character sequence that will mess up your screen when
+printed, then use `-exec' instead of `-ok'.
+
+ If you want to rename the file instead, you can use `mv' instead of
+`rm':
+
+ find . -maxdepth 1 -inum 12345 -ok mv '{}' NEW-FILE-NAME \;
+
+
+File: find.info, Node: Fixing Permissions, Next: Classifying Files, Prev: Strange File Names, Up: Common Tasks
+
+Fixing Permissions
+==================
+
+ Suppose you want to make sure that everyone can write to the
+directories in a certain directory tree. Here is a way to find
+directories lacking either user or group write permission (or both),
+and fix their permissions:
+
+ find . -type d -not -perm -ug=w | xargs chmod ug+w
+
+You could also reverse the operations, if you want to make sure that
+directories do *not* have world write permission.
+
+
+File: find.info, Node: Classifying Files, Prev: Fixing Permissions, Up: Common Tasks
+
+Classifying Files
+=================
+
+ If you want to classify a set of files into several groups based on
+different criteria, you can use the comma operator to perform multiple
+independent tests on the files. Here is an example:
+
+ find / -type d \( -perm -o=w -fprint allwrite , \
+ -perm -o=x -fprint allexec \)
+
+ echo "Directories that can be written to by everyone:"
+ cat allwrite
+ echo ""
+ echo "Directories with search permissions for everyone:"
+ cat allexec
+
+ `find' has only to make one scan through the directory tree (which
+is one of the most time consuming parts of its work).
+
+
+File: find.info, Node: Databases, Next: File Permissions, Prev: Common Tasks, Up: Top
+
+File Name Databases
+*******************
+
+ The file name databases used by `locate' contain lists of files that
+were in particular directory trees when the databases were last
+updated. The file name of the default database is determined when
+`locate' and `updatedb' are configured and installed. The frequency
+with which the databases are updated and the directories for which they
+contain entries depend on how often `updatedb' is run, and with which
+arguments.
+
+* Menu:
+
+* Database Locations::
+* Database Formats::
+
+
+File: find.info, Node: Database Locations, Next: Database Formats, Up: Databases
+
+Database Locations
+==================
+
+ There can be multiple file name databases. Users can select which
+databases `locate' searches using an environment variable or a command
+line option. The system administrator can choose the file name of the
+default database, the frequency with which the databases are updated,
+and the directories for which they contain entries. File name
+databases are updated by running the `updatedb' program, typically
+nightly.
+
+ In networked environments, it often makes sense to build a database
+at the root of each filesystem, containing the entries for that
+filesystem. `updatedb' is then run for each filesystem on the
+fileserver where that filesystem is on a local disk, to prevent
+thrashing the network. Here are the options to `updatedb' to select
+which directories each database contains entries for:
+
+`--localpaths='PATH...''
+ Non-network directories to put in the database. Default is `/'.
+
+`--netpaths='PATH...''
+ Network (NFS, AFS, RFS, etc.) directories to put in the database.
+ Default is none.
+
+`--prunepaths='PATH...''
+ Directories to not put in the database, which would otherwise be.
+ Default is `/tmp /usr/tmp /var/tmp /afs'.
+
+`--output=DBFILE'
+ The database file to build. Default is system-dependent, but
+ typically `/usr/local/var/locatedb'.
+
+`--netuser=USER'
+ The user to search network directories as, using `su'. Default is
+ `daemon'.
+
+
+File: find.info, Node: Database Formats, Prev: Database Locations, Up: Databases
+
+Database Formats
+================
+
+ The file name databases contain lists of files that were in
+particular directory trees when the databases were last updated. The
+file name database format changed starting with GNU `locate' version
+4.0 to allow machines with diffent byte orderings to share the
+databases. The new GNU `locate' can read both the old and new database
+formats. However, old versions of `locate' and `find' produce incorrect
+results if given a new-format database.
+
+* Menu:
+
+* New Database Format::
+* Sample Database::
+* Old Database Format::
+
+
+File: find.info, Node: New Database Format, Next: Sample Database, Up: Database Formats
+
+New Database Format
+-------------------
+
+ `updatedb' runs a program called `frcode' to "front-compress" the
+list of file names, which reduces the database size by a factor of 4 to
+5. Front-compression (also known as incremental encoding) works as
+follows.
+
+ The database entries are a sorted list (case-insensitively, for
+users' convenience). Since the list is sorted, each entry is likely to
+share a prefix (initial string) with the previous entry. Each database
+entry begins with an offset-differential count byte, which is the
+additional number of characters of prefix of the preceding entry to use
+beyond the number that the preceding entry is using of its predecessor.
+(The counts can be negative.) Following the count is a
+null-terminated ASCII remainder--the part of the name that follows the
+shared prefix.
+
+ If the offset-differential count is larger than can be stored in a
+byte (+/-127), the byte has the value 0x80 and the count follows in a
+2-byte word, with the high byte first (network byte order).
+
+ Every database begins with a dummy entry for a file called
+`LOCATE02', which `locate' checks for to ensure that the database file
+has the correct format; it ignores the entry in doing the search.
+
+ Databases can not be concatenated together, even if the first (dummy)
+entry is trimmed from all but the first database. This is because the
+offset-differential count in the first entry of the second and following
+databases will be wrong.
+
+
+File: find.info, Node: Sample Database, Next: Old Database Format, Prev: New Database Format, Up: Database Formats
+
+Sample Database
+---------------
+
+ Sample input to `frcode':
+
+ /usr/src
+ /usr/src/cmd/aardvark.c
+ /usr/src/cmd/armadillo.c
+ /usr/tmp/zoo
+
+ Length of the longest prefix of the preceding entry to share:
+
+ 0 /usr/src
+ 8 /cmd/aardvark.c
+ 14 rmadillo.c
+ 5 tmp/zoo
+
+ Output from `frcode', with trailing nulls changed to newlines and
+count bytes made printable:
+
+ 0 LOCATE02
+ 0 /usr/src
+ 8 /cmd/aardvark.c
+ 6 rmadillo.c
+ -9 tmp/zoo
+
+ (6 = 14 - 8, and -9 = 5 - 14)
+
+
+File: find.info, Node: Old Database Format, Prev: Sample Database, Up: Database Formats
+
+Old Database Format
+-------------------
+
+ The old database format is used by Unix `locate' and `find' programs
+and earlier releases of the GNU ones. `updatedb' produces this format
+if given the `--old-format' option.
+
+ `updatedb' runs programs called `bigram' and `code' to produce
+old-format databases. The old format differs from the new one in the
+following ways. Instead of each entry starting with an
+offset-differential count byte and ending with a null, byte values from
+0 through 28 indicate offset-differential counts from -14 through 14.
+The byte value indicating that a long offset-differential count follows
+is 0x1e (30), not 0x80. The long counts are stored in host byte order,
+which is not necessarily network byte order, and host integer word size,
+which is usually 4 bytes. They also represent a count 14 less than
+their value. The database lines have no termination byte; the start of
+the next line is indicated by its first byte having a value <= 30.
+
+ In addition, instead of starting with a dummy entry, the old database
+format starts with a 256 byte table containing the 128 most common
+bigrams in the file list. A bigram is a pair of adjacent bytes. Bytes
+in the database that have the high bit set are indexes (with the high
+bit cleared) into the bigram table. The bigram and offset-differential
+count coding makes these databases 20-25% smaller than the new format,
+but makes them not 8-bit clean. Any byte in a file name that is in the
+ranges used for the special codes is replaced in the database by a
+question mark, which not coincidentally is the shell wildcard to match a
+single character.
+
+
+File: find.info, Node: File Permissions, Next: Reference, Prev: Databases, Up: Top
+
+File Permissions
+****************
+
+ Each file has a set of "permissions" that control the kinds of
+access that users have to that file. The permissions for a file are
+also called its "access mode". They can be represented either in
+symbolic form or as an octal number.
+
+* Menu:
+
+* Mode Structure:: Structure of file permissions.
+* Symbolic Modes:: Mnemonic permissions representation.
+* Numeric Modes:: Permissions as octal numbers.
+
+
+File: find.info, Node: Mode Structure, Next: Symbolic Modes, Up: File Permissions
+
+Structure of File Permissions
+=============================
+
+ There are three kinds of permissions that a user can have for a file:
+
+ 1. permission to read the file. For directories, this means
+ permission to list the contents of the directory.
+
+ 2. permission to write to (change) the file. For directories, this
+ means permission to create and remove files in the directory.
+
+ 3. permission to execute the file (run it as a program). For
+ directories, this means permission to access files in the
+ directory.
+
+ There are three categories of users who may have different
+permissions to perform any of the above operations on a file:
+
+ 1. the file's owner;
+
+ 2. other users who are in the file's group;
+
+ 3. everyone else.
+
+ Files are given an owner and group when they are created. Usually
+the owner is the current user and the group is the group of the
+directory the file is in, but this varies with the operating system, the
+filesystem the file is created on, and the way the file is created. You
+can change the owner and group of a file by using the `chown' and
+`chgrp' commands.
+
+ In addition to the three sets of three permissions listed above, a
+file's permissions have three special components, which affect only
+executable files (programs) and, on some systems, directories:
+
+ 1. set the process's effective user ID to that of the file upon
+ execution (called the "setuid bit"). No effect on directories.
+
+ 2. set the process's effective group ID to that of the file upon
+ execution (called the "setgid bit"). For directories on some
+ systems, put files created in the directory into the same group as
+ the directory, no matter what group the user who creates them is
+ in.
+
+ 3. save the program's text image on the swap device so it will load
+ more quickly when run (called the "sticky bit"). For directories
+ on some systems, prevent users from removing files that they do
+ not own in the directory; this is called making the directory
+ "append-only".
+
+
+File: find.info, Node: Symbolic Modes, Next: Numeric Modes, Prev: Mode Structure, Up: File Permissions
+
+Symbolic Modes
+==============
+
+ "Symbolic modes" represent changes to files' permissions as
+operations on single-character symbols. They allow you to modify either
+all or selected parts of files' permissions, optionally based on their
+previous values, and perhaps on the current `umask' as well (*note
+Umask and Protection::.).
+
+ The format of symbolic modes is:
+
+ [ugoa...][[+-=][rwxXstugo...]...][,...]
+
+ The following sections describe the operators and other details of
+symbolic modes.
+
+* Menu:
+
+* Setting Permissions:: Basic operations on permissions.
+* Copying Permissions:: Copying existing permissions.
+* Changing Special Permissions:: Special permissions.
+* Conditional Executability:: Conditionally affecting executability.
+* Multiple Changes:: Making multiple changes.
+* Umask and Protection:: The effect of the umask.
+
+
+File: find.info, Node: Setting Permissions, Next: Copying Permissions, Up: Symbolic Modes
+
+Setting Permissions
+-------------------
+
+ The basic symbolic operations on a file's permissions are adding,
+removing, and setting the permission that certain users have to read,
+write, and execute the file. These operations have the following
+format:
+
+ USERS OPERATION PERMISSIONS
+
+The spaces between the three parts above are shown for readability only;
+symbolic modes can not contain spaces.
+
+ The USERS part tells which users' access to the file is changed. It
+consists of one or more of the following letters (or it can be empty;
+*note Umask and Protection::., for a description of what happens then).
+When more than one of these letters is given, the order that they are
+in does not matter.
+
+`u'
+ the user who owns the file;
+
+`g'
+ other users who are in the file's group;
+
+`o'
+ all other users;
+
+`a'
+ all users; the same as `ugo'.
+
+ The OPERATION part tells how to change the affected users' access to
+the file, and is one of the following symbols:
+
+`+'
+ to add the PERMISSIONS to whatever permissions the USERS already
+ have for the file;
+
+`-'
+ to remove the PERMISSIONS from whatever permissions the USERS
+ already have for the file;
+
+`='
+ to make the PERMISSIONS the only permissions that the USERS have
+ for the file.
+
+ The PERMISSIONS part tells what kind of access to the file should be
+changed; it is zero or more of the following letters. As with the
+USERS part, the order does not matter when more than one letter is
+given. Omitting the PERMISSIONS part is useful only with the `='
+operation, where it gives the specified USERS no access at all to the
+file.
+
+`r'
+ the permission the USERS have to read the file;
+
+`w'
+ the permission the USERS have to write to the file;
+
+`x'
+ the permission the USERS have to execute the file.
+
+ For example, to give everyone permission to read and write a file,
+but not to execute it, use:
+
+ a=rw
+
+ To remove write permission for from all users other than the file's
+owner, use:
+
+ go-w
+
+The above command does not affect the access that the owner of the file
+has to it, nor does it affect whether other users can read or execute
+the file.
+
+ To give everyone except a file's owner no permission to do anything
+with that file, use the mode below. Other users could still remove the
+file, if they have write permission on the directory it is in.
+
+ go=
+
+Another way to specify the same thing is:
+
+ og-rxw
+
+
+File: find.info, Node: Copying Permissions, Next: Changing Special Permissions, Prev: Setting Permissions, Up: Symbolic Modes
+
+Copying Existing Permissions
+----------------------------
+
+ You can base part of a file's permissions on part of its existing
+permissions. To do this, instead of using `r', `w', or `x' after the
+operator, you use the letter `u', `g', or `o'. For example, the mode
+
+ o+g
+
+adds the permissions for users who are in a file's group to the
+permissions that other users have for the file. Thus, if the file
+started out as mode 664 (`rw-rw-r--'), the above mode would change it
+to mode 666 (`rw-rw-rw-'). If the file had started out as mode 741
+(`rwxr----x'), the above mode would change it to mode 745
+(`rwxr--r-x'). The `-' and `=' operations work analogously.
+
+
+File: find.info, Node: Changing Special Permissions, Next: Conditional Executability, Prev: Copying Permissions, Up: Symbolic Modes
+
+Changing Special Permissions
+----------------------------
+
+ In addition to changing a file's read, write, and execute
+permissions, you can change its special permissions. *Note Mode
+Structure::, for a summary of these permissions.
+
+ To change a file's permission to set the user ID on execution, use
+`u' in the USERS part of the symbolic mode and `s' in the PERMISSIONS
+part.
+
+ To change a file's permission to set the group ID on execution, use
+`g' in the USERS part of the symbolic mode and `s' in the PERMISSIONS
+part.
+
+ To change a file's permission to stay permanently on the swap device,
+use `o' in the USERS part of the symbolic mode and `t' in the
+PERMISSIONS part.
+
+ For example, to add set user ID permission to a program, you can use
+the mode:
+
+ u+s
+
+ To remove both set user ID and set group ID permission from it, you
+can use the mode:
+
+ ug-s
+
+ To cause a program to be saved on the swap device, you can use the
+mode:
+
+ o+t
+
+ Remember that the special permissions only affect files that are
+executable, plus, on some systems, directories (on which they have
+different meanings; *note Mode Structure::.). Using `a' in the USERS
+part of a symbolic mode does not cause the special permissions to be
+affected; thus,
+
+ a+s
+
+has *no effect*. You must use `u', `g', and `o' explicitly to affect
+the special permissions. Also, the combinations `u+t', `g+t', and
+`o+s' have no effect.
+
+ The `=' operator is not very useful with special permissions; for
+example, the mode:
+
+ o=t
+
+does cause the file to be saved on the swap device, but it also removes
+all read, write, and execute permissions that users not in the file's
+group might have had for it.
+
+
+File: find.info, Node: Conditional Executability, Next: Multiple Changes, Prev: Changing Special Permissions, Up: Symbolic Modes
+
+Conditional Executability
+-------------------------
+
+ There is one more special type of symbolic permission: if you use
+`X' instead of `x', execute permission is affected only if the file
+already had execute permission or is a directory. It affects
+directories' execute permission even if they did not initially have any
+execute permissions set.
+
+ For example, this mode:
+
+ a+X
+
+gives all users permission to execute files (or search directories) if
+anyone could before.
+
+
+File: find.info, Node: Multiple Changes, Next: Umask and Protection, Prev: Conditional Executability, Up: Symbolic Modes
+
+Making Multiple Changes
+-----------------------
+
+ The format of symbolic modes is actually more complex than described
+above (*note Setting Permissions::.). It provides two ways to make
+multiple changes to files' permissions.
+
+ The first way is to specify multiple OPERATION and PERMISSIONS parts
+after a USERS part in the symbolic mode.
+
+ For example, the mode:
+
+ og+rX-w
+
+gives users other than the owner of the file read permission and, if it
+is a directory or if someone already had execute permission to it,
+gives them execute permission; and it also denies them write permission
+to it file. It does not affect the permission that the owner of the
+file has for it. The above mode is equivalent to the two modes:
+
+ og+rX
+ og-w
+
+ The second way to make multiple changes is to specify more than one
+simple symbolic mode, separated by commas. For example, the mode:
+
+ a+r,go-w
+
+gives everyone permission to read the file and removes write permission
+on it for all users except its owner. Another example:
+
+ u=rwx,g=rx,o=
+
+sets all of the non-special permissions for the file explicitly. (It
+gives users who are not in the file's group no permission at all for
+it.)
+
+ The two methods can be combined. The mode:
+
+ a+r,g+x-w
+
+gives all users permission to read the file, and gives users who are in
+the file's group permission to execute it, as well, but not permission
+to write to it. The above mode could be written in several different
+ways; another is:
+
+ u+r,g+rx,o+r,g-w
+
+
+File: find.info, Node: Umask and Protection, Prev: Multiple Changes, Up: Symbolic Modes
+
+The Umask and Protection
+------------------------
+
+ If the USERS part of a symbolic mode is omitted, it defaults to `a'
+(affect all users), except that any permissions that are *set* in the
+system variable `umask' are *not affected*. The value of `umask' can
+be set using the `umask' command. Its default value varies from system
+to system.
+
+ Omitting the USERS part of a symbolic mode is generally not useful
+with operations other than `+'. It is useful with `+' because it
+allows you to use `umask' as an easily customizable protection against
+giving away more permission to files than you intended to.
+
+ As an example, if `umask' has the value 2, which removes write
+permission for users who are not in the file's group, then the mode:
+
+ +w
+
+adds permission to write to the file to its owner and to other users who
+are in the file's group, but *not* to other users. In contrast, the
+mode:
+
+ a+w
+
+ignores `umask', and *does* give write permission for the file to all
+users.
+
+
+File: find.info, Node: Numeric Modes, Prev: Symbolic Modes, Up: File Permissions
+
+Numeric Modes
+=============
+
+ File permissions are stored internally as 16 bit integers. As an
+alternative to giving a symbolic mode, you can give an octal (base 8)
+number that corresponds to the internal representation of the new mode.
+This number is always interpreted in octal; you do not have to add a
+leading 0, as you do in C. Mode 0055 is the same as mode 55.
+
+ A numeric mode is usually shorter than the corresponding symbolic
+mode, but it is limited in that it can not take into account a file's
+previous permissions; it can only set them absolutely.
+
+ The permissions granted to the user, to other users in the file's
+group, and to other users not in the file's group are each stored as
+three bits, which are represented as one octal digit. The three special
+permissions are also each stored as one bit, and they are as a group
+represented as another octal digit. Here is how the bits are arranged
+in the 16 bit integer, starting with the lowest valued bit:
+
+ Value in Corresponding
+ Mode Permission
+
+ Other users not in the file's group:
+ 1 Execute
+ 2 Write
+ 4 Read
+
+ Other users in the file's group:
+ 10 Execute
+ 20 Write
+ 40 Read
+
+ The file's owner:
+ 100 Execute
+ 200 Write
+ 400 Read
+
+ Special permissions:
+ 1000 Save text image on swap device
+ 2000 Set group ID on execution
+ 4000 Set user ID on execution
+
+ For example, numeric mode 4755 corresponds to symbolic mode
+`u=rwxs,go=rx', and numeric mode 664 corresponds to symbolic mode
+`ug=rw,o=r'. Numeric mode 0 corresponds to symbolic mode `ugo='.
+
+
+File: find.info, Node: Reference, Next: Primary Index, Prev: File Permissions, Up: Top
+
+Reference
+*********
+
+ Below are summaries of the command line syntax for the programs
+discussed in this manual.
+
+* Menu:
+
+* Invoking find::
+* Invoking locate::
+* Invoking updatedb::
+* Invoking xargs::
+
+
+File: find.info, Node: Invoking find, Next: Invoking locate, Up: Reference
+
+Invoking `find'
+===============
+
+ find [FILE...] [EXPRESSION]
+
+ `find' searches the directory tree rooted at each file name FILE by
+evaluating the EXPRESSION on each file it finds in the tree.
+
+ `find' considers the first argument that begins with `-', `(', `)',
+`,', or `!' to be the beginning of the expression; any arguments before
+it are paths to search, and any arguments after it are the rest of the
+expression. If no paths are given, the current directory is used. If
+no expression is given, the expression `-print' is used.
+
+ `find' exits with status 0 if all files are processed successfully,
+greater than 0 if errors occur.
+
+ *Note Primary Index::, for a summary of all of the tests, actions,
+and options that the expression can contain.
+
+ `find' also recognizes two options for administrative use:
+
+`--help'
+ Print a summary of the command-line argument format and exit.
+
+`--version'
+ Print the version number of `find' and exit.
+
+
+File: find.info, Node: Invoking locate, Next: Invoking updatedb, Prev: Invoking find, Up: Reference
+
+Invoking `locate'
+=================
+
+ locate [OPTION...] PATTERN...
+
+`--database=PATH'
+`-d PATH'
+ Instead of searching the default file name database, search the
+ file name databases in PATH, which is a colon-separated list of
+ database file names. You can also use the environment variable
+ `LOCATE_PATH' to set the list of database files to search. The
+ option overrides the environment variable if both are used.
+
+`--help'
+ Print a summary of the options to `locate' and exit.
+
+`--version'
+ Print the version number of `locate' and exit.
+
+
+File: find.info, Node: Invoking updatedb, Next: Invoking xargs, Prev: Invoking locate, Up: Reference
+
+Invoking `updatedb'
+===================
+
+ updatedb [OPTION...]
+
+`--localpaths='PATH...''
+ Non-network directories to put in the database. Default is `/'.
+
+`--netpaths='PATH...''
+ Network (NFS, AFS, RFS, etc.) directories to put in the database.
+ Default is none.
+
+`--prunepaths='PATH...''
+ Directories to not put in the database, which would otherwise be.
+ Default is `/tmp /usr/tmp /var/tmp /afs'.
+
+`--output=DBFILE'
+ The database file to build. Default is system-dependent, but
+ typically `/usr/local/var/locatedb'.
+
+`--netuser=USER'
+ The user to search network directories as, using `su'(1). Default
+ is `daemon'.
+
+
+File: find.info, Node: Invoking xargs, Prev: Invoking updatedb, Up: Reference
+
+Invoking `xargs'
+================
+
+ xargs [OPTION...] [COMMAND [INITIAL-ARGUMENTS]]
+
+ `xargs' exits with the following status:
+
+0
+ if it succeeds
+
+123
+ if any invocation of the command exited with status 1-125
+
+124
+ if the command exited with status 255
+
+125
+ if the command is killed by a signal
+
+126
+ if the command cannot be run
+
+127
+ if the command is not found
+
+1
+ if some other error occurred.
+
+`--null'
+`-0'
+ Input filenames are terminated by a null character instead of by
+ whitespace, and the quotes and backslash are not special (every
+ character is taken literally). Disables the end of file string,
+ which is treated like any other argument.
+
+`--eof[=EOF-STR]'
+`-e[EOF-STR]'
+ Set the end of file string to EOF-STR. If the end of file string
+ occurs as a line of input, the rest of the input is ignored. If
+ EOF-STR is omitted, there is no end of file string. If this
+ option is not given, the end of file string defaults to `_'.
+
+`--help'
+ Print a summary of the options to `xargs' and exit.
+
+`--replace[=REPLACE-STR]'
+`-i[REPLACE-STR]'
+ Replace occurences of REPLACE-STR in the initial arguments with
+ names read from standard input. Also, unquoted blanks do not
+ terminate arguments. If REPLACE-STR is omitted, it defaults to
+ `{}' (like for `find -exec'). Implies `-x' and `-l 1'.
+
+`--max-lines[=MAX-LINES]'
+`-l[MAX-LINES]'
+ Use at most MAX-LINES nonblank input lines per command line;
+ MAX-LINES defaults to 1 if omitted. Trailing blanks cause an
+ input line to be logically continued on the next input line, for
+ the purpose of counting the lines. Implies `-x'.
+
+`--max-args=MAX-ARGS'
+`-n MAX-ARGS'
+ Use at most MAX-ARGS arguments per command line. Fewer than
+ MAX-ARGS arguments will be used if the size (see the `-s' option)
+ is exceeded, unless the `-x' option is given, in which case
+ `xargs' will exit.
+
+`--interactive'
+`-p'
+ Prompt the user about whether to run each command line and read a
+ line from the terminal. Only run the command line if the response
+ starts with `y' or `Y'. Implies `-t'.
+
+`--no-run-if-empty'
+`-r'
+ If the standard input does not contain any nonblanks, do not run
+ the command. By default, the command is run once even if there is
+ no input.
+
+`--max-chars=MAX-CHARS'
+`-s MAX-CHARS'
+ Use at most MAX-CHARS characters per command line, including the
+ command and initial arguments and the terminating nulls at the
+ ends of the argument strings.
+
+`--verbose'
+`-t'
+ Print the command line on the standard error output before
+ executing it.
+
+`--version'
+ Print the version number of `xargs' and exit.
+
+`--exit'
+`-x'
+ Exit if the size (see the -S option) is exceeded.
+
+`--max-procs=MAX-PROCS'
+`-P MAX-PROCS'
+ Run up to MAX-PROCS processes at a time; the default is 1. If
+ MAX-PROCS is 0, `xargs' will run as many processes as possible at
+ a time.
+
+
+File: find.info, Node: Primary Index, Prev: Reference, Up: Top
+
+`find' Primary Index
+********************
+
+ This is a list of all of the primaries (tests, actions, and options)
+that make up `find' expressions for selecting files. *Note find
+Expressions::, for more information on expressions.
+
+* Menu:
+
+* -amin: Age Ranges.
+* -anewer: Comparing Timestamps.
+* -atime: Age Ranges.
+* -cmin: Age Ranges.
+* -cnewer: Comparing Timestamps.
+* -ctime: Age Ranges.
+* -daystart: Age Ranges.
+* -depth: Directories.
+* -empty: Size.
+* -exec: Single File.
+* -false: Combining Primaries With Operators.
+* -fls: Print File Information.
+* -follow: Symbolic Links.
+* -fprint: Print File Name.
+* -fprint0: Safe File Name Handling.
+* -fprintf: Print File Information.
+* -fstype: Filesystems.
+* -gid: Owner.
+* -group: Owner.
+* -ilname: Symbolic Links.
+* -iname: Base Name Patterns.
+* -inum: Hard Links.
+* -ipath: Full Name Patterns.
+* -iregex: Full Name Patterns.
+* -links: Hard Links.
+* -lname: Symbolic Links.
+* -ls: Print File Information.
+* -maxdepth: Directories.
+* -mindepth: Directories.
+* -mmin: Age Ranges.
+* -mount: Filesystems.
+* -mtime: Age Ranges.
+* -name: Base Name Patterns.
+* -newer: Comparing Timestamps.
+* -nogroup: Owner.
+* -noleaf: Directories.
+* -nouser: Owner.
+* -ok: Querying.
+* -path: Full Name Patterns.
+* -perm: Permissions.
+* -print: Print File Name.
+* -print0: Safe File Name Handling.
+* -printf: Print File Information.
+* -prune: Directories.
+* -regex: Full Name Patterns.
+* -size: Size.
+* -true: Combining Primaries With Operators.
+* -type: Type.
+* -uid: Owner.
+* -used: Comparing Timestamps.
+* -user: Owner.
+* -xdev: Filesystems.
+* -xtype: Type.
+
+
diff --git a/doc/find.texi b/doc/find.texi
index 1d5f6ab5..0b8d6f42 100644
--- a/doc/find.texi
+++ b/doc/find.texi
@@ -6,66 +6,82 @@
@c @setchapternewpage odd
@c %**end of header
-@include version.texi
-@include ../locate/dblocation.texi
+@set EDITION 1.1
+@set VERSION 4.1
+@set UPDATED November 1994
@iftex
@finalout
@end iftex
-@dircategory Basics
-@direntry
-* Finding files: (find). Operating on files matching certain criteria.
-@end direntry
-
-@dircategory Individual utilities
-@direntry
-* find: (find)Invoking find. Finding and acting on files.
-* locate: (find)Invoking locate. Finding files in a database.
-* updatedb: (find)Invoking updatedb. Building the locate database.
-* xargs: (find)Invoking xargs. Operating on many files.
-@end direntry
-
-@copying
+@ifinfo
+@format
+START-INFO-DIR-ENTRY
+* Finding Files: (find). Listing and operating on files
+ that match certain criteria.
+END-INFO-DIR-ENTRY
+@end format
This file documents the GNU utilities for finding files that match
certain criteria and performing various operations on them.
-Copyright (C) 1994, 1996, 1998, 2000, 2001, 2003, 2004, 2005, 2006,
-2007 Free Software Foundation, Inc.
+Copyright (C) 1994 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
-Permission is granted to copy, distribute and/or modify this document
-under the terms of the GNU Free Documentation License, Version 1.2 or
-any later version published by the Free Software Foundation; with no
-Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
-Texts. A copy of the license is included in the section entitled
-``GNU Free Documentation License.''
-@end copying
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Foundation.
+@end ifinfo
@titlepage
@title Finding Files
@subtitle Edition @value{EDITION}, for GNU @code{find} version @value{VERSION}
@subtitle @value{UPDATED}
-@author by David MacKenzie and James Youngman
+@author by David MacKenzie
@page
@vskip 0pt plus 1filll
-@insertcopying{}
-@end titlepage
+Copyright @copyright{} 1994 Free Software Foundation, Inc.
-@contents
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
-@ifnottex
-@node Top
-@top GNU Findutils
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Foundation.
+@end titlepage
+
+@node Top, Introduction, , (dir)
@comment node-name, next, previous, up
-@insertcopying
+@ifinfo
This file documents the GNU utilities for finding files that match
certain criteria and performing various actions on them.
-
This is edition @value{EDITION}, for @code{find} version @value{VERSION}.
-@end ifnottex
+@end ifinfo
@c The master menu, created with texinfo-master-menu, goes here.
@@ -73,77 +89,34 @@ This is edition @value{EDITION}, for @code{find} version @value{VERSION}.
* Introduction:: Summary of the tasks this manual describes.
* Finding Files:: Finding files that match certain criteria.
* Actions:: Doing things to files you have found.
+* Common Tasks:: Solutions to common real-world problems.
* Databases:: Maintaining file name databases.
* File Permissions:: How to control access to files.
-* Date input formats:: Specifying literal times.
* Reference:: Summary of how to invoke the programs.
-* Common Tasks:: Solutions to common real-world problems.
-* Worked Examples:: Examples demonstrating more complex points.
-* Security Considerations:: Security issues relating to findutils.
-* Error Messages:: Explanations of some messages you might see.
-* GNU Free Documentation License:: Copying and sharing this manual.
* Primary Index:: The components of @code{find} expressions.
@end menu
-@node Introduction
+@node Introduction, Finding Files, Top, Top
@chapter Introduction
-This manual shows how to find files that meet criteria you specify,
-and how to perform various actions on the files that you find. The
-principal programs that you use to perform these tasks are
-@code{find}, @code{locate}, and @code{xargs}. Some of the examples in
-this manual use capabilities specific to the GNU versions of those
-programs.
-
-GNU @code{find} was originally written by Eric Decker, with
-enhancements by David MacKenzie, Jay Plett, and Tim Wood. GNU
-@code{xargs} was originally written by Mike Rendell, with enhancements
-by David MacKenzie. GNU @code{locate} and its associated utilities
-were originally written by James Woods, with enhancements by David
-MacKenzie. The idea for @samp{find -print0} and @samp{xargs -0} came
-from Dan Bernstein. The current maintainer of GNU findutils (and this
-manual) is James Youngman. Many other people have contributed bug
-fixes, small improvements, and helpful suggestions. Thanks!
-
-To report a bug in GNU findutils, please use the form on the Savannah
-web site at
-@code{http://savannah.gnu.org/bugs/?group=findutils}. Reporting bugs
-this way means that you will then be able to track progress in fixing
-the problem.
-
-If you don't have web access, you can also just send mail to the
-mailing list. The mailing list @email{bug-findutils@@gnu.org} carries
-discussion of bugs in findutils, questions and answers about the
-software and discussion of the development of the programs. To join
-the list, send email to @email{bug-findutils-request@@gnu.org}.
-
-Please read any relevant sections of this manual before asking for
-help on the mailing list. You may also find it helpful to read the
-NON-BUGS section of the @code{find} manual page.
-
-If you ask for help on the mailing list, people will be able to help
-you much more effectively if you include the following things:
-
-@itemize @bullet
-@item The version of the software you are running. You can find this
-out by running @samp{locate --version}.
-@item What you were trying to do
-@item The @emph{exact} command line you used
-@item The @emph{exact} output you got (if this is very long, try to
-find a smaller example which exhibits the same problem)
-@item The output you expected to get
-@end itemize
-
-It may also be the case that the bug you are describing has already
-been fixed, if it is a bug. Please check the most recent findutils
-releases at @url{ftp://ftp.gnu.org/gnu/findutils} and, if possible,
-the development branch at @url{ftp://alpha.gnu.org/gnu/findutils}.
-If you take the time to check that your bug still exists in current
-releases, this will greatly help people who want to help you solve
-your problem. Please also be aware that if you obtained findutils as
-part of the GNU/Linux 'distribution', the distributions often lag
-seriously behind findutils releases, even the stable release. Please
-check the GNU FTP site.
+This manual shows how to find files that meet criteria you specify, and
+how to perform various actions on the files that you find. The
+principal programs that you use to perform these tasks are @code{find},
+@code{locate}, and @code{xargs}. Some of the examples in this manual
+use capabilities specific to the GNU versions of those programs.
+
+GNU @code{find} was originally written by Eric Decker, with enhancements
+by David MacKenzie, Jay Plett, and Tim Wood. GNU @code{xargs} was
+originally written by Mike Rendell, with enhancements by David
+MacKenzie. GNU @code{locate} and its associated utilities were
+originally written by James Woods, with enhancements by David MacKenzie.
+The idea for @samp{find -print0} and @samp{xargs -0} came from Dan
+Bernstein. Many other people have contributed bug fixes, small
+improvements, and helpful suggestions. Thanks!
+
+Mail suggestions and bug reports for these programs to
+@code{bug-gnu-utils@@prep.ai.mit.edu}. Please include the version
+number, which you can get by running @samp{find --version}.
@menu
* Scope::
@@ -154,12 +127,12 @@ check the GNU FTP site.
@node Scope
@section Scope
-For brevity, the word @dfn{file} in this manual means a regular file,
-a directory, a symbolic link, or any other kind of node that has a
-directory entry. A directory entry is also called a @dfn{file name}.
-A file name may contain some, all, or none of the directories in a
-path that leads to the file. These are all examples of what this
-manual calls ``file names'':
+For brevity, the word @dfn{file} in this manual means a regular file, a
+directory, a symbolic link, or any other kind of node that has a
+directory entry. A directory entry is also called a @dfn{file name}. A
+file name may contain some, all, or none of the directories in a path
+that leads to the file. These are all examples of what this manual
+calls ``file names'':
@example
parser.c
@@ -169,9 +142,9 @@ fred/.cshrc
/usr/local/include/termcap.h
@end example
-A @dfn{directory tree} is a directory and the files it contains, all
-of its subdirectories and the files they contain, etc. It can also be
-a single non-directory file.
+A @dfn{directory tree} is a directory and the files it contains, all of
+its subdirectories and the files they contain, etc. It can also be a
+single non-directory file.
These programs enable you to find the files in one or more directory
trees that:
@@ -190,7 +163,7 @@ are of a certain type (regular file, directory, symbolic link, etc.);
@item
are owned by a certain user or group;
@item
-have certain access permissions or special mode bits;
+have certain access permissions;
@item
contain text that matches a certain pattern;
@item
@@ -202,9 +175,9 @@ or some combination of the above.
Once you have found the files you're looking for (or files that are
potentially the ones you're looking for), you can do more to them than
simply list their names. You can get any combination of the files'
-attributes, or process the files in many ways, either individually or
-in groups of various sizes. Actions that you might want to perform on
-the files you have found include, but are not limited to:
+attributes, or process the files in many ways, either individually or in
+groups of various sizes. Actions that you might want to perform on the
+files you have found include, but are not limited to:
@itemize @bullet
@item
@@ -237,16 +210,13 @@ find @r{[}@var{file}@dots{}@r{]} @r{[}@var{expression}@r{]}
@end example
@noindent
-Here is a typical use of @code{find}. This example prints the names
-of all files in the directory tree rooted in @file{/usr/src} whose
-name ends with @samp{.c} and that are larger than 100 Kilobytes.
+Here is a typical use of @code{find}. This example prints the names of
+all files in the directory tree rooted in @file{/usr/src} whose name
+ends with @samp{.c} and that are larger than 100 Kilobytes.
@example
find /usr/src -name '*.c' -size +100k -print
@end example
-Notice that the wildcard must be enclosed in quotes in order to
-protect it from expansion by the shell.
-
@code{locate} searches special file name databases for file names that
match patterns. The system administrator runs the @code{updatedb}
program to create the databases. @code{locate} is run like this:
@@ -257,18 +227,18 @@ locate @r{[}@var{option}@dots{}@r{]} @var{pattern}@dots{}
@noindent
This example prints the names of all files in the default file name
-database whose name ends with @samp{Makefile} or @samp{makefile}.
-Which file names are stored in the database depends on how the system
+database whose name ends with @samp{Makefile} or @samp{makefile}. Which
+file names are stored in the database depends on how the system
administrator ran @code{updatedb}.
@example
locate '*[Mm]akefile'
@end example
-The name @code{xargs}, pronounced EX-args, means ``combine
-arguments.'' @code{xargs} builds and executes command lines by
-gathering together arguments it reads on the standard input. Most
-often, these arguments are lists of file names generated by
-@code{find}. @code{xargs} is run like this:
+The name @code{xargs}, pronounced EX-args, means ``combine arguments.''
+@code{xargs} builds and executes command lines by gathering together
+arguments it reads on the standard input. Most often, these arguments
+are lists of file names generated by @code{find}. @code{xargs} is run
+like this:
@example
xargs @r{[}@var{option}@dots{}@r{]} @r{[}@var{command} @r{[}@var{initial-arguments}@r{]}@r{]}
@@ -285,16 +255,15 @@ xargs grep typedef < file-list
@node find Expressions
@section @code{find} Expressions
-The expression that @code{find} uses to select files consists of one
-or more @dfn{primaries}, each of which is a separate command line
-argument to @code{find}. @code{find} evaluates the expression each
-time it processes a file. An expression can contain any of the
-following types of primaries:
+The expression that @code{find} uses to select files consists of one or
+more @dfn{primaries}, each of which is a separate command line argument
+to @code{find}. @code{find} evaluates the expression each time it
+processes a file. An expression can contain any of the following types
+of primaries:
@table @dfn
@item options
-affect overall operation rather than the processing of a specific
-file;
+affect overall operation rather than the processing of a specific file;
@item tests
return a true or false value, depending on the file's attributes;
@item actions
@@ -307,21 +276,17 @@ evaluated.
You can omit the operator between two primaries; it defaults to
@samp{-and}. @xref{Combining Primaries With Operators}, for ways to
connect primaries into more complex expressions. If the expression
-contains no actions other than @samp{-prune}, @samp{-print} is
-performed on all files for which the entire expression is true
-(@pxref{Print File Name}).
+contains no actions other than @samp{-prune}, @samp{-print} is performed
+on all files for which the entire expression is true (@pxref{Print File
+Name}).
Options take effect immediately, rather than being evaluated for each
file when their place in the expression is reached. Therefore, for
clarity, it is best to place them at the beginning of the expression.
-There are two exceptions to this; @samp{-daystart} and @samp{-follow}
-have different effects depending on where in the command line they
-appear. This can be confusing, so it's best to keep them at the
-beginning, too.
Many of the primaries take arguments, which immediately follow them in
-the next command line argument to @code{find}. Some arguments are
-file names, patterns, or other strings; others are numbers. Numeric
+the next command line argument to @code{find}. Some arguments are file
+names, patterns, or other strings; others are numbers. Numeric
arguments can be specified as
@table @code
@@ -333,13 +298,12 @@ for less than @var{n},
for exactly @var{n}.
@end table
-@node Finding Files
+@node Finding Files, Actions, Introduction, Top
@chapter Finding Files
By default, @code{find} prints to the standard output the names of the
-files that match the given criteria. @xref{Actions}, for how to get
-more information about the matching files.
-
+files that match the given criteria. @xref{Actions}, for how to get more
+information about the matching files.
@menu
* Name::
@@ -348,7 +312,7 @@ more information about the matching files.
* Size::
* Type::
* Owner::
-* Mode Bits::
+* Permissions::
* Contents::
* Directories::
* Filesystems::
@@ -358,15 +322,14 @@ more information about the matching files.
@node Name
@section Name
-Here are ways to search for files whose name matches a certain
-pattern. @xref{Shell Pattern Matching}, for a description of the
-@var{pattern} arguments to these tests.
+Here are ways to search for files whose name matches a certain pattern.
+@xref{Shell Pattern Matching}, for a description of the @var{pattern}
+arguments to these tests.
-Each of these tests has a case-sensitive version and a
-case-insensitive version, whose name begins with @samp{i}. In a
-case-insensitive comparison, the patterns @samp{fo*} and @samp{F??}
-match the file names @file{Foo}, @samp{FOO}, @samp{foo}, @samp{fOo},
-etc.
+Each of these tests has a case-sensitive version and a case-insensitive
+version, whose name begins with @samp{i}. In a case-insensitive
+comparison, the patterns @samp{fo*} and @samp{F??} match the file names
+@file{Foo}, @samp{FOO}, @samp{foo}, @samp{fOo}, etc.
@menu
* Base Name Patterns::
@@ -380,128 +343,38 @@ etc.
@deffn Test -name pattern
@deffnx Test -iname pattern
-True if the base of the file name (the path with the leading
-directories removed) matches shell pattern @var{pattern}. For
-@samp{-iname}, the match is case-insensitive.@footnote{Because we
-need to perform case-insensitive matching, the GNU fnmatch
-implementation is always used; if the C library includes the GNU
-implementation, we use that and otherwise we use the one from gnulib}
-To ignore a whole directory tree, use @samp{-prune}
-(@pxref{Directories}). As an example, to find Texinfo source files in
-@file{/usr/local/doc}:
+True if the base of the file name (the path with the leading directories
+removed) matches shell pattern @var{pattern}. For @samp{-iname}, the
+match is case-insensitive. To ignore a whole directory tree, use
+@samp{-prune} (@pxref{Directories}). As an example, to find Texinfo
+source files in @file{/usr/local/doc}:
@example
find /usr/local/doc -name '*.texi'
@end example
-
-Notice that the wildcard must be enclosed in quotes in order to
-protect it from expansion by the shell.
-
-As of findutils version 4.2.2, patterns for @samp{-name} and
-@samp{-iname} will match a file name with a leading @samp{.}. For
-example the command @samp{find /tmp -name \*bar} will match the file
-@file{/tmp/.foobar}. Braces within the pattern (@samp{@{@}}) are not
-considered to be special (that is, @code{find . -name 'foo@{1,2@}'}
-matches a file named @file{foo@{1,2@}}, not the files @file{foo1} and
-@file{foo2}.
@end deffn
-
@node Full Name Patterns
@subsection Full Name Patterns
@deffn Test -path pattern
-@deffnx Test -wholename pattern
+@deffnx Test -ipath pattern
True if the entire file name, starting with the command line argument
under which the file was found, matches shell pattern @var{pattern}.
-To ignore a whole directory tree, use @samp{-prune} rather than
-checking every file in the tree (@pxref{Directories}). The ``entire
-file name'' as used by @code{find} starts with the starting-point
-specified on the command line, and is not converted to an absolute
-pathname, so for example @code{cd /; find tmp -wholename /tmp} will
-never match anything. The name @samp{-wholename} is GNU-specific,
-but @samp{-path} is more portable; it is supported by HP-UX
-@code{find} and will soon be part of POSIX.
+For @samp{-ipath}, the match is case-insensitive. To ignore a whole
+directory tree, use @samp{-prune} rather than checking every file in the
+tree (@pxref{Directories}).
@end deffn
-@deffn Test -ipath pattern
-@deffnx Test -iwholename pattern
-These tests are like @samp{-wholename} and @samp{-path}, but the match
-is case-insensitive.
-@end deffn
-
-
-In the context of the tests @samp{-path}, @samp{-wholename},
-@samp{-ipath} and @samp{-wholename}, a ``full path'' is the name of
-all the directories traversed from @code{find}'s start point to the
-file being tested, followed by the base name of the file itself.
-These paths are often not absolute paths; for example
-
-@example
-$ cd /tmp
-$ mkdir -p foo/bar/baz
-$ find foo -path foo/bar -print
-foo/bar
-$ find foo -path /tmp/foo/bar -print
-$ find /tmp/foo -path /tmp/foo/bar -print
-/tmp/foo/bar
-@end example
-
-Notice that the second @code{find} command prints nothing, even though
-@file{/tmp/foo/bar} exists and was examined by @code{find}.
-
-Unlike file name expansion on the command line, a @samp{*} in the pattern
-will match both @samp{/} and leading dots in file names:
-
-@example
-$ find . -path '*f'
-./quux/bar/baz/f
-$ find . -path '*/*config'
-./quux/bar/baz/.config
-@end example
-
-
@deffn Test -regex expr
@deffnx Test -iregex expr
True if the entire file name matches regular expression @var{expr}.
-This is a match on the whole path, not a search. For example, to
-match a file named @file{./fubar3}, you can use the regular expression
-@samp{.*bar.} or @samp{.*b.*3}, but not @samp{f.*r3}. @xref{Regexps,
-, Syntax of Regular Expressions, emacs, The GNU Emacs Manual}, for a
+This is a match on the whole path, not a search. For example, to match
+a file named @file{./fubar3}, you can use the regular expression
+@samp{.*bar.} or @samp{.*b.*3}, but not @samp{b.*r3}. @xref{Regexps, ,
+Syntax of Regular Expressions, emacs, The GNU Emacs Manual}, for a
description of the syntax of regular expressions. For @samp{-iregex},
-the match is case-insensitive. There are several varieties of regular
-expressions; by default this test uses POSIX basic regular
-expressions, but this can be changed with the option
-@samp{-regextype}.
-@end deffn
-
-@deffn Option -regextype name
-This option controls the variety of regular expression syntax
-understood by the @samp{-regex} and @samp{-iregex} tests. This option
-is positional; that is, it only affects regular expressions which
-occur later in the command line. If this option is not given, GNU
-Emacs regular expressions are assumed. Currently-implemented types
-are
-
-
-@table @samp
-@item emacs
-Regular expressions compatible with GNU Emacs; this is also the
-default behaviour if this option is not used.
-@item posix-awk
-Regular expressions compatible with the POSIX awk command (not GNU awk)
-@item posix-basic
-POSIX Basic Regular Expressions.
-@item posix-egrep
-Regular expressions compatible with the POSIX egrep command
-@item posix-extended
-POSIX Extended Regular Expressions
-@end table
-
-@ref{Regular Expressions} for more information on the regular
-expression dialects understood by GNU findutils.
-
-
+the match is case-insensitive.
@end deffn
@node Fast Full Name Search
@@ -510,9 +383,9 @@ expression dialects understood by GNU findutils.
To search for files by name without having to actually scan the
directories on the disk (which can be slow), you can use the
@code{locate} program. For each shell pattern you give it,
-@code{locate} searches one or more databases of file names and
-displays the file names that contain the pattern. @xref{Shell Pattern
-Matching}, for details about shell patterns.
+@code{locate} searches one or more databases of file names and displays
+the file names that contain the pattern. @xref{Shell Pattern Matching},
+for details about shell patterns.
If a pattern is a plain string---it contains no
metacharacters---@code{locate} displays all file names in the database
@@ -523,11 +396,6 @@ should usually begin with a @samp{*}, and will most often end with one
as well. The exceptions are patterns that are intended to explicitly
match the beginning or end of a file name.
-If you only want @code{locate} to match against the last component of
-the file names (the ``base name'' of the files) you can use the
-@samp{--basename} option. The opposite behaviour is the default, but
-can be selected explicitly by using the option @samp{--wholename}.
-
The command
@example
locate @var{pattern}
@@ -550,9 +418,8 @@ choose the file name of the default database, the frequency with which
the databases are updated, and the directories for which they contain
entries.
-Here is how to select which file name databases @code{locate}
-searches. The default is system-dependent. At the time this document
-was generated, the default was @file{@value{LOCATE_DB}}.
+Here is how to select which file name databases @code{locate} searches.
+The default is system-dependent.
@table @code
@item --database=@var{path}
@@ -564,18 +431,6 @@ database file names. You can also use the environment variable
option overrides the environment variable if both are used.
@end table
-GNU @code{locate} can read file name databases generated by the
-@code{slocate} package. However, these generally contain a list of
-all the files on the system, and so when using this database,
-@code{locate} will produce output only for files which are accessible
-to you. @xref{Invoking locate}, for a description of the
-@samp{--existing} option which is used to do this.
-
-The @code{updatedb} program can also generate database in a format
-compatible with @code{slocate}. @xref{Invoking updatedb}, for a
-description of its @samp{--dbformat} and @samp{--output} options.
-
-
@node Shell Pattern Matching
@subsection Shell Pattern Matching
@@ -584,9 +439,9 @@ names, to shell patterns. A @dfn{shell pattern} is a string that may
contain the following special characters, which are known as
@dfn{wildcards} or @dfn{metacharacters}.
-You must quote patterns that contain metacharacters to prevent the
-shell from expanding them itself. Double and single quotes both work;
-so does escaping with a backslash.
+You must quote patterns that contain metacharacters to prevent the shell
+from expanding them itself. Double and single quotes both work; so does
+escaping with a backslash.
@table @code
@item *
@@ -597,13 +452,13 @@ Matches any one character.
@item [@var{string}]
Matches exactly one character that is a member of the string
-@var{string}. This is called a @dfn{character class}. As a
-shorthand, @var{string} may contain ranges, which consist of two
-characters with a dash between them. For example, the class
-@samp{[a-z0-9_]} matches a lowercase letter, a number, or an
-underscore. You can negate a class by placing a @samp{!} or @samp{^}
-immediately after the opening bracket. Thus, @samp{[^A-Z@@]} matches
-any character except an uppercase letter or an at sign.
+@var{string}. This is called a @dfn{character class}. As a shorthand,
+@var{string} may contain ranges, which consist of two characters with a
+dash between them. For example, the class @samp{[a-z0-9_]} matches a
+lowercase letter, a number, or an underscore. You can negate a class by
+placing a @samp{!} or @samp{^} immediately after the opening bracket.
+Thus, @samp{[^A-Z@@]} matches any character except an uppercase letter
+or an at sign.
@item \
Removes the special meaning of the character that follows it. This
@@ -611,21 +466,16 @@ works even in character classes.
@end table
In the @code{find} tests that do shell pattern matching (@samp{-name},
-@samp{-wholename}, etc.), wildcards in the pattern will match a
-@samp{.} at the beginning of a file name. This is also the case for
-@code{locate}. Thus, @samp{find -name '*macs'} will match a file
-named @file{.emacs}, as will @samp{locate '*macs'}.
+@samp{-path}, etc.), wildcards in the pattern do not match a @samp{.}
+at the beginning of a file name. This is not the case for
+@code{locate}. Thus, @samp{find -name '*macs'} does not match a file
+named @file{.emacs}, but @samp{locate '*macs'} does.
Slash characters have no special significance in the shell pattern
-matching that @code{find} and @code{locate} do, unlike in the shell,
-in which wildcards do not match them. Therefore, a pattern
-@samp{foo*bar} can match a file name @samp{foo3/bar}, and a pattern
-@samp{./sr*sc} can match a file name @samp{./src/misc}.
-
-If you want to locate some files with the @samp{locate} command but
-don't need to see the full list you can use the @samp{--limit} option
-to see just a small number of results, or the @samp{--count} option to
-display only the total number of matches.
+matching that @code{find} and @code{locate} do, unlike in the shell, in
+which wildcards do not match them. Therefore, a pattern @samp{foo*bar}
+can match a file name @samp{foo3/bar}, and a pattern @samp{./sr*sc} can
+match a file name @samp{./src/misc}.
@node Links
@section Links
@@ -633,8 +483,8 @@ display only the total number of matches.
There are two ways that files can be linked together. @dfn{Symbolic
links} are a special type of file whose contents are a portion of the
name of another file. @dfn{Hard links} are multiple directory entries
-for one file; the file names all have the same index node
-(@dfn{inode}) number on the disk.
+for one file; the file names all have the same index node (@dfn{inode})
+number on the disk.
@menu
* Symbolic Links::
@@ -644,176 +494,68 @@ for one file; the file names all have the same index node
@node Symbolic Links
@subsection Symbolic Links
-Symbolic links are names that reference other files. GNU @code{find}
-will handle symbolic links in one of two ways; firstly, it can
-dereference the links for you - this means that if it comes across a
-symbolic link, it examines the file that the link points to, in order
-to see if it matches the criteria you have specified. Secondly, it
-can check the link itself in case you might be looking for the actual
-link. If the file that the symbolic link points to is also within the
-directory hierarchy you are searching with the @code{find} command,
-you may not see a great deal of difference between these two
-alternatives.
-
-By default, @code{find} examines symbolic links themselves when it
-finds them (and, if it later comes across the linked-to file, it will
-examine that, too). If you would prefer @code{find} to dereference
-the links and examine the file that each link points to, specify the
-@samp{-L} option to @code{find}. You can explicitly specify the
-default behaviour by using the @samp{-P} option. The @samp{-H}
-option is a half-way-between option which ensures that any symbolic
-links listed on the command line are dereferenced, but other symbolic
-links are not.
-
-Symbolic links are different to ``hard links'' in the sense that you
-need permission to search the directories
-in the linked-to file name to
-dereference the link. This can mean that even if you specify the
-@samp{-L} option, @code{find} may not be able to determine the
-properties of the file that the link points to (because you don't have
-sufficient permission). In this situation, @code{find} uses the
-properties of the link itself. This also occurs if a symbolic link
-exists but points to a file that is missing.
-
-The options controlling the behaviour of @code{find} with respect to
-links are as follows :-
-
-@table @samp
-@item -P
-@code{find} does not dereference symbolic links at all. This is the
-default behaviour. This option must be specified before any of the
-file names on the command line.
-@item -H
-@code{find} does not dereference symbolic links (except in the case of
-file names on the command line, which are dereferenced). If a
-symbolic link cannot be dereferenced, the information for the symbolic
-link itself is used. This option must be specified before any of the
-file names on the command line.
-@item -L
-@code{find} dereferences symbolic links where possible, and where this
-is not possible it uses the properties of the symbolic link itself.
-This option must be specified before any of the file names on the
-command line. Use of this option also implies the same behaviour as
-the @samp{-noleaf} option. If you later use the @samp{-H} or
-@samp{-P} options, this does not turn off @samp{-noleaf}.
-
-@item -follow
-This option forms part of the ``expression'' and must be specified
-after the file names, but it is otherwise equivalent to @samp{-L}.
-The @samp{-follow} option affects only those tests which appear after
-it on the command line. This option is deprecated. Where possible,
-you should use @samp{-L} instead.
-@end table
+@deffn Test -lname pattern
+@deffnx Test -ilname pattern
+True if the file is a symbolic link whose contents match shell pattern
+@var{pattern}. For @samp{-ilname}, the match is case-insensitive.
+@xref{Shell Pattern Matching}, for details about the @var{pattern}
+argument. So, to list any symbolic links to @file{sysdep.c} in the
+current directory and its subdirectories, you can do:
-The following differences in behavior occur when the @samp{-L} option
-is used:
+@example
+find . -lname '*sysdep.c'
+@end example
+@end deffn
+
+@deffn Option -follow
+Dereference symbolic links. The following differences in behavior occur
+when this option is given:
@itemize @bullet
@item
@code{find} follows symbolic links to directories when searching
directory trees.
@item
-@samp{-lname} and @samp{-ilname} always return false (unless they
-happen to match broken symbolic links).
+@samp{-lname} and @samp{-ilname} always return false.
@item
@samp{-type} reports the types of the files that symbolic links point
-to. This means that in combination with @samp{-L}, @samp{-type l}
-will be true only for broken symbolic links. To check for symbolic
-links when @samp{-L} has been specified, use @samp{-xtype l}.
+to.
@item
Implies @samp{-noleaf} (@pxref{Directories}).
@end itemize
-
-If the @samp{-L} option or the @samp{-H} option is used,
-the file names used as arguments to @samp{-newer}, @samp{-anewer}, and
-@samp{-cnewer} are dereferenced and the timestamp from the pointed-to
-file is used instead (if possible -- otherwise the timestamp from the
-symbolic link is used).
-
-@deffn Test -lname pattern
-@deffnx Test -ilname pattern
-True if the file is a symbolic link whose contents match shell pattern
-@var{pattern}. For @samp{-ilname}, the match is case-insensitive.
-@xref{Shell Pattern Matching}, for details about the @var{pattern}
-argument. If the @samp{-L} option is in effect, this test will always
-return false for symbolic links unless they are broken. So, to list
-any symbolic links to @file{sysdep.c} in the current directory and its
-subdirectories, you can do:
-
-@example
-find . -lname '*sysdep.c'
-@end example
@end deffn
@node Hard Links
@subsection Hard Links
-Hard links allow more than one name to refer to the same file. To
-find all the names which refer to the same file as NAME, use
-@samp{-samefile NAME}. If you are not using the @samp{-L} option, you
-can confine your search to one filesystem using the @samp{-xdev}
-option. This is useful because hard links cannot point outside a
-single filesystem, so this can cut down on needless searching.
-
-If the @samp{-L} option is in effect, and NAME is in fact a symbolic
-link, the symbolic link will be dereferenced. Hence you are searching
-for other links (hard or symbolic) to the file pointed to by NAME. If
-@samp{-L} is in effect but NAME is not itself a symbolic link, other
-symbolic links to the file NAME will be matched.
-
-You can also search for files by inode number. This can occasionally
-be useful in diagnosing problems with filesystems for example, because
-@code{fsck} tends to print inode numbers. Inode numbers also
-occasionally turn up in log messages for some types of software, and
-are used to support the @code{ftok()} library function.
-
-You can learn a file's inode number and the number of links to it by
-running @samp{ls -li} or @samp{find -ls}.
-
-You can search for hard links to inode number NUM by using @samp{-inum
-NUM}. If there are any filesystem mount points below the directory
-where you are starting the search, use the @samp{-xdev} option unless
-you are also using the @samp{-L} option. Using @samp{-xdev} this
-saves needless searching, since hard links to a file must be on the
-same filesystem. @xref{Filesystems}.
-
-@deffn Test -samefile NAME
-File is a hard link to the same inode as NAME. If the @samp{-L}
-option is in effect, symbolic links to the same file as NAME points to
-are also matched.
-@end deffn
+To find hard links, first get the inode number of the file whose links
+you want to find. You can learn a file's inode number and the number of
+links to it by running @samp{ls -i} or @samp{find -ls}. If the file has
+more than one link, you can search for the other links by passing that
+inode number to @samp{-inum}. Add the @samp{-xdev} option if you are
+starting the search at a directory that has other filesystems mounted on
+it, such as @file{/usr} on many systems. Doing this saves needless
+searching, since hard links to a file must be on the same filesystem.
+@xref{Filesystems}.
@deffn Test -inum n
-File has inode number @var{n}. The @samp{+} and @samp{-} qualifiers
-also work, though these are rarely useful. Much of the time it is
-easier to use @samp{-samefile} rather than this option.
+File has inode number @var{n}.
@end deffn
-You can also search for files that have a certain number of links,
-with @samp{-links}. Directories normally have at least two hard
-links; their @file{.} entry is the second one. If they have
-subdirectories, each of those also has a hard link called @file{..} to
-its parent directory. The @file{.} and @file{..} directory entries
-are not normally searched unless they are mentioned on the @code{find}
-command line.
+You can also search for files that have a certain number of links, with
+@samp{-links}. Directories normally have at least two hard links; their
+@file{.} entry is the second one. If they have subdirectories, each of
+those also has a hard link called @file{..} to its parent directory.
@deffn Test -links n
File has @var{n} hard links.
@end deffn
-@deffn Test -links +n
-File has more than @var{n} hard links.
-@end deffn
-
-@deffn Test -links -n
-File has fewer than @var{n} hard links.
-@end deffn
-
@node Time
@section Time
-Each file has three time stamps, which record the last time that
-certain operations were performed on the file:
+Each file has three time stamps, which record the last time that certain
+operations were performed on the file:
@enumerate
@item
@@ -824,14 +566,6 @@ change the status (modify the file or its attributes)
modify (change the file's contents)
@end enumerate
-Some systems also provide a timestamp that indicates when a file was
-@emph{created}. For example, the UFS2 fileystem under NetBSD-3.1
-records the @emph{birth time} of each file. This information is also
-available under other versions of BSD and some versions of Cygwin.
-However, even on systems which support file birth time, files may
-exist for which this information was not recorded (for example, UFS1
-file systems simply do not contain this information).
-
You can search for files whose time stamps are within a certain age
range, or compare them to other time stamps.
@@ -850,22 +584,16 @@ These tests are mainly useful with ranges (@samp{+@var{n}} and
@deffnx Test -ctime n
@deffnx Test -mtime n
True if the file was last accessed (or its status changed, or it was
-modified) @var{n}*24 hours ago. The number of 24-hour periods since
-the file's timestamp is always rounded down; therefore 0 means ``less
-than 24 hours ago'', 1 means ``between 24 and 48 hours ago'', and so
-forth. Fractional values are supported but this only really makes
-sense for the case where ranges (@samp{+@var{n}} and @samp{-@var{n}})
-are used.
+modified) @var{n}*24 hours ago.
@end deffn
@deffn Test -amin n
@deffnx Test -cmin n
@deffnx Test -mmin n
True if the file was last accessed (or its status changed, or it was
-modified) @var{n} minutes ago. These tests provide finer granularity
-of measurement than @samp{-atime} et al., but rounding is done in a
-similar way (again, fractions are supported). For example, to list
-files in @file{/u/bill} that were last read from 2 to 6 minutes ago:
+modified) @var{n} minutes ago. These tests provide finer granularity of
+measurement than @samp{-atime} et al. For example, to list files in
+@file{/u/bill} that were last read from 2 to 6 hours ago:
@example
find /u/bill -amin +2 -amin -6
@@ -873,75 +601,24 @@ find /u/bill -amin +2 -amin -6
@end deffn
@deffn Option -daystart
-Measure times from the beginning of today rather than from 24 hours
-ago. So, to list the regular files in your home directory that were
-modified yesterday, do
+Measure times from the beginning of today rather than from 24 hours ago.
+So, to list the regular files in your home directory that were modified
+yesterday, do
@example
-find ~/ -daystart -type f -mtime 1
+find ~ -daystart -type f -mtime 1
@end example
-
-The @samp{-daystart} option is unlike most other options in that it
-has an effect on the way that other tests are performed. The affected
-tests are @samp{-amin}, @samp{-cmin}, @samp{-mmin}, @samp{-atime},
-@samp{-ctime} and @samp{-mtime}. The @samp{-daystart} option only
-affects the behaviour of any tests which appear after it on the
-command line.
@end deffn
@node Comparing Timestamps
@subsection Comparing Timestamps
-@deffn Test -newerXY reference
-Succeeds if timestamp @samp{X} of the file being considered is newer
-than timestamp @samp{Y} of the file @file{reference}. The latters
-@samp{X} and @samp{Y} can be any of the following letters:
-
-@table @samp
-@item a
-Last-access time of @file{reference}
-@item B
-Birth time of @file{reference} (when this is not known, the test cannot succeed)
-@item c
-Last-change time of @file{reference}
-@item m
-Last-modification time of @file{reference}
-@item t
-The @file{reference} argument is interpreted as a literal time, rather
-than the name of a file. @xref{Date input formats}, for a description
-of how the timestamp is understood. Tests of the form @samp{-newerXt}
-are valid but tests of the form @samp{-newertY} are not.
-@end table
-
-For example the test @code{-newerac /tmp/foo} succeeds for all files
-which have been accessed more recently than @file{/tmp/foo} was
-changed. Here @samp{X} is @samp{a} and @samp{Y} is @samp{c}.
-
-Not all files have a known birth time. If @samp{Y} is @samp{b} and
-the birth time of @file{reference} is not available, @code{find} exits
-with an explanatory error message. If @samp{X} is @samp{b} and we do
-not know the birth time the file currently being considered, the test
-simply fails (that is, it behaves like @code{-false} does).
-
-Some operating systems (for example, most implementations of Unix) do
-not support file birth times. Some others, for example NetBSD-3.1,
-do. Even on operating systems which support file birth times, the
-information may not be available for specific files. For example,
-under NetBSD, file birth times are supported on UFS2 file systems, but
-not UFS1 file systems.
-
-@end deffn
-
-
-
-There are two ways to list files in @file{/usr} modified after
-February 1 of the current year. One uses @samp{-newermt}:
-
-@example
-find /usr -newermt "Feb 1"
-@end example
-
-The other way of doing this works on the versions of find before 4.3.3:
+As an alternative to comparing timestamps to the current time, you can
+compare them to another file's timestamp. That file's timestamp could
+be updated by another program when some event occurs. Or you could set
+it to a particular fixed date using the @code{touch} command. For
+example, to list files in @file{/usr} modified after February 1 of the
+current year:
@c Idea from Rick Sladkey.
@example
@@ -974,51 +651,30 @@ could perhaps be archived or removed to save disk space.
@node Size
@section Size
-@deffn Test -size n@r{[}bckwMG@r{]}
+@deffn Test -size n@r{[}bckw@r{]}
True if the file uses @var{n} units of space, rounding up. The units
are 512-byte blocks by default, but they can be changed by adding a
one-character suffix to @var{n}:
@table @code
@item b
-512-byte blocks (never 1024)
+512-byte blocks
@item c
bytes
@item k
kilobytes (1024 bytes)
@item w
2-byte words
-@item M
-Megabytes (units of 1048576 bytes)
-@item G
-Gigabytes (units of 1073741824 bytes)
@end table
-The `b' suffix always considers blocks to be 512 bytes. This is not
-affected by the setting (or non-setting) of the POSIXLY_CORRECT
-environment variable. This behaviour is different to the behaviour of
-the @samp{-ls} action). If you want to use 1024-byte units, use the
-`k' suffix instead.
-
-The number can be prefixed with a `+' or a `-'. A plus sign indicates
-that the test should succeed if the file uses at least @var{n} units
-of storage (a common use of this test) and a minus sign
-indicates that the test should succeed if the file uses less than
-@var{n} units of storage. There is no `=' prefix, because that's the
-default anyway.
-
The size does not count indirect blocks, but it does count blocks in
-sparse files that are not actually allocated. In other words, it's
-consistent with the result you get for @samp{ls -l} or @samp{wc -c}.
-This handling of sparse files differs from the output of the @samp{%k}
-and @samp{%b} format specifiers for the @samp{-printf} predicate.
-
+sparse files that are not actually allocated.
@end deffn
@deffn Test -empty
True if the file is empty and is either a regular file or a directory.
-This might help determine good candidates for deletion. This test is
-useful with @samp{-depth} (@pxref{Directories}) and @samp{-delete}
+This might make it a good candidate for deletion. This test is useful
+with @samp{-depth} (@pxref{Directories}) and @samp{-exec rm -rf '@{@}' ';'}
(@pxref{Single File}).
@end deffn
@@ -1040,45 +696,19 @@ named pipe (FIFO)
@item f
regular file
@item l
-symbolic link; if @samp{-L} is in effect, this is true only for broken
-symbolic links. If you want to search for symbolic links when
-@samp{-L} is in effect, use @samp{-xtype} instead of @samp{-type}.
+symbolic link
@item s
socket
-@item D
-door (Solaris)
@end table
@end deffn
@deffn Test -xtype c
-This test behaves the same as @samp{-type} unless the file is a
-symbolic link. If the file is a symbolic link, the result is as
-follows (in the table below, @samp{X} should be understood to
-represent any letter except @samp{l}):
-
-@table @samp
-@item @samp{-P -xtype l}
-True if the symbolic link is broken
-@item @samp{-P -xtype X}
-True if the (ultimate) target file is of type @samp{X}.
-@item @samp{-L -xtype l}
-Always true
-@item @samp{-L -xtype X}
-False unless the symbolic link is broken
-@end table
-
-In other words, for symbolic links, @samp{-xtype} checks the type of
-the file that @samp{-type} does not check.
-
-The @samp{-H} option also affects the behaviour of @samp{-xtype}.
-When @samp{-H} is in effect, @samp{-xtype} behaves as if @samp{-L} had
-been specified when examining files listed on the command line, and as
-if @samp{-P} had been specified otherwise. If neither @samp{-H} nor
-@samp{-L} was specified, @samp{-xtype} behaves as if @samp{-P} had
-been specified.
-
-@xref{Symbolic Links}, for more information on @samp{-follow} and
-@samp{-L}.
+The same as @samp{-type} unless the file is a symbolic link. For
+symbolic links: if @samp{-follow} has not been given, true if the file
+is a link to a file of type @var{c}; if @samp{-follow} has been given,
+true if @var{c} is @samp{l}. In other words, for symbolic links,
+@samp{-xtype} checks the type of the file that @samp{-type} does not
+check. @xref{Symbolic Links}, for more information on @samp{-follow}.
@end deffn
@node Owner
@@ -1086,8 +716,8 @@ been specified.
@deffn Test -user uname
@deffnx Test -group gname
-True if the file is owned by user @var{uname} (belongs to group
-@var{gname}). A numeric ID is allowed.
+True if the file is owned by user @var{uname} (belongs to group @var{gname}).
+A numeric ID is allowed.
@end deffn
@deffn Test -uid n
@@ -1100,154 +730,36 @@ support ranges (@samp{+@var{n}} and @samp{-@var{n}}), unlike
@deffn Test -nouser
@deffnx Test -nogroup
True if no user corresponds to the file's numeric user ID (no group
-corresponds to the numeric group ID). These cases usually mean that
-the files belonged to users who have since been removed from the
-system. You probably should change the ownership of such files to an
-existing user or group, using the @code{chown} or @code{chgrp}
-program.
+corresponds to the numeric group ID). These cases usually mean that the
+files belonged to users who have since been removed from the system.
+You probably should change the ownership of such files to an existing
+user or group, using the @code{chown} or @code{chgrp} program.
@end deffn
-@node Mode Bits
-@section File Mode Bits
+@node Permissions
+@section Permissions
-@xref{File Permissions}, for information on how file mode bits are
+@xref{File Permissions}, for information on how file permissions are
structured and how to specify them.
-Four tests determine what users can do with files. These are
-@samp{-readable}, @samp{-writable}, @samp{-executable} and
-@samp{-perm}. The first three tests ask the operating system if the
-current user can perform the relevant operation on a file, while
-@samp{-perm} just examines the file's mode. The file mode may give
-a misleading impression of what the user can actually do, because the
-file may have an access control list, or exist on a read-only
-filesystem, for example. Of these four tests though, only
-@samp{-perm} is specified by the POSIX standard.
-
-The @samp{-readable}, @samp{-writable} and @samp{-executable} tests
-are implemented via the @code{access} system call. This is
-implemented within the operating system itself. If the file being
-considered is on an NFS filesystem, the remote system may allow or
-forbid read or write operations for reasons of which the NFS client
-cannot take account. This includes user-ID mapping, either in the
-general sense or the more restricted sense in which remote superusers
-are treated by the NFS server as if they are the local user
-@samp{nobody} on the NFS server.
-
-None of the tests in this section should be used to verify that a user
-is authorised to perform any operation (on the file being tested or
-any other file) because of the possibility of a race condition. That
-is, the situation may change between the test and an action being
-taken on the basis of the result of that test.
-
-
-@deffn Test -readable
-True if the file can be read by the invoking user.
-@end deffn
-
-@deffn Test -writable
-True if the file can be written by the invoking user. This is an
-in-principle check, and other things may prevent a successful write
-operation; for example, the filesystem might be full.
-@end deffn
-
-@deffn Test -executable
-True if the file can be executed/searched by the invoking user.
-@end deffn
-
-@deffn Test -perm pmode
-
-True if the file's mode bits match @var{pmode}, which can be
-either a symbolic or numeric @var{mode} (@pxref{File Permissions})
-optionally prefixed by @samp{-} or @samp{/}.
-
-A @var{pmode} that starts with neither @samp{-} nor @samp{/} matches
-if @var{mode} exactly matches the file mode bits.
-
-A @var{pmode} that starts with @samp{+} but which is not valid (for
-example @samp{+a+x}) is an error if the POSIXLY_CORRECT environment
-variable it set. Otherwise this is treated as if the initial
-@samp{+} were a @samp{/}, for backward compatibility.
-
-A @var{pmode} that starts with @samp{-} matches if
-@emph{all} the file mode bits set in @var{mode} are set for the file;
-bits not set in @var{mode} are ignored.
-
-A @var{pmode} that starts with @samp{/} matches if
-@emph{any} of the file mode bits set in @var{mode} are set for the file;
-bits not set in @var{mode} are ignored.
-This is a GNU extension.
-
-If you don't use the @samp{/} or @samp{-} form with a symbolic mode
-string, you may have to specify a rather complex mode string. For
-example @samp{-perm g=w} will only match files that have mode 0020
-(that is, ones for which group write permission is the only file mode bit
-set). It is more likely that you will want to use the @samp{/} or
-@samp{-} forms, for example @samp{-perm -g=w}, which matches any file
-with group write permission.
-
-
-@table @samp
-@item -perm 664
-Match files that have read and write permission for their owner,
-and group, but that the rest of the world can read but not write to.
-Do not match files that meet these criteria but have other file mode
-bits set (for example if someone can execute/search the file).
-
-@item -perm -664
-Match files that have read and write permission for their owner,
-and group, but that the rest of the world can read but not write to,
-without regard to the presence of any extra file mode bits (for
-example the executable bit). This matches a file with mode
-0777, for example.
-
-@item -perm /222
-Match files that are writable by somebody (their owner, or
-their group, or anybody else).
-
-@item -perm /022
-Match files that are writable by either their owner or their
-group. The files don't have to be writable by both the owner and
-group to be matched; either will do.
-
-@item -perm /g+w,o+w
-As above.
-
-@item -perm /g=w,o=w
-As above.
-
-@item -perm -022
-Match files that are writable by both their owner and their
-group.
-
-@item -perm -444 -perm /222 ! -perm /111
-Match files that are readable for everybody, have at least one
-write bit set (i.e., somebody can write to them), but that cannot be
-executed/searched by anybody. Note that in some shells the @samp{!} must be
-escaped;.
-
-@item -perm -a+r -perm /a+w ! -perm /a+x
-As above.
-
-
-@item -perm -g+w,o+w
-As above.
-@end table
-
-@quotation Warning
-If you specify @samp{-perm /000} or @samp{-perm /mode} where the
-symbolic mode @samp{mode} has no bits set, the test matches all files.
-Versions of GNU @code{find} prior to 4.3.3 matched no files in this
-situation.
-@end quotation
-
+@deffn Test -perm mode
+True if the
+file's permissions are exactly @var{mode} (which can be numeric or symbolic).
+Symbolic modes use mode 0 as a point of departure.
+If @var{mode} starts with @samp{-}, true if
+@emph{all} of the permissions set in @var{mode} are set for the file;
+permissions not set in @var{mode} are ignored.
+If @var{mode} starts with @samp{+}, true if
+@emph{any} of the permissions set in @var{mode} are set for the file;
+permissions not set in @var{mode} are ignored.
@end deffn
@node Contents
@section Contents
-To search for files based on their contents, you can use the
-@code{grep} program. For example, to find out which C source files in
-the current directory contain the string @samp{thing}, you can do:
+To search for files based on their contents, you can use the @code{grep}
+program. For example, to find out which C source files in the current
+directory contain the string @samp{thing}, you can do:
@example
grep -l thing *.[ch]
@@ -1261,12 +773,12 @@ this:
find . -name '*.[ch]' | xargs grep -l thing
@end example
-The @samp{-l} option causes @code{grep} to print only the names of
-files that contain the string, rather than the lines that contain it.
-The string argument (@samp{thing}) is actually a regular expression,
-so it can contain metacharacters. This method can be refined a little
-by using the @samp{-r} option to make @code{xargs} not run @code{grep}
-if @code{find} produces no output, and using the @code{find} action
+The @samp{-l} option causes @code{grep} to print only the names of files
+that contain the string, rather than the lines that contain it. The
+string argument (@samp{thing}) is actually a regular expression, so it
+can contain metacharacters. This method can be refined a little by
+using the @samp{-r} option to make @code{xargs} not run @code{grep} if
+@code{find} produces no output, and using the @code{find} action
@samp{-print0} and the @code{xargs} option @samp{-0} to avoid
misinterpreting files whose names contain spaces:
@@ -1274,8 +786,8 @@ misinterpreting files whose names contain spaces:
find . -name '*.[ch]' -print0 | xargs -r -0 grep -l thing
@end example
-For a fuller treatment of finding files whose contents match a
-pattern, see the manual page for @code{grep}.
+For a fuller treatment of finding files whose contents match a pattern,
+see the manual page for @code{grep}.
@node Directories
@section Directories
@@ -1286,8 +798,8 @@ slice of a directory tree.
@deffn Option -maxdepth levels
Descend at most @var{levels} (a non-negative integer) levels of
-directories below the command line arguments. @samp{-maxdepth 0}
-means only apply the tests and actions to the command line arguments.
+directories below the command line arguments. @samp{-maxdepth 0} means
+only apply the tests and actions to the command line arguments.
@end deffn
@deffn Option -mindepth levels
@@ -1301,66 +813,21 @@ Process each directory's contents before the directory itself. Doing
this is a good idea when producing lists of files to archive with
@code{cpio} or @code{tar}. If a directory does not have write
permission for its owner, its contents can still be restored from the
-archive since the directory's permissions are restored after its
-contents.
-@end deffn
-
-@deffn Option -d
-This is a deprecated synonym for @samp{-depth}, for compatibility with
-Mac OS X, FreeBSD and OpenBSD. The @samp{-depth} option is a POSIX
-feature, so it is better to use that.
+archive since the directory's permissions are restored after its contents.
@end deffn
@deffn Action -prune
-If the file is a directory, do not descend into it. The result is
-true. For example, to skip the directory @file{src/emacs} and all
-files and directories under it, and print the names of the other files
-found:
-
-@example
-find . -wholename './src/emacs' -prune -o -print
-@end example
+If @samp{-depth} is not given, true; do not descend the current
+directory. If @samp{-depth} is given, false; no effect. @samp{-prune}
+only affects tests and actions that come after it in the expression, not
+those that come before.
-The above command will not print @file{./src/emacs} among its list of
-results. This however is not due to the effect of the @samp{-prune}
-action (which only prevents further descent, it doesn't make sure we
-ignore that item). Instead, this effect is due to the use of
-@samp{-o}. Since the left hand side of the ``or'' condition has
-succeeded for @file{./src/emacs}, it is not necessary to evaluate the
-right-hand-side (@samp{-print}) at all for this particular file. If
-you wanted to print that directory name you could use either an extra
-@samp{-print} action:
+For example, to skip the directory @file{src/emacs} and all files and
+directories under it, and print the names of the other files found:
@example
-find . -wholename './src/emacs' -prune -print -o -print
+find . -path './src/emacs' -prune -o -print
@end example
-
-or use the comma operator:
-
-@example
-find . -wholename './src/emacs' -prune , -print
-@end example
-
-If the @samp{-depth} option is in effect, the subdirectories will have
-already been visited in any case. Hence @samp{-prune} has no effect
-in this case.
-
-Because @samp{-delete} implies @samp{-depth}, using @samp{-prune} in
-combination with @samp{-delete} may well result in the deletion of
-more files than you intended.
-@end deffn
-
-
-@deffn Action -quit
-Exit immediately (with return value zero if no errors have occurred).
-This is different to @samp{-prune} because @samp{-prune} only applies
-to the contents of pruned directories, whilt @samp{-quit} simply makes
-@code{find} stop immediately. No child processes will be left
-running, but no more files specified on the command line will be
-processed. For example, @code{find /tmp/foo /tmp/bar -print -quit}
-will print only @samp{/tmp/foo}. Any command lines which have been
-built by @samp{-exec ... \+} or @samp{-execdir ... \+} are invoked
-before the program is exited.
@end deffn
@deffn Option -noleaf
@@ -1368,55 +835,30 @@ Do not optimize by assuming that directories contain 2 fewer
subdirectories than their hard link count. This option is needed when
searching filesystems that do not follow the Unix directory-link
convention, such as CD-ROM or MS-DOS filesystems or AFS volume mount
-points. Each directory on a normal Unix filesystem has at least 2
-hard links: its name and its @file{.} entry. Additionally, its
+points. Each directory on a normal Unix filesystem has at least 2 hard
+links: its name and its @file{.} entry. Additionally, its
subdirectories (if any) each have a @file{..} entry linked to that
directory. When @code{find} is examining a directory, after it has
-statted 2 fewer subdirectories than the directory's link count, it
-knows that the rest of the entries in the directory are
-non-directories (@dfn{leaf} files in the directory tree). If only the
-files' names need to be examined, there is no need to stat them; this
-gives a significant increase in search speed.
+statted 2 fewer subdirectories than the directory's link count, it knows
+that the rest of the entries in the directory are non-directories
+(@dfn{leaf} files in the directory tree). If only the files' names need
+to be examined, there is no need to stat them; this gives a significant
+increase in search speed.
@end deffn
-@deffn Option -ignore_readdir_race
-If a file disappears after its name has been read from a directory but
-before @code{find} gets around to examining the file with @code{stat},
-don't issue an error message. If you don't specify this option, an
-error message will be issued. This option can be useful in system
-scripts (cron scripts, for example) that examine areas of the
-filesystem that change frequently (mail queues, temporary directories,
-and so forth), because this scenario is common for those sorts of
-directories. Completely silencing error messages from @code{find} is
-undesirable, so this option neatly solves the problem. There is no
-way to search one part of the filesystem with this option on and part
-of it with this option off, though. When this option is turned on and
-find discovers that one of the start-point files specified on the
-command line does not exist, no error message will be issued.
-
-@end deffn
-
-@deffn Option -noignore_readdir_race
-This option reverses the effect of the @samp{-ignore_readdir_race}
-option.
-@end deffn
-
-
@node Filesystems
@section Filesystems
A @dfn{filesystem} is a section of a disk, either on the local host or
mounted from a remote host over a network. Searching network
-filesystems can be slow, so it is common to make @code{find} avoid
-them.
+filesystems can be slow, so it is common to make @code{find} avoid them.
There are two ways to avoid searching certain filesystems. One way is
to tell @code{find} to only search one filesystem:
@deffn Option -xdev
@deffnx Option -mount
-Don't descend directories on other filesystems. These options are
-synonyms.
+Don't descend directories on other filesystems. These options are synonyms.
@end deffn
The other way is to check the type of filesystem each file is on, and
@@ -1428,13 +870,12 @@ filesystem types vary among different versions of Unix; an incomplete
list of filesystem types that are accepted on some version of Unix or
another is:
@example
-ext2 ext3 proc sysfs ufs 4.2 4.3 nfs tmp mfs S51K S52K
+ufs 4.2 4.3 nfs tmp mfs S51K S52K
@end example
-You can use @samp{-printf} with the @samp{%F} directive to see the
-types of your filesystems. The @samp{%D} directive shows the device
-number. @xref{Print File Information}. @samp{-fstype} is usually
-used with @samp{-prune} to avoid searching remote filesystems
-(@pxref{Directories}).
+You can use @samp{-printf} with the @samp{%F} directive to see the types
+of your filesystems. @xref{Print File Information}. @samp{-fstype} is
+usually used with @samp{-prune} to avoid searching remote filesystems
+(@pxref{Directories}).
@end deffn
@node Combining Primaries With Operators
@@ -1445,46 +886,33 @@ The operators are, in order of decreasing precedence:
@table @code
@item @asis{( @var{expr} )}
-@findex ()
Force precedence. True if @var{expr} is true.
@item @asis{! @var{expr}}
@itemx @asis{-not @var{expr}}
-@findex !
-@findex -not
-True if @var{expr} is false. In some shells, it is necessary to
-protect the @samp{!} from shell interpretation by quoting it.
+True if @var{expr} is false.
@item @asis{@var{expr1 expr2}}
@itemx @asis{@var{expr1} -a @var{expr2}}
@itemx @asis{@var{expr1} -and @var{expr2}}
-@findex -a
-@findex -and
And; @var{expr2} is not evaluated if @var{expr1} is false.
@item @asis{@var{expr1} -o @var{expr2}}
@itemx @asis{@var{expr1} -or @var{expr2}}
-@findex -o
-@findex -or
Or; @var{expr2} is not evaluated if @var{expr1} is true.
@item @asis{@var{expr1} , @var{expr2}}
-@findex ,
List; both @var{expr1} and @var{expr2} are always evaluated. True if
@var{expr2} is true. The value of @var{expr1} is discarded. This
operator lets you do multiple independent operations on one traversal,
-without depending on whether other operations succeeded. The two
-operations @var{expr1} and @var{expr2} are not always fully
-independent, since @var{expr1} might have side effects like touching
-or deleting files, or it might use @samp{-prune} which would also
-affect @var{expr2}.
+without depending on whether other operations succeeded.
@end table
@code{find} searches the directory tree rooted at each file name by
-evaluating the expression from left to right, according to the rules
-of precedence, until the outcome is known (the left hand side is false
-for @samp{-and}, true for @samp{-or}), at which point @code{find}
-moves on to the next file name.
+evaluating the expression from left to right, according to the rules of
+precedence, until the outcome is known (the left hand side is false for
+@samp{-and}, true for @samp{-or}), at which point @code{find} moves on
+to the next file name.
There are two other tests that can be useful in complex expressions:
@@ -1496,21 +924,19 @@ Always true.
Always false.
@end deffn
-@node Actions
+@node Actions, Common Tasks, Finding Files, Top
@chapter Actions
There are several ways you can print information about the files that
match the criteria you gave in the @code{find} expression. You can
print the information either to the standard output or to a file that
you name. You can also execute commands that have the file names as
-arguments. You can use those commands as further filters to select
-files.
+arguments. You can use those commands as further filters to select files.
@menu
* Print File Name::
* Print File Information::
* Run Commands::
-* Delete Files::
* Adding Tests::
@end menu
@@ -1518,67 +944,18 @@ files.
@section Print File Name
@deffn Action -print
-True; print the entire file name on the standard output, followed by a
-newline. If there is the faintest possibility that one of the files
-for which you are searching might contain a newline, you should use
-@samp{-print0} instead.
+True; print the full file name on the standard output, followed by a
+newline.
@end deffn
@deffn Action -fprint file
-True; print the entire file name into file @var{file}, followed by a
+True; print the full file name into file @var{file}, followed by a
newline. If @var{file} does not exist when @code{find} is run, it is
-created; if it does exist, it is truncated to 0 bytes. The named
-output file is always created, even if no output is sent to it. The
-file names @file{/dev/stdout} and @file{/dev/stderr} are handled
-specially; they refer to the standard output and standard error
-output, respectively.
-
-If there is the faintest possibility that one of the files for which
-you are searching might contain a newline, you should use
-@samp{-fprint0} instead.
+created; if it does exist, it is truncated to 0 bytes. The file names
+@file{/dev/stdout} and @file{/dev/stderr} are handled specially; they
+refer to the standard output and standard error output, respectively.
@end deffn
-
-@c @deffn Option -show-control-chars how
-@c This option affects how some of @code{find}'s actions treat
-@c unprintable characters in file names. If @samp{how} is
-@c @samp{literal}, any subsequent actions (i.e., actions further on in the
-@c command line) print file names as-is.
-@c
-@c If this option is not specified, it currently defaults to @samp{safe}.
-@c If @samp{how} is @samp{safe}, C-like backslash escapes are used to
-@c indicate the non-printable characters for @samp{-ls} and @samp{-fls}.
-@c On the other hand, @samp{-print}, @samp{-fprint}, @samp{-fprintf} and
-@c @code{-printf} all quote unprintable characters if the data is going
-@c to a tty, and otherwise the data is emitted literally.
-@c
-@c @table @code
-@c @item -ls
-@c Escaped if @samp{how} is @samp{safe}
-@c @item -fls
-@c Escaped if @samp{how} is @samp{safe}
-@c @item -print
-@c Always quoted if stdout is a tty,
-@c @samp{-show-control-chars} is ignored
-@c @item -print0
-@c Always literal, never escaped
-@c @item -fprint
-@c Always quoted if the destination is a tty;
-@c @samp{-show-control-chars} is ignored
-@c @item -fprint0
-@c Always literal, never escaped
-@c @item -fprintf
-@c If the destination is a tty, the @samp{%f},
-@c @samp{%F}, @samp{%h}, @samp{%l}, @samp{%p},
-@c and @samp{%P} directives produce quoted
-@c strings if stdout is a tty and are treated
-@c literally otherwise.
-@c @item -printf
-@c As for @code{-fprintf}.
-@c @end table
-@c @end deffn
-
-
@node Print File Information
@section Print File Information
@@ -1594,23 +971,23 @@ The fields are:
@enumerate
@item
-The inode number of the file. @xref{Hard Links}, for how to find
-files based on their inode number.
+The inode number of the file. @xref{Hard Links}, for how to find files
+based on their inode number.
@item
the number of blocks in the file. The block counts are of 1K blocks,
-unless the environment variable @code{POSIXLY_CORRECT} is set, in
-which case 512-byte blocks are used. @xref{Size}, for how to find
-files based on their size.
+unless the environment variable @code{POSIXLY_CORRECT} is set, in which
+case 512-byte blocks are used. @xref{Size}, for how to find files based
+on their size.
@item
-The file's type and file mode bits. The type is shown as a dash for a
+The file's type and permissions. The type is shown as a dash for a
regular file; for other file types, a letter like for @samp{-type} is
-used (@pxref{Type}). The file mode bits are read, write, and execute/search for
-the file's owner, its group, and other users, respectively; a dash
-means the permission is not granted. @xref{File Permissions}, for
-more details about file permissions. @xref{Mode Bits}, for how to
-find files based on their file mode bits.
+used (@pxref{Type}). The permissions are read, write, and execute for
+the file's owner, its group, and other users, respectively; a dash means
+the permission is not granted. @xref{File Permissions}, for more details
+about file permissions. @xref{Permissions}, for how to find files based
+on their permissions.
@item
The number of hard links to the file.
@@ -1628,37 +1005,26 @@ The file's size in bytes.
The date the file was last modified.
@item
-The file's name. @samp{-ls} quotes non-printable characters in the
-file names using C-like backslash escapes. This may change soon, as
-the treatment of unprintable characters is harmonised for @samp{-ls},
-@samp{-fls}, @samp{-print}, @samp{-fprint}, @samp{-printf} and
-@samp{-fprintf}.
+The file's name. @samp{-ls} quotes non-printable characters in the file
+names using C-like backslash escapes.
@end enumerate
@end deffn
@deffn Action -fls file
True; like @samp{-ls} but write to @var{file} like @samp{-fprint}
-(@pxref{Print File Name}). The named output file is always created,
-even if no output is sent to it.
+(@pxref{Print File Name}).
@end deffn
@deffn Action -printf format
True; print @var{format} on the standard output, interpreting @samp{\}
escapes and @samp{%} directives. Field widths and precisions can be
-specified as with the @code{printf} C function. Format flags (like
-@samp{#} for example) may not work as you expect because many of the
-fields, even numeric ones, are printed with %s. Numeric flags which
-are affected in this way include G, U, b, D, k and n. This difference
-in behaviour means though that the format flag @samp{-} will work; it
-forces left-alignment of the field. Unlike @samp{-print},
-@samp{-printf} does not add a newline at the end of the string. If
-you want a newline at the end of the string, add a @samp{\n}.
+specified as with the @code{printf} C function. Unlike @samp{-print},
+@samp{-printf} does not add a newline at the end of the string.
@end deffn
@deffn Action -fprintf file format
True; like @samp{-printf} but write to @var{file} like @samp{-fprint}
-(@pxref{Print File Name}). The output file is always created, even if
-no output is ever sent to it.
+(@pxref{Print File Name}).
@end deffn
@menu
@@ -1670,7 +1036,7 @@ no output is ever sent to it.
@node Escapes
@subsection Escapes
-The escapes that @samp{-printf} and @samp{-fprintf} recognise are:
+The escapes that @samp{-printf} and @samp{-fprintf} recognize are:
@table @code
@item \a
@@ -1691,10 +1057,6 @@ Horizontal tab.
Vertical tab.
@item \\
A literal backslash (@samp{\}).
-@item \0
-ASCII NUL.
-@item \NNN
-The character whose ASCII code is NNN (octal).
@end table
A @samp{\} character followed by any other character is treated as an
@@ -1705,27 +1067,13 @@ printed to the standard error output (because it was probably a typo).
@subsection Format Directives
@samp{-printf} and @samp{-fprintf} support the following format
-directives to print information about the file being processed. The C
-@code{printf} function, field width and precision specifiers are
-supported, as applied to string (%s) types. That is, you can specify
-"minimum field width"."maximum field width" for each directive.
-Format flags (like @samp{#} for example) may not work as you expect
-because many of the fields, even numeric ones, are printed with %s.
-The format flag @samp{-} does work; it forces left-alignment of the
-field.
+directives to print information about the file being processed. Unlike
+the C @code{printf} function, they do not support field width specifiers.
@samp{%%} is a literal percent sign. A @samp{%} character followed by
-an unrecognised character (i.e., not a known directive or @code{printf}
-field width and precision specifier), is discarded (but the
-unrecognised character is printed), and a warning message is printed
-to the standard error output (because it was probably a typo). Don't
-rely on this behaviour, because other directives may be added in the
-future.
-
-A @samp{%} at the end of the format argument causes undefined
-behaviour since there is no following character. In some locales, it
-may hide your door keys, while in others it may remove the final page
-from the novel you are reading.
+any other character is discarded (but the other character is printed),
+and a warning message is printed to the standard error output (because
+it was probably a typo).
@menu
* Name Directives::
@@ -1733,7 +1081,6 @@ from the novel you are reading.
* Size Directives::
* Location Directives::
* Time Directives::
-* Formatting Flags::
@end menu
@node Name Directives
@@ -1741,29 +1088,17 @@ from the novel you are reading.
@table @code
@item %p
-@c supports %-X.Yp
-File's name (not the absolute path name, but the name of the file as
-it was encountered by @code{find} - that is, as a relative path from
-one of the starting points).
+File's name.
@item %f
-File's name with any leading directories removed (only the last
-element).
-@c supports %-X.Yf
+File's name with any leading directories removed (only the last element).
@item %h
Leading directories of file's name (all but the last element and the
-slash before it). If the file's name contains no slashes (for example
-because it was named on the command line and is in the current working
-directory), then ``%h'' expands to ``.''. This prevents ``%h/%f''
-expanding to ``/foo'', which would be surprising and probably not
-desirable.
-@c supports %-X.Yh
+slash before it).
@item %P
File's name with the name of the command line argument under which
it was found removed from the beginning.
-@c supports %-X.YP
@item %H
Command line argument under which file was found.
-@c supports %-X.YH
@end table
@node Ownership Directives
@@ -1771,33 +1106,15 @@ Command line argument under which file was found.
@table @code
@item %g
-@c supports %-X.Yg
File's group name, or numeric group ID if the group has no name.
@item %G
-@c supports %-X.Yg
-@c TODO: Needs to support # flag and 0 flag
File's numeric group ID.
@item %u
-@c supports %-X.Yu
File's user name, or numeric user ID if the user has no name.
@item %U
-@c supports %-X.Yu
-@c TODO: Needs to support # flag
File's numeric user ID.
@item %m
-@c full support, including # and 0.
-File's mode bits (in octal). If you always want to have a leading
-zero on the number, use the '#' format flag, for example '%#m'.
-
-The file mode bit numbers used are the traditional Unix
-numbers, which will be as expected on most systems, but if your
-system's file mode bit layout differs from the traditional Unix
-semantics, you will see a difference between the mode as printed by
-@samp{%m} and the mode as it appears in @code{struct stat}.
-
-@item %M
-File's type and mode bits (in symbolic form, as for @code{ls}). This
-directive is supported in findutils 4.2.5 and later.
+File's permissions (in octal).
@end table
@node Size Directives
@@ -1805,27 +1122,11 @@ directive is supported in findutils 4.2.5 and later.
@table @code
@item %k
-The amount of disk space used for this file in 1K blocks. Since disk
-space is allocated in multiples of the filesystem block size this is
-usually greater than %s/1024, but it can also be smaller if the file
-is a sparse file (that is, it has ``holes'').
+File's size in 1K blocks (rounded up).
@item %b
-The amount of disk space used for this file in 512-byte blocks. Since
-disk space is allocated in multiples of the filesystem block size this
-is usually greater than %s/512, but it can also be smaller if the
-file is a sparse file (that is, it has ``holes'').
+File's size in 512-byte blocks (rounded up).
@item %s
File's size in bytes.
-@item %S
-File's sparseness. This is calculated as @code{(BLOCKSIZE*st_blocks /
-st_size)}. The exact value you will get for an ordinary file of a
-certain length is system-dependent. However, normally sparse files
-will have values less than 1.0, and files which use indirect blocks
-and have few holes may have a value which is greater than 1.0. The
-value used for BLOCKSIZE is system-dependent, but is usually 512
-bytes. If the file size is zero, the value printed is undefined. On
-systems which lack support for st_blocks, a file's sparseness is
-assumed to be 1.0.
@end table
@node Location Directives
@@ -1833,13 +1134,8 @@ assumed to be 1.0.
@table @code
@item %d
-File's depth in the directory tree (depth below a file named on the
-command line, not depth below the root directory). Files named on the
-command line have a depth of 0. Subdirectories immediately below them
-have a depth of 1, and so on.
-@item %D
-The device number on which the file exists (the @code{st_dev} field of
-@code{struct stat}), in decimal.
+File's depth in the directory tree; files named on the command line
+have a depth of 0.
@item %F
Type of the filesystem the file is on; this value can be used for
@samp{-fstype} (@pxref{Directories}).
@@ -1849,14 +1145,6 @@ Object of symbolic link (empty string if file is not a symbolic link).
File's inode number (in decimal).
@item %n
Number of hard links to file.
-@item %y
-Type of the file as used with @samp{-type}. If the file is a symbolic
-link, @samp{l} will be printed.
-@item %Y
-Type of the file as used with @samp{-type}. If the file is a symbolic
-link, it is dereferenced. If the file is a broken symbolic link,
-@samp{N} is printed.
-
@end table
@node Time Directives
@@ -1871,23 +1159,22 @@ Wed Nov 2 00:42:36 1994
@table @code
@item %a
-File's last access time in the format returned by the C @code{ctime}
-function.
+File's last access time in the format returned by the C @code{ctime} function.
@item %A@var{k}
File's last access time in the format specified by @var{k}
-(@pxref{Time Formats}).
+(@pxref{Time Formats}).
@item %c
-File's last status change time in the format returned by the C
-@code{ctime} function.
+File's last status change time in the format returned by the C @code{ctime}
+function.
@item %C@var{k}
File's last status change time in the format specified by @var{k}
(@pxref{Time Formats}).
@item %t
-File's last modification time in the format returned by the C
-@code{ctime} function.
+File's last modification time in the format returned by the C @code{ctime}
+function.
@item %T@var{k}
-File's last modification time in the format specified by @var{k}
-(@pxref{Time Formats}).
+File's last modification time in the format specified by @var{k}
+(@pxref{Time Formats}).
@end table
@node Time Formats
@@ -1925,20 +1212,11 @@ time zone (e.g., EDT), or nothing if no time zone is determinable
@item M
minute (00..59)
@item S
-second (00..61). There is a fractional part.
+second (00..61)
@item @@
-seconds since Jan. 1, 1970, 00:00 GMT, with fractional part.
+seconds since Jan. 1, 1970, 00:00 GMT.
@end table
-The fractional part of the seconds field is of indeterminate length
-and precision. That is, the length of the fractional part of the
-seconds field will in general vary between findutils releases and
-between systems. This means that it is unwise to assume that field
-has any specific length. The length of this field is not usually a
-guide to the precision of timestamps in the underlying file system.
-
-
-
@node Date Components
@subsubsection Date Components
@@ -1976,7 +1254,7 @@ last two digits of year (00..99)
@subsubsection Combined Time Formats
The following format directives print combinations of time and date
-components.
+components.
@table @code
@item r
@@ -1986,41 +1264,13 @@ time, 24-hour (hh:mm:ss)
@item X
locale's time representation (H:M:S)
@item c
-locale's date and time in ctime format (Sat Nov 04 12:02:33 EST
-1989). This format does not include any fractional part in the
-seconds field.
+locale's date and time (Sat Nov 04 12:02:33 EST 1989)
@item D
date (mm/dd/yy)
@item x
locale's date representation (mm/dd/yy)
-@item +
-Date and time, separated by '+', for example
-`2004-04-28+22:22:05.0000000000'.
-The time is given in the current timezone (which may be affected by
-setting the TZ environment variable). This is a GNU extension. The
-seconds field includes a fractional part.
@end table
-@node Formatting Flags
-@subsubsection Formatting Flags
-
-The @samp{%m} and @samp{%d} directives support the @samp{#}, @samp{0}
-and @samp{+} flags, but the other directives do not, even if they
-print numbers. Numeric directives that do not support these flags
-include
-
-@samp{G},
-@samp{U},
-@samp{b},
-@samp{D},
-@samp{k} and
-@samp{n}.
-
-All fields support the format flag @samp{-}, which makes fields
-left-aligned. That is, if the field width is greater than the actual
-contents of the field, the requisite number of spaces are printed
-after the field content instead of before it.
-
@node Run Commands
@section Run Commands
@@ -2039,176 +1289,73 @@ perform arbitrary actions on the files.
Here is how to run a command on one file at a time.
-@deffn Action -execdir command ;
-Execute @var{command}; true if zero status is returned. @code{find}
-takes all arguments after @samp{-exec} to be part of the command until
-an argument consisting of @samp{;} is reached. It replaces the string
+@deffn Action -exec command ;
+Execute @var{command}; true if 0 status is returned. @code{find} takes
+all arguments after @samp{-exec} to be part of the command until an
+argument consisting of @samp{;} is reached. It replaces the string
@samp{@{@}} by the current file name being processed everywhere it
occurs in the command. Both of these constructions need to be escaped
-(with a @samp{\}) or quoted to protect them from expansion by the
-shell. The command is executed in the directory in which @code{find}
-was run.
+(with a @samp{\}) or quoted to protect them from expansion by the shell.
+The command is executed in the directory in which @code{find} was run.
-For example, to compare each C header file in or below the current
-directory with the file @file{/tmp/master}:
+For example, to compare each C header file in the current directory with
+the file @file{/tmp/master}:
@example
-find . -name '*.h' -execdir diff -u '@{@}' /tmp/master ';'
+find . -name '*.h' -exec diff -u '@{@}' /tmp/master ';'
@end example
@end deffn
-If you use @samp{-execdir}, you must ensure that the @samp{$PATH}
-variable contains only absolute directory names. Having an empty
-element in @samp{$PATH} or explicitly including @samp{.} (or any other
-non-absolute name) is insecure. GNU find will refuse to run if you
-use @samp{-execdir} and it thinks your @samp{$PATH} setting is
-insecure. For example:
-
-@table @samp
-@item /bin:/usr/bin:
-Insecure; empty path element (at the end)
-@item :/bin:/usr/bin:/usr/local/bin
-Insecure; empty path element (at the start)
-@item /bin:/usr/bin::/usr/local/bin
-Insecure; empty path element (two colons in a row)
-@item /bin:/usr/bin:.:/usr/local/bin
-Insecure; @samp{.} is a path element (@file{.} is not an absolute file name)
-@item /bin:/usr/bin:sbin:/usr/local/bin
-Insecure; @samp{sbin} is not an absolute file name
-@item /bin:/usr/bin:/sbin:/usr/local/bin
-Secure (if you control the contents of those directories and any access to them)
-@end table
-
-Another similar option, @samp{-exec} is supported, but is less secure.
-@xref{Security Considerations}, for a discussion of the security
-problems surrounding @samp{-exec}.
-
-
-@deffn Action -exec command ;
-This insecure variant of the @samp{-execdir} action is specified by
-POSIX. The main difference is that the command is executed in the
-directory from which @code{find} was invoked, meaning that @samp{@{@}}
-is expanded to a relative path starting with the name of one of the
-starting directories, rather than just the basename of the matched
-file.
-
-While some implementations of @code{find} replace the @samp{@{@}} only
-where it appears on its own in an argument, GNU @code{find} replaces
-@samp{@{@}} wherever it appears.
-@end deffn
-
-
@node Multiple Files
@subsection Multiple Files
-Sometimes you need to process files one at a time. But usually this
-is not necessary, and, it is faster to run a command on as many files
-as possible at a time, rather than once per file. Doing this saves on
-the time it takes to start up the command each time.
-
-The @samp{-execdir} and @samp{-exec} actions have variants that build
-command lines containing as many matched files as possible.
-
-@deffn Action -execdir command @{@} +
-This works as for @samp{-execdir command ;}, except that the
-@samp{@{@}} at the end of the command is expanded to a list of names
-of matching files. This expansion is done in such a way as to avoid
-exceeding the maximum command line length available on the system.
-Only one @samp{@{@}} is allowed within the command, and it must appear
-at the end, immediately before the @samp{+}. A @samp{+} appearing in
-any position other than immediately after @samp{@{@}} is not
-considered to be special (that is, it does not terminate the command).
-@end deffn
-
-
-@deffn Action -exec command @{@} +
-This insecure variant of the @samp{-execdir} action is specified by
-POSIX. The main difference is that the command is executed in the
-directory from which @code{find} was invoked, meaning that @samp{@{@}}
-is expanded to a relative path starting with the name of one of the
-starting directories, rather than just the basename of the matched
-file.
-@end deffn
-
-Before @code{find} exits, any partially-built command lines are
-executed. This happens even if the exit was caused by the
-@samp{-quit} action. However, some types of error (for example not
-being able to invoke @code{stat()} on the current directory) can cause
-an immediate fatal exit. In this situation, any partially-built
-command lines will not be invoked (this prevents possible infinite
-loops).
-
-At first sight, it looks like the list of filenames to be processed
-can only be at the end of the command line, and that this might be a
-problem for some comamnds (@code{cp} and @code{rsync} for example).
-
-However, there is a slightly obscure but powerful workarouund for this
-problem which takes advantage of the behaviour of @code{sh -c}:-
-
-@example
-find startpoint -tests @dots{} -exec sh -c 'scp "$@@" remote:/dest' sh @{@} +
-@end example
-
-In the example above, the filenames we want to work on need to occur
-on the @code{scp} command line before the name of the destination. We
-use the shell to invoke the command @code{scp "$@@" remote:/dest} and
-the shell expands @code{"$@@"} to the list of filenames we want to
-process.
+Sometimes you need to process files alone. But when you
+don't, it is faster to run a command on as many files as possible at a
+time, rather than once per file. Doing this saves on the time it takes
+to start up the command each time.
-Another, but less secure, way to run a command on more than one file
-at once, is to use the @code{xargs} command, which is invoked like
-this:
+To run a command on more than one file at once, use the @code{xargs}
+command, which is invoked like this:
@example
xargs @r{[}@var{option}@dots{}@r{]} @r{[}@var{command} @r{[}@var{initial-arguments}@r{]}@r{]}
@end example
-@code{xargs} normally reads arguments from the standard input. These
-arguments are delimited by blanks (which can be protected with double
-or single quotes or a backslash) or newlines. It executes the
-@var{command} (default is @file{/bin/echo}) one or more times with any
-@var{initial-arguments} followed by arguments read from standard
-input. Blank lines on the standard input are ignored. If the
-@samp{-L} option is in use, trailing blanks indicate that @code{xargs}
-should consider the following line to be part of this one.
+@code{xargs} reads arguments from the standard input, delimited by
+blanks (which can be protected with double or single quotes or a
+backslash) or newlines. It executes the @var{command} (default is
+@file{/bin/echo}) one or more times with any @var{initial-arguments}
+followed by arguments read from standard input. Blank lines on the
+standard input are ignored.
-Instead of blank-delimited names, it is safer to use @samp{find
--print0} or @samp{find -fprint0} and process the output by giving the
-@samp{-0} or @samp{--null} option to GNU @code{xargs}, GNU @code{tar},
-GNU @code{cpio}, or @code{perl}. The @code{locate} command also has a
-@samp{-0} or @samp{--null} option which does the same thing.
+Instead of blank-delimited names, it is safer to use @samp{find -print0}
+or @samp{find -fprint0} and process the output by giving the @samp{-0}
+or @samp{--null} option to GNU @code{xargs}, GNU @code{tar}, GNU
+@code{cpio}, or @code{perl}.
-You can use shell command substitution (backquotes) to process a list
-of arguments, like this:
+You can use shell command substitution (backquotes) to process a list of
+arguments, like this:
@example
grep -l sprintf `find $HOME -name '*.c' -print`
@end example
However, that method produces an error if the length of the @samp{.c}
-file names exceeds the operating system's command line length limit.
-@code{xargs} avoids that problem by running the command as many times
-as necessary without exceeding the limit:
+file names exceeds the operating system's command-line length limit.
+@code{xargs} avoids that problem by running the command as many times as
+necessary without exceeding the limit:
@example
-find $HOME -name '*.c' -print | xargs grep -l sprintf
+find $HOME -name '*.c' -print | grep -l sprintf
@end example
However, if the command needs to have its standard input be a terminal
(@code{less}, for example), you have to use the shell command
-substitution method or use the @samp{--arg-file} option of
-@code{xargs}.
-
-The @code{xargs} command will process all its input, building command
-lines and executing them, unless one of the commands exits with a
-status of 255 (this will cause xargs to issue an error message and
-stop) or it reads a line contains the end of file string specified
-with the @samp{--eof} option.
+substitution method.
@menu
* Unsafe File Name Handling::
* Safe File Name Handling::
-* Unusual Characters in File Names::
* Limiting Command Size::
* Interspersing File Names::
@end menu
@@ -2217,31 +1364,25 @@ with the @samp{--eof} option.
@subsubsection Unsafe File Name Handling
Because file names can contain quotes, backslashes, blank characters,
-and even newlines, it is not safe to process them using @code{xargs}
-in its default mode of operation. But since most files' names do not
-contain blanks, this problem occurs only infrequently. If you are
-only searching through files that you know have safe names, then you
-need not be concerned about it.
-
-Error messages issued by @code{find} and @code{locate} quote unusual
-characters in file names in order to prevent unwanted changes in the
-terminal's state.
-
+and even newlines, it is not safe to process them using @code{xargs} in its
+default mode of operation. But since most files' names do not contain
+blanks, this problem occurs only infrequently. If you are only
+searching through files that you know have safe names, then you need not
+be concerned about it.
@c This example is adapted from:
@c From: pfalstad@stone.Princeton.EDU (Paul John Falstad)
@c Newsgroups: comp.unix.shell
@c Subject: Re: Beware xargs security holes
@c Date: 16 Oct 90 19:12:06 GMT
-@c
-In many applications, if @code{xargs} botches processing a file
-because its name contains special characters, some data might be lost.
-The importance of this problem depends on the importance of the data
-and whether anyone notices the loss soon enough to correct it.
-However, here is an extreme example of the problems that using
-blank-delimited names can cause. If the following command is run
-daily from @code{cron}, then any user can remove any file on the
-system:
+@c
+In many applications, if @code{xargs} botches processing a file because
+its name contains special characters, some data might be lost. The
+importance of this problem depends on the importance of the data and
+whether anyone notices the loss soon enough to correct it. However,
+here is an extreme example of the problems that using blank-delimited
+names can cause. If the following command is run daily from
+@code{cron}, then any user can remove any file on the system:
@example
find / -name '#*' -atime +7 -print | xargs rm
@@ -2258,8 +1399,8 @@ vmunix'
and then @code{cron} would delete @file{/vmunix}, if it ran
@code{xargs} with @file{/} as its current directory.
-To delete other files, for example @file{/u/joeuser/.plan}, you could
-do this:
+To delete other files, for example @file{/u/joeuser/.plan}, you could do
+this:
@example
eg$ mkdir '#
@@ -2279,174 +1420,63 @@ eg$ find . -name '#*' -print | xargs echo
@subsubsection Safe File Name Handling
Here is how to make @code{find} output file names so that they can be
-used by other programs without being mangled or misinterpreted. You
-can process file names generated this way by giving the @samp{-0} or
+used by other programs without being mangled or misinterpreted. You can
+process file names generated this way by giving the @samp{-0} or
@samp{--null} option to GNU @code{xargs}, GNU @code{tar}, GNU
@code{cpio}, or @code{perl}.
@deffn Action -print0
-True; print the entire file name on the standard output, followed by a
+True; print the full file name on the standard output, followed by a
null character.
@end deffn
@deffn Action -fprint0 file
True; like @samp{-print0} but write to @var{file} like @samp{-fprint}
-(@pxref{Print File Name}). The output file is always created.
+(@pxref{Print File Name}).
@end deffn
-As of findutils version 4.2.4, the @code{locate} program also has a
-@samp{--null} option which does the same thing. For similarity with
-@code{xargs}, the short form of the option @samp{-0} can also be used.
-
-If you want to be able to handle file names safely but need to run
-commands which want to be connected to a terminal on their input, you
-can use the @samp{--arg-file} option to @code{xargs} like this:
-
-@example
-find / -name xyzzy -print0 > list
-xargs --null --arg-file=list munge
-@end example
-
-The example above runs the @code{munge} program on all the files named
-@file{xyzzy} that we can find, but @code{munge}'s input will still be
-the terminal (or whatever the shell was using as standard input). If
-your shell has the ``process substitution'' feature @samp{<(...)}, you
-can do this in just one step:
-
-@example
-xargs --null --arg-file=<(find / -name xyzzy -print0) munge
-@end example
-
-@node Unusual Characters in File Names
-@subsubsection Unusual Characters in File Names
-As discussed above, you often need to be careful about how the names
-of files are handled by @code{find} and other programs. If the output
-of @code{find} is not going to another program but instead is being
-shown on a terminal, this can still be a problem. For example, some
-character sequences can reprogram the function keys on some terminals.
-@xref{Security Considerations}, for a discussion of other security
-problems relating to @code{find}.
-
-Unusual characters are handled differently by various
-actions, as described below.
-
-@table @samp
-@item -print0
-@itemx -fprint0
-Always print the exact file name, unchanged, even if the output is
-going to a terminal.
-@item -ok
-@itemx -okdir
-Always print the exact file name, unchanged. This will probably
-change in a future release.
-@item -ls
-@itemx -fls
-Unusual characters are always escaped. White space, backslash, and
-double quote characters are printed using C-style escaping (for
-example @samp{\f}, @samp{\"}). Other unusual characters are printed
-using an octal escape. Other printable characters (for @samp{-ls} and
-@samp{-fls} these are the characters between octal 041 and 0176) are
-printed as-is.
-@item -printf
-@itemx -fprintf
-If the output is not going to a terminal, it is printed as-is.
-Otherwise, the result depends on which directive is in use:
-
-@table @asis
-@item %D, %F, %H, %Y, %y
-These expand to values which are not under control of files' owners,
-and so are printed as-is.
-@item %a, %b, %c, %d, %g, %G, %i, %k, %m, %M, %n, %s, %t, %u, %U
-These have values which are under the control of files' owners but
-which cannot be used to send arbitrary data to the terminal, and so
-these are printed as-is.
-@item %f, %h, %l, %p, %P
-The output of these directives is quoted if the output is going to a
-terminal.
-
-This quoting is performed in the same way as for GNU @code{ls}. This
-is not the same quoting mechanism as the one used for @samp{-ls} and
-@samp{fls}. If you are able to decide what format to use for the
-output of @code{find} then it is normally better to use @samp{\0} as a
-terminator than to use newline, as file names can contain white space
-and newline characters.
-@end table
-@item -print
-@itemx -fprint
-Quoting is handled in the same way as for the @samp{%p} directive of
-@samp{-printf} and @samp{-fprintf}. If you are using @code{find} in a
-script or in a situation where the matched files might have arbitrary
-names, you should consider using @samp{-print0} instead of
-@samp{-print}.
-@end table
-
-
-The @code{locate} program quotes and escapes unusual characters in
-file names in the same way as @code{find}'s @samp{-print} action.
-
-The behaviours described above may change soon, as the treatment of
-unprintable characters is harmonised for @samp{-ls}, @samp{-fls},
-@samp{-print}, @samp{-fprint}, @samp{-printf} and @samp{-fprintf}.
-
@node Limiting Command Size
@subsubsection Limiting Command Size
-@code{xargs} gives you control over how many arguments it passes to
-the command each time it executes it. By default, it uses up to
-@code{ARG_MAX} - 2k, or 128k, whichever is smaller, characters per
-command. It uses as many lines and arguments as fit within that
-limit. The following options modify those values.
+@code{xargs} gives you control over how many arguments it passes to the
+command each time it executes it. By default, it uses up to
+@code{ARG_MAX} - 2k, or 20k, whichever is smaller, characters per
+command. It uses as many lines and arguments as fit within that limit.
+The following options modify those values.
@table @code
@item --no-run-if-empty
@itemx -r
If the standard input does not contain any nonblanks, do not run the
-command. By default, the command is run once even if there is no
-input. This option is a GNU extension.
+command. By default, the command is run once even if there is no input.
@item --max-lines@r{[}=@var{max-lines}@r{]}
-@itemx -L @var{max-lines}
@itemx -l@r{[}@var{max-lines}@r{]}
Use at most @var{max-lines} nonblank input lines per command line;
-@var{max-lines} defaults to 1 if omitted; omitting the argument is not
-allowed in the case of the @samp{-L} option. Trailing blanks cause an
+@var{max-lines} defaults to 1 if omitted. Trailing blanks cause an
input line to be logically continued on the next input line, for the
-purpose of counting the lines. Implies @samp{-x}. The preferred name
-for this option is @samp{-L} as this is specified by POSIX.
+purpose of counting the lines. Implies @samp{-x}.
@item --max-args=@var{max-args}
@itemx -n @var{max-args}
Use at most @var{max-args} arguments per command line. Fewer than
@var{max-args} arguments will be used if the size (see the @samp{-s}
-option) is exceeded, unless the @samp{-x} option is given, in which
-case @code{xargs} will exit.
+option) is exceeded, unless the @samp{-x} option is given, in which case
+@code{xargs} will exit.
@item --max-chars=@var{max-chars}
@itemx -s @var{max-chars}
Use at most @var{max-chars} characters per command line, including the
-command initial arguments and the terminating nulls at the ends of the
-argument strings. If you specify a value for this option which is too
-large or small, a warning message is printed and the appropriate upper
-or lower limit is used instead. You can use @samp{--show-limits}
-option to understand the command-line limits applying to @code{xargs}
-and how this is affected by any other options. The POSIX limits shown
-when you do this have already been adjusted to take into account the
-size of your environment variables.
-
-The largest allowed value is system-dependent, and is calculated as
-the argument length limit for exec, less the size of your environment,
-less 2048 bytes of headroom. If this value is more than 128KiB,
-128Kib is used as the default value; otherwise, the default value is
-the maximum.
-
+command and initial arguments and the terminating nulls at the ends of
+the argument strings.
@item --max-procs=@var{max-procs}
@itemx -P @var{max-procs}
Run up to @var{max-procs} processes at a time; the default is 1. If
@var{max-procs} is 0, @code{xargs} will run as many processes as
-possible at a time. Use the @samp{-n}, @samp{-s}, or @samp{-L} option
-with @samp{-P}; otherwise chances are that the command will be run
-only once.
+possible at a time. Use the @samp{-n}, @samp{-s}, or @samp{-l} option
+with @samp{-P}; otherwise chances are that the command will be run only
+once.
@end table
@node Interspersing File Names
@@ -2459,88 +1489,42 @@ operation is equivalent to @samp{find -exec} (@pxref{Single File}).
@table @code
@item --replace@r{[}=@var{replace-str}@r{]}
-@itemx -I @var{replace-str}
-@itemx -i @var{replace-str}
-Replace occurrences of @var{replace-str} in the initial arguments with
-names read from the input. Also, unquoted blanks do not terminate
-arguments; instead, the input is split at newlines only. For the
-@samp{-i} option, if @var{replace-str} is omitted for @samp{--replace}
-or @samp{-i}, it defaults to @samp{@{@}} (like for @samp{find -exec}).
-Implies @samp{-x} and @samp{-l 1}. @samp{-i} is deprecated in favour
-of @samp{-I}. As an example, to sort each file in the @file{bills}
-directory, leaving the output in that file name with @file{.sorted}
-appended, you could do:
+@itemx -i@r{[}@var{replace-str}@r{]}
+Replace occurences of @var{replace-str} in the initial arguments with
+names read from standard input. Also, unquoted blanks do not terminate
+arguments. If @var{replace-str} is omitted, it defaults to @samp{@{@}}
+(like for @samp{find -exec}). Implies @samp{-x} and @samp{-l 1}. As an
+example, to sort each file the @file{bills} directory, leaving the
+output in that file name with @file{.sorted} appended, you could do:
@example
-find bills -type f | xargs -I XX sort -o XX.sorted XX
+find bills -type f | xargs -iXX sort -o XX.sorted XX
@end example
@noindent
-The equivalent command using @samp{find -execdir} is:
+The equivalent command using @samp{find -exec} is:
@example
-find bills -type f -execdir sort -o '@{@}.sorted' '@{@}' ';'
+find bills -type f -exec sort -o '@{@}.sorted' '@{@}' ';'
@end example
@end table
-
-When you use the @samp{-I} option, each line read from the input is
-buffered internally. This means that there is an upper limit on the
-length of input line that xargs will accept when used with the
-@samp{-I} option. To work around this limitation, you can use the
-@samp{-s} option to increase the amount of buffer space that xargs
-uses, and you can also use an extra invocation of xargs to ensure that
-very long lines do not occur. For example:
-
-@example
-somecommand | xargs -s 50000 echo | xargs -I '@{@}' -s 100000 rm '@{@}'
-@end example
-
-Here, the first invocation of @code{xargs} has no input line length
-limit because it doesn't use the @samp{-I} option. The second
-invocation of @code{xargs} does have such a limit, but we have ensured
-that the it never encounters a line which is longer than it can
-handle.
-
-This is not an ideal solution. Instead, the @samp{-I} option should
-not impose a line length limit (apart from any limit imposed by the
-operating system) and so one might consider this limitation to be a
-bug. A better solution would be to allow @code{xargs -I} to
-automatically move to a larger value for the @samp{-s} option when
-this is needed.
-
-This sort of problem doesn't occur with the output of @code{find}
-because it emits just one filename per line.
-
@node Querying
@subsection Querying
To ask the user whether to execute a command on a single file, you can
-use the @code{find} primary @samp{-okdir} instead of @samp{-execdir},
-and the @code{find} primary @samp{-ok} instead of @samp{-exec}:
-
-@deffn Action -okdir command ;
-Like @samp{-execdir} (@pxref{Single File}), but ask the user first (on
-the standard input); if the response does not start with @samp{y} or
-@samp{Y}, do not run the command, and return false. If the command is
-run, its standard input is redirected from @file{/dev/null}.
-@end deffn
+use the @code{find} primary @samp{-ok} instead of @samp{-exec}:
@deffn Action -ok command ;
-This insecure variant of the @samp{-okdir} action is specified by
-POSIX. The main difference is that the command is executed in the
-directory from which @code{find} was invoked, meaning that @samp{@{@}}
-is expanded to a relative path starting with the name of one of the
-starting directories, rather than just the basename of the matched
-file. If the command is run, its standard input is redirected from
-@file{/dev/null}.
+Like @samp{-exec} (@pxref{Single File}), but ask the user first (on
+the standard input); if the response does not start with @samp{y} or
+@samp{Y}, do not run the command, and return false.
@end deffn
-When processing multiple files with a single command, to query the
-user you give @code{xargs} the following option. When using this
-option, you might find it useful to control the number of files
-processed per invocation of the command (@pxref{Limiting Command
-Size}).
+When processing multiple files with a single command, to query the user
+you give @code{xargs} the following option. When using this option, you
+might find it useful to control the number of files processed per
+invocation of the command (@pxref{Limiting Command Size}).
@table @code
@item --interactive
@@ -2550,36 +1534,15 @@ from the terminal. Only run the command line if the response starts
with @samp{y} or @samp{Y}. Implies @samp{-t}.
@end table
-@node Delete Files
-@section Delete Files
-
-@deffn Action -delete
-Delete files or directories; true if removal succeeded. If the
-removal failed, an error message is issued.
-
-The use of the @samp{-delete} action on the command line automatically
-turns on the @samp{-depth} option (@pxref{find Expressions}). This
-can be surprising if you were previously just testing with
-@samp{-print}, so it is usually best to remember to use @samp{-depth}
-explicitly.
-
-If @samp{-delete} fails, @code{find}'s exit status will be nonzero
-(when it eventually exits).
-@end deffn
-
@node Adding Tests
@section Adding Tests
You can test for file attributes that none of the @code{find} builtin
-tests check. To do this, use @code{xargs} to run a program that
-filters a list of files printed by @code{find}. If possible, use
-@code{find} builtin tests to pare down the list, so the program run by
-@code{xargs} has less work to do. The tests builtin to @code{find}
-will likely run faster than tests that other programs perform.
-
-For reasons of efficiency it is often useful to limit the number of
-times an external program has to be run. For this reason, it is often
-a good idea to implement ``extended'' tests by using @code{xargs}.
+tests check. To do this, use @code{xargs} to run a program that filters
+a list of files printed by @code{find}. If possible, use @code{find}
+builtin tests to pare down the list, so the program run by @code{xargs}
+has less work to do. The tests builtin to @code{find} will likely run
+faster than tests that other programs perform.
For example, here is a way to print the names of all of the unstripped
binaries in the @file{/usr/local} directory tree. Builtin tests avoid
@@ -2587,7 +1550,7 @@ running @code{file} on files that are not regular files or are not
executable.
@example
-find /usr/local -type f -perm /a=x | xargs file |
+find /usr/local -type f -perm +a=x | xargs file |
grep 'not stripped' | cut -d: -f1
@end example
@@ -2595,1118 +1558,44 @@ find /usr/local -type f -perm /a=x | xargs file |
The @code{cut} program removes everything after the file name from the
output of @code{file}.
-However, using @code{xargs} can present important security problems
-(@pxref{Security Considerations}). These can be avoided by using
-@samp{-execdir}. The @samp{-execdir} action is also a useful way of
-putting your own test in the middle of a set of other tests or actions
-for @code{find} (for example, you might want to use @samp{-prune}).
-
@c Idea from Martin Weitzel.
-To place a special test somewhere in the middle of a @code{find}
-expression, you can use @samp{-execdir} (or, less securely,
-@samp{-exec}) to run a program that performs the test. Because
-@samp{-execdir} evaluates to the exit status of the executed program,
-you can use a program (which can be a shell script) that tests for a
-special attribute and make it exit with a true (zero) or false
-(non-zero) status. It is a good idea to place such a special test
-@emph{after} the builtin tests, because it starts a new process which
-could be avoided if a builtin test evaluates to false.
-
-Here is a shell script called @code{unstripped} that checks whether
-its argument is an unstripped binary file:
-
-@example
-#! /bin/sh
-file "$1" | grep -q "not stripped"
-@end example
-
-
-This script relies on the shell exiting with the status of
-the last command in the pipeline, in this case @code{grep}. The
-@code{grep} command exits with a true status if it found any matches,
-false if not. Here is an example of using the script (assuming it is
-in your search path). It lists the stripped executables (and shell
-scripts) in the file @file{sbins} and the unstripped ones in
-@file{ubins}.
-
-@example
-find /usr/local -type f -perm /a=x \
- \( -execdir unstripped '@{@}' \; -fprint ubins -o -fprint sbins \)
-@end example
-
-
-@node Databases
-@chapter File Name Databases
-
-The file name databases used by @code{locate} contain lists of files
-that were in particular directory trees when the databases were last
-updated. The file name of the default database is determined when
-@code{locate} and @code{updatedb} are configured and installed. The
-frequency with which the databases are updated and the directories for
-which they contain entries depend on how often @code{updatedb} is run,
-and with which arguments.
-
-You can obtain some statistics about the databases by using
-@samp{locate --statistics}.
-
-@menu
-* Database Locations::
-* Database Formats::
-* Newline Handling::
-@end menu
-
-
-@node Database Locations
-@section Database Locations
-
-There can be multiple file name databases. Users can select which
-databases @code{locate} searches using the @code{LOCATE_PATH}
-environment variable or a command line option. The system
-administrator can choose the file name of the default database, the
-frequency with which the databases are updated, and the directories
-for which they contain entries. File name databases are updated by
-running the @code{updatedb} program, typically nightly.
-
-In networked environments, it often makes sense to build a database at
-the root of each filesystem, containing the entries for that
-filesystem. @code{updatedb} is then run for each filesystem on the
-fileserver where that filesystem is on a local disk, to prevent
-thrashing the network.
-
-@xref{Invoking updatedb}, for the description of the options to
-@code{updatedb}. These options can be used to specify which
-directories are indexed by each database file.
-
-The default location for the locate database depends on how findutils
-is built, but the findutils installation accompanying this manual uses
-the default location @file{@value{LOCATE_DB}}.
-
-If no database exists at @file{@value{LOCATE_DB}} but the user did not
-specify where to look (by using @samp{-d} or setting
-@code{LOCATE_PATH}), then @code{locate} will also check for a
-``secure'' database in @file{/var/lib/slocate/slocate.db}.
-
-@node Database Formats
-@section Database Formats
-
-The file name databases contain lists of files that were in particular
-directory trees when the databases were last updated. The file name
-database format changed starting with GNU @code{locate} version 4.0 to
-allow machines with different byte orderings to share the databases.
-
-GNU @code{locate} can read both the old and new database formats.
-However, old versions of @code{locate} (on other Unix systems, or GNU
-@code{locate} before version 4.0) produce incorrect results if run
-against a database in something other than the old format.
-
-Support for the old database format will eventually be discontinued,
-first in @code{updatedb} and later in @code{locate}.
-
-If you run @samp{locate --statistics}, the resulting summary indicates
-the type of each @code{locate} database. You select which database
-format @code{updatedb} will use with the @samp{--dbformat} option.
-
-
-@menu
-* LOCATE02 Database Format::
-* Sample LOCATE02 Database::
-* slocate Database Format::
-* Old Database Format::
-@end menu
-
-@node LOCATE02 Database Format
-@subsection LOCATE02 Database Format
-
-@code{updatedb} runs a program called @code{frcode} to
-@dfn{front-compress} the list of file names, which reduces the
-database size by a factor of 4 to 5. Front-compression (also known as
-incremental encoding) works as follows.
-
-The database entries are a sorted list (case-insensitively, for users'
-convenience). Since the list is sorted, each entry is likely to share
-a prefix (initial string) with the previous entry. Each database
-entry begins with an offset-differential count byte, which is the
-additional number of characters of prefix of the preceding entry to
-use beyond the number that the preceding entry is using of its
-predecessor. (The counts can be negative.) Following the count is a
-null-terminated ASCII remainder---the part of the name that follows
-the shared prefix.
-
-If the offset-differential count is larger than can be stored in a
-byte (+/-127), the byte has the value 0x80 and the count follows in a
-2-byte word, with the high byte first (network byte order).
-
-Every database begins with a dummy entry for a file called
-@file{LOCATE02}, which @code{locate} checks for to ensure that the
-database file has the correct format; it ignores the entry in doing
-the search.
-
-Databases cannot be concatenated together, even if the first (dummy)
-entry is trimmed from all but the first database. This is because the
-offset-differential count in the first entry of the second and
-following databases will be wrong.
-
-In the output of @samp{locate --statistics}, the new database format
-is referred to as @samp{LOCATE02}.
-
-@node Sample LOCATE02 Database
-@subsection Sample LOCATE02 Database
-
-Sample input to @code{frcode}:
-@c with nulls changed to newlines:
-
-@example
-/usr/src
-/usr/src/cmd/aardvark.c
-/usr/src/cmd/armadillo.c
-/usr/tmp/zoo
-@end example
-
-Length of the longest prefix of the preceding entry to share:
-
-@example
-0 /usr/src
-8 /cmd/aardvark.c
-14 rmadillo.c
-5 tmp/zoo
-@end example
-
-Output from @code{frcode}, with trailing nulls changed to newlines
-and count bytes made printable:
-
-@example
-0 LOCATE02
-0 /usr/src
-8 /cmd/aardvark.c
-6 rmadillo.c
--9 tmp/zoo
-@end example
-
-(6 = 14 - 8, and -9 = 5 - 14)
-
-@node slocate Database Format
-@subsection slocate Database Format
-
-The @code{slocate} program uses a database format similar to, but not
-quite the same as, GNU @code{locate}. The first byte of the database
-specifies its @dfn{security level}. If the security level is 0,
-@code{slocate} will read, match and print filenames on the basis of
-the information in the database only. However, if the security level
-byte is 1, @code{slocate} omits entries from its output if the
-invoking user is unable to access them. The second byte of the
-database is zero. The second byte is immediately followed by the
-first database entry. The first entry in the database is not preceded
-by any differential count or dummy entry. Instead the differential
-count for the first item is assumed to be zero.
-.P
-Starting with the second entry (if any) in the database, data is
-interpreted as for the GNU LOCATE02 format.
-
-@node Old Database Format
-@subsection Old Database Format
-
-The old database format is used by Unix @code{locate} and @code{find}
-programs and earlier releases of the GNU ones. @code{updatedb}
-produces this format if given the @samp{--old-format} option.
-
-@code{updatedb} runs programs called @code{bigram} and @code{code} to
-produce old-format databases. The old format differs from the new one
-in the following ways. Instead of each entry starting with an
-offset-differential count byte and ending with a null, byte values
-from 0 through 28 indicate offset-differential counts from -14 through
-14. The byte value indicating that a long offset-differential count
-follows is 0x1e (30), not 0x80. The long counts are stored in host
-byte order, which is not necessarily network byte order, and host
-integer word size, which is usually 4 bytes. They also represent a
-count 14 less than their value. The database lines have no
-termination byte; the start of the next line is indicated by its first
-byte having a value <= 30.
-
-In addition, instead of starting with a dummy entry, the old database
-format starts with a 256 byte table containing the 128 most common
-bigrams in the file list. A bigram is a pair of adjacent bytes.
-Bytes in the database that have the high bit set are indexes (with the
-high bit cleared) into the bigram table. The bigram and
-offset-differential count coding makes these databases 20-25% smaller
-than the new format, but makes them not 8-bit clean. Any byte in a
-file name that is in the ranges used for the special codes is replaced
-in the database by a question mark, which not coincidentally is the
-shell wildcard to match a single character.
-
-The old format therefore cannot faithfully store entries with
-non-ASCII characters. It therefore should not be used in
-internationalised environments. That is, most installations should
-not use it.
-
-Because the long counts are stored by the @code{code} program as
-native-order machine words, the database format is not eaily used in
-environments which differ in terms of byte order. If locate databases
-are to be shared between machines, the LOCATE02 database format should
-be used. This has other benefits as discussed above. However, the
-length of the filename currently being processed can normally be used
-to place reasonable limits on the long counts and so this information
-is used by locate to help it guess the byte ordering of the old format
-database. Unless it finds evidence to the contrary, @code{locate}
-will assume that the byte order of the database is the same as the
-native byte order of the machine running @code{locate}. The output of
-@samp{locate --statistics} also includes information about the byte
-order of old-format databases.
-
-The output of @samp{locate --statistics} will give an incorrect count
-of the number of file names containing newlines or high-bit characters
-for old-format databases.
-
-Old versions of GNU @code{locate} fail to correctly handle very long
-file names, possibly leading to security problems relating to a heap
-buffer overrun. @xref{Security Considerations for locate}, for a
-detailed explanation.
-
-@node Newline Handling
-@section Newline Handling
-
-Within the database, file names are terminated with a null character.
-This is the case for both the old and the new format.
-
-When the new database format is being used, the compression technique
-used to generate the database though relies on the ability to sort the
-list of files before they are presented to @code{frcode}.
-
-If the system's sort command allows its input list of files to be
-separated with null characters via the @samp{-z} option, this option
-is used and therefore @code{updatedb} and @code{locate} will both
-correctly handle file names containing newlines. If the @code{sort}
-command lacks support for this, the list of files is delimited with
-the newline character, meaning that parts of file names containing
-newlines will be incorrectly sorted. This can result in both
-incorrect matches and incorrect failures to match.
-
-On the other hand, if you are using the old database format, file
-names with embedded newlines are not correctly handled. There is no
-technical limitation which enforces this, it's just that the
-@code{bigram} program has not been updated to support lists of file
-names separated by nulls.
-
-So, if you are using the new database format (this is the default) and
-your system uses GNU @code{sort}, newlines will be correctly handled
-at all times. Otherwise, newlines may not be correctly handled.
-
-@node File Permissions
-@chapter File Permissions
-
-@include perm.texi
-
-@include getdate.texi
-
-@node Reference
-@chapter Reference
-
-Below are summaries of the command line syntax for the programs
-discussed in this manual.
-
-@menu
-* Invoking find::
-* Invoking locate::
-* Invoking updatedb::
-* Invoking xargs::
-* Regular Expressions::
-* Environment Variables::
-@end menu
-
-@node Invoking find
-@section Invoking @code{find}
-
-@example
-find @r{[-H] [-L] [-P] [-D @var{debugoptions}] [-O@var{level}]} @r{[}@var{file}@dots{}@r{]} @r{[}@var{expression}@r{]}
-@end example
-
-@code{find} searches the directory tree rooted at each file name
-@var{file} by evaluating the @var{expression} on each file it finds in
-the tree.
-
-The command line may begin with the @samp{-H}, @samp{-L}, @samp{-P},
-@samp{-D} and @samp{-O} options. These are followed by a list of
-files or directories that should be searched. If no files to search
-are specified, the current directory (@file{.}) is used.
-
-This list of files to search is followed by a list of expressions
-describing the files we wish to search for. The first part of the
-expression is recognised by the fact that it begins with @samp{-}
-followed by some other letters (for example @samp{-print}), or is
-either @samp{(} or @samp{!}. Any arguments after it are the rest of
-the expression.
-
-If no expression is given, the expression @samp{-print} is used.
-
-The @code{find} command exits with status zero if all files matched
-are processed successfully, greater than zero if errors occur.
-
-The @code{find} program also recognises two options for administrative
-use:
-
-@table @samp
-@item --help
-Print a summary of the command line usage and exit.
-@item --version
-Print the version number of @code{find} and exit.
-@end table
-
-The @samp{-version} option is a synonym for @samp{--version}
-
-
-@menu
-* Filesystem Traversal Options::
-* Warning Messages::
-* Optimisation Options::
-* Debug Options::
-* Find Expressions::
-@end menu
-
-@node Filesystem Traversal Options
-@subsection Filesystem Traversal Options
-
-The options @samp{-H}, @samp{-L} or @samp{-P} may be specified at the
-start of the command line (if none of these is specified, @samp{-P} is
-assumed). If you specify more than one of these options, the last one
-specified takes effect (but note that the @samp{-follow} option is
-equivalent to @samp{-L}).
-
-@table @code
-@item -P
-Never follow symbolic links (this is the default), except in the case
-of the @samp{-xtype} predicate.
-@item -L
-Always follow symbolic links, except in the case of the @samp{-xtype}
-predicate.
-@item -H
-Follow symbolic links specified in the list of files to search, or
-which are otherwise specified on the command line.
-@end table
-
-If @code{find} would follow a symbolic link, but cannot for any reason
-(for example, because it has insufficient permissions or the link is
-broken), it falls back on using the properties of the symbolic link
-itself. @ref{Symbolic Links} for a more complete description of how
-symbolic links are handled.
-
-@node Warning Messages
-@subsection Warning Messages
-
-If there is an error on the @code{find} command line, an error message
-is normally issued. However, there are some usages that are
-inadvisable but which @code{find} should still accept. Under these
-circumstances, @code{find} may issue a warning message.
-
-By default, warnings are enabled only if @code{find} is being run
-interactively (specifically, if the standard input is a terminal) and
-the POSIXLY_CORRECT environment variable is not set. Warning messages
-can be controlled explicitly by the use of options on the command
-line:
-
-@table @code
-@item -warn
-Issue warning messages where appropriate.
-@item -nowarn
-Do not issue warning messages.
-@end table
-
-These options take effect at the point on the command line where they
-are specified. Therefore it's not useful to specify @samp{-nowarn} at
-the end of the command line. The warning messages affected by the
-above options are triggered by:
-
-@itemize @minus
-@item
-Use of the @samp{-d} option which is deprecated; please use
-@samp{-depth} instead, since the latter is POSIX-compliant.
-@item
-Use of the @samp{-ipath} option which is deprecated; please use
-@samp{-iwholename} instead.
-@item
-Specifying an option (for example @samp{-mindepth}) after a non-option
-(for example @samp{-type} or @samp{-print}) on the command line.
-@item
-Use of the @samp{-name} or @samp{-iname} option with a slash character
-in the pattern. Since the name predicates only compare against the
-basename of the visited files, the only file that can match a slash is
-the root directory itself.
-@end itemize
-
-The default behaviour above is designed to work in that way so that
-existing shell scripts don't generate spurious errors, but people will
-be made aware of the problem.
-
-Some warning messages are issued for less common or more serious
-problems, and consequently cannot be turned off:
-
-@itemize @minus
-@item
-Use of an unrecognised backslash escape sequence with @samp{-fprintf}
-@item
-Use of an unrecognised formatting directive with @samp{-fprintf}
-@end itemize
-
-@node Optimisation Options
-@subsection Optimisation Options
-
-The @samp{-O@var{level}} option sets @code{find}'s optimisation level
-to @var{level}. The default optimisation level is 1.
-
-At certain optimisation levels, @code{find} reorders tests to speed up
-execution while preserving the overall effect; that is, predicates
-with side effects are not reordered relative to each other. The
-optimisations performed at each optimisation level are as follows.
-
-@table @samp
-@item 0
-Currently equivalent to optimisation level 1.
-
-@item 1
-This is the default optimisation level and corresponds to the
-traditional behaviour. Expressions are reordered so that tests based
-only on the names of files (for example@samp{ -name} and
-@samp{-regex}) are performed first.
-
-@item 2
-Any @samp{-type} or @samp{-xtype} tests are performed after any tests
-based only on the names of files, but before any tests that require
-information from the inode. On many modern versions of Unix, file
-types are returned by @code{readdir()} and so these predicates are
-faster to evaluate than predicates which need to stat the file first.
-
-@item 3
-At this optimisation level, the full cost-based query optimiser is
-enabled. The order of tests is modified so that cheap (i.e., fast)
-tests are performed first and more expensive ones are performed later,
-if necessary. Within each cost band, predicates are evaluated earlier
-or later according to whether they are likely to succeed or not. For
-@samp{-o}, predicates which are likely to succeed are evaluated
-earlier, and for @samp{-a}, predicates which are likely to fail are
-evaluated earlier.
-@end table
-
-
-@node Debug Options
-@subsection Debug Options
-
-The @samp{-D} option makes @code{find} produce diagnostic output.
-Much of the information is useful only for diagnosing problems, and so
-most people will not find this option helpful.
-
-The list of debug options should be comma separated. Compatibility of
-the debug options is not guaranteed between releases of findutils.
-For a complete list of valid debug options, see the output of
-@code{find -D help}. Valid debug options include:
-@table @samp
-@item help
-Explain the debugging options.
-@item tree
-Show the expression tree in its original and optimised form.
-@item stat
-Print messages as files are examined with the stat and lstat system
-calls. The find program tries to minimise such calls.
-@item opt
-Prints diagnostic information relating to the optimisation of the
-expression tree; see the @samp{-O} option.
-@item rates
-Prints a summary indicating how often each predicate succeeded or
-failed.
-@end table
-
-@node Find Expressions
-@subsection Find Expressions
-
-The final part of the @code{find} command line is a list of
-expressions. @xref{Primary Index}, for a summary of all of the tests,
-actions, and options that the expression can contain. If the
-expression is missing, @samp{-print} is assumed.
-
-@node Invoking locate
-@section Invoking @code{locate}
-
-@example
-locate @r{[}@var{option}@dots{}@r{]} @var{pattern}@dots{}
-@end example
-
-For each @var{pattern} given @code{locate} searches one or more file
-name databases returning each match of @var{pattern}.
-
-For each @var{pattern} given @code{locate} searches one or more file
-name databases returning each match of @var{pattern}.
-
-@table @code
-@item --all
-@itemx -A
-Print only names which match all non-option arguments, not those
-matching one or more non-option arguments.
-
-@item --basename
-@itemx -b
-The specified pattern is matched against just the last component of
-the name of a file in the @code{locate} database. This last
-component is also called the ``base name''. For example, the base
-name of @file{/tmp/mystuff/foo.old.c} is @file{foo.old.c}. If the
-pattern contains metacharacters, it must match the base name exactly.
-If not, it must match part of the base name.
-
-@item --count
-@itemx -c
-Instead of printing the matched file names, just print the total
-number of matches found, unless @samp{--print} (@samp{-p}) is also
-present.
+If you want to place a special test somewhere in the middle of a
+@code{find} expression, you can use @samp{-exec} to run a program that
+performs the test. Because @samp{-exec} evaluates to the exit status of
+the executed program, you can write a program (which can be a shell
+script) that tests for a special attribute and make it exit with a true
+(zero) or false (non-zero) status. It is a good idea to place such a
+special test @emph{after} the builtin tests, because it starts a new
+process which could be avoided if a builtin test evaluates to false.
+Use this method only when @code{xargs} is not flexible enough, because
+starting one or more new processes to test each file is slower than
+using @code{xargs} to start one process that tests many files.
-
-@item --database=@var{path}
-@itemx -d @var{path}
-Instead of searching the default @code{locate} database
-@file{@value{LOCATE_DB}}, @code{locate} searches the file
-name databases in @var{path}, which is a colon-separated list of
-database file names. You can also use the environment variable
-@code{LOCATE_PATH} to set the list of database files to search. The
-option overrides the environment variable if both are used. Empty
-elements in @var{path} (that is, a leading or trailing colon, or two
-colons in a row) are taken to stand for the default database.
-A database can be supplied on stdin, using @samp{-} as an element
-of @samp{path}. If more than one element of @samp{path} is @samp{-},
-later instances are ignored (but a warning message is printed).
-
-@item --existing
-@itemx -e
-Only print out such names which currently exist (instead of such names
-which existed when the database was created). Note that this may slow
-down the program a lot, if there are many matches in the database.
-The way in which broken symbolic links are treated is affected by the
-@samp{-L}, @samp{-P} and @samp{-H} options. Please note that it is
-possible for the file to be deleted after @code{locate} has checked
-that it exists, but before you use it. This option is automatically
-turned on when reading an @code{slocate} database in secure mode
-(@pxref{slocate Database Format}).
-
-@item --non-existing
-@itemx -E
-Only print out such names which currently do not exist (instead of
-such names which existed when the database was created). Note that
-this may slow down the program a lot, if there are many matches in the
-database. The way in which broken symbolic links are treated is
-affected by the @samp{-L}, @samp{-P} and @samp{-H} options. Please
-note that @code{locate} checks that the file does not exist, but a
-file of the same name might be created after @code{locate}'s check but
-before you read @code{locate}'s output.
-
-@item --follow
-@itemx -L
-If testing for the existence of files (with the @samp{-e} or @samp{-E}
-options), consider broken symbolic links to be non-existing. This is
-the default behaviour.
-
-@item --nofollow
-@itemx -P
-@itemx -H
-If testing for the existence of files (with the @samp{-e} or @samp{-E}
-options), treat broken symbolic links as if they were existing files.
-The @samp{-H} form of this option is provided purely for similarity
-with @code{find}; the use of @samp{-P} is recommended over @samp{-H}.
-
-@item --ignore-case
-@itemx -i
-Ignore case distinctions in both the pattern and the file names.
-
-@item --limit=N
-@itemx -l N
-Limit the number of results printed to N. When used with the
-@samp{--count} option, the value printed will never be larger than
-this limit.
-@item --max-database-age=D
-Normally, @code{locate} will issue a warning message when it searches
-a database which is more than 8 days old. This option changes that
-value to something other than 8. The effect of specifying a negative
-value is undefined.
-@item --mmap
-@itemx -m
-Accepted but does nothing. The option is supported only to provide
-compatibility with BSD's @code{locate}.
-
-@item --null
-@itemx -0
-Results are separated with the ASCII NUL character rather than the
-newline character. To get the full benefit of the use of this option,
-use the new @code{locate} database format (that is the default
-anyway).
-
-@item --print
-@itemx -p
-Print search results when they normally would not, because of the
-presence of @samp{--statistics} (@samp{-S}) or @samp{--count}
-(@samp{-c}).
-
-@item --wholename
-@itemx -w
-The specified pattern is matched against the whole name of the file in
-the @code{locate} database. If the pattern contains metacharacters,
-it must match exactly. If not, it must match part of the whole file
-name. This is the default behaviour.
-
-@item --regex
-@itemx -r
-Instead of using substring or shell glob matching, the pattern
-specified on the command line is understood to be a regular
-expression. GNU Emacs-style regular expressions are assumed unless
-the @samp{--regextype} option is also given. File names from the
-@code{locate} database are matched using the specified regular
-expression. If the @samp{-i} flag is also given, matching is
-case-insensitive. Matches are performed against the whole path name,
-and so by default a pathname will be matched if any part of it matches
-the specified regular expression. The regular expression may use
-@samp{^} or @samp{$} to anchor a match at the beginning or end of a
-pathname.
-
-@item --regextype
-This option changes the regular expression syntax and behaviour used
-by the @samp{--regex} option. @ref{Regular Expressions} for more
-information on the regular expression dialects understood by GNU
-findutils.
-
-@item --stdio
-@itemx -s
-Accepted but does nothing. The option is supported only to provide
-compatibility with BSD's @code{locate}.
-
-@item --statistics
-@itemx -S
-Print some summary information for each @code{locate} database. No
-search is performed unless non-option arguments are given.
-Although the BSD version of locate also has this option, the format of the
-output is different.
-
-@item --help
-Print a summary of the command line usage for @code{locate} and exit.
-
-@item --version
-Print the version number of @code{locate} and exit.
-@end table
-
-@node Invoking updatedb
-@section Invoking @code{updatedb}
+Here is a shell script called @code{unstripped} that checks whether its
+argument is an unstripped binary file:
@example
-updatedb @r{[}@var{option}@dots{}@r{]}
+#!/bin/sh
+file $1 | grep 'not stripped' > /dev/null
@end example
-@code{updatedb} creates and updates the database of file names used by
-@code{locate}. @code{updatedb} generates a list of files similar to
-the output of @code{find} and then uses utilities for optimizing the
-database for performance. @code{updatedb} is often run periodically
-as a @code{cron} job and configured with environment variables or
-command options. Typically, operating systems have a shell script
-that ``exports'' configurations for variable definitions and uses
-another shell script that ``sources'' the configuration file into the
-environment and then executes @code{updatedb} in the environment.
-
-@code{updatedb} creates and updates the database of file names used by
-@code{locate}. @code{updatedb} generates a list of files similar to
-the output of @code{find} and then uses utilities for optimizing the
-database for performance. @code{updatedb} is often run periodically
-as a @code{cron} job and configured with environment variables or
-command options. Typically, operating systems have a shell script
-that ``exports'' configurations for variable definitions and uses
-another shell script that ``sources'' the configuration file into the
-environment and then executes @code{updatedb} in the environment.
-
-@table @code
-@item --findoptions='@var{OPTION}@dots{}'
-Global options to pass on to @code{find}.
-The environment variable @code{FINDOPTIONS} also sets this value.
-Default is none.
-
-@item --localpaths='@var{path}@dots{}'
-Non-network directories to put in the database.
-Default is @file{/}.
-
-@item --netpaths='@var{path}@dots{}'
-Network (NFS, AFS, RFS, etc.) directories to put in the database.
-The environment variable @code{NETPATHS} also sets this value.
-Default is none.
-
-@item --prunepaths='@var{path}@dots{}'
-Directories to omit from the database, which would otherwise be
-included. The environment variable @code{PRUNEPATHS} also sets this
-value. Default is @file{/tmp /usr/tmp /var/tmp /afs}. The paths are
-used as regular expressions (with @code{find ... -regex}, so you need
-to specify these paths in the same way that @code{find} will encounter
-them. This means for example that the paths must not include trailing
-slashes.
-
-@item --prunefs='@var{path}@dots{}'
-Filesystems to omit from the database, which would otherwise be
-included. Note that files are pruned when a filesystem is reached;
-Any filesystem mounted under an undesired filesystem will be ignored.
-The environment variable @code{PRUNEFS} also sets this value. Default
-is @file{nfs NFS proc}.
-
-@item --output=@var{dbfile}
-The database file to build. The default is system-dependent, but
-when this document was formatted it was @file{@value{LOCATE_DB}}.
-
-@item --localuser=@var{user}
-The user to search the non-network directories as, using @code{su}.
-Default is to search the non-network directories as the current user.
-You can also use the environment variable @code{LOCALUSER} to set this user.
-
-@item --netuser=@var{user}
-The user to search network directories as, using @code{su}. Default
-@code{user} is @code{daemon}. You can also use the environment variable
-@code{NETUSER} to set this user.
-
-@item --old-format
-Generate a @code{locate} database in the old format, for compatibility
-with versions of @code{locate} other than GNU @code{locate}. Using
-this option means that @code{locate} will not be able to properly
-handle non-ASCII characters in file names (that is, file names
-containing characters which have the eighth bit set, such as many of
-the characters from the ISO-8859-1 character set). @xref{Database
-Formats}, for a detailed description of the supported database
-formats.
-
-@item --dbformat=@var{FORMAT}
-Generate the locate database in format @code{FORMAT}. Supported
-database formats include @code{LOCATE02} (which is the default),
-@code{old} and @code{slocate}. The @code{old} format exists for
-compatibility with implementations of @code{locate} on other Unix
-systems. The @code{slocate} format exists for compatibility with
-@code{slocate}. @xref{Database Formats}, for a detailed description
-of each format.
-
-@item --help
-Print a summary of the command line usage and exit.
-@item --version
-Print the version number of @code{updatedb} and exit.
-@end table
-
-@node Invoking xargs
-@section Invoking @code{xargs}
+This script relies on the fact that the shell exits with the status of
+the last program it executed, in this case @code{grep}. @code{grep}
+exits with a true status if it found any matches, false if not. Here is
+an example of using the script (assuming it is in your search path). It
+lists the stripped executables in the file @file{sbins} and the
+unstripped ones in @file{ubins}.
@example
-xargs @r{[}@var{option}@dots{}@r{]} @r{[}@var{command} @r{[}@var{initial-arguments}@r{]}@r{]}
+find /usr/local -type f -perm +a=x \
+ \( -exec unstripped '@{@}' \; -fprint ubins -o -fprint sbins \)
@end example
-@code{xargs} exits with the following status:
-
-@table @asis
-@item 0
-if it succeeds
-@item 123
-if any invocation of the command exited with status 1-125
-@item 124
-if the command exited with status 255
-@item 125
-if the command is killed by a signal
-@item 126
-if the command cannot be run
-@item 127
-if the command is not found
-@item 1
-if some other error occurred.
-@end table
-
-Exit codes greater than 128 are used by the shell to indicate that
-a program died due to a fatal signal.
-
-
-@menu
-* xargs options::
-* Invoking the shell from xargs::
-@end menu
-
-@node xargs options
-@subsection xargs options
-
-@table @code
-@item --arg-file@r{=@var{inputfile}}
-@itemx -a @r{@var{inputfile}}
-Read names from the file @var{inputfile} instead of standard input.
-If you use this option, the standard input stream remains unchanged
-when commands are run. Otherwise, stdin is redirected from
-@file{/dev/null}.
-
-@item --null
-@itemx -0
-Input file names are terminated by a null character instead of by
-whitespace, and any quotes and backslash characters are not considered
-special (every character is taken literally). Disables the end of
-file string, which is treated like any other argument.
-
-@item --delimiter @var{delim}
-@itemx -d @var{delim}
-
-Input file names are terminated by the specified character @var{delim}
-instead of by whitespace, and any quotes and backslash characters are
-not considered special (every character is taken literally). Disables
-the end of file string, which is treated like any other argument.
-
-The specified delimiter may be a single character, a C-style character
-escape such as @samp{\n}, or an octal or hexadecimal escape code.
-Octal and hexadecimal escape codes are understood as for the
-@code{printf} command. Multibyte characters are not supported.
-
-
-@item -E @var{eof-str}
-@itemx --eof@r{[}=@var{eof-str}@r{]}
-@itemx -e@r{[}@var{eof-str}@r{]}
-Set the end of file string to @var{eof-str}. If the end of file
-string occurs as a line of input, the rest of the input is ignored.
-If @var{eof-str} is omitted (@samp{-e}) or blank (either @samp{-e} or
-@samp{-E}), there is no end of file string. The @samp{-e} form of
-this option is deprecated in favour of the POSIX-compliant @samp{-E}
-option, which you should use instead. As of GNU xargs version 4.2.9,
-the default behaviour of xargs is not to have a logical end-of-file
-marker. The POSIX standard (IEEE Std 1003.1, 2004 Edition) allows
-this.
-
-@item --help
-Print a summary of the options to @code{xargs} and exit.
-
-@item -I @var{replace-str}
-@itemx --replace@r{[}=@var{replace-str}@r{]}
-@itemx -i@r{[}@var{replace-str}@r{]}
-Replace occurrences of @var{replace-str} in the initial arguments with
-names read from standard input. Also, unquoted blanks do not
-terminate arguments; instead, the input is split at newlines only. If
-@var{replace-str} is omitted (omitting it is allowed only for
-@samp{-i}), it defaults to @samp{@{@}} (like for @samp{find -exec}).
-Implies @samp{-x} and @samp{-l 1}. The @samp{-i} option is deprecated
-in favour of the @samp{-I} option.
-
-@item -L @var{max-lines}
-@itemx --max-lines@r{[}=@var{max-lines}@r{]}
-@itemx -l@r{[}@var{max-lines}@r{]}
-Use at most @var{max-lines} non-blank input lines per command line.
-For @samp{-l}, @var{max-lines} defaults to 1 if omitted. For
-@samp{-L}, the argument is mandatory. Trailing blanks cause an input
-line to be logically continued on the next input line, for the purpose
-of counting the lines. Implies @samp{-x}. The @samp{-l} form of this
-option is deprecated in favour of the POSIX-compliant @samp{-L}
-option.
-
-@item --max-args=@var{max-args}
-@itemx -n @var{max-args}
-Use at most @var{max-args} arguments per command line. Fewer than
-@var{max-args} arguments will be used if the size (see the @samp{-s}
-option) is exceeded, unless the @samp{-x} option is given, in which
-case @code{xargs} will exit.
-
-@item --interactive
-@itemx -p
-Prompt the user about whether to run each command line and read a line
-from the terminal. Only run the command line if the response starts
-with @samp{y} or @samp{Y}. Implies @samp{-t}.
-
-@item --no-run-if-empty
-@itemx -r
-If the standard input is completely empty, do not run the
-command. By default, the command is run once even if there is no
-input.
-
-@item --max-chars=@var{max-chars}
-@itemx -s @var{max-chars}
-Use at most @var{max-chars} characters per command line, including the
-command, initial arguments and any terminating nulls at the ends of
-the argument strings.
-
-@item --show-limits
-Display the limits on the command-line length which are imposed by the
-operating system, @code{xargs}' choice of buffer size and the
-@samp{-s} option. Pipe the input from @file{/dev/null} (and perhaps
-specify @samp{--no-run-if-empty}) if you don't want @code{xargs} to do
-anything.
-
-@item --verbose
-@itemx -t
-Print the command line on the standard error output before executing
-it.
-
-@item --version
-Print the version number of @code{xargs} and exit.
-
-@item --exit
-@itemx -x
-Exit if the size (see the @samp{-s} option) is exceeded.
-
-
-@item --max-procs=@var{max-procs}
-@itemx -P @var{max-procs}
-Run simultaneously up to @var{max-procs} processes at once; the default is 1. If
-@var{max-procs} is 0, @code{xargs} will run as many processes as
-possible simultaneously.
-@end table
-
-@node Invoking the shell from xargs
-@subsection Invoking the shell from xargs
-
-Normally, @code{xargs} will exec the command you specified directly,
-without invoking a shell. This is normally the behaviour one would
-want. It's somewhat more efficient and avoids problems with shell
-metacharacters, for example. However, sometimes it is necessary to
-manipulate the environment of a command before it is run, in a way
-that @code{xargs} does not directly support.
-
-Invoking a shell from @code{xargs} is a good way of performing such
-manipulations. However, some care must be taken to prevent problems,
-for example unwanted interpretation of shell metacharacters.
-
-This command moves a set of files into an archive directory:
-
-@example
-find /foo -maxdepth 1 -atime +366 -exec mv @{@} /archive \;
-@end example
-
-However, this will only move one file at a time. We cannot in this
-case use @code{-exec ... +} because the matched file names are added
-at the end of the command line, while the destination directory would
-need to be specified last. We also can't use @code{xargs} in the
-obvious way for the same reason. One way of working around this
-problem is to make use of the special properties of GNU @code{mv}; it
-has a @code{-t} option that allows the target directory to be
-specified before the list of files to be moved. However, while this
-technique works for GNU @code{mv}, it doesn't solve the more general
-problem.
-
-Here is a more general technique for solving this problem:
-
-@example
-find /foo -maxdepth 1 -atime +366 -print0 |
-xargs -r0 sh -c 'mv "$@@" /archive' move
-@end example
-
-Here, a shell is being invoked. There are two shell instances to
-think about. The first is the shell which launches the xargs command
-(this might be the shell into which you are typing, for example). The
-second is the shell launched by @code{xargs} (in fact it will probably
-launch several, one after the other, depending on how many files need
-to be archived). We'l refer to this second shell as a subshell.
-
-Our example uses the @code{-c} option of @code{sh}. Its argument is a
-shell command to be executed by the subshell. Along with the rest of
-that command, the $@@ is enclosed by single quotes to make sure it is
-passed to the subshell without being expanded by the parent shell. It
-is also enclosed with double quotes so that the subshell will expand
-@code{$@@} correctly even if one of the file names contains a space or
-newline.
-
-The subshell will use any non-option arguments as positional
-parameters (that is, in the expansion of @code{$@@}). Because
-@code{xargs} launches the @code{sh -c} subshell with a list of files,
-those files will end up as the expansion of @code{$@@}.
-
-You may also notice the @samp{move} at the end of the command line.
-This is used as the value of @code{$0} by the subshell. We include it
-because otherwise the name of the first file to be moved would be used
-instead. If that happened it would not be included in the subshell's
-expansion of @code{$@@}, and so it wouldn't actually get moved.
-
-
-Another reason to use the @code{sh -c} construct could be to
-perform redirection:
-
-@example
-find /usr/include -name '*.h' | xargs grep -wl mode_t |
-xargs -r sh -c 'exec emacs "$@@" < /dev/tty' Emacs
-@end example
-
-Notice that we use the shell builtin @code{exec} here. That's simply
-because the subshell needs to do nothing once Emacs has been invoked.
-Therefore instead of keeping a @code{sh} process around for no reason,
-we just arrange for the subshell to exec Emacs, saving an extra
-process creation.
-
-Sometimes, though, it can be helpful to keep the shell process around:
-
-@example
-find /foo -maxdepth 1 -atime +366 -print0 |
-xargs -r0 sh -c 'mv "$@@" /archive || exit 255' move
-@end example
-
-Here, the shell will exit with status 255 if any @code{mv} failed.
-This causes @code{xargs} to stop immediately.
-
-
-@node Regular Expressions
-@section Regular Expressions
-
-The @samp{-regex} and @samp{-iregex} tests of @code{find} allow
-matching by regular expression, as does the @samp{--regex} option of
-@code{locate}. There are many different types of Regular Expression,
-but the type used by @code{find} and @code{locate} is the same as is
-used in GNU Emacs. Both programs provide an option which allows you
-to select an alternative regular expression syntax; for @code{find}
-this is the @samp{-regextype} option, and for @code{locate} this is
-the @samp{--regextype} option.
-
-These options take a single argument, which indicates the specific
-regular expression syntax and behaviour that should be used. This
-should be one of the following:
-
-@include regexprops.texi
-
-@node Environment Variables
-@section Environment Variables
-@table @var
-@item LANG
-Provides a default value for the internationalisation variables that
-are unset or null.
-@item LC_ALL
-If set to a non-empty string value, override the values of all the
-other internationalisation variables.
-@item LC_COLLATE
-The POSIX standard specifies that this variable affects the pattern
-matching to be used for the `\-name' option. GNU find uses the
-GNU version of the @code{fnmatch} library function.
-
-POSIX also specifies that the `LC_COLLATE' environment
-variable affects the interpretation of the user's response to the
-query issued by `\-ok', but this is not the case for GNU find.
-@item LC_CTYPE
-This variable affects the treatment of character classes used with
-the @samp{-name} test, if the system's
-@code{fnmatch} library function supports this. It has no effect on the behaviour
-of the @samp{-ok} expression.
-@item LC_MESSAGES
-Determines the locale to be used for internationalised messages.
-@item NLSPATH
-Determines the location of the internationalisation message catalogues.
-@item PATH
-Affects the directories which are searched to find the executables
-invoked by @samp{-exec}, @samp{-execdir} @samp{-ok} and @samp{-okdir}.
-If the @var{PATH} environment variable includes the current directory
-(by explicitly including @samp{.} or by having an empty element), and
-the find command line includes @samp{-execdir} or @samp{-okdir},
-@code{find} will refuse to run. @xref{Security Considerations}, for a
-more detailed discussion of security matters.
-
-@item POSIXLY_CORRECT
-Determines the block size used by @samp{-ls} and @samp{-fls}.
-If @var{POSIXLY_CORRECT} is set, blocks are units of 512 bytes. Otherwise
-they are units of 1024 bytes.
-
-Setting this variable also turns off warning messages (that is, implies
-@samp{-nowarn}) by default, because POSIX requires that apart from
-the output for @samp{-ok}, all messages printed on stderr are
-diagnositcs and must result in a non-zero exit status.
-
-Arguments to @samp{-perm} beginning with @samp{+} are treated
-differently when POSIXLY_CORRECT is set. See
-@ref{Mode Bits,-perm,File Mode Bits}.
-
-@item TZ
-Affects the time zone used for some of the time-related format
-directives of @samp{-printf} and @samp{-fprintf}.
-@end table
-
-
-
-@node Common Tasks
+@node Common Tasks, Databases, Actions, Top
@chapter Common Tasks
-The sections that follow contain some extended examples that both give
-a good idea of the power of these programs, and show you how to solve
+The sections that follow contain some extended examples that both give a
+good idea of the power of these programs, and show you how to solve
common real-world problems.
@menu
@@ -3721,10 +1610,10 @@ common real-world problems.
@node Viewing And Editing
@section Viewing And Editing
-To view a list of files that meet certain criteria, simply run your
-file viewing program with the file names as arguments. Shells
-substitute a command enclosed in backquotes with its output, so the
-whole command looks like this:
+To view a list of files that meet certain criteria, simply run your file
+viewing program with the file names as arguments. Shells substitute a
+command enclosed in backquotes with its output, so the whole command
+looks like this:
@example
less `find /usr/include -name '*.h' | xargs grep -l mode_t`
@@ -3732,58 +1621,26 @@ less `find /usr/include -name '*.h' | xargs grep -l mode_t`
@noindent
You can edit those files by giving an editor name instead of a file
-viewing program:
-
-@example
-emacs `find /usr/include -name '*.h' | xargs grep -l mode_t`
-@end example
-
-Because there is a limit to the length of any individual command line,
-there is a limit to the number of files that can be handled in this
-way. We can get around this difficulty by using xargs like this:
-
-@example
-find /usr/include -name '*.h' | xargs grep -l mode_t > todo
-xargs --arg-file=todo emacs
-@end example
-
-Here, @code{xargs} will run @code{emacs} as many times as necessary to
-visit all of the files listed in the file @file{todo}. Generating a
-temporary file is not always convenient, though. This command does
-much the same thing without needing one:
-
-@example
-find /usr/include -name '*.h' | xargs grep -l mode_t |
-xargs sh -c 'emacs "$@@" < /dev/tty' Emacs
-@end example
-
-The example above illustrates a useful trick; Using @code{sh -c} you
-can invoke a shell command from @code{xargs}. The @code{$@@} in the
-command line is expanded by the shell to a list of arguments as
-provided by @code{xargs}. The single quotes in the command line
-protect the @code{$@@} against expansion by your interactive shell
-(which will normally have no arguments and thus expand @code{$@@} to
-nothing). The capitalised @samp{Emacs} on the command line is used as
-@code{$0} by the shell that @code{xargs} launches.
+viewing program.
@node Archiving
@section Archiving
-You can pass a list of files produced by @code{find} to a file
-archiving program. GNU @code{tar} and @code{cpio} can both read lists
-of file names from the standard input---either delimited by nulls (the
-safe way) or by blanks (the lazy, risky default way). To use
-null-delimited names, give them the @samp{--null} option. You can
-store a file archive in a file, write it on a tape, or send it over a
-network to extract on another machine.
-
-One common use of @code{find} to archive files is to send a list of
-the files in a directory tree to @code{cpio}. Use @samp{-depth} so if
-a directory does not have write permission for its owner, its contents
-can still be restored from the archive since the directory's
-permissions are restored after its contents. Here is an example of
-doing this using @code{cpio}; you could use a more complex @code{find}
-expression to archive only certain files.
+You can pass a list of files produced by @code{find} to a file archiving
+program. GNU @code{tar} and @code{cpio} can both read lists of file
+names from the standard input---either delimited by nulls (the safe way)
+or by blanks (the lazy, risky default way). To use null-delimited
+names, give them the @samp{--null} option. You can store a file archive
+in a file, write it on a tape, or send it over a network to extract on
+another machine.
+
+One common use of @code{find} to archive files is to send a list of the
+files in a directory tree to @code{cpio}. Use @samp{-depth} so if a
+directory does not have write permission for its owner, its contents can
+still be restored from the archive since the directory's permissions are
+restored after its contents. Here is an example of doing this using
+@code{cpio}; you could use a more complex @code{find} expression to
+archive only certain files.
@example
find . -depth -print0 |
@@ -3819,41 +1676,30 @@ find . -depth -print0 | cpio -0o -Hnewc |
@section Cleaning Up
@c Idea from Jim Meyering.
-This section gives examples of removing unwanted files in various
-situations. Here is a command to remove the CVS backup files created
-when an update requires a merge:
+This section gives examples of removing unwanted files in various situations.
+Here is a command to remove the CVS backup files created when an update
+requires a merge:
@example
find . -name '.#*' -print0 | xargs -0r rm -f
@end example
-The command above works, but the following is safer:
-
-@example
-find . -name '.#*' -depth -delete
-@end example
-
@c Idea from Franc,ois Pinard.
-You can run this command to clean out your clutter in @file{/tmp}.
-You might place it in the file your shell runs when you log out
+You can run this command to clean out your clutter in @file{/tmp}. You
+might place it in the file your shell runs when you log out
(@file{.bash_logout}, @file{.logout}, or @file{.zlogout}, depending on
which shell you use).
@example
-find /tmp -depth -user "$LOGNAME" -type f -delete
+find /tmp -user $LOGNAME -type f -print0 | xargs -0 -r rm -f
@end example
-If your @code{find} command removes directories, you may find that
-you get a spurious error message when @code{find} tries to recurse
-into a directory that has now been removed. Using the @samp{-depth}
-option will normally resolve this problem.
-
@c Idea from Noah Friedman.
To remove old Emacs backup and auto-save files, you can use a command
like the following. It is especially important in this case to use
null-terminated file names because Emacs packages like the VM mailer
-often create temporary file names with spaces in them, like
-@file{#reply to David J. MacKenzie<1>#}.
+often create temporary file names with spaces in them, like @file{#reply
+to David J. MacKenzie<1>#}.
@example
find ~ \( -name '*~' -o -name '#*#' \) -print0 |
@@ -3864,46 +1710,17 @@ Removing old files from @file{/tmp} is commonly done from @code{cron}:
@c Idea from Kaveh Ghazi.
@example
-find /tmp /var/tmp -depth -not -type d -mtime +3 -delete
-find /tmp /var/tmp -depth -mindepth 1 -type d -empty -delete
-@end example
-
-The second @code{find} command above cleans out empty directories
-depth-first (@samp{-delete} implies @samp{-depth} anyway), hoping that
-the parents become empty and can be removed too. It uses
-@samp{-mindepth} to avoid removing @file{/tmp} itself if it becomes
-totally empty.
-
-
-Lastly, an example of a program that almost certainly does not do what
-the user intended:
-
-@c inspired by Savannah bug #20865 (Bruno De Fraine)
-@example
-find dirname -delete -name quux
-@end example
+find /tmp /var/tmp -not -type d -mtime +3 -print0 |
+ xargs --null --no-run-if-empty rm -f
-If the user hoped to delete only files named @file{quux} they will get
-an unpleasant surprise; this command will attempt to delete everything
-at or below the starting point @file{dirname}. This is because
-@code{find} evaluates the items on the command line as an expression.
-The @code{find} program will normally execute an action if the
-preceeding action succeeds. Here, there is no action or test before
-the @samp{-delete} so it will always be executed. The @samp{-name
-quux} test will be performed for files we successfully deleted, but
-that test has no effect since @samp{-delete} also disables the default
-@samp{-print} operation. So the above example will probably delete a
-lot of files the user didn't want to delete.
-
-This command is also likely to do something you did not intend:
-@example
-find dirname -path dirname/foo -prune -o -delete
+find /tmp /var/tmp -depth -mindepth 1 -type d -empty -print0 |
+ xargs --null --no-run-if-empty rmdir
@end example
-Because @samp{-delete} turns on @samp{-depth}, the @samp{-prune}
-action has no effect and files in @file{dirname/foo} will be deleted
-too.
-
+The second @code{find} command above uses @samp{-depth} so it cleans out
+empty directories depth-first, hoping that the parents become empty and
+can be removed too. It uses @samp{-mindepth} to avoid removing
+@file{/tmp} itself if it becomes totally empty.
@node Strange File Names
@section Strange File Names
@@ -3914,62 +1731,60 @@ too.
@c Subject: Unix - Frequently Asked Questions (2/7) [Frequent posting]
@c Subject: How do I remove a file with funny characters in the filename ?
@c Date: Thu Mar 18 17:16:55 EST 1993
-@code{find} can help you remove or rename a file with strange
-characters in its name. People are sometimes stymied by files whose
-names contain characters such as spaces, tabs, control characters, or
-characters with the high bit set. The simplest way to remove such
-files is:
+@code{find} can help you remove or rename a file with strange characters
+in its name. People are sometimes stymied by files whose names contain
+characters such as spaces, tabs, control characters, or characters with
+the high bit set. The simplest way to remove such files is:
@example
rm -i @var{some*pattern*that*matches*the*problem*file}
@end example
@code{rm} asks you whether to remove each file matching the given
-pattern. If you are using an old shell, this approach might not work
-if the file name contains a character with the high bit set; the shell
-may strip it off. A more reliable way is:
+pattern. If you are using an old shell, this approach might not work if
+the file name contains a character with the high bit set; the shell may
+strip it off. A more reliable way is:
@example
-find . -maxdepth 1 @var{tests} -okdir rm '@{@}' \;
+find . -maxdepth 1 @var{tests} -ok rm '@{@}' \;
@end example
@noindent
where @var{tests} uniquely identify the file. The @samp{-maxdepth 1}
-option prevents @code{find} from wasting time searching for the file
-in any subdirectories; if there are no subdirectories, you may omit
-it. A good way to uniquely identify the problem file is to figure out
-its inode number; use
+option prevents @code{find} from wasting time searching for the file in
+any subdirectories; if there are no subdirectories, you may omit it. A
+good way to uniquely identify the problem file is to figure out its
+inode number; use
@example
ls -i
@end example
-Suppose you have a file whose name contains control characters, and
-you have found that its inode number is 12345. This command prompts
-you for whether to remove it:
+Suppose you have a file whose name contains control characters, and you
+have found that its inode number is 12345. This command prompts you for
+whether to remove it:
@example
-find . -maxdepth 1 -inum 12345 -okdir rm -f '@{@}' \;
+find . -maxdepth 1 -inum 12345 -ok rm -f '@{@}' \;
@end example
-If you don't want to be asked, perhaps because the file name may
-contain a strange character sequence that will mess up your screen
-when printed, then use @samp{-execdir} instead of @samp{-okdir}.
+If you don't want to be asked, perhaps because the file name may contain
+a strange character sequence that will mess up your screen when printed,
+then use @samp{-exec} instead of @samp{-ok}.
-If you want to rename the file instead, you can use @code{mv} instead
-of @code{rm}:
+If you want to rename the file instead, you can use @code{mv} instead of
+@code{rm}:
@example
-find . -maxdepth 1 -inum 12345 -okdir mv '@{@}' @var{new-file-name} \;
+find . -maxdepth 1 -inum 12345 -ok mv '@{@}' @var{new-file-name} \;
@end example
@node Fixing Permissions
@section Fixing Permissions
-Suppose you want to make sure that everyone can write to the
-directories in a certain directory tree. Here is a way to find
-directories lacking either user or group write permission (or both),
-and fix their permissions:
+Suppose you want to make sure that everyone can write to the directories in a
+certain directory tree. Here is a way to find directories lacking either
+user or group write permission (or both), and fix their permissions:
@example
find . -type d -not -perm -ug=w | xargs chmod ug+w
@@ -4002,1264 +1817,383 @@ echo "Directories with search permissions for everyone:"
cat allexec
@end example
-@code{find} has only to make one scan through the directory tree
-(which is one of the most time consuming parts of its work).
-
-@node Worked Examples
-@chapter Worked Examples
+@code{find} has only to make one scan through the directory tree (which
+is one of the most time consuming parts of its work).
-The tools in the findutils package, and in particular @code{find},
-have a large number of options. This means that quite often,
-there is more than one way to do things. Some of the options
-and facilities only exist for compatibility with other tools, and
-findutils provides improved ways of doing things.
+@node Databases, File Permissions, Common Tasks, Top
+@chapter File Name Databases
-This chapter describes a number of useful tasks that are commonly
-performed, and compares the different ways of achieving them.
+The file name databases used by @code{locate} contain lists of files
+that were in particular directory trees when the databases were last
+updated. The file name of the default database is determined when
+@code{locate} and @code{updatedb} are configured and installed. The
+frequency with which the databases are updated and the directories for
+which they contain entries depend on how often @code{updatedb} is run,
+and with which arguments.
@menu
-* Deleting Files::
-* Copying A Subset of Files::
-* Updating A Timestamp File::
+* Database Locations::
+* Database Formats::
@end menu
-@node Deleting Files
-@section Deleting Files
-
-One of the most common tasks that @code{find} is used for is locating
-files that can be deleted. This might include:
-
-@itemize
-@item
-Files last modified more than 3 years ago which haven't been accessed
-for at least 2 years
-@item
-Files belonging to a certain user
-@item
-Temporary files which are no longer required
-@end itemize
-
-This example concentrates on the actual deletion task rather than on
-sophisticated ways of locating the files that need to be deleted.
-We'll assume that the files we want to delete are old files underneath
-@file{/var/tmp/stuff}.
-
-@subsection The Traditional Way
-
-The traditional way to delete files in @file{/var/tmp/stuff} that have
-not been modified in over 90 days would have been:
-
-@smallexample
-find /var/tmp/stuff -mtime +90 -exec /bin/rm @{@} \;
-@end smallexample
-
-The above command uses @samp{-exec} to run the @code{/bin/rm} command
-to remove each file. This approach works and in fact would have
-worked in Version 7 Unix in 1979. However, there are a number of
-problems with this approach.
-
-
-The most obvious problem with the approach above is that it causes
-@code{find} to fork every time it finds a file that needs to delete,
-and the child process then has to use the @code{exec} system call to
-launch @code{/bin/rm}. All this is quite inefficient. If we are
-going to use @code{/bin/rm} to do this job, it is better to make it
-delete more than one file at a time.
-
-The most obvious way of doing this is to use the shell's command
-expansion feature:
-
-@smallexample
-/bin/rm `find /var/tmp/stuff -mtime +90 -print`
-@end smallexample
-or you could use the more modern form
-@smallexample
-/bin/rm $(find /var/tmp/stuff -mtime +90 -print)
-@end smallexample
-
-The commands above are much more efficient than the first attempt.
-However, there is a problem with them. The shell has a maximum
-command length which is imposed by the operating system (the actual
-limit varies between systems). This means that while the command
-expansion technique will usually work, it will suddenly fail when
-there are lots of files to delete. Since the task is to delete
-unwanted files, this is precisely the time we don't want things to go
-wrong.
-
-@subsection Making Use of xargs
-
-So, is there a way to be more efficient in the use of @code{fork()}
-and @code{exec()} without running up against this limit?
-Yes, we can be almost optimally efficient by making use
-of the @code{xargs} command. The @code{xargs} command reads arguments
-from its standard input and builds them into command lines. We can
-use it like this:
-
-@smallexample
-find /var/tmp/stuff -mtime +90 -print | xargs /bin/rm
-@end smallexample
-
-For example if the files found by @code{find} are
-@file{/var/tmp/stuff/A},
-@file{/var/tmp/stuff/B} and
-@file{/var/tmp/stuff/C} then @code{xargs} might issue the commands
-
-@smallexample
-/bin/rm /var/tmp/stuff/A /var/tmp/stuff/B
-/bin/rm /var/tmp/stuff/C
-@end smallexample
-
-The above assumes that @code{xargs} has a very small maximum command
-line length. The real limit is much larger but the idea is that
-@code{xargs} will run @code{/bin/rm} as many times as necessary to get
-the job done, given the limits on command line length.
-
-This usage of @code{xargs} is pretty efficient, and the @code{xargs}
-command is widely implemented (all modern versions of Unix offer it).
-So far then, the news is all good. However, there is bad news too.
-
-@subsection Unusual characters in filenames
-
-Unix-like systems allow any characters to appear in file names with
-the exception of the ASCII NUL character and the backslash.
-Backslashes can occur in path names (as the directory separator) but
-not in the names of actual directory entries. This means that the
-list of files that @code{xargs} reads could in fact contain white space
-characters --- spaces, tabs and newline characters. Since by default,
-@code{xargs} assumes that the list of files it is reading uses white
-space as an argument separator, it cannot correctly handle the case
-where a filename actually includes white space. This makes the
-default behaviour of @code{xargs} almost useless for handling
-arbitrary data.
-
-To solve this problem, GNU findutils introduced the @samp{-print0}
-action for @code{find}. This uses the ASCII NUL character to separate
-the entries in the file list that it produces. This is the ideal
-choice of separator since it is the only character that cannot appear
-within a path name. The @samp{-0} option to @code{xargs} makes it
-assume that arguments are separated with ASCII NUL instead of white
-space. It also turns off another misfeature in the default behaviour
-of @code{xargs}, which is that it pays attention to quote characters
-in its input. Some versions of @code{xargs} also terminate when they
-see a lone @samp{_} in the input, but GNU @code{find} no longer does
-that (since it has become an optional behaviour in the Unix standard).
-
-So, putting @code{find -print0} together with @code{xargs -0} we get
-this command:
-
-@smallexample
-find /var/tmp/stuff -mtime +90 -print0 | xargs -0 /bin/rm
-@end smallexample
-
-The result is an efficient way of proceeding that
-correctly handles all the possible characters that could appear in the
-list of files to delete. This is good news. However, there is, as
-I'm sure you're expecting, also more bad news. The problem is that
-this is not a portable construct; although other versions of Unix
-(notably BSD-derived ones) support @samp{-print0}, it's not
-universal. So, is there a more universal mechanism?
-
-@subsection Going back to -exec
-
-There is indeed a more universal mechanism, which is a slight
-modification to the @samp{-exec} action. The normal @samp{-exec}
-action assumes that the command to run is terminated with a semicolon
-(the semicolon normally has to be quoted in order to protect it from
-interpretation as the shell command separator). The SVR4 edition of
-Unix introduced a slight variation, which involves terminating the
-command with @samp{+} instead:
-
-@smallexample
-find /var/tmp/stuff -mtime +90 -exec /bin/rm @{@} \+
-@end smallexample
-
-The above use of @samp{-exec} causes @code{find} to build up a long
-command line and then issue it. This can be less efficient than some
-uses of @code{xargs}; for example @code{xargs} allows new command
-lines to be built up while the previous command is still executing, and
-allows you to specify a number of commands to run in parallel.
-However, the @code{find @dots{} -exec @dots{} +} construct has the advantage
-of wide portability. GNU findutils did not support @samp{-exec @dots{} +}
-until version 4.2.12; one of the reasons for this is that it already
-had the @samp{-print0} action in any case.
-
-
-@subsection A more secure version of -exec
-
-The command above seems to be efficient and portable. However,
-within it lurks a security problem. The problem is shared with
-all the commands we've tried in this worked example so far, too. The
-security problem is a race condition; that is, if it is possible for
-somebody to manipulate the filesystem that you are searching while you
-are searching it, it is possible for them to persuade your @code{find}
-command to cause the deletion of a file that you can delete but they
-normally cannot.
-
-The problem occurs because the @samp{-exec} action is defined by the
-@acronym{POSIX} standard to invoke its command with the same working directory
-as @code{find} had when it was started. This means that the arguments
-which replace the @{@} include a relative path from @code{find}'s
-starting point down the file that needs to be deleted. For example,
-
-@smallexample
-find /var/tmp/stuff -mtime +90 -exec /bin/rm @{@} \+
-@end smallexample
-
-might actually issue the command:
-
-@smallexample
-/bin/rm /var/tmp/stuff/A /var/tmp/stuff/B /var/tmp/stuff/passwd
-@end smallexample
-
-Notice the file @file{/var/tmp/stuff/passwd}. Likewise, the command:
-
-@smallexample
-cd /var/tmp && find stuff -mtime +90 -exec /bin/rm @{@} \+
-@end smallexample
-
-might actually issue the command:
-
-@smallexample
-/bin/rm stuff/A stuff/B stuff/passwd
-@end smallexample
-
-If an attacker can rename @file{stuff} to something else (making use
-of their write permissions in @file{/var/tmp}) they can replace it
-with a symbolic link to @file{/etc}. That means that the
-@code{/bin/rm} command will be invoked on @file{/etc/passwd}. If you
-are running your @code{find} command as root, the attacker has just managed
-to delete a vital file. All they needed to do to achieve this was
-replace a subdirectory with a symbolic link at the vital moment.
-
-There is however, a simple solution to the problem. This is an action
-which works a lot like @code{-exec} but doesn't need to traverse a
-chain of directories to reach the file that it needs to work on. This
-is the @samp{-execdir} action, which was introduced by the BSD family
-of operating systems. The command,
-
-@smallexample
-find /var/tmp/stuff -mtime +90 -execdir /bin/rm @{@} \+
-@end smallexample
-
-might delete a set of files by performing these actions:
-
-@enumerate
-@item
-Change directory to /var/tmp/stuff/foo
-@item
-Invoke @code{/bin/rm ./file1 ./file2 ./file3}
-@item
-Change directory to /var/tmp/stuff/bar
-@item
-Invoke @code{/bin/rm ./file99 ./file100 ./file101}
-@end enumerate
-
-This is a much more secure method. We are no longer exposed to a race
-condition. For many typical uses of @code{find}, this is the best
-strategy. It's reasonably efficient, but the length of the command
-line is limited not just by the operating system limits, but also by
-how many files we actually need to delete from each directory.
-
-Is it possible to do any better? In the case of general file
-processing, no. However, in the specific case of deleting files it is
-indeed possible to do better.
-
-@subsection Using the -delete action
-
-The most efficient and secure method of solving this problem is to use
-the @samp{-delete} action:
-
-@smallexample
-find /var/tmp/stuff -mtime +90 -delete
-@end smallexample
-
-This alternative is more efficient than any of the @samp{-exec} or
-@samp{-execdir} actions, since it entirely avoids the overhead of
-forking a new process and using @code{exec} to run @code{/bin/rm}. It
-is also normally more efficient than @code{xargs} for the same
-reason. The file deletion is performed from the directory containing
-the entry to be deleted, so the @samp{-delete} action has the same
-security advantages as the @samp{-execdir} action has.
-
-The @samp{-delete} action was introduced by the BSD family of
-operating systems.
-
-@subsection Improving things still further
-
-Is it possible to improve things still further? Not without either
-modifying the system library to the operating system or having more specific
-knowledge of the layout of the filesystem and disk I/O subsystem, or
-both.
+@node Database Locations
+@section Database Locations
-The @code{find} command traverses the filesystem, reading
-directories. It then issues a separate system call for each file to
-be deleted. If we could modify the operating system, there are
-potential gains that could be made:
+There can be multiple file name databases. Users can select which
+databases @code{locate} searches using an environment variable or a
+command line option. The system administrator can choose the file name
+of the default database, the frequency with which the databases are
+updated, and the directories for which they contain entries. File name
+databases are updated by running the @code{updatedb} program, typically
+nightly.
-@itemize
-@item
-We could have a system call to which we pass more than one filename
-for deletion
-@item
-Alternatively, we could pass in a list of inode numbers (on GNU/Linux
-systems, @code{readdir()} also returns the inode number of each
-directory entry) to be deleted.
-@end itemize
+In networked environments, it often makes sense to build a database at
+the root of each filesystem, containing the entries for that filesystem.
+@code{updatedb} is then run for each filesystem on the fileserver where
+that filesystem is on a local disk, to prevent thrashing the network.
+Here are the options to @code{updatedb} to select which directories each
+database contains entries for:
-The above possibilities sound interesting, but from the kernel's point
-of view it is difficult to enforce standard Unix access controls for
-such processing by inode number. Such a facility would probably
-need to be restricted to the superuser.
+@table @code
+@item --localpaths='@var{path}@dots{}'
+Non-network directories to put in the database.
+Default is @file{/}.
-Another way of improving performance would be to increase the
-parallelism of the process. For example if the directory hierarchy we
-are searching is actually spread across a number of disks, we might
-somehow be able to arrange for @code{find} to process each disk in
-parallel. In practice GNU @code{find} doesn't have such an intimate
-understanding of the system's filesystem layout and disk I/O
-subsystem.
+@item --netpaths='@var{path}@dots{}'
+Network (NFS, AFS, RFS, etc.) directories to put in the database.
+Default is none.
-However, since the system administrator can have such an understanding
-they can take advantage of it like so:
+@item --prunepaths='@var{path}@dots{}'
+Directories to not put in the database, which would otherwise be.
+Default is @file{/tmp /usr/tmp /var/tmp /afs}.
-@smallexample
-find /var/tmp/stuff1 -mtime +90 -delete &
-find /var/tmp/stuff2 -mtime +90 -delete &
-find /var/tmp/stuff3 -mtime +90 -delete &
-find /var/tmp/stuff4 -mtime +90 -delete &
-wait
-@end smallexample
+@item --output=@var{dbfile}
+The database file to build.
+Default is system-dependent, but typically @file{/usr/local/var/locatedb}.
-In the example above, four separate instances of @code{find} are used
-to search four subdirectories in parallel. The @code{wait} command
-simply waits for all of these to complete. Whether this approach is
-more or less efficient than a single instance of @code{find} depends
-on a number of things:
+@item --netuser=@var{user}
+The user to search network directories as, using @code{su}.
+Default is @code{daemon}.
+@end table
-@itemize
-@item
-Are the directories being searched in parallel actually on separate
-disks? If not, this parallel search might just result in a lot of
-disk head movement and so the speed might even be slower.
-@item
-Other activity - are other programs also doing things on those disks?
-@end itemize
+@node Database Formats
+@section Database Formats
+The file name databases contain lists of files that were in particular
+directory trees when the databases were last updated. The file name
+database format changed starting with GNU @code{locate} version 4.0 to
+allow machines with diffent byte orderings to share the databases. The
+new GNU @code{locate} can read both the old and new database formats.
+However, old versions of @code{locate} and @code{find} produce incorrect
+results if given a new-format database.
-@subsection Conclusion
+@menu
+* New Database Format::
+* Sample Database::
+* Old Database Format::
+@end menu
-The fastest and most secure way to delete files with the help of
-@code{find} is to use @samp{-delete}. Using @code{xargs -0 -P N} can
-also make effective use of the disk, but it is not as secure.
+@node New Database Format
+@subsection New Database Format
-In the case where we're doing things other than deleting files, the
-most secure alternative is @samp{-execdir @dots{} +}, but this is not as
-portable as the insecure action @samp{-exec @dots{} +}.
+@code{updatedb} runs a program called @code{frcode} to
+@dfn{front-compress} the list of file names, which reduces the database
+size by a factor of 4 to 5. Front-compression (also known as
+incremental encoding) works as follows.
-The @samp{-delete} action is not completely portable, but the only
-other possibility which is as secure (@samp{-execdir}) is no more
-portable. The most efficient portable alternative is @samp{-exec
-@dots{}+}, but this is insecure and isn't supported by versions of GNU
-findutils prior to 4.2.12.
+The database entries are a sorted list (case-insensitively, for users'
+convenience). Since the list is sorted, each entry is likely to share a
+prefix (initial string) with the previous entry. Each database entry
+begins with an offset-differential count byte, which is the additional
+number of characters of prefix of the preceding entry to use beyond the
+number that the preceding entry is using of its predecessor. (The
+counts can be negative.) Following the count is a null-terminated ASCII
+remainder---the part of the name that follows the shared prefix.
+
+If the offset-differential count is larger than can be stored in a byte
+(+/-127), the byte has the value 0x80 and the count follows in a 2-byte
+word, with the high byte first (network byte order).
-@node Copying A Subset of Files
-@section Copying A Subset of Files
+Every database begins with a dummy entry for a file called
+@file{LOCATE02}, which @code{locate} checks for to ensure that the
+database file has the correct format; it ignores the entry in doing the
+search.
-Suppose you want to copy some files from @file{/source-dir} to
-@file{/dest-dir}, but there are a small number of files in
-@file{/source-dir} you don't want to copy.
+Databases can not be concatenated together, even if the first (dummy)
+entry is trimmed from all but the first database. This is because the
+offset-differential count in the first entry of the second and following
+databases will be wrong.
-One option of course is @code{cp /source-dir /dest-dir} followed by
-deletion of the unwanted material under @file{/dest-dir}. But often
-that can be inconvenient, because for example we would have copied a
-large amount of extraneous material, or because @file{/dest-dir} is
-too small. Naturally there are many other possible reasons why this
-strategy may be unsuitable.
+@node Sample Database
+@subsection Sample Database
-So we need to have some way of identifying which files we want to
-copy, and we need to have a way of copying that file list. The second
-part of this condition is met by @code{cpio -p}. Of course, we can
-identify the files we wish to copy by using @code{find}. Here is a
-command that solves our problem:
+Sample input to @code{frcode}:
+@c with nulls changed to newlines:
@example
-cd /source-dir
-find . -name '.snapshot' -prune -o \( \! -name '*~' -print0 \) |
-cpio -pmd0 /dest-dir
+/usr/src
+/usr/src/cmd/aardvark.c
+/usr/src/cmd/armadillo.c
+/usr/tmp/zoo
@end example
-The first part of the @code{find} command here identifies files or
-directoires named @file{.snapshot} and tells @code{find} not to
-recurse into them (since they do not need to be copied). The
-combination @code{-name '.snapshot' -prune} yields false for anything
-that didn't get pruned, but it is exactly those files we want to
-copy. Therefore we need to use an OR (@samp{-o}) condition to
-introduce the rest of our expression. The remainder of the expression
-simply arranges for the name of any file not ending in @samp{~} to be
-printed.
-
-Using @code{-print0} ensures that white space characters in file names
-do not pose a problem. The @code{cpio} command does the actual work
-of copying files. The program as a whole fails if the @code{cpio}
-program returns nonzero. If the @code{find} command returns non-zero
-on the other hand, the Unix shell will not diagnose a problem (since
-@code{find} is not the last command in the pipeline).
-
-
-@node Updating A Timestamp File
-@section Updating A Timestamp File
-
-Suppose we have a directory full of files which is maintained with a
-set of automated tools; perhaps one set of tools updates them and
-another set of tools uses the result. In this situation, it might be
-useful for the second set of tools to know if the files have recently
-been changed. It might be useful, for example, to have a 'timestamp'
-file which gives the timestamp on the newest file in the collection.
-
-We can use @code{find} to achieve this, but there are several
-different ways to do it.
-
-@subsection Updating the Timestamp The Wrong Way
-
-The obvious but wrong answer is just to use @samp{-newer}:-
-
-@smallexample
-find subdir -newer timestamp -exec touch -r @{@} timestamp \;
-@end smallexample
-
-This does the right sort of thing but has a bug. Suppose that two
-files in the subdirectory have been updated, and that these are called
-@file{file1} and @file{file2}. The command above will update
-@file{timestamp} with the modification time of @file{file1} or that of
-@file{file2}, but we don't know which one. Since the timestamps on
-@file{file1} and @file{file2} will in general be different, this could
-well be the wrong value.
-
-One solution to this problem is to modify @code{find} to recheck the
-modification time of @file{timestamp} every time a file is to be
-compared against it, but that will reduce the performance of
-@code{find}.
-
-@subsection Using the test utility to compare timestamps
-
-The @code{test} command can be used to compare timestamps:
-
-@smallexample
-find subdir -exec test @{@} -nt timestamp \; -exec touch -r @{@} timestamp \;
-@end smallexample
-
-This will ensure that any changes made to the modification time of
-@file{timestamp} that take place during the execution of @code{find}
-are taken into account. This resolves our earlier problem, but
-unfortunately this runs much more slowly.
-
-@subsection A combined approach
-
-We can of course still use @samp{-newer} to cut down on the number of
-calls to @code{test}:
-
-@smallexample
-find subdir -newer timestamp -a \
- -exec test @{@} -nt timestamp \; -a \
- -exec touch -r @{@} timestamp \;
-@end smallexample
-
-Here, the @samp{-newer} test excludes all the files which are
-definitely older than the timestamp, but all the files which are newer
-than the old value of the timestamp are compared against the current
-updated timestamp.
-
-This is indeed faster in general, but the speed difference will depend
-on how many updated files there are.
-
-@subsection Using -printf and sort to compare timestamps
-
-It is possible to use the @samp{-printf} action to abandon the use of
-@code{test} entirely:
-
-@smallexample
-newest=$(find subdir -newer timestamp -printf "%A@:%p\n" |
- sort -n |
- tail -1 |
- cut -d: -f2- )
-touch -r "$@{newest:-timestamp@}" timestamp
-@end smallexample
-
-The command above works by generating a list of the timestamps and
-names of all the files which are newer than the timestamp. The
-@code{sort}, @code{tail} and @code{cut} commands simply pull out the
-name of the file with the largest timestamp value (that is, the latest
-file). The @code{touch} command is then used to update the timestamp,
-
-The @code{"$@{newest:-timestamp@}"} expression simply expands to the
-value of @code{$newest} if that variable is set, but to
-@file{timestamp} otherwise. This ensures that an argument is always
-given to the @samp{-r} option of the @code{touch} command.
-
-This approach seems quite efficient, but unfortunately it has a
-problem. Many operating systems now keep file modification time
-information at a granularity which is finer than one second.
-Findutils version 4.3.3 and later will print a fractional part with
-%A@@, but older versions will not.
-
-
-@subsection Solving the problem with make
-
-Another tool which often works with timestamps is @code{make}. We can
-use @code{find} to generate a @file{Makefile} file on the fly and then
-use @code{make} to update the timestamps:
-
-@smallexample
-makefile=$(mktemp)
-find subdir \
- \( \! -xtype l \) \
- -newer timestamp \
- -printf "timestamp:: %p\n\ttouch -r %p timestamp\n\n" > "$makefile"
-make -f "$makefile"
-rm -f "$makefile"
-@end smallexample
-
-Unfortunately although the solution above is quite elegant, it fails
-to cope with white space within file names, and adjusting it to do so
-would require a rather complex shell script.
-
-
-@subsection Coping with odd filenames too
-
-We can fix both of these problems (looping and problems with white
-space), and do things more efficiently too. The following command
-works with newlines and doesn't need to sort the list of filenames.
-
-@smallexample
-find subdir -newer timestamp -printf "%A@@:%p\0" |
- perl -0 newest.pl |
- xargs --no-run-if-empty --null -i \
- find @{@} -maxdepth 0 -newer timestamp -exec touch -r @{@} timestamp \;
-@end smallexample
-
-The first @code{find} command generates a list of files which are
-newer than the original timestamp file, and prints a list of them with
-their timestamps. The @file{newest.pl} script simply filters out all
-the filenames which have timestamps which are older than whatever the
-newest file is:-
-
-@smallexample
-@verbatim
-#! /usr/bin/perl -0
-my @newest = ();
-my $latest_stamp = undef;
-while (<>) {
- my ($stamp, $name) = split(/:/);
- if (!defined($latest_stamp) || ($tstamp > $latest_stamp)) {
- $latest_stamp = $stamp;
- @newest = ();
- }
- if ($tstamp >= $latest_stamp) {
- push @newest, $name;
- }
-}
-print join("\0", @newest);
-@end verbatim
-@end smallexample
-
-This prints a list of zero or more files, all of which are newer than
-the original timestamp file, and which have the same timestamp as each
-other, to the nearest second. The second @code{find} command takes
-each resulting file one at a time, and if that is newer than the
-timestamp file, the timestamp is updated.
-
-@node Security Considerations
-@chapter Security Considerations
-
-Security considerations are important if you are using @code{find} or
-@code{xargs} to search for or process files that don't belong to you
-or which other people have control. Security considerations
-relating to @code{locate} may also apply if you have files which you
-do not want others to see.
-
-The most severe forms of security problems affecting
-@code{find} and related programs are when third parties bring
-about a situation allowing them to do something
-they would normally not be able to accomplish. This is called @emph{privilege
-elevation}. This might include deleting files they would not normally
-be able to delete. It is common for the operating system to periodically
-invoke @code{find} for self-maintenance purposes. These invocations of
-@code{find} are particularly problematic from a security point of view
-as these are often invoked by the superuser and search the entire
-filesystem hierarchy. Generally, the severity of any associated problem depends
-on what the system is going to do with the files found by @code{find}.
-
-@menu
-* Levels of Risk:: What is your level of exposure to security problems?
-* Security Considerations for find:: Security problems with find
-* Security Considerations for xargs:: Security problems with xargs
-* Security Considerations for locate:: Security problems with locate
-* Security Summary:: That was all very complex, what does it boil down to?
-@end menu
-
-
-@node Levels of Risk
-@section Levels of Risk
-
-There are some security risks inherent in the use of @code{find},
-@code{xargs} and (to a lesser extent) @code{locate}. The severity of
-these risks depends on what sort of system you are using:
-
-@table @strong
-@item High risk
-Multi-user systems where you do not control (or trust) the other
-users, and on which you execute @code{find}, including areas where
-those other users can manipulate the filesystem (for example beneath
-@file{/home} or @file{/tmp}).
-
-@item Medium Risk
-Systems where the actions of other users can create file names chosen
-by them, but to which they don't have access while @code{find} is
-being run. This access might include leaving programs running (shell
-background jobs, @code{at} or @code{cron} tasks, for example). On
-these sorts of systems, carefully written commands (avoiding use of
-@samp{-print} for example) should not expose you to a high degree of
-risk. Most systems fall into this category.
-
-@item Low Risk
-Systems to which untrusted parties do not have access, cannot create
-file names of their own choice (even remotely) and which contain no
-security flaws which might enable an untrusted third party to gain
-access. Most systems do not fall into this category because there are
-many ways in which external parties can affect the names of files that
-are created on your system. The system on which I am writing this for
-example automatically downloads software updates from the Internet;
-the names of the files in which these updates exist are chosen by
-third parties@footnote{Of course, I trust these parties to a large
-extent anyway, because I install software provided by them; I choose
-to trust them in this way, and that's a deliberate choice}.
-@end table
-
-In the discussion above, ``risk'' denotes the likelihood that someone
-can cause @code{find}, @code{xargs}, @code{locate} or some other
-program which is controlled by them to do something you did not
-intend. The levels of risk suggested do not take any account of the
-consequences of this sort of event. That is, if you operate a ``low
-risk'' type system, but the consequences of a security problem are
-disastrous, then you should still give serious thought to all the
-possible security problems, many of which of course will not be
-discussed here -- this section of the manual is intended to be
-informative but not comprehensive or exhaustive.
-
-If you are responsible for the operation of a system where the
-consequences of a security problem could be very important, you should
-do two things:-
+Length of the longest prefix of the preceding entry to share:
-@enumerate
-@item Define a security policy which defines who is allowed to do what
-on your system.
-@item Seek competent advice on how to enforce your policy, detect
-breaches of that policy, and take account of any potential problems
-that might fall outside the scope of your policy.
-@end enumerate
+@example
+0 /usr/src
+8 /cmd/aardvark.c
+14 rmadillo.c
+5 tmp/zoo
+@end example
+Output from @code{frcode}, with trailing nulls changed to newlines
+and count bytes made printable:
-@node Security Considerations for find
-@section Security Considerations for @code{find}
+@example
+0 LOCATE02
+0 /usr/src
+8 /cmd/aardvark.c
+6 rmadillo.c
+-9 tmp/zoo
+@end example
+(6 = 14 - 8, and -9 = 5 - 14)
-Some of the actions @code{find} might take have a direct effect;
-these include @code{-exec} and @code{-delete}. However, it is also
-common to use @code{-print} explicitly or implicitly, and so if
-@code{find} produces the wrong list of file names, that can also be a
-security problem; consider the case for example where @code{find} is
-producing a list of files to be deleted.
+@node Old Database Format
+@subsection Old Database Format
-We normally assume that the @code{find} command line expresses the
-file selection criteria and actions that the user had in mind -- that
-is, the command line is ``trusted'' data.
+The old database format is used by Unix @code{locate} and @code{find}
+programs and earlier releases of the GNU ones. @code{updatedb} produces
+this format if given the @samp{--old-format} option.
-From a security analysis point of view, the output of @code{find}
-should be correct; that is, the output should contain only the names
-of those files which meet the user's criteria specified on the command
-line. This applies for the @code{-exec} and @code{-delete} actions;
-one can consider these to be part of the output.
+@code{updatedb} runs programs called @code{bigram} and @code{code} to
+produce old-format databases. The old format differs from the new one
+in the following ways. Instead of each entry starting with an
+offset-differential count byte and ending with a null, byte values from
+0 through 28 indicate offset-differential counts from -14 through 14.
+The byte value indicating that a long offset-differential count follows
+is 0x1e (30), not 0x80. The long counts are stored in host byte order,
+which is not necessarily network byte order, and host integer word size,
+which is usually 4 bytes. They also represent a count 14 less than
+their value. The database lines have no termination byte; the start of
+the next line is indicated by its first byte having a value <= 30.
-On the other hand, the contents of the filesystem can be manipulated
-by other people, and hence we regard this as ``untrusted'' data. This
-implies that the @code{find} command line is a filter which converts
-the untrusted contents of the filesystem into a correct list of output
-files.
+In addition, instead of starting with a dummy entry, the old database
+format starts with a 256 byte table containing the 128 most common
+bigrams in the file list. A bigram is a pair of adjacent bytes. Bytes
+in the database that have the high bit set are indexes (with the high
+bit cleared) into the bigram table. The bigram and offset-differential
+count coding makes these databases 20-25% smaller than the new format,
+but makes them not 8-bit clean. Any byte in a file name that is in the
+ranges used for the special codes is replaced in the database by a
+question mark, which not coincidentally is the shell wildcard to match a
+single character.
+
+@node File Permissions, Reference, Databases, Top
+@chapter File Permissions
-The filesystem will in general change while @code{find} is searching
-it; in fact, most of the potential security problems with @code{find}
-relate to this issue in some way.
+@include perm.texi
-@dfn{Race conditions} are a general class of security problem where the
-relative ordering of actions taken by @code{find} (for example) and
-something else are critically important in getting the correct and expected result@footnote{This is more or less the
-definition of the term ``race condition''} .
+@node Reference, Primary Index, File Permissions, Top
+@chapter Reference
-For @code{find}, an attacker might move or rename files or directories in
-the hope that an action might be taken against a file which was not
-normally intended to be affected. Alternatively, this sort of attack
-might be intended to persuade @code{find} to search part of the
-filesystem which would not normally be included in the search
-(defeating the @code{-prune} action for example).
+Below are summaries of the command line syntax for the programs
+discussed in this manual.
@menu
-* Problems with -exec and filenames::
-* Changing the Current Working Directory::
-* Race Conditions with -exec::
-* Race Conditions with -print and -print0::
+* Invoking find::
+* Invoking locate::
+* Invoking updatedb::
+* Invoking xargs::
@end menu
-@node Problems with -exec and filenames
-@subsection Problems with -exec and filenames
-
-It is safe in many cases to use the @samp{-execdir} action with any
-file name. Because @samp{-execdir} prefixes the arguments it passes
-to programs with @samp{./}, you will not accidentally pass an argument
-which is interpreted as an option. For example the file @file{-f}
-would be passed to @code{rm} as @file{./-f}, which is harmless.
-
-However, your degree of safety does depend on the nature of the
-program you are running. For example constructs such as these two commands
-
-@example
-# risky
-find -exec sh -c "something @{@}" \;
-find -execdir sh -c "something @{@}" \;
-@end example
-
-are very dangerous. The reason for this is that the @samp{@{@}} is
-expanded to a filename which might contain a semicolon or other
-characters special to the shell. If for example someone creates the
-file @file{/tmp/foo; rm -rf $HOME} then the two commands above could
-delete someone's home directory.
-
-So for this reason do not run any command which will pass untrusted
-data (such as the names of files) to commands which interpret
-arguments as commands to be further interpreted (for example
-@samp{sh}).
-
-In the case of the shell, there is a clever workaround for this
-problem:
+@node Invoking find, Invoking locate, , Reference
+@section Invoking @code{find}
@example
-# safer
-find -exec sh -c 'something "$@@"' @{@} \;
-find -execdir sh -c 'something "$@@"' @{@}\;
+find @r{[}@var{file}@dots{}@r{]} @r{[}@var{expression}@r{]}
@end example
-This approach is not guaranteed to avoid every problem, but it is much
-safer than substituting data of an attacker's choice into the text of
-a shell command.
-
-@node Changing the Current Working Directory
-@subsection Changing the Current Working Directory
-
-As @code{find} searches the filesystem, it finds subdirectories and
-then searches within them by changing its working directory. First,
-@code{find} reaches and recognises a subdirectory. It then decides if that
-subdirectory meets the criteria for being searched; that is, any
-@samp{-xdev} or @samp{-prune} expressions are taken into account. The
-@code{find} program will then change working directory and proceed to
-search the directory.
-
-A race condition attack might take the form that once the checks
-relevant to @samp{-xdev} and @samp{-prune} have been done, an attacker
-might rename the directory that was being considered, and put in its
-place a symbolic link that actually points somewhere else.
-
-The idea behind this attack is to fool @code{find} into going into the
-wrong directory. This would leave @code{find} with a working
-directory chosen by an attacker, bypassing any protection apparently
-provided by @samp{-xdev} and @samp{-prune}, and any protection
-provided by being able to @emph{not} list particular directories on
-the @code{find} command line. This form of attack is particularly
-problematic if the attacker can predict when the @code{find} command
-will be run, as is the case with @code{cron} tasks for example.
-
-GNU @code{find} has specific safeguards to prevent this general class
-of problem. The exact form of these safeguards depends on the
-properties of your system.
-
-@menu
-* O_NOFOLLOW:: Safely changing directory using fchdir().
-* Systems without O_NOFOLLOW:: Checking for symbolic links after chdir().
-@end menu
-
-@node O_NOFOLLOW
-@subsubsection O_NOFOLLOW
+@code{find} searches the directory tree rooted at each file name
+@var{file} by evaluating the @var{expression} on each file it finds in
+the tree.
-If your system supports the O_NOFOLLOW flag @footnote{GNU/Linux
-(kernel version 2.1.126 and later) and FreeBSD (3.0-CURRENT and later)
-support this} to the @code{open(2)} system call, @code{find} uses it
-when safely changing directory. The target directory is first opened
-and then @code{find} changes working directory with the
-@code{fchdir()} system call. This ensures that symbolic links are not
-followed, preventing the sort of race condition attack in which use
-is made of symbolic links.
+@code{find} considers the first argument that begins with @samp{-},
+@samp{(}, @samp{)}, @samp{,}, or @samp{!} to be the beginning of the
+expression; any arguments before it are paths to search, and any
+arguments after it are the rest of the expression. If no paths are
+given, the current directory is used. If no expression is given, the
+expression @samp{-print} is used.
-If for any reason this approach does not work, @code{find} will fall
-back on the method which is normally used if O_NOFOLLOW is not
-supported.
+@code{find} exits with status 0 if all files are processed successfully,
+greater than 0 if errors occur.
-You can tell if your system supports O_NOFOLLOW by running
+@xref{Primary Index}, for a summary of all of the tests, actions, and
+options that the expression can contain.
-@example
-find --version
-@end example
+@code{find} also recognizes two options for administrative use:
-This will tell you the version number and which features are enabled.
-For example, if I run this on my system now, this gives:
-@example
-GNU find version 4.2.18-CVS
-Features enabled: D_TYPE O_NOFOLLOW(enabled)
-@end example
+@table @code
+@item --help
+Print a summary of the command-line argument format and exit.
+@item --version
+Print the version number of @code{find} and exit.
+@end table
-Here, you can see that I am running a version of @code{find} which was
-built from the development (CVS) code prior to the release of
-findutils-4.2.18, and that the D_TYPE and O_NOFOLLOW features are
-present. O_NOFOLLOW is qualified with ``enabled''. This simply means
-that the current system seems to support O_NOFOLLOW. This check is
-needed because it is possible to build @code{find} on a system that
-defines O_NOFOLLOW and then run it on a system that ignores the
-O_NOFOLLOW flag. We try to detect such cases at startup by checking
-the operating system and version number; when this happens you will
-see ``O_NOFOLLOW(disabled)'' instead.
-
-@node Systems without O_NOFOLLOW
-@subsubsection Systems without O_NOFOLLOW
-
-The strategy for preventing this type of problem on systems that lack
-support for the O_NOFOLLOW flag is more complex. Each time
-@code{find} changes directory, it examines the directory it is about
-to move to, issues the @code{chdir()} system call, and then checks
-that it has ended up in the subdirectory it expected. If all is as
-expected, processing continues as normal. However, there are two main
-reasons why the directory might change: the use of an automounter and
-the someone removing the old directory and replacing it with something
-else while @code{find} is trying to descend into it.
-
-Where a filesystem ``automounter'' is in use it can be the case that
-the use of the @code{chdir()} system call can itself cause a new
-filesystem to be mounted at that point. On systems that do not
-support O_NOFOLLOW, this will cause @code{find}'s security check to
-fail.
-
-However, this does not normally represent a security problem, since
-the automounter configuration is normally set up by the system
-administrator. Therefore, if the @code{chdir()} sanity check fails,
-@code{find} will make one more attempt@footnote{This may not be the
-case for the fts-based executable}. If that succeeds, execution
-carries on as normal. This is the usual case for automounters.
-
-Where an attacker is trying to exploit a race condition, the problem
-may not have gone away on the second attempt. If this is the case,
-@code{find} will issue a warning message and then ignore that
-subdirectory. When this happens, actions such as @samp{-exec} or
-@samp{-print} may already have taken place for the problematic
-subdirectory. This is because @code{find} applies tests and actions
-to directories before searching within them (unless @samp{-depth} was
-specified).
-
-Because of the nature of the directory-change operation and security
-check, in the worst case the only things that @code{find} would have
-done with the directory are to move into it and back out to the
-original parent. No operations would have been performed within that
-directory.
-
-@node Race Conditions with -exec
-@subsection Race Conditions with -exec
-
-The @samp{-exec} action causes another program to be run. It passes
-to the program the name of the file which is being considered at the
-time. The invoked program will typically then perform some action
-on that file. Once again, there is a race condition which can be
-exploited here. We shall take as a specific example the command
+@node Invoking locate, Invoking updatedb, Invoking find, Reference
+@section Invoking @code{locate}
@example
-find /tmp -path /tmp/umsp/passwd -exec /bin/rm
+locate @r{[}@var{option}@dots{}@r{]} @var{pattern}@dots{}
@end example
-In this simple example, we are identifying just one file to be deleted
-and invoking @code{/bin/rm} to delete it. A problem exists because
-there is a time gap between the point where @code{find} decides that
-it needs to process the @samp{-exec} action and the point where the
-@code{/bin/rm} command actually issues the @code{unlink()} system
-call to delete the file from the filesystem. Within this time period, an attacker can rename the
-@file{/tmp/umsp} directory, replacing it with a symbolic link to
-@file{/etc}. There is no way for @code{/bin/rm} to determine that it
-is working on the same file that @code{find} had in mind. Once the
-symbolic link is in place, the attacker has persuaded @code{find} to
-cause the deletion of the @file{/etc/passwd} file, which is not the
-effect intended by the command which was actually invoked.
-
-One possible defence against this type of attack is to modify the
-behaviour of @samp{-exec} so that the @code{/bin/rm} command is run
-with the argument @file{./passwd} and a suitable choice of working
-directory. This would allow the normal sanity check that @code{find}
-performs to protect against this form of attack too. Unfortunately,
-this strategy cannot be used as the POSIX standard specifies that the
-current working directory for commands invoked with @samp{-exec} must
-be the same as the current working directory from which @code{find}
-was invoked. This means that the @samp{-exec} action is inherently
-insecure and can't be fixed.
-
-GNU @code{find} implements a more secure variant of the @samp{-exec}
-action, @samp{-execdir}. The @samp{-execdir} action
-ensures that it is not necessary to dereference subdirectories to
-process target files. The current directory used to invoke programs
-is the same as the directory in which the file to be processed exists
-(@file{/tmp/umsp} in our example, and only the basename of the file to
-be processed is passed to the invoked command, with a @samp{./}
-prepended (giving @file{./passwd} in our example).
-
-The @samp{-execdir} action refuses to do anything if the current
-directory is included in the @var{$PATH} environment variable. This
-is necessary because @samp{-execdir} runs programs in the same
-directory in which it finds files -- in general, such a directory
-might be writable by untrusted users. For similar reasons,
-@samp{-execdir} does not allow @samp{@{@}} to appear in the name of
-the command to be run.
-
-@node Race Conditions with -print and -print0
-@subsection Race Conditions with -print and -print0
-
-The @samp{-print} and @samp{-print0} actions can be used to produce a
-list of files matching some criteria, which can then be used with some
-other command, perhaps with @code{xargs}. Unfortunately, this means
-that there is an unavoidable time gap between @code{find} deciding
-that one or more files meet its criteria and the relevant command
-being executed. For this reason, the @samp{-print} and @samp{-print0}
-actions are just as insecure as @samp{-exec}.
-
-In fact, since the construction
-
-@example
-find @dots{} -print | xargs @enddots{}
-@end example
+@table @code
+@item --database=@var{path}
+@itemx -d @var{path}
+Instead of searching the default file name database, search the file
+name databases in @var{path}, which is a colon-separated list of
+database file names. You can also use the environment variable
+@code{LOCATE_PATH} to set the list of database files to search. The
+option overrides the environment variable if both are used.
-does not cope correctly with newlines or other ``white space'' in
-file names, and copes poorly with file names containing quotes, the
-@samp{-print} action is less secure even than @samp{-print0}.
+@item --help
+Print a summary of the options to @code{locate} and exit.
+@item --version
+Print the version number of @code{locate} and exit.
+@end table
-@comment node-name, next, previous, up
-@comment @node Security Considerations for xargs
-@node Security Considerations for xargs
-@section Security Considerations for @code{xargs}
-
-The description of the race conditions affecting the @samp{-print}
-action of @code{find} shows that @code{xargs} cannot be secure if it
-is possible for an attacker to modify a filesystem after @code{find}
-has started but before @code{xargs} has completed all its actions.
-
-However, there are other security issues that exist even if it is not
-possible for an attacker to have access to the filesystem in real
-time. Firstly, if it is possible for an attacker to create files with
-names of their choice on the filesystem, then @code{xargs} is
-insecure unless the @samp{-0} option is used. If a file with the name
-@file{/home/someuser/foo/bar\n/etc/passwd} exists (assume that
-@samp{\n} stands for a newline character), then @code{find @dots{} -print}
-can be persuaded to print three separate lines:
+@node Invoking updatedb, Invoking xargs, Invoking locate, Reference
+@section Invoking @code{updatedb}
@example
-/home/someuser/foo/bar
-
-/etc/passwd
+updatedb @r{[}@var{option}@dots{}@r{]}
@end example
-If it finds a blank line in the input, @code{xargs} will ignore it.
-Therefore, if some action is to be taken on the basis of this list of
-files, the @file{/etc/passwd} file would be included even if this was
-not the intent of the person running find. There are circumstances in
-which an attacker can use this to their advantage. The same
-consideration applies to file names containing ordinary spaces rather
-than newlines, except that of course the list of file names will no
-longer contain an ``extra'' newline.
-
-This problem is an unavoidable consequence of the default behaviour of
-the @code{xargs} command, which is specified by the POSIX standard.
-The only ways to avoid this problem are either to avoid all use of
-@code{xargs} in favour for example of @samp{find -exec} or (where
-available) @samp{find -execdir}, or to use the @samp{-0} option, which
-ensures that @code{xargs} considers file names to be separated by
-ASCII NUL characters rather than whitespace. However, useful as this
-option is, the POSIX standard does not make it mandatory.
-
-POSIX also specifies that @code{xargs} interprets quoting and trailing
-whitespace specially in filenames, too. This means that using
-@code{find ... -print | xargs ...} can cause the commands run by
-@code{xargs} to receive a list of file names which is not the same as
-the list printed by @code{find}. The interpretation of quotes and
-trailing whitespace is turned off by the @samp{-0} argument to
-@code{xargs}, which is another reason to use that option.
-
-@comment node-name, next, previous, up
-@node Security Considerations for locate
-@section Security Considerations for @code{locate}
-
-@subsection Race Conditions
-It is fairly unusual for the output of @code{locate} to be fed into
-another command. However, if this were to be done, this would raise
-the same set of security issues as the use of @samp{find @dots{} -print}.
-Although the problems relating to whitespace in file names can be
-resolved by using @code{locate}'s @samp{-0} option, this still leaves
-the race condition problems associated with @samp{find @dots{} -print0}.
-There is no way to avoid these problems in the case of @code{locate}.
-
-@subsection Long File Name Bugs with Old-Format Databases
-Old versions of @code{locate} have a bug in the way that old-format
-databases are read. This bug affects the following versions of
-@code{locate}:
+@table @code
+@item --localpaths='@var{path}@dots{}'
+Non-network directories to put in the database.
+Default is @file{/}.
-@enumerate
-@item All releases prior to 4.2.31
-@item All 4.3.x releases prior to 4.3.7
-@end enumerate
+@item --netpaths='@var{path}@dots{}'
+Network (NFS, AFS, RFS, etc.) directories to put in the database.
+Default is none.
-The affected versions of @code{locate} read file names into a
-fixed-length 1026 byte buffer, allocated on the heap. This buffer is
-not extended if file names are too long to fit into the buffer. No
-range checking on the length of the filename is performed. This could
-in theory lead to a privilege escalation attack. Findutils versions
-4.3.0 to 4.3.6 are also affected.
+@item --prunepaths='@var{path}@dots{}'
+Directories to not put in the database, which would otherwise be.
+Default is @file{/tmp /usr/tmp /var/tmp /afs}.
-On systems using the old database format and affected versions of
-@code{locate}, carefully-chosen long file names could in theory allow
-malicious users to run code of their choice as any user invoking
-locate.
+@item --output=@var{dbfile}
+The database file to build.
+Default is system-dependent, but typically @file{/usr/local/var/locatedb}.
-If remote users can choose the names of files stored on your system,
-and these files are indexed by @code{updatedb}, this may be a remote
-security vulnerability. Findutils version 4.2.31 and findutils
-version 4.3.7 include fixes for this problem. The @code{updatedb},
-@code{bigram} and @code{code} programs do no appear to be affected.
+@item --netuser=@var{user}
+The user to search network directories as, using @code{su}(1).
+Default is @code{daemon}.
+@end table
-If you are also using GNU coreutils, you can use the following command
-to determine the length of the longest file name on a given system:
+@node Invoking xargs, , Invoking updatedb, Reference
+@section Invoking @code{xargs}
@example
-find / -print0 | tr -c '\0' 'x' | tr '\0' '\n' | wc -L
+xargs @r{[}@var{option}@dots{}@r{]} @r{[}@var{command} @r{[}@var{initial-arguments}@r{]}@r{]}
@end example
-Although this problem is significant, the old database format is not
-the default, and use of the old database format is not common. Most
-installations and most users will not be affected by this problem.
-
+@code{xargs} exits with the following status:
+@table @asis
+@item 0
+if it succeeds
+@item 123
+if any invocation of the command exited with status 1-125
+@item 124
+if the command exited with status 255
+@item 125
+if the command is killed by a signal
+@item 126
+if the command cannot be run
+@item 127
+if the command is not found
+@item 1
+if some other error occurred.
+@end table
-@node Security Summary
-@section Summary
+@table @code
+@item --null
+@itemx -0
+Input filenames are terminated by a null character instead of by
+whitespace, and the quotes and backslash are not special (every
+character is taken literally). Disables the end of file string, which
+is treated like any other argument.
-Where untrusted parties can create files on the system, or affect the
-names of files that are created, all uses for @code{find},
-@code{locate} and @code{xargs} have known security problems except the
-following:
+@item --eof@r{[}=@var{eof-str}@r{]}
+@itemx -e@r{[}@var{eof-str}@r{]}
+Set the end of file string to @var{eof-str}. If the end of file string
+occurs as a line of input, the rest of the input is ignored. If
+@var{eof-str} is omitted, there is no end of file string. If this
+option is not given, the end of file string defaults to @samp{_}.
-@table @asis
-@item Informational use only
-Uses where the programs are used to prepare lists of file names upon
-which no further action will ever be taken.
-
-@item @samp{-delete}
-Use of the @samp{-delete} action with @code{find} to delete files
-which meet specified criteria
-
-@item @samp{-execdir}
-Use of the @samp{-execdir} action with @code{find} where the
-@env{PATH} environment variable contains directories which contain
-only trusted programs.
-@end table
+@item --help
+Print a summary of the options to @code{xargs} and exit.
-@comment node-name, next, previous, up
-@node Error Messages
-@chapter Error Messages
-
-This section describes some of the error messages sometimes made by
-@code{find}, @code{xargs}, or @code{locate}, explains them and in some
-cases provides advice as to what you should do about this.
-
-This manual is written in English. The GNU findutils software
-features translations of error messages for many languages. For this
-reason the error messages produced by the programs are made to be as
-self-explanatory as possible. This approach avoids leaving people to
-figure out which test an English-language error message corresponds
-to. Error messages which are self-explanatory will not normally be
-mentioned in this document. For those messages mentioned in this
-document, only the English-language version of the message will be
-listed.
+@item --replace@r{[}=@var{replace-str}@r{]}
+@itemx -i@r{[}@var{replace-str}@r{]}
+Replace occurences of @var{replace-str} in the initial arguments with
+names read from standard input. Also, unquoted blanks do not terminate
+arguments. If @var{replace-str} is omitted, it defaults to @samp{@{@}}
+(like for @samp{find -exec}). Implies @samp{-x} and @samp{-l 1}.
-@menu
-* Error Messages From find::
-* Error Messages From xargs::
-* Error Messages From locate::
-* Error Messages From updatedb::
-@end menu
+@item --max-lines@r{[}=@var{max-lines}@r{]}
+@itemx -l@r{[}@var{max-lines}@r{]}
+Use at most @var{max-lines} nonblank input lines per command line;
+@var{max-lines} defaults to 1 if omitted. Trailing blanks cause an
+input line to be logically continued on the next input line, for the
+purpose of counting the lines. Implies @samp{-x}.
-@node Error Messages From find
-@section Error Messages From @code{find}
-
-Most error messages produced by find are self-explanatory. Error
-messages sometimes include a filename. When this happens, the
-filename is quoted in order to prevent any unusual characters in the
-filename making unwanted changes in the state of the terminal.
-
-@table @samp
-@item invalid predicate `-foo'
-This means that the @code{find} command line included something that
-started with a dash or other special character. The @code{find}
-program tried to interpret this as a test, action or option, but
-didn't recognise it. If it was intended to be a test, check what was
-specified against the documentation. If, on the other hand, the
-string is the name of a file which has been expanded from a wildcard
-(for example because you have a @samp{*} on the command line),
-consider using @samp{./*} or just @samp{.} instead.
-
-@item unexpected extra predicate
-This usually happens if you have an extra bracket on the command line
-(for example @samp{find . -print \)}).
-
-@item Warning: filesystem /path/foo has recently been mounted
-@itemx Warning: filesystem /path/foo has recently been unmounted
-These messages might appear when @code{find} moves into a directory
-and finds that the device number and inode are different to what it
-expected them to be. If the directory @code{find} has moved into is
-on an network filesystem (NFS), it will not issue this message, because
-@code{automount} frequently mounts new filesystems on directories as
-you move into them (that is how it knows you want to use the
-filesystem). So, if you do see this message, be wary ---
-@code{automount} may not have been responsible. Consider the
-possibility that someone else is manipulating the filesystem while
-@code{find} is running. Some people might do this in order to mislead
-@code{find} or persuade it to look at one set of files when it thought
-it was looking at another set.
-
-@item /path/foo changed during execution of find (old device number 12345, new device number 6789, filesystem type is <whatever>) [ref XXX]
-This message is issued when @code{find} moves into a directory and ends up
-somewhere it didn't expect to be. This happens in one of two
-circumstances. Firstly, this happens when @code{automount} intervenes
-on a system where @code{find} doesn't know how to determine what
-the current set of mounted filesystems is.
-
-Secondly, this can happen when the device number of a directory
-appears to change during a change of current directory, but
-@code{find} is moving up the filesystem hierarchy rather than down into it.
-In order to prevent @code{find} wandering off into some unexpected
-part of the filesystem, we stop it at this point.
-
-@item Don't know how to use getmntent() to read `/etc/mtab'. This is a bug.
-This message is issued when a problem similar to the above occurs on a
-system where @code{find} doesn't know how to figure out the current
-list of mount points. Ask for help on @email{bug-findutils@@gnu.org}.
-
-@item /path/foo/bar changed during execution of find (old inode number 12345, new inode number 67893, filesystem type is <whatever>) [ref XXX]"),
-This message is issued when @code{find} moves into a directory and
-discovers that the inode number of that directory
-is different from the inode number that it obtained when it examined the
-directory previously. This usually means that while
-@code{find} was deep in a directory hierarchy doing a
-time consuming operation, somebody has moved one of the parent directories to
-another location in the same filesystem. This may or may not have been done
-maliciously. In any case, @code{find} stops at this point
-to avoid traversing parts of the filesystem that it wasn't
-intended. You can use @code{ls -li} or @code{find /path -inum
-12345 -o -inum 67893} to find out more about what has happened.
-
-@item sanity check of the fnmatch() library function failed.
-Please submit a bug report. You may well be asked questions about
-your system, and if you compiled the @code{findutils} code yourself,
-you should keep your copy of the build tree around. The likely
-explanation is that your system has a buggy implementation of
-@code{fnmatch} that looks enough like the GNU version to fool
-@code{configure}, but which doesn't work properly.
-
-@item cannot fork
-This normally happens if you use the @code{-exec} action or
-something similar (@code{-ok} and so forth) but the system has run out
-of free process slots. This is either because the system is very busy
-and the system has reached its maximum process limit, or because you
-have a resource limit in place and you've reached it. Check the
-system for runaway processes (with @code{ps}, if possible). Some process
-slots are normally reserved for use by @samp{root}.
-
-@item some-program terminated by signal 99
-Some program which was launched with @code{-exec} or similar was killed
-with a fatal signal. This is just an advisory message.
-@end table
+@item --max-args=@var{max-args}
+@itemx -n @var{max-args}
+Use at most @var{max-args} arguments per command line. Fewer than
+@var{max-args} arguments will be used if the size (see the @samp{-s}
+option) is exceeded, unless the @samp{-x} option is given, in which case
+@code{xargs} will exit.
+@item --interactive
+@itemx -p
+Prompt the user about whether to run each command line and read a line
+from the terminal. Only run the command line if the response starts
+with @samp{y} or @samp{Y}. Implies @samp{-t}.
-@node Error Messages From xargs
-@section Error Messages From xargs
-
-@table @samp
-@item environment is too large for exec
-This message means that you have so many environment variables set (or
-such large values for them) that there is no room within the
-system-imposed limits on program command line argument length to
-invoke any program. This is an unlikely situation and is more likely
-result of an attempt to test the limits of @code{xargs}, or break it.
-Please try unsetting some environment variables, or exiting the
-current shell. You can also use @samp{xargs --show-limits} to
-understand the relevant sizes.
-
-@item can not fit single argument within argument list size limit
-You are using the @samp{-I} option and @code{xargs} doesn't have
-enough space to build a command line because it has read a really
-large item and it doesn't fit. You can probably work around this
-problem with the @samp{-s} option, but the default size is pretty
-large. This is a rare situation and is more likely an attempt to test
-the limits of @code{xargs}, or break it. Otherwise, you will need to
-try to shorten the problematic argument or not use @code{xargs}.
-
-@item cannot fork
-See the description of the similar message for @code{find}.
-
-@item <program>: exited with status 255; aborting
-When a command run by @code{xargs} exits with status 255, @code{xargs}
-is supposed to stop. If this is not what you intended, wrap the
-program you are trying to invoke in a shell script which doesn't
-return status 255.
-
-@item <program>: terminated by signal 99
-See the description of the similar message for @code{find}.
-@end table
+@item --no-run-if-empty
+@itemx -r
+If the standard input does not contain any nonblanks, do not run the
+command. By default, the command is run once even if there is no input.
-@node Error Messages From locate
-@section Error Messages From @code{locate}
-
-@table @samp
-@item warning: database @file{@value{LOCATE_DB}} is more than 8 days old
-The @code{locate} program relies on a database which is periodically
-built by the @code{updatedb} program. That hasn't happened in a long
-time. To fix this problem, run @code{updatedb} manually. This can
-often happen on systems that are generally not left on, so the
-periodic ``cron'' task which normally does this doesn't get a chance
-to run.
-
-@item locate database @file{@value{LOCATE_DB}} is corrupt or invalid
-This should not happen. Re-run @code{updatedb}. If that works, but
-@code{locate} still produces this error, run @code{locate --version}
-and @code{updatedb --version}. These should produce the same output.
-If not, you are using a mixed toolset; check your @samp{$PATH}
-environment variable and your shell aliases (if you have any). If
-both programs claim to be GNU versions, this is a bug; all versions of
-these programs should interoperate without problem. Ask for help on
-@email{bug-findutils@@gnu.org}.
-@end table
+@item --max-chars=@var{max-chars}
+@itemx -s @var{max-chars}
+Use at most @var{max-chars} characters per command line, including the
+command and initial arguments and the terminating nulls at the ends of
+the argument strings.
+@item --verbose
+@itemx -t
+Print the command line on the standard error output before executing
+it.
-@node Error Messages From updatedb
-@section Error Messages From updatedb
+@item --version
+Print the version number of @code{xargs} and exit.
-The @code{updatedb} program (and the programs it invokes) do issue
-error messages, but none seem to be candidates for guidance. If
-you are having a problem understanding one of these, ask for help on
-@email{bug-findutils@@gnu.org}.
+@item --exit
+@itemx -x
+Exit if the size (see the @var{-s} option) is exceeded.
-@node GNU Free Documentation License
-@appendix GNU Free Documentation License
-@include fdl.texi
+@item --max-procs=@var{max-procs}
+@itemx -P @var{max-procs}
+Run up to @var{max-procs} processes at a time; the default is 1. If
+@var{max-procs} is 0, @code{xargs} will run as many processes as
+possible at a time.
+@end table
-@node Primary Index
+@node Primary Index, , Reference, Top
@unnumbered @code{find} Primary Index
This is a list of all of the primaries (tests, actions, and options)
@@ -5268,37 +2202,5 @@ Expressions}, for more information on expressions.
@printindex fn
+@contents
@bye
-
-@comment texi related words used by Emacs' spell checker ispell.el
-
-@comment LocalWords: texinfo setfilename settitle setchapternewpage
-@comment LocalWords: iftex finalout ifinfo DIR titlepage vskip pt
-@comment LocalWords: filll dir samp dfn noindent xref pxref
-@comment LocalWords: var deffn texi deffnx itemx emph asis
-@comment LocalWords: findex smallexample subsubsection cindex
-@comment LocalWords: dircategory direntry itemize
-
-@comment other words used by Emacs' spell checker ispell.el
-@comment LocalWords: README fred updatedb xargs Plett Rendell akefile
-@comment LocalWords: args grep Filesystems fo foo fOo wildcards iname
-@comment LocalWords: ipath regex iregex expr fubar regexps
-@comment LocalWords: metacharacters macs sr sc inode lname ilname
-@comment LocalWords: sysdep noleaf ls inum xdev filesystems usr atime
-@comment LocalWords: ctime mtime amin cmin mmin al daystart Sladkey rm
-@comment LocalWords: anewer cnewer bckw rf xtype uname gname uid gid
-@comment LocalWords: nouser nogroup chown chgrp perm ch maxdepth
-@comment LocalWords: mindepth cpio src CD AFS statted stat fstype ufs
-@comment LocalWords: nfs tmp mfs printf fprint dils rw djm Nov lwall
-@comment LocalWords: POSIXLY fls fprintf strftime locale's EDT GMT AP
-@comment LocalWords: EST diff perl backquotes sprintf Falstad Oct cron
-@comment LocalWords: eg vmunix mkdir afs allexec allwrite ARG bigram
-@comment LocalWords: bigrams cd chmod comp crc CVS dbfile dum eof
-@comment LocalWords: fileserver filesystem fn frcode Ghazi Hnewc iXX
-@comment LocalWords: joeuser Kaveh localpaths localuser LOGNAME
-@comment LocalWords: Meyering mv netpaths netuser nonblank nonblanks
-@comment LocalWords: ois ok Pinard printindex proc procs prunefs
-@comment LocalWords: prunepaths pwd RFS rmadillo rmdir rsh sbins str
-@comment LocalWords: su Timar ubins ug unstripped vf VM Weitzel
-@comment LocalWords: wildcard zlogout basename execdir wholename iwholename
-@comment LocalWords: timestamp timestamps Solaris FreeBSD OpenBSD POSIX
diff --git a/doc/perm.texi b/doc/perm.texi
index 41b24f6d..ee43938a 100644
--- a/doc/perm.texi
+++ b/doc/perm.texi
@@ -46,9 +46,9 @@ everyone else.
Files are given an owner and group when they are created. Usually the
owner is the current user and the group is the group of the directory
the file is in, but this varies with the operating system, the
-file system the file is created on, and the way the file is created. You
-can change the owner and group of a file by using the @command{chown} and
-@command{chgrp} commands.
+filesystem the file is created on, and the way the file is created. You
+can change the owner and group of a file by using the @code{chown} and
+@code{chgrp} commands.
In addition to the three sets of three permissions listed above, a
file's permissions have three special components, which affect only
@@ -57,11 +57,11 @@ executable files (programs) and, on some systems, directories:
@enumerate
@item
@cindex setuid
-Set the process's effective user ID to that of the file upon execution
+set the process's effective user ID to that of the file upon execution
(called the @dfn{setuid bit}). No effect on directories.
@item
@cindex setgid
-Set the process's effective group ID to that of the file upon execution
+set the process's effective group ID to that of the file upon execution
(called the @dfn{setgid bit}). For directories on some systems, put
files created in the directory into the same group as the directory, no
matter what group the user who creates them is in.
@@ -69,48 +69,13 @@ matter what group the user who creates them is in.
@cindex sticky
@cindex swap space, saving text image in
@cindex text image, saving in swap space
-@cindex restricted deletion flag
-prevent users from removing or renaming a file in a directory
-unless they own the file or the directory; this is called the
-@dfn{restricted deletion flag} for the directory.
-For regular files on some systems, save the program's text image on the
-swap device so it will load more quickly when run; this is called the
-@dfn{sticky bit}.
+@cindex append-only directories
+save the program's text image on the swap device so it will load more
+quickly when run (called the @dfn{sticky bit}). For directories on some
+systems, prevent users from removing files that they do not own in the
+directory; this is called making the directory @dfn{append-only}.
@end enumerate
-In addition to the permissions listed above, there may be file attributes
-specific to the file system, e.g: access control lists (ACLs), whether a
-file is compressed, whether a file can be modified (immutability), whether
-a file can be dumped. These are usually set using programs
-specific to the file system. For example:
-@c should probably say a lot more about ACLs... someday
-
-@table @asis
-@item ext2
-On @acronym{GNU} and @acronym{GNU}/Linux the file permissions
-(``attributes'') specific to
-the ext2 file system are set using @command{chattr}.
-
-@item FFS
-On FreeBSD the file permissions (``flags'') specific to the FFS
-file system are set using @command{chrflags}.
-@end table
-
-Although a file's permission ``bits'' allow an operation on that file,
-that operation may still fail, because:
-
-@itemize
-@item
-the file-system-specific permissions do not permit it;
-
-@item
-the file system is mounted as read-only.
-@end itemize
-
-For example, if the immutable attribute is set on a file,
-it cannot be modified, regardless of the fact that you
-may have just run @code{chmod a+w FILE}.
-
@node Symbolic Modes
@section Symbolic Modes
@@ -124,13 +89,9 @@ their previous values, and perhaps on the current @code{umask} as well
The format of symbolic modes is:
@example
-@r{[}ugoa@dots{}@r{][}+-=@r{]}@var{perms}@dots{}@r{[},@dots{}@r{]}
+@r{[}ugoa@dots{}@r{][[}+-=@r{][}rwxXstugo@dots{}@r{]}@dots{}@r{][},@dots{}@r{]}
@end example
-@noindent
-where @var{perms} is either zero or more letters from the set
-@samp{rwxXst}, or a single letter from the set @samp{ugo}.
-
The following sections describe the operators and other details of
symbolic modes.
@@ -157,7 +118,7 @@ format:
@noindent
The spaces between the three parts above are shown for readability only;
-symbolic modes cannot contain spaces.
+symbolic modes can not contain spaces.
The @var{users} part tells which users' access to the file is changed.
It consists of one or more of the following letters (or it can be empty;
@@ -199,7 +160,7 @@ have for the file.
@end table
The @var{permissions} part tells what kind of access to the file should
-be changed; it is normally zero or more of the following letters. As with the
+be changed; it is zero or more of the following letters. As with the
@var{users} part, the order does not matter when more than one letter is
given. Omitting the @var{permissions} part is useful only with the
@samp{=} operation, where it gives the specified @var{users} no access
@@ -224,7 +185,7 @@ but not to execute it, use:
a=rw
@end example
-To remove write permission for all users other than the file's
+To remove write permission for from all users other than the file's
owner, use:
@example
@@ -248,7 +209,7 @@ go=
Another way to specify the same thing is:
@example
-og-rwx
+og-rxw
@end example
@node Copying Permissions
@@ -256,17 +217,17 @@ og-rwx
@cindex copying existing permissions
@cindex permissions, copying existing
-You can base a file's permissions on its existing permissions. To do
-this, instead of using a series of @samp{r}, @samp{w}, or @samp{x}
-letters after the
-operator, you use the letter @samp{u}, @samp{g}, or @samp{o}. For
-example, the mode
+You can base part of a file's permissions on part of its existing
+permissions. To do this, instead of using @samp{r}, @samp{w}, or
+@samp{x} after the operator, you use the letter @samp{u}, @samp{g}, or
+@samp{o}. For example, the mode
@example
o+g
@end example
@noindent
+@c FIXME describe the ls -l notation for showing permissions.
adds the permissions for users who are in a file's group to the
permissions that other users have for the file. Thus, if the file
started out as mode 664 (@samp{rw-rw-r--}), the above mode would change
@@ -291,34 +252,45 @@ To change a file's permission to set the group ID on execution, use
@samp{g} in the @var{users} part of the symbolic mode and
@samp{s} in the @var{permissions} part.
-To change a file's permission to set the restricted deletion flag or sticky bit,
-omit the @var{users} part of the symbolic mode (or use @samp{a}) and put
+To change a file's permission to stay permanently on the swap device,
+use @samp{o} in the @var{users} part of the symbolic mode and
@samp{t} in the @var{permissions} part.
-For example, to add set-user-ID permission to a program,
+For example, to add set user ID permission to a program,
you can use the mode:
@example
u+s
@end example
-To remove both set-user-ID and set-group-ID permission from
+To remove both set user ID and set group ID permission from
it, you can use the mode:
@example
ug-s
@end example
-To set the restricted deletion flag or sticky bit, you can use
+To cause a program to be saved on the swap device, you can use
the mode:
@example
-+t
+o+t
@end example
-The combination @samp{o+s} has no effect. On @acronym{GNU} systems
-the combinations @samp{u+t} and @samp{g+t} have no effect, and
-@samp{o+t} acts like plain @samp{+t}.
+Remember that the special permissions only affect files that are
+executable, plus, on some systems, directories (on which they have
+different meanings; @pxref{Mode Structure}). Using @samp{a}
+in the @var{users} part of a symbolic mode does not cause the special
+permissions to be affected; thus,
+
+@example
+a+s
+@end example
+
+@noindent
+has @emph{no effect}. You must use @samp{u}, @samp{g}, and @samp{o}
+explicitly to affect the special permissions. Also, the
+combinations @samp{u+t}, @samp{g+t}, and @samp{o+s} have no effect.
The @samp{=} operator is not very useful with special permissions; for
example, the mode:
@@ -328,7 +300,7 @@ o=t
@end example
@noindent
-does set the restricted deletion flag or sticky bit, but it also
+does cause the file to be saved on the swap device, but it also
removes all read, write, and execute permissions that users not in the
file's group might have had for it.
@@ -338,7 +310,9 @@ file's group might have had for it.
@cindex conditional executability
There is one more special type of symbolic permission: if you use
@samp{X} instead of @samp{x}, execute permission is affected only if the
-file is a directory or already had execute permission.
+file already had execute permission or is a directory. It affects
+directories' execute permission even if they did not initially have any
+execute permissions set.
For example, this mode:
@@ -347,8 +321,8 @@ a+X
@end example
@noindent
-gives all users permission to search directories, or to execute files if
-anyone could execute them before.
+gives all users permission to execute files (or search directories) if
+anyone could before.
@node Multiple Changes
@subsection Making Multiple Changes
@@ -371,7 +345,7 @@ og+rX-w
gives users other than the owner of the file read permission and, if
it is a directory or if someone already had execute permission
to it, gives them execute permission; and it also denies them write
-permission to the file. It does not affect the permission that the
+permission to it file. It does not affect the permission that the
owner of the file has for it. The above mode is equivalent to
the two modes:
@@ -459,23 +433,22 @@ the file to all users.
@cindex numeric modes
@cindex file permissions, numeric
@cindex octal numbers for file modes
-As an
+File permissions are stored internally as 16 bit integers. As an
alternative to giving a symbolic mode, you can give an octal (base 8)
-number that represents the new mode.
+number that corresponds to the internal representation of the new mode.
This number is always interpreted in octal; you do not have to add a
leading 0, as you do in C. Mode 0055 is the same as mode 55.
A numeric mode is usually shorter than the corresponding symbolic
-mode, but it is limited in that it cannot take into account a file's
+mode, but it is limited in that it can not take into account a file's
previous permissions; it can only set them absolutely.
-The permissions granted to the user,
-to other users in the file's group,
-and to other users not in the file's group each require three
+The permissions granted to the user, to other users in the file's group,
+and to other users not in the file's group are each stored as three
bits, which are represented as one octal digit. The three special
-permissions also require one bit each, and they are as a group
-represented as another octal digit. Here is how the bits are arranged,
-starting with the lowest valued bit:
+permissions are also each stored as one bit, and they are as a group
+represented as another octal digit. Here is how the bits are arranged
+in the 16 bit integer, starting with the lowest valued bit:
@example
Value in Corresponding
@@ -497,7 +470,7 @@ Mode Permission
400 Read
Special permissions:
-1000 Restricted deletion flag or sticky bit
+1000 Save text image on swap device
2000 Set group ID on execution
4000 Set user ID on execution
@end example
@@ -505,4 +478,4 @@ Mode Permission
For example, numeric mode 4755 corresponds to symbolic mode
@samp{u=rwxs,go=rx}, and numeric mode 664 corresponds to symbolic mode
@samp{ug=rw,o=r}. Numeric mode 0 corresponds to symbolic mode
-@samp{a=}.
+@samp{ugo=}.
diff --git a/doc/texinfo.tex b/doc/texinfo.tex
new file mode 100644
index 00000000..93bc18f6
--- /dev/null
+++ b/doc/texinfo.tex
@@ -0,0 +1,4365 @@
+%% TeX macros to handle texinfo files
+
+% Copyright (C) 1985, 86, 88, 90, 91, 92, 93, 1994 Free Software Foundation, Inc.
+
+%This texinfo.tex file 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 texinfo.tex file 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 texinfo.tex file; see the file COPYING. If not, write
+%to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
+%USA.
+
+
+%In other words, you are welcome to use, share and improve this program.
+%You are forbidden to forbid anyone else to use, share and improve
+%what you give them. Help stamp out software-hoarding!
+
+% This automatically updates the version number based on RCS.
+\def\deftexinfoversion$#1: #2 ${\def\texinfoversion{#2}}
+\deftexinfoversion$Revision$
+\message{Loading texinfo package [Version \texinfoversion]:}
+
+% Print the version number if in a .fmt file.
+\everyjob{\message{[Texinfo version \texinfoversion]}\message{}}
+
+% Save some parts of plain tex whose names we will redefine.
+
+\let\ptextilde=\~
+\let\ptexlbrace=\{
+\let\ptexrbrace=\}
+\let\ptexdots=\dots
+\let\ptexdot=\.
+\let\ptexstar=\*
+\let\ptexend=\end
+\let\ptexbullet=\bullet
+\let\ptexb=\b
+\let\ptexc=\c
+\let\ptexi=\i
+\let\ptext=\t
+\let\ptexl=\l
+\let\ptexL=\L
+
+% Be sure we're in horizontal mode when doing a tie, since we make space
+% equivalent to this in @example-like environments. Otherwise, a space
+% at the beginning of a line will start with \penalty -- and
+% since \penalty is valid in vertical mode, we'd end up putting the
+% penalty on the vertical list instead of in the new paragraph.
+{\catcode`@ = 11
+ \gdef\tie{\leavevmode\penalty\@M\ }
+}
+\let\~ = \tie % And make it available as @~.
+
+\message{Basics,}
+\chardef\other=12
+
+% If this character appears in an error message or help string, it
+% starts a new line in the output.
+\newlinechar = `^^J
+
+% Set up fixed words for English.
+\ifx\putwordChapter\undefined{\gdef\putwordChapter{Chapter}}\fi%
+\def\putwordInfo{Info}%
+\ifx\putwordSee\undefined{\gdef\putwordSee{See}}\fi%
+\ifx\putwordsee\undefined{\gdef\putwordsee{see}}\fi%
+\ifx\putwordfile\undefined{\gdef\putwordfile{file}}\fi%
+\ifx\putwordpage\undefined{\gdef\putwordpage{page}}\fi%
+\ifx\putwordsection\undefined{\gdef\putwordsection{section}}\fi%
+\ifx\putwordSection\undefined{\gdef\putwordSection{Section}}\fi%
+\ifx\putwordTableofContents\undefined{\gdef\putwordTableofContents{Table of Contents}}\fi%
+\ifx\putwordShortContents\undefined{\gdef\putwordShortContents{Short Contents}}\fi%
+\ifx\putwordAppendix\undefined{\gdef\putwordAppendix{Appendix}}\fi%
+
+% Ignore a token.
+%
+\def\gobble#1{}
+
+\hyphenation{ap-pen-dix}
+\hyphenation{mini-buf-fer mini-buf-fers}
+\hyphenation{eshell}
+
+% Margin to add to right of even pages, to left of odd pages.
+\newdimen \bindingoffset \bindingoffset=0pt
+\newdimen \normaloffset \normaloffset=\hoffset
+\newdimen\pagewidth \newdimen\pageheight
+\pagewidth=\hsize \pageheight=\vsize
+
+% Sometimes it is convenient to have everything in the transcript file
+% and nothing on the terminal. We don't just call \tracingall here,
+% since that produces some useless output on the terminal.
+%
+\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}%
+\def\loggingall{\tracingcommands2 \tracingstats2
+ \tracingpages1 \tracingoutput1 \tracinglostchars1
+ \tracingmacros2 \tracingparagraphs1 \tracingrestores1
+ \showboxbreadth\maxdimen\showboxdepth\maxdimen
+}%
+
+%---------------------Begin change-----------------------
+%
+%%%% For @cropmarks command.
+% Dimensions to add cropmarks at corners Added by P. A. MacKay, 12 Nov. 1986
+%
+\newdimen\cornerlong \newdimen\cornerthick
+\newdimen \topandbottommargin
+\newdimen \outerhsize \newdimen \outervsize
+\cornerlong=1pc\cornerthick=.3pt % These set size of cropmarks
+\outerhsize=7in
+%\outervsize=9.5in
+% Alternative @smallbook page size is 9.25in
+\outervsize=9.25in
+\topandbottommargin=.75in
+%
+%---------------------End change-----------------------
+
+% \onepageout takes a vbox as an argument. Note that \pagecontents
+% does insertions itself, but you have to call it yourself.
+\chardef\PAGE=255 \output={\onepageout{\pagecontents\PAGE}}
+\def\onepageout#1{\hoffset=\normaloffset
+\ifodd\pageno \advance\hoffset by \bindingoffset
+\else \advance\hoffset by -\bindingoffset\fi
+{\escapechar=`\\\relax % makes sure backslash is used in output files.
+\shipout\vbox{{\let\hsize=\pagewidth \makeheadline} \pagebody{#1}%
+{\let\hsize=\pagewidth \makefootline}}}%
+\advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi}
+
+%%%% For @cropmarks command %%%%
+
+% Here is a modification of the main output routine for Near East Publications
+% This provides right-angle cropmarks at all four corners.
+% The contents of the page are centerlined into the cropmarks,
+% and any desired binding offset is added as an \hskip on either
+% site of the centerlined box. (P. A. MacKay, 12 November, 1986)
+%
+\def\croppageout#1{\hoffset=0pt % make sure this doesn't mess things up
+{\escapechar=`\\\relax % makes sure backslash is used in output files.
+ \shipout
+ \vbox to \outervsize{\hsize=\outerhsize
+ \vbox{\line{\ewtop\hfill\ewtop}}
+ \nointerlineskip
+ \line{\vbox{\moveleft\cornerthick\nstop}
+ \hfill
+ \vbox{\moveright\cornerthick\nstop}}
+ \vskip \topandbottommargin
+ \centerline{\ifodd\pageno\hskip\bindingoffset\fi
+ \vbox{
+ {\let\hsize=\pagewidth \makeheadline}
+ \pagebody{#1}
+ {\let\hsize=\pagewidth \makefootline}}
+ \ifodd\pageno\else\hskip\bindingoffset\fi}
+ \vskip \topandbottommargin plus1fill minus1fill
+ \boxmaxdepth\cornerthick
+ \line{\vbox{\moveleft\cornerthick\nsbot}
+ \hfill
+ \vbox{\moveright\cornerthick\nsbot}}
+ \nointerlineskip
+ \vbox{\line{\ewbot\hfill\ewbot}}
+ }}
+ \advancepageno
+ \ifnum\outputpenalty>-20000 \else\dosupereject\fi}
+%
+% Do @cropmarks to get crop marks
+\def\cropmarks{\let\onepageout=\croppageout }
+
+\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}}
+{\catcode`\@ =11
+\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi
+\dimen@=\dp#1 \unvbox#1
+\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi
+\ifr@ggedbottom \kern-\dimen@ \vfil \fi}
+}
+
+%
+% Here are the rules for the cropmarks. Note that they are
+% offset so that the space between them is truly \outerhsize or \outervsize
+% (P. A. MacKay, 12 November, 1986)
+%
+\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong}
+\def\nstop{\vbox
+ {\hrule height\cornerthick depth\cornerlong width\cornerthick}}
+\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong}
+\def\nsbot{\vbox
+ {\hrule height\cornerlong depth\cornerthick width\cornerthick}}
+
+% Parse an argument, then pass it to #1. The argument is the rest of
+% the input line (except we remove a trailing comment). #1 should be a
+% macro which expects an ordinary undelimited TeX argument.
+%
+\def\parsearg#1{%
+ \let\next = #1%
+ \begingroup
+ \obeylines
+ \futurelet\temp\parseargx
+}
+
+% If the next token is an obeyed space (from an @example environment or
+% the like), remove it and recurse. Otherwise, we're done.
+\def\parseargx{%
+ % \obeyedspace is defined far below, after the definition of \sepspaces.
+ \ifx\obeyedspace\temp
+ \expandafter\parseargdiscardspace
+ \else
+ \expandafter\parseargline
+ \fi
+}
+
+% Remove a single space (as the delimiter token to the macro call).
+{\obeyspaces %
+ \gdef\parseargdiscardspace {\futurelet\temp\parseargx}}
+
+{\obeylines %
+ \gdef\parseargline#1^^M{%
+ \endgroup % End of the group started in \parsearg.
+ %
+ % First remove any @c comment, then any @comment.
+ % Result of each macro is put in \toks0.
+ \argremovec #1\c\relax %
+ \expandafter\argremovecomment \the\toks0 \comment\relax %
+ %
+ % Call the caller's macro, saved as \next in \parsearg.
+ \expandafter\next\expandafter{\the\toks0}%
+ }%
+}
+
+% Since all \c{,omment} does is throw away the argument, we can let TeX
+% do that for us. The \relax here is matched by the \relax in the call
+% in \parseargline; it could be more or less anything, its purpose is
+% just to delimit the argument to the \c.
+\def\argremovec#1\c#2\relax{\toks0 = {#1}}
+\def\argremovecomment#1\comment#2\relax{\toks0 = {#1}}
+
+% \argremovec{,omment} might leave us with trailing spaces, though; e.g.,
+% @end itemize @c foo
+% will have two active spaces as part of the argument with the
+% `itemize'. Here we remove all active spaces from #1, and assign the
+% result to \toks0.
+%
+% This loses if there are any *other* active characters besides spaces
+% in the argument -- _ ^ +, for example -- since they get expanded.
+% Fortunately, Texinfo does not define any such commands. (If it ever
+% does, the catcode of the characters in questionwill have to be changed
+% here.) But this means we cannot call \removeactivespaces as part of
+% \argremovec{,omment}, since @c uses \parsearg, and thus the argument
+% that \parsearg gets might well have any character at all in it.
+%
+\def\removeactivespaces#1{%
+ \begingroup
+ \ignoreactivespaces
+ \edef\temp{#1}%
+ \global\toks0 = \expandafter{\temp}%
+ \endgroup
+}
+
+% Change the active space to expand to nothing.
+%
+\begingroup
+ \obeyspaces
+ \gdef\ignoreactivespaces{\obeyspaces\let =\empty}
+\endgroup
+
+
+\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next}
+
+%% These are used to keep @begin/@end levels from running away
+%% Call \inENV within environments (after a \begingroup)
+\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi}
+\def\ENVcheck{%
+\ifENV\errmessage{Still within an environment. Type Return to continue.}
+\endgroup\fi} % This is not perfect, but it should reduce lossage
+
+% @begin foo is the same as @foo, for now.
+\newhelp\EMsimple{Type <Return> to continue.}
+
+\outer\def\begin{\parsearg\beginxxx}
+
+\def\beginxxx #1{%
+\expandafter\ifx\csname #1\endcsname\relax
+{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else
+\csname #1\endcsname\fi}
+
+% @end foo executes the definition of \Efoo.
+%
+\def\end{\parsearg\endxxx}
+\def\endxxx #1{%
+ \removeactivespaces{#1}%
+ \edef\endthing{\the\toks0}%
+ %
+ \expandafter\ifx\csname E\endthing\endcsname\relax
+ \expandafter\ifx\csname \endthing\endcsname\relax
+ % There's no \foo, i.e., no ``environment'' foo.
+ \errhelp = \EMsimple
+ \errmessage{Undefined command `@end \endthing'}%
+ \else
+ \unmatchedenderror\endthing
+ \fi
+ \else
+ % Everything's ok; the right environment has been started.
+ \csname E\endthing\endcsname
+ \fi
+}
+
+% There is an environment #1, but it hasn't been started. Give an error.
+%
+\def\unmatchedenderror#1{%
+ \errhelp = \EMsimple
+ \errmessage{This `@end #1' doesn't have a matching `@#1'}%
+}
+
+% Define the control sequence \E#1 to give an unmatched @end error.
+%
+\def\defineunmatchedend#1{%
+ \expandafter\def\csname E#1\endcsname{\unmatchedenderror{#1}}%
+}
+
+
+% Single-spacing is done by various environments (specifically, in
+% \nonfillstart and \quotations).
+\newskip\singlespaceskip \singlespaceskip = 12.5pt
+\def\singlespace{%
+ % Why was this kern here? It messes up equalizing space above and below
+ % environments. --karl, 6may93
+ %{\advance \baselineskip by -\singlespaceskip
+ %\kern \baselineskip}%
+ \setleading \singlespaceskip
+}
+
+%% Simple single-character @ commands
+
+% @@ prints an @
+% Kludge this until the fonts are right (grr).
+\def\@{{\tt \char '100}}
+
+% This is turned off because it was never documented
+% and you can use @w{...} around a quote to suppress ligatures.
+%% Define @` and @' to be the same as ` and '
+%% but suppressing ligatures.
+%\def\`{{`}}
+%\def\'{{'}}
+
+% Used to generate quoted braces.
+
+\def\mylbrace {{\tt \char '173}}
+\def\myrbrace {{\tt \char '175}}
+\let\{=\mylbrace
+\let\}=\myrbrace
+
+% @: forces normal size whitespace following.
+\def\:{\spacefactor=1000 }
+
+% @* forces a line break.
+\def\*{\hfil\break\hbox{}\ignorespaces}
+
+% @. is an end-of-sentence period.
+\def\.{.\spacefactor=3000 }
+
+% @enddots{} is an end-of-sentence ellipsis.
+\gdef\enddots{$\mathinner{\ldotp\ldotp\ldotp\ldotp}$\spacefactor=3000}
+
+% @! is an end-of-sentence bang.
+\gdef\!{!\spacefactor=3000 }
+
+% @? is an end-of-sentence query.
+\gdef\?{?\spacefactor=3000 }
+
+% @w prevents a word break. Without the \leavevmode, @w at the
+% beginning of a paragraph, when TeX is still in vertical mode, would
+% produce a whole line of output instead of starting the paragraph.
+\def\w#1{\leavevmode\hbox{#1}}
+
+% @group ... @end group forces ... to be all on one page, by enclosing
+% it in a TeX vbox. We use \vtop instead of \vbox to construct the box
+% to keep its height that of a normal line. According to the rules for
+% \topskip (p.114 of the TeXbook), the glue inserted is
+% max (\topskip - \ht (first item), 0). If that height is large,
+% therefore, no glue is inserted, and the space between the headline and
+% the text is small, which looks bad.
+%
+\def\group{\begingroup
+ \ifnum\catcode13=\active \else
+ \errhelp = \groupinvalidhelp
+ \errmessage{@group invalid in context where filling is enabled}%
+ \fi
+ %
+ % The \vtop we start below produces a box with normal height and large
+ % depth; thus, TeX puts \baselineskip glue before it, and (when the
+ % next line of text is done) \lineskip glue after it. (See p.82 of
+ % the TeXbook.) Thus, space below is not quite equal to space
+ % above. But it's pretty close.
+ \def\Egroup{%
+ \egroup % End the \vtop.
+ \endgroup % End the \group.
+ }%
+ %
+ \vtop\bgroup
+ % We have to put a strut on the last line in case the @group is in
+ % the midst of an example, rather than completely enclosing it.
+ % Otherwise, the interline space between the last line of the group
+ % and the first line afterwards is too small. But we can't put the
+ % strut in \Egroup, since there it would be on a line by itself.
+ % Hence this just inserts a strut at the beginning of each line.
+ \everypar = {\strut}%
+ %
+ % Since we have a strut on every line, we don't need any of TeX's
+ % normal interline spacing.
+ \offinterlineskip
+ %
+ % OK, but now we have to do something about blank
+ % lines in the input in @example-like environments, which normally
+ % just turn into \lisppar, which will insert no space now that we've
+ % turned off the interline space. Simplest is to make them be an
+ % empty paragraph.
+ \ifx\par\lisppar
+ \edef\par{\leavevmode \par}%
+ %
+ % Reset ^^M's definition to new definition of \par.
+ \obeylines
+ \fi
+ %
+ % Do @comment since we are called inside an environment such as
+ % @example, where each end-of-line in the input causes an
+ % end-of-line in the output. We don't want the end-of-line after
+ % the `@group' to put extra space in the output. Since @group
+ % should appear on a line by itself (according to the Texinfo
+ % manual), we don't worry about eating any user text.
+ \comment
+}
+%
+% TeX puts in an \escapechar (i.e., `@') at the beginning of the help
+% message, so this ends up printing `@group can only ...'.
+%
+\newhelp\groupinvalidhelp{%
+group can only be used in environments such as @example,^^J%
+where each line of input produces a line of output.}
+
+% @need space-in-mils
+% forces a page break if there is not space-in-mils remaining.
+
+\newdimen\mil \mil=0.001in
+
+\def\need{\parsearg\needx}
+
+% Old definition--didn't work.
+%\def\needx #1{\par %
+%% This method tries to make TeX break the page naturally
+%% if the depth of the box does not fit.
+%{\baselineskip=0pt%
+%\vtop to #1\mil{\vfil}\kern -#1\mil\penalty 10000
+%\prevdepth=-1000pt
+%}}
+
+\def\needx#1{%
+ % Go into vertical mode, so we don't make a big box in the middle of a
+ % paragraph.
+ \par
+ %
+ % Don't add any leading before our big empty box, but allow a page
+ % break, since the best break might be right here.
+ \allowbreak
+ \nointerlineskip
+ \vtop to #1\mil{\vfil}%
+ %
+ % TeX does not even consider page breaks if a penalty added to the
+ % main vertical list is 10000 or more. But in order to see if the
+ % empty box we just added fits on the page, we must make it consider
+ % page breaks. On the other hand, we don't want to actually break the
+ % page after the empty box. So we use a penalty of 9999.
+ %
+ % There is an extremely small chance that TeX will actually break the
+ % page at this \penalty, if there are no other feasible breakpoints in
+ % sight. (If the user is using lots of big @group commands, which
+ % almost-but-not-quite fill up a page, TeX will have a hard time doing
+ % good page breaking, for example.) However, I could not construct an
+ % example where a page broke at this \penalty; if it happens in a real
+ % document, then we can reconsider our strategy.
+ \penalty9999
+ %
+ % Back up by the size of the box, whether we did a page break or not.
+ \kern -#1\mil
+ %
+ % Do not allow a page break right after this kern.
+ \nobreak
+}
+
+% @br forces paragraph break
+
+\let\br = \par
+
+% @dots{} output some dots
+
+\def\dots{$\ldots$}
+
+% @page forces the start of a new page
+
+\def\page{\par\vfill\supereject}
+
+% @exdent text....
+% outputs text on separate line in roman font, starting at standard page margin
+
+% This records the amount of indent in the innermost environment.
+% That's how much \exdent should take out.
+\newskip\exdentamount
+
+% This defn is used inside fill environments such as @defun.
+\def\exdent{\parsearg\exdentyyy}
+\def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}}
+
+% This defn is used inside nofill environments such as @example.
+\def\nofillexdent{\parsearg\nofillexdentyyy}
+\def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount
+\leftline{\hskip\leftskip{\rm#1}}}}
+
+%\hbox{{\rm#1}}\hfil\break}}
+
+% @include file insert text of that file as input.
+
+\def\include{\parsearg\includezzz}
+%Use \input\thisfile to avoid blank after \input, which may be an active
+%char (in which case the blank would become the \input argument).
+%The grouping keeps the value of \thisfile correct even when @include
+%is nested.
+\def\includezzz #1{\begingroup
+\def\thisfile{#1}\input\thisfile
+\endgroup}
+
+\def\thisfile{}
+
+% @center line outputs that line, centered
+
+\def\center{\parsearg\centerzzz}
+\def\centerzzz #1{{\advance\hsize by -\leftskip
+\advance\hsize by -\rightskip
+\centerline{#1}}}
+
+% @sp n outputs n lines of vertical space
+
+\def\sp{\parsearg\spxxx}
+\def\spxxx #1{\par \vskip #1\baselineskip}
+
+% @comment ...line which is ignored...
+% @c is the same as @comment
+% @ignore ... @end ignore is another way to write a comment
+
+\def\comment{\catcode 64=\other \catcode 123=\other \catcode 125=\other%
+\parsearg \commentxxx}
+
+\def\commentxxx #1{\catcode 64=0 \catcode 123=1 \catcode 125=2 }
+
+\let\c=\comment
+
+% Prevent errors for section commands.
+% Used in @ignore and in failing conditionals.
+\def\ignoresections{%
+\let\chapter=\relax
+\let\unnumbered=\relax
+\let\top=\relax
+\let\unnumberedsec=\relax
+\let\unnumberedsection=\relax
+\let\unnumberedsubsec=\relax
+\let\unnumberedsubsection=\relax
+\let\unnumberedsubsubsec=\relax
+\let\unnumberedsubsubsection=\relax
+\let\section=\relax
+\let\subsec=\relax
+\let\subsubsec=\relax
+\let\subsection=\relax
+\let\subsubsection=\relax
+\let\appendix=\relax
+\let\appendixsec=\relax
+\let\appendixsection=\relax
+\let\appendixsubsec=\relax
+\let\appendixsubsection=\relax
+\let\appendixsubsubsec=\relax
+\let\appendixsubsubsection=\relax
+\let\contents=\relax
+\let\smallbook=\relax
+\let\titlepage=\relax
+}
+
+% Used in nested conditionals, where we have to parse the Texinfo source
+% and so want to turn off most commands, in case they are used
+% incorrectly.
+%
+\def\ignoremorecommands{%
+ \let\defcv = \relax
+ \let\deffn = \relax
+ \let\deffnx = \relax
+ \let\defindex = \relax
+ \let\defivar = \relax
+ \let\defmac = \relax
+ \let\defmethod = \relax
+ \let\defop = \relax
+ \let\defopt = \relax
+ \let\defspec = \relax
+ \let\deftp = \relax
+ \let\deftypefn = \relax
+ \let\deftypefun = \relax
+ \let\deftypevar = \relax
+ \let\deftypevr = \relax
+ \let\defun = \relax
+ \let\defvar = \relax
+ \let\defvr = \relax
+ \let\ref = \relax
+ \let\xref = \relax
+ \let\printindex = \relax
+ \let\pxref = \relax
+ \let\settitle = \relax
+ \let\include = \relax
+ \let\lowersections = \relax
+ \let\down = \relax
+ \let\raisesections = \relax
+ \let\up = \relax
+ \let\set = \relax
+ \let\clear = \relax
+ \let\item = \relax
+ \let\message = \relax
+}
+
+% Ignore @ignore ... @end ignore.
+%
+\def\ignore{\doignore{ignore}}
+
+% Also ignore @ifinfo, @ifhtml, @html, @menu, and @direntry text.
+%
+\def\ifinfo{\doignore{ifinfo}}
+\def\ifhtml{\doignore{ifhtml}}
+\def\html{\doignore{html}}
+\def\menu{\doignore{menu}}
+\def\direntry{\doignore{direntry}}
+
+% Ignore text until a line `@end #1'.
+%
+\def\doignore#1{\begingroup
+ % Don't complain about control sequences we have declared \outer.
+ \ignoresections
+ %
+ % Define a command to swallow text until we reach `@end #1'.
+ \long\def\doignoretext##1\end #1{\enddoignore}%
+ %
+ % Make sure that spaces turn into tokens that match what \doignoretext wants.
+ \catcode32 = 10
+ %
+ % And now expand that command.
+ \doignoretext
+}
+
+% What we do to finish off ignored text.
+%
+\def\enddoignore{\endgroup\ignorespaces}%
+
+\newif\ifwarnedobs\warnedobsfalse
+\def\obstexwarn{%
+ \ifwarnedobs\relax\else
+ % We need to warn folks that they may have trouble with TeX 3.0.
+ % This uses \immediate\write16 rather than \message to get newlines.
+ \immediate\write16{}
+ \immediate\write16{***WARNING*** for users of Unix TeX 3.0!}
+ \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).}
+ \immediate\write16{If you are running another version of TeX, relax.}
+ \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.}
+ \immediate\write16{ Then upgrade your TeX installation if you can.}
+ \immediate\write16{If you are stuck with version 3.0, run the}
+ \immediate\write16{ script ``tex3patch'' from the Texinfo distribution}
+ \immediate\write16{ to use a workaround.}
+ \immediate\write16{}
+ \warnedobstrue
+ \fi
+}
+
+% **In TeX 3.0, setting text in \nullfont hangs tex. For a
+% workaround (which requires the file ``dummy.tfm'' to be installed),
+% uncomment the following line:
+%%%%%\font\nullfont=dummy\let\obstexwarn=\relax
+
+% Ignore text, except that we keep track of conditional commands for
+% purposes of nesting, up to an `@end #1' command.
+%
+\def\nestedignore#1{%
+ \obstexwarn
+ % We must actually expand the ignored text to look for the @end
+ % command, so that nested ignore constructs work. Thus, we put the
+ % text into a \vbox and then do nothing with the result. To minimize
+ % the change of memory overflow, we follow the approach outlined on
+ % page 401 of the TeXbook: make the current font be a dummy font.
+ %
+ \setbox0 = \vbox\bgroup
+ % Don't complain about control sequences we have declared \outer.
+ \ignoresections
+ %
+ % Define `@end #1' to end the box, which will in turn undefine the
+ % @end command again.
+ \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}%
+ %
+ % We are going to be parsing Texinfo commands. Most cause no
+ % trouble when they are used incorrectly, but some commands do
+ % complicated argument parsing or otherwise get confused, so we
+ % undefine them.
+ %
+ % We can't do anything about stray @-signs, unfortunately;
+ % they'll produce `undefined control sequence' errors.
+ \ignoremorecommands
+ %
+ % Set the current font to be \nullfont, a TeX primitive, and define
+ % all the font commands to also use \nullfont. We don't use
+ % dummy.tfm, as suggested in the TeXbook, because not all sites
+ % might have that installed. Therefore, math mode will still
+ % produce output, but that should be an extremely small amount of
+ % stuff compared to the main input.
+ %
+ \nullfont
+ \let\tenrm = \nullfont \let\tenit = \nullfont \let\tensl = \nullfont
+ \let\tenbf = \nullfont \let\tentt = \nullfont \let\smallcaps = \nullfont
+ \let\tensf = \nullfont
+ % Similarly for index fonts (mostly for their use in
+ % smallexample)
+ \let\indrm = \nullfont \let\indit = \nullfont \let\indsl = \nullfont
+ \let\indbf = \nullfont \let\indtt = \nullfont \let\indsc = \nullfont
+ \let\indsf = \nullfont
+ %
+ % Don't complain when characters are missing from the fonts.
+ \tracinglostchars = 0
+ %
+ % Don't bother to do space factor calculations.
+ \frenchspacing
+ %
+ % Don't report underfull hboxes.
+ \hbadness = 10000
+ %
+ % Do minimal line-breaking.
+ \pretolerance = 10000
+ %
+ % Do not execute instructions in @tex
+ \def\tex{\doignore{tex}}
+}
+
+% @set VAR sets the variable VAR to an empty value.
+% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE.
+%
+% Since we want to separate VAR from REST-OF-LINE (which might be
+% empty), we can't just use \parsearg; we have to insert a space of our
+% own to delimit the rest of the line, and then take it out again if we
+% didn't need it.
+%
+\def\set{\parsearg\setxxx}
+\def\setxxx#1{\setyyy#1 \endsetyyy}
+\def\setyyy#1 #2\endsetyyy{%
+ \def\temp{#2}%
+ \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty
+ \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted.
+ \fi
+}
+\def\setzzz#1#2 \endsetzzz{\expandafter\xdef\csname SET#1\endcsname{#2}}
+
+% @clear VAR clears (i.e., unsets) the variable VAR.
+%
+\def\clear{\parsearg\clearxxx}
+\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax}
+
+% @value{foo} gets the text saved in variable foo.
+%
+\def\value#1{\expandafter
+ \ifx\csname SET#1\endcsname\relax
+ {\{No value for ``#1''\}}
+ \else \csname SET#1\endcsname \fi}
+
+% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined
+% with @set.
+%
+\def\ifset{\parsearg\ifsetxxx}
+\def\ifsetxxx #1{%
+ \expandafter\ifx\csname SET#1\endcsname\relax
+ \expandafter\ifsetfail
+ \else
+ \expandafter\ifsetsucceed
+ \fi
+}
+\def\ifsetsucceed{\conditionalsucceed{ifset}}
+\def\ifsetfail{\nestedignore{ifset}}
+\defineunmatchedend{ifset}
+
+% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been
+% defined with @set, or has been undefined with @clear.
+%
+\def\ifclear{\parsearg\ifclearxxx}
+\def\ifclearxxx #1{%
+ \expandafter\ifx\csname SET#1\endcsname\relax
+ \expandafter\ifclearsucceed
+ \else
+ \expandafter\ifclearfail
+ \fi
+}
+\def\ifclearsucceed{\conditionalsucceed{ifclear}}
+\def\ifclearfail{\nestedignore{ifclear}}
+\defineunmatchedend{ifclear}
+
+% @iftex always succeeds; we read the text following, through @end
+% iftex). But `@end iftex' should be valid only after an @iftex.
+%
+\def\iftex{\conditionalsucceed{iftex}}
+\defineunmatchedend{iftex}
+
+% We can't just want to start a group at @iftex (for example) and end it
+% at @end iftex, since then @set commands inside the conditional have no
+% effect (they'd get reverted at the end of the group). So we must
+% define \Eiftex to redefine itself to be its previous value. (We can't
+% just define it to fail again with an ``unmatched end'' error, since
+% the @ifset might be nested.)
+%
+\def\conditionalsucceed#1{%
+ \edef\temp{%
+ % Remember the current value of \E#1.
+ \let\nece{prevE#1} = \nece{E#1}%
+ %
+ % At the `@end #1', redefine \E#1 to be its previous value.
+ \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}%
+ }%
+ \temp
+}
+
+% We need to expand lots of \csname's, but we don't want to expand the
+% control sequences after we've constructed them.
+%
+\def\nece#1{\expandafter\noexpand\csname#1\endcsname}
+
+% @asis just yields its argument. Used with @table, for example.
+%
+\def\asis#1{#1}
+
+% @math means output in math mode.
+% We don't use $'s directly in the definition of \math because control
+% sequences like \math are expanded when the toc file is written. Then,
+% we read the toc file back, the $'s will be normal characters (as they
+% should be, according to the definition of Texinfo). So we must use a
+% control sequence to switch into and out of math mode.
+%
+% This isn't quite enough for @math to work properly in indices, but it
+% seems unlikely it will ever be needed there.
+%
+\let\implicitmath = $
+\def\math#1{\implicitmath #1\implicitmath}
+
+% @bullet and @minus need the same treatment as @math, just above.
+\def\bullet{\implicitmath\ptexbullet\implicitmath}
+\def\minus{\implicitmath-\implicitmath}
+
+\def\node{\ENVcheck\parsearg\nodezzz}
+\def\nodezzz#1{\nodexxx [#1,]}
+\def\nodexxx[#1,#2]{\gdef\lastnode{#1}}
+\let\nwnode=\node
+\let\lastnode=\relax
+
+\def\donoderef{\ifx\lastnode\relax\else
+\expandafter\expandafter\expandafter\setref{\lastnode}\fi
+\global\let\lastnode=\relax}
+
+\def\unnumbnoderef{\ifx\lastnode\relax\else
+\expandafter\expandafter\expandafter\unnumbsetref{\lastnode}\fi
+\global\let\lastnode=\relax}
+
+\def\appendixnoderef{\ifx\lastnode\relax\else
+\expandafter\expandafter\expandafter\appendixsetref{\lastnode}\fi
+\global\let\lastnode=\relax}
+
+\let\refill=\relax
+
+% @setfilename is done at the beginning of every texinfo file.
+% So open here the files we need to have open while reading the input.
+% This makes it possible to make a .fmt file for texinfo.
+\def\setfilename{%
+ \readauxfile
+ \opencontents
+ \openindices
+ \fixbackslash % Turn off hack to swallow `\input texinfo'.
+ \global\let\setfilename=\comment % Ignore extra @setfilename cmds.
+ \comment % Ignore the actual filename.
+}
+
+\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend}
+
+\def\inforef #1{\inforefzzz #1,,,,**}
+\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}},
+ node \samp{\ignorespaces#1{}}}
+
+\message{fonts,}
+
+% Font-change commands.
+
+% Texinfo supports the sans serif font style, which plain TeX does not.
+% So we set up a \sf analogous to plain's \rm, etc.
+\newfam\sffam
+\def\sf{\fam=\sffam \tensf}
+\let\li = \sf % Sometimes we call it \li, not \sf.
+
+%% Try out Computer Modern fonts at \magstephalf
+\let\mainmagstep=\magstephalf
+
+% Set the font macro #1 to the font named #2, adding on the
+% specified font prefix (normally `cm').
+\def\fontprefix{cm}
+\def\setfont#1#2{\font#1=\fontprefix#2}
+
+% Enter `@setfontprefix dc' to use the dc fonts instead of the cm fonts.
+\def\setfontprefix{\parsearg\\setfontprefixzzz}
+\def\setfontprefixzzz#1{\gdef\fontprefix{#1}}
+
+\ifx\bigger\relax
+\let\mainmagstep=\magstep1
+\setfont\textrm{r12}
+\setfont\texttt{tt12}
+\else
+\setfont\textrm{r10 scaled \mainmagstep}
+\setfont\texttt{tt10 scaled \mainmagstep}
+\fi
+% Instead of cmb10, you many want to use cmbx10.
+% cmbx10 is a prettier font on its own, but cmb10
+% looks better when embedded in a line with cmr10.
+\setfont\textbf{b10 scaled \mainmagstep}
+\setfont\textit{ti10 scaled \mainmagstep}
+\setfont\textsl{sl10 scaled \mainmagstep}
+\setfont\textsf{ss10 scaled \mainmagstep}
+\setfont\textsc{csc10 scaled \mainmagstep}
+\setfont\texti{mi10 scaled \mainmagstep}
+\setfont\textsy{sy10 scaled \mainmagstep}
+
+% A few fonts for @defun, etc.
+\setfont\defbf{bx10 scaled \magstep1} %was 1314
+\setfont\deftt{tt10 scaled \magstep1}
+\def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf}
+
+% Fonts for indices and small examples.
+% We actually use the slanted font rather than the italic,
+% because texinfo normally uses the slanted fonts for that.
+% Do not make many font distinctions in general in the index, since they
+% aren't very useful.
+\setfont\ninett{tt9}
+\setfont\indrm{r9}
+\setfont\indit{sl9}
+\let\indsl=\indit
+\let\indtt=\ninett
+\let\indsf=\indrm
+\let\indbf=\indrm
+\let\indsc=\indrm
+\setfont\indi{mi9}
+\setfont\indsy{sy9}
+
+% Fonts for headings
+\setfont\chaprm{bx12 scaled \magstep2}
+\setfont\chapit{ti12 scaled \magstep2}
+\setfont\chapsl{sl12 scaled \magstep2}
+\setfont\chaptt{tt12 scaled \magstep2}
+\setfont\chapsf{ss12 scaled \magstep2}
+\let\chapbf=\chaprm
+\setfont\chapsc{csc10 scaled\magstep3}
+\setfont\chapi{mi12 scaled \magstep2}
+\setfont\chapsy{sy10 scaled \magstep3}
+
+\setfont\secrm{bx12 scaled \magstep1}
+\setfont\secit{ti12 scaled \magstep1}
+\setfont\secsl{sl12 scaled \magstep1}
+\setfont\sectt{tt12 scaled \magstep1}
+\setfont\secsf{ss12 scaled \magstep1}
+\setfont\secbf{bx12 scaled \magstep1}
+\setfont\secsc{csc10 scaled\magstep2}
+\setfont\seci{mi12 scaled \magstep1}
+\setfont\secsy{sy10 scaled \magstep2}
+
+% \setfont\ssecrm{bx10 scaled \magstep1} % This size an font looked bad.
+% \setfont\ssecit{cmti10 scaled \magstep1} % The letters were too crowded.
+% \setfont\ssecsl{sl10 scaled \magstep1}
+% \setfont\ssectt{tt10 scaled \magstep1}
+% \setfont\ssecsf{ss10 scaled \magstep1}
+
+%\setfont\ssecrm{b10 scaled 1315} % Note the use of cmb rather than cmbx.
+%\setfont\ssecit{ti10 scaled 1315} % Also, the size is a little larger than
+%\setfont\ssecsl{sl10 scaled 1315} % being scaled magstep1.
+%\setfont\ssectt{tt10 scaled 1315}
+%\setfont\ssecsf{ss10 scaled 1315}
+
+%\let\ssecbf=\ssecrm
+
+\setfont\ssecrm{bx12 scaled \magstephalf}
+\setfont\ssecit{ti12 scaled \magstephalf}
+\setfont\ssecsl{sl12 scaled \magstephalf}
+\setfont\ssectt{tt12 scaled \magstephalf}
+\setfont\ssecsf{ss12 scaled \magstephalf}
+\setfont\ssecbf{bx12 scaled \magstephalf}
+\setfont\ssecsc{csc10 scaled \magstep1}
+\setfont\sseci{mi12 scaled \magstephalf}
+\setfont\ssecsy{sy10 scaled \magstep1}
+% The smallcaps and symbol fonts should actually be scaled \magstep1.5,
+% but that is not a standard magnification.
+
+% Fonts for title page:
+\setfont\titlerm{bx12 scaled \magstep3}
+\let\authorrm = \secrm
+
+% In order for the font changes to affect most math symbols and letters,
+% we have to define the \textfont of the standard families. Since
+% texinfo doesn't allow for producing subscripts and superscripts, we
+% don't bother to reset \scriptfont and \scriptscriptfont (which would
+% also require loading a lot more fonts).
+%
+\def\resetmathfonts{%
+ \textfont0 = \tenrm \textfont1 = \teni \textfont2 = \tensy
+ \textfont\itfam = \tenit \textfont\slfam = \tensl \textfont\bffam = \tenbf
+ \textfont\ttfam = \tentt \textfont\sffam = \tensf
+}
+
+
+% The font-changing commands redefine the meanings of \tenSTYLE, instead
+% of just \STYLE. We do this so that font changes will continue to work
+% in math mode, where it is the current \fam that is relevant in most
+% cases, not the current. Plain TeX does, for example,
+% \def\bf{\fam=\bffam \tenbf} By redefining \tenbf, we obviate the need
+% to redefine \bf itself.
+\def\textfonts{%
+ \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl
+ \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc
+ \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy
+ \resetmathfonts}
+\def\chapfonts{%
+ \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl
+ \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc
+ \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy
+ \resetmathfonts}
+\def\secfonts{%
+ \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl
+ \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc
+ \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy
+ \resetmathfonts}
+\def\subsecfonts{%
+ \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl
+ \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc
+ \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy
+ \resetmathfonts}
+\def\indexfonts{%
+ \let\tenrm=\indrm \let\tenit=\indit \let\tensl=\indsl
+ \let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc
+ \let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy
+ \resetmathfonts}
+
+% Set up the default fonts, so we can use them for creating boxes.
+%
+\textfonts
+
+% Count depth in font-changes, for error checks
+\newcount\fontdepth \fontdepth=0
+
+% Fonts for short table of contents.
+\setfont\shortcontrm{r12}
+\setfont\shortcontbf{bx12}
+\setfont\shortcontsl{sl12}
+
+%% Add scribe-like font environments, plus @l for inline lisp (usually sans
+%% serif) and @ii for TeX italic
+
+% \smartitalic{ARG} outputs arg in italics, followed by an italic correction
+% unless the following character is such as not to need one.
+\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi}
+\def\smartitalic#1{{\sl #1}\futurelet\next\smartitalicx}
+
+\let\i=\smartitalic
+\let\var=\smartitalic
+\let\dfn=\smartitalic
+\let\emph=\smartitalic
+\let\cite=\smartitalic
+
+\def\b#1{{\bf #1}}
+\let\strong=\b
+
+% We can't just use \exhyphenpenalty, because that only has effect at
+% the end of a paragraph. Restore normal hyphenation at the end of the
+% group within which \nohyphenation is presumably called.
+%
+\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation}
+\def\restorehyphenation{\hyphenchar\font = `- }
+
+\def\t#1{%
+ {\tt \nohyphenation \rawbackslash \frenchspacing #1}%
+ \null
+}
+\let\ttfont = \t
+%\def\samp #1{`{\tt \rawbackslash \frenchspacing #1}'\null}
+\def\samp #1{`\tclose{#1}'\null}
+\def\key #1{{\tt \nohyphenation \uppercase{#1}}\null}
+\def\ctrl #1{{\tt \rawbackslash \hat}#1}
+
+\let\file=\samp
+
+% @code is a modification of @t,
+% which makes spaces the same size as normal in the surrounding text.
+\def\tclose#1{%
+ {%
+ % Change normal interword space to be same as for the current font.
+ \spaceskip = \fontdimen2\font
+ %
+ % Switch to typewriter.
+ \tt
+ %
+ % But `\ ' produces the large typewriter interword space.
+ \def\ {{\spaceskip = 0pt{} }}%
+ %
+ % Turn off hyphenation.
+ \nohyphenation
+ %
+ \rawbackslash
+ \frenchspacing
+ #1%
+ }%
+ \null
+}
+
+% We *must* turn on hyphenation at `-' and `_' in \code.
+% Otherwise, it is too hard to avoid overful hboxes
+% in the Emacs manual, the Library manual, etc.
+
+% Unfortunately, TeX uses one parameter (\hyphenchar) to control
+% both hyphenation at - and hyphenation within words.
+% We must therefore turn them both off (\tclose does that)
+% and arrange explicitly to hyphenate an a dash.
+% -- rms.
+{
+\catcode`\-=\active
+\catcode`\_=\active
+\global\def\code{\begingroup \catcode`\-=\active \let-\codedash \catcode`\_=\active \let_\codeunder \codex}
+% The following is used by \doprintindex to insure that long function names
+% wrap around. It is necessary for - and _ to be active before the index is
+% read from the file, as \entry parses the arguments long before \code is
+% ever called. -- mycroft
+\global\def\indexbreaks{\catcode`\-=\active \let-\realdash \catcode`\_=\active \let_\realunder}
+}
+\def\realdash{-}
+\def\realunder{_}
+\def\codedash{-\discretionary{}{}{}}
+\def\codeunder{\normalunderscore\discretionary{}{}{}}
+\def\codex #1{\tclose{#1}\endgroup}
+
+%\let\exp=\tclose %Was temporary
+
+% @kbd is like @code, except that if the argument is just one @key command,
+% then @kbd has no effect.
+
+\def\xkey{\key}
+\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}%
+\ifx\one\xkey\ifx\threex\three \key{#2}%
+\else\tclose{\look}\fi
+\else\tclose{\look}\fi}
+
+% Typeset a dimension, e.g., `in' or `pt'. The only reason for the
+% argument is to make the input look right: @dmn{pt} instead of
+% @dmn{}pt.
+%
+\def\dmn#1{\thinspace #1}
+
+\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par}
+
+\def\l#1{{\li #1}\null} %
+
+\def\r#1{{\rm #1}} % roman font
+% Use of \lowercase was suggested.
+\def\sc#1{{\smallcaps#1}} % smallcaps font
+\def\ii#1{{\it #1}} % italic font
+
+\message{page headings,}
+
+\newskip\titlepagetopglue \titlepagetopglue = 1.5in
+\newskip\titlepagebottomglue \titlepagebottomglue = 2pc
+
+% First the title page. Must do @settitle before @titlepage.
+\def\titlefont#1{{\titlerm #1}}
+
+\newif\ifseenauthor
+\newif\iffinishedtitlepage
+
+\def\shorttitlepage{\parsearg\shorttitlepagezzz}
+\def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}%
+ \endgroup\page\hbox{}\page}
+
+\def\titlepage{\begingroup \parindent=0pt \textfonts
+ \let\subtitlerm=\tenrm
+% I deinstalled the following change because \cmr12 is undefined.
+% This change was not in the ChangeLog anyway. --rms.
+% \let\subtitlerm=\cmr12
+ \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}%
+ %
+ \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}%
+ %
+ % Leave some space at the very top of the page.
+ \vglue\titlepagetopglue
+ %
+ % Now you can print the title using @title.
+ \def\title{\parsearg\titlezzz}%
+ \def\titlezzz##1{\leftline{\titlefont{##1}}
+ % print a rule at the page bottom also.
+ \finishedtitlepagefalse
+ \vskip4pt \hrule height 4pt width \hsize \vskip4pt}%
+ % No rule at page bottom unless we print one at the top with @title.
+ \finishedtitlepagetrue
+ %
+ % Now you can put text using @subtitle.
+ \def\subtitle{\parsearg\subtitlezzz}%
+ \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}%
+ %
+ % @author should come last, but may come many times.
+ \def\author{\parsearg\authorzzz}%
+ \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi
+ {\authorfont \leftline{##1}}}%
+ %
+ % Most title ``pages'' are actually two pages long, with space
+ % at the top of the second. We don't want the ragged left on the second.
+ \let\oldpage = \page
+ \def\page{%
+ \iffinishedtitlepage\else
+ \finishtitlepage
+ \fi
+ \oldpage
+ \let\page = \oldpage
+ \hbox{}}%
+% \def\page{\oldpage \hbox{}}
+}
+
+\def\Etitlepage{%
+ \iffinishedtitlepage\else
+ \finishtitlepage
+ \fi
+ % It is important to do the page break before ending the group,
+ % because the headline and footline are only empty inside the group.
+ % If we use the new definition of \page, we always get a blank page
+ % after the title page, which we certainly don't want.
+ \oldpage
+ \endgroup
+ \HEADINGSon
+}
+
+\def\finishtitlepage{%
+ \vskip4pt \hrule height 2pt width \hsize
+ \vskip\titlepagebottomglue
+ \finishedtitlepagetrue
+}
+
+%%% Set up page headings and footings.
+
+\let\thispage=\folio
+
+\newtoks \evenheadline % Token sequence for heading line of even pages
+\newtoks \oddheadline % Token sequence for heading line of odd pages
+\newtoks \evenfootline % Token sequence for footing line of even pages
+\newtoks \oddfootline % Token sequence for footing line of odd pages
+
+% Now make Tex use those variables
+\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline
+ \else \the\evenheadline \fi}}
+\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline
+ \else \the\evenfootline \fi}\HEADINGShook}
+\let\HEADINGShook=\relax
+
+% Commands to set those variables.
+% For example, this is what @headings on does
+% @evenheading @thistitle|@thispage|@thischapter
+% @oddheading @thischapter|@thispage|@thistitle
+% @evenfooting @thisfile||
+% @oddfooting ||@thisfile
+
+\def\evenheading{\parsearg\evenheadingxxx}
+\def\oddheading{\parsearg\oddheadingxxx}
+\def\everyheading{\parsearg\everyheadingxxx}
+
+\def\evenfooting{\parsearg\evenfootingxxx}
+\def\oddfooting{\parsearg\oddfootingxxx}
+\def\everyfooting{\parsearg\everyfootingxxx}
+
+{\catcode`\@=0 %
+
+\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish}
+\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish}
+\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\everyheadingxxx #1{\everyheadingyyy #1@|@|@|@|\finish}
+\gdef\everyheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish}
+\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish}
+\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\everyfootingxxx #1{\everyfootingyyy #1@|@|@|@|\finish}
+\gdef\everyfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}
+\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+%
+}% unbind the catcode of @.
+
+% @headings double turns headings on for double-sided printing.
+% @headings single turns headings on for single-sided printing.
+% @headings off turns them off.
+% @headings on same as @headings double, retained for compatibility.
+% @headings after turns on double-sided headings after this page.
+% @headings doubleafter turns on double-sided headings after this page.
+% @headings singleafter turns on single-sided headings after this page.
+% By default, they are off.
+
+\def\headings #1 {\csname HEADINGS#1\endcsname}
+
+\def\HEADINGSoff{
+\global\evenheadline={\hfil} \global\evenfootline={\hfil}
+\global\oddheadline={\hfil} \global\oddfootline={\hfil}}
+\HEADINGSoff
+% When we turn headings on, set the page number to 1.
+% For double-sided printing, put current file name in lower left corner,
+% chapter name on inside top of right hand pages, document
+% title on inside top of left hand pages, and page numbers on outside top
+% edge of all pages.
+\def\HEADINGSdouble{
+%\pagealignmacro
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+}
+% For single-sided printing, chapter title goes across top left of page,
+% page number on top right.
+\def\HEADINGSsingle{
+%\pagealignmacro
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+}
+\def\HEADINGSon{\HEADINGSdouble}
+
+\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex}
+\let\HEADINGSdoubleafter=\HEADINGSafter
+\def\HEADINGSdoublex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+}
+
+\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex}
+\def\HEADINGSsinglex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+}
+
+% Subroutines used in generating headings
+% Produces Day Month Year style of output.
+\def\today{\number\day\space
+\ifcase\month\or
+January\or February\or March\or April\or May\or June\or
+July\or August\or September\or October\or November\or December\fi
+\space\number\year}
+
+% Use this if you want the Month Day, Year style of output.
+%\def\today{\ifcase\month\or
+%January\or February\or March\or April\or May\or June\or
+%July\or August\or September\or October\or November\or December\fi
+%\space\number\day, \number\year}
+
+% @settitle line... specifies the title of the document, for headings
+% It generates no output of its own
+
+\def\thistitle{No Title}
+\def\settitle{\parsearg\settitlezzz}
+\def\settitlezzz #1{\gdef\thistitle{#1}}
+
+\message{tables,}
+
+% @tabs -- simple alignment
+
+% These don't work. For one thing, \+ is defined as outer.
+% So these macros cannot even be defined.
+
+%\def\tabs{\parsearg\tabszzz}
+%\def\tabszzz #1{\settabs\+#1\cr}
+%\def\tabline{\parsearg\tablinezzz}
+%\def\tablinezzz #1{\+#1\cr}
+%\def\&{&}
+
+% Tables -- @table, @ftable, @vtable, @item(x), @kitem(x), @xitem(x).
+
+% default indentation of table text
+\newdimen\tableindent \tableindent=.8in
+% default indentation of @itemize and @enumerate text
+\newdimen\itemindent \itemindent=.3in
+% margin between end of table item and start of table text.
+\newdimen\itemmargin \itemmargin=.1in
+
+% used internally for \itemindent minus \itemmargin
+\newdimen\itemmax
+
+% Note @table, @vtable, and @vtable define @item, @itemx, etc., with
+% these defs.
+% They also define \itemindex
+% to index the item name in whatever manner is desired (perhaps none).
+
+\newif\ifitemxneedsnegativevskip
+
+\def\itemxpar{\par\ifitemxneedsnegativevskip\vskip-\parskip\nobreak\fi}
+
+\def\internalBitem{\smallbreak \parsearg\itemzzz}
+\def\internalBitemx{\itemxpar \parsearg\itemzzz}
+
+\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz}
+\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \itemxpar \parsearg\xitemzzz}
+
+\def\internalBkitem{\smallbreak \parsearg\kitemzzz}
+\def\internalBkitemx{\itemxpar \parsearg\kitemzzz}
+
+\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}%
+ \itemzzz {#1}}
+
+\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}%
+ \itemzzz {#1}}
+
+\def\itemzzz #1{\begingroup %
+ \advance\hsize by -\rightskip
+ \advance\hsize by -\tableindent
+ \setbox0=\hbox{\itemfont{#1}}%
+ \itemindex{#1}%
+ \nobreak % This prevents a break before @itemx.
+ %
+ % Be sure we are not still in the middle of a paragraph.
+ %{\parskip = 0in
+ %\par
+ %}%
+ %
+ % If the item text does not fit in the space we have, put it on a line
+ % by itself, and do not allow a page break either before or after that
+ % line. We do not start a paragraph here because then if the next
+ % command is, e.g., @kindex, the whatsit would get put into the
+ % horizontal list on a line by itself, resulting in extra blank space.
+ \ifdim \wd0>\itemmax
+ %
+ % Make this a paragraph so we get the \parskip glue and wrapping,
+ % but leave it ragged-right.
+ \begingroup
+ \advance\leftskip by-\tableindent
+ \advance\hsize by\tableindent
+ \advance\rightskip by0pt plus1fil
+ \leavevmode\unhbox0\par
+ \endgroup
+ %
+ % We're going to be starting a paragraph, but we don't want the
+ % \parskip glue -- logically it's part of the @item we just started.
+ \nobreak \vskip-\parskip
+ %
+ % Stop a page break at the \parskip glue coming up. Unfortunately
+ % we can't prevent a possible page break at the following
+ % \baselineskip glue.
+ \nobreak
+ \endgroup
+ \itemxneedsnegativevskipfalse
+ \else
+ % The item text fits into the space. Start a paragraph, so that the
+ % following text (if any) will end up on the same line. Since that
+ % text will be indented by \tableindent, we make the item text be in
+ % a zero-width box.
+ \noindent
+ \rlap{\hskip -\tableindent\box0}\ignorespaces%
+ \endgroup%
+ \itemxneedsnegativevskiptrue%
+ \fi
+}
+
+\def\item{\errmessage{@item while not in a table}}
+\def\itemx{\errmessage{@itemx while not in a table}}
+\def\kitem{\errmessage{@kitem while not in a table}}
+\def\kitemx{\errmessage{@kitemx while not in a table}}
+\def\xitem{\errmessage{@xitem while not in a table}}
+\def\xitemx{\errmessage{@xitemx while not in a table}}
+
+%% Contains a kludge to get @end[description] to work
+\def\description{\tablez{\dontindex}{1}{}{}{}{}}
+
+\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex}
+{\obeylines\obeyspaces%
+\gdef\tablex #1^^M{%
+\tabley\dontindex#1 \endtabley}}
+
+\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex}
+{\obeylines\obeyspaces%
+\gdef\ftablex #1^^M{%
+\tabley\fnitemindex#1 \endtabley
+\def\Eftable{\endgraf\afterenvbreak\endgroup}%
+\let\Etable=\relax}}
+
+\def\vtable{\begingroup\inENV\obeylines\obeyspaces\vtablex}
+{\obeylines\obeyspaces%
+\gdef\vtablex #1^^M{%
+\tabley\vritemindex#1 \endtabley
+\def\Evtable{\endgraf\afterenvbreak\endgroup}%
+\let\Etable=\relax}}
+
+\def\dontindex #1{}
+\def\fnitemindex #1{\doind {fn}{\code{#1}}}%
+\def\vritemindex #1{\doind {vr}{\code{#1}}}%
+
+{\obeyspaces %
+\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup%
+\tablez{#1}{#2}{#3}{#4}{#5}{#6}}}
+
+\def\tablez #1#2#3#4#5#6{%
+\aboveenvbreak %
+\begingroup %
+\def\Edescription{\Etable}% Neccessary kludge.
+\let\itemindex=#1%
+\ifnum 0#3>0 \advance \leftskip by #3\mil \fi %
+\ifnum 0#4>0 \tableindent=#4\mil \fi %
+\ifnum 0#5>0 \advance \rightskip by #5\mil \fi %
+\def\itemfont{#2}%
+\itemmax=\tableindent %
+\advance \itemmax by -\itemmargin %
+\advance \leftskip by \tableindent %
+\exdentamount=\tableindent
+\parindent = 0pt
+\parskip = \smallskipamount
+\ifdim \parskip=0pt \parskip=2pt \fi%
+\def\Etable{\endgraf\afterenvbreak\endgroup}%
+\let\item = \internalBitem %
+\let\itemx = \internalBitemx %
+\let\kitem = \internalBkitem %
+\let\kitemx = \internalBkitemx %
+\let\xitem = \internalBxitem %
+\let\xitemx = \internalBxitemx %
+}
+
+% This is the counter used by @enumerate, which is really @itemize
+
+\newcount \itemno
+
+\def\itemize{\parsearg\itemizezzz}
+
+\def\itemizezzz #1{%
+ \begingroup % ended by the @end itemsize
+ \itemizey {#1}{\Eitemize}
+}
+
+\def\itemizey #1#2{%
+\aboveenvbreak %
+\itemmax=\itemindent %
+\advance \itemmax by -\itemmargin %
+\advance \leftskip by \itemindent %
+\exdentamount=\itemindent
+\parindent = 0pt %
+\parskip = \smallskipamount %
+\ifdim \parskip=0pt \parskip=2pt \fi%
+\def#2{\endgraf\afterenvbreak\endgroup}%
+\def\itemcontents{#1}%
+\let\item=\itemizeitem}
+
+% Set sfcode to normal for the chars that usually have another value.
+% These are `.?!:;,'
+\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000
+ \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 }
+
+% \splitoff TOKENS\endmark defines \first to be the first token in
+% TOKENS, and \rest to be the remainder.
+%
+\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}%
+
+% Allow an optional argument of an uppercase letter, lowercase letter,
+% or number, to specify the first label in the enumerated list. No
+% argument is the same as `1'.
+%
+\def\enumerate{\parsearg\enumeratezzz}
+\def\enumeratezzz #1{\enumeratey #1 \endenumeratey}
+\def\enumeratey #1 #2\endenumeratey{%
+ \begingroup % ended by the @end enumerate
+ %
+ % If we were given no argument, pretend we were given `1'.
+ \def\thearg{#1}%
+ \ifx\thearg\empty \def\thearg{1}\fi
+ %
+ % Detect if the argument is a single token. If so, it might be a
+ % letter. Otherwise, the only valid thing it can be is a number.
+ % (We will always have one token, because of the test we just made.
+ % This is a good thing, since \splitoff doesn't work given nothing at
+ % all -- the first parameter is undelimited.)
+ \expandafter\splitoff\thearg\endmark
+ \ifx\rest\empty
+ % Only one token in the argument. It could still be anything.
+ % A ``lowercase letter'' is one whose \lccode is nonzero.
+ % An ``uppercase letter'' is one whose \lccode is both nonzero, and
+ % not equal to itself.
+ % Otherwise, we assume it's a number.
+ %
+ % We need the \relax at the end of the \ifnum lines to stop TeX from
+ % continuing to look for a <number>.
+ %
+ \ifnum\lccode\expandafter`\thearg=0\relax
+ \numericenumerate % a number (we hope)
+ \else
+ % It's a letter.
+ \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax
+ \lowercaseenumerate % lowercase letter
+ \else
+ \uppercaseenumerate % uppercase letter
+ \fi
+ \fi
+ \else
+ % Multiple tokens in the argument. We hope it's a number.
+ \numericenumerate
+ \fi
+}
+
+% An @enumerate whose labels are integers. The starting integer is
+% given in \thearg.
+%
+\def\numericenumerate{%
+ \itemno = \thearg
+ \startenumeration{\the\itemno}%
+}
+
+% The starting (lowercase) letter is in \thearg.
+\def\lowercaseenumerate{%
+ \itemno = \expandafter`\thearg
+ \startenumeration{%
+ % Be sure we're not beyond the end of the alphabet.
+ \ifnum\itemno=0
+ \errmessage{No more lowercase letters in @enumerate; get a bigger
+ alphabet}%
+ \fi
+ \char\lccode\itemno
+ }%
+}
+
+% The starting (uppercase) letter is in \thearg.
+\def\uppercaseenumerate{%
+ \itemno = \expandafter`\thearg
+ \startenumeration{%
+ % Be sure we're not beyond the end of the alphabet.
+ \ifnum\itemno=0
+ \errmessage{No more uppercase letters in @enumerate; get a bigger
+ alphabet}
+ \fi
+ \char\uccode\itemno
+ }%
+}
+
+% Call itemizey, adding a period to the first argument and supplying the
+% common last two arguments. Also subtract one from the initial value in
+% \itemno, since @item increments \itemno.
+%
+\def\startenumeration#1{%
+ \advance\itemno by -1
+ \itemizey{#1.}\Eenumerate\flushcr
+}
+
+% @alphaenumerate and @capsenumerate are abbreviations for giving an arg
+% to @enumerate.
+%
+\def\alphaenumerate{\enumerate{a}}
+\def\capsenumerate{\enumerate{A}}
+\def\Ealphaenumerate{\Eenumerate}
+\def\Ecapsenumerate{\Eenumerate}
+
+% Definition of @item while inside @itemize.
+
+\def\itemizeitem{%
+\advance\itemno by 1
+{\let\par=\endgraf \smallbreak}%
+\ifhmode \errmessage{\in hmode at itemizeitem}\fi
+{\parskip=0in \hskip 0pt
+\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}%
+\vadjust{\penalty 1200}}%
+\flushcr}
+
+% @multitable macros
+% Amy Hendrickson, 8/18/94
+%
+% @multitable ... @endmultitable will make as many columns as desired.
+% Contents of each column will wrap at width given in preamble. Width
+% can be specified either with sample text given in a template line,
+% or in percent of \hsize, the current width of text on page.
+
+% Table can continue over pages but will only break between lines.
+
+% To make preamble:
+%
+% Either define widths of columns in terms of percent of \hsize:
+% @multitable @percentofhsize .2 .3 .5
+% @item ...
+%
+% Numbers following @percentofhsize are the percent of the total
+% current hsize to be used for each column. You may use as many
+% columns as desired.
+
+% Or use a template:
+% @multitable {Column 1 template} {Column 2 template} {Column 3 template}
+% @item ...
+% using the widest term desired in each column.
+
+
+% Each new table line starts with @item, each subsequent new column
+% starts with @tab. Empty columns may be produced by supplying @tab's
+% with nothing between them for as many times as empty columns are needed,
+% ie, @tab@tab@tab will produce two empty columns.
+
+% @item, @tab, @multicolumn or @endmulticolumn do not need to be on their
+% own lines, but it will not hurt if they are.
+
+% Sample multitable:
+
+% @multitable {Column 1 template} {Column 2 template} {Column 3 template}
+% @item first col stuff @tab second col stuff @tab third col
+% @item
+% first col stuff
+% @tab
+% second col stuff
+% @tab
+% third col
+% @item first col stuff @tab second col stuff
+% @tab Many paragraphs of text may be used in any column.
+%
+% They will wrap at the width determined by the template.
+% @item@tab@tab This will be in third column.
+% @endmultitable
+
+% Default dimensions may be reset by user.
+% @intableparskip will set vertical space between paragraphs in table.
+% @intableparindent will set paragraph indent in table.
+% @spacebetweencols will set horizontal space to be left between columns.
+% @spacebetweenlines will set vertical space to be left between lines.
+
+%%%%
+% Dimensions
+
+\newdimen\intableparskip
+\newdimen\intableparindent
+\newdimen\spacebetweencols
+\newdimen\spacebetweenlines
+\intableparskip=0pt
+\intableparindent=6pt
+\spacebetweencols=12pt
+\spacebetweenlines=12pt
+
+%%%%
+% Macros used to set up halign preamble:
+\let\endsetuptable\relax
+\def\xendsetuptable{\endsetuptable}
+\let\percentofhsize\relax
+\def\xpercentofhsize{\percentofhsize}
+\newif\ifsetpercent
+
+\newcount\colcount
+\def\setuptable#1{\def\firstarg{#1}%
+\ifx\firstarg\xendsetuptable\let\go\relax%
+\else
+ \ifx\firstarg\xpercentofhsize\global\setpercenttrue%
+ \else
+ \ifsetpercent
+ \if#1.\else%
+ \global\advance\colcount by1 %
+ \expandafter\xdef\csname col\the\colcount\endcsname{.#1\hsize}%
+ \fi
+ \else
+ \global\advance\colcount by1
+ \setbox0=\hbox{#1}%
+ \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}%
+ \fi%
+ \fi%
+ \let\go\setuptable%
+\fi\go}
+%%%%
+% multitable syntax
+\def\tab{&}
+
+%%%%
+% @multitable ... @endmultitable definitions:
+
+\def\multitable#1\item{\bgroup
+\let\item\cr
+\tolerance=9500
+\hbadness=9500
+\parskip=\intableparskip
+\parindent=\intableparindent
+\overfullrule=0pt
+\global\colcount=0\relax%
+\def\Emultitable{\global\setpercentfalse\global\everycr{}\cr\egroup\egroup}%
+ % To parse everything between @multitable and @item :
+\def\one{#1}\expandafter\setuptable\one\endsetuptable
+ % Need to reset this to 0 after \setuptable.
+\global\colcount=0\relax%
+ %
+ % This preamble sets up a generic column definition, which will
+ % be used as many times as user calls for columns.
+ % \vtop will set a single line and will also let text wrap and
+ % continue for many paragraphs if desired.
+\halign\bgroup&\global\advance\colcount by 1\relax%
+\vtop{\hsize=\expandafter\csname col\the\colcount\endcsname
+ % In order to keep entries from bumping into each other
+ % we will add a \leftskip of \spacebetweencols to all columns after
+ % the first one.
+ % If a template has been used, we will add \spacebetweencols
+ % to the width of each template entry.
+ % If user has set preamble in terms of percent of \hsize
+ % we will use that dimension as the width of the column, and
+ % the \leftskip will keep entries from bumping into each other.
+ % Table will start at left margin and final column will justify at
+ % right margin.
+\ifnum\colcount=1
+\else
+ \ifsetpercent
+ \else
+ % If user has <not> set preamble in terms of percent of \hsize
+ % we will advance \hsize by \spacebetweencols
+ \advance\hsize by \spacebetweencols
+ \fi
+ % In either case we will make \leftskip=\spacebetweencols:
+\leftskip=\spacebetweencols
+\fi
+\noindent##}\cr%
+ % \everycr will reset column counter, \colcount, at the end of
+ % each line. Every column entry will cause \colcount to advance by one.
+ % The table preamble
+ % looks at the current \colcount to find the correct column width.
+\global\everycr{\noalign{\nointerlineskip\vskip\spacebetweenlines
+\filbreak%% keeps underfull box messages off when table breaks over pages.
+\global\colcount=0\relax}}}
+
+\message{indexing,}
+% Index generation facilities
+
+% Define \newwrite to be identical to plain tex's \newwrite
+% except not \outer, so it can be used within \newindex.
+{\catcode`\@=11
+\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}}
+
+% \newindex {foo} defines an index named foo.
+% It automatically defines \fooindex such that
+% \fooindex ...rest of line... puts an entry in the index foo.
+% It also defines \fooindfile to be the number of the output channel for
+% the file that accumulates this index. The file's extension is foo.
+% The name of an index should be no more than 2 characters long
+% for the sake of vms.
+
+\def\newindex #1{
+\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file
+\openout \csname#1indfile\endcsname \jobname.#1 % Open the file
+\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex
+\noexpand\doindex {#1}}
+}
+
+% @defindex foo == \newindex{foo}
+
+\def\defindex{\parsearg\newindex}
+
+% Define @defcodeindex, like @defindex except put all entries in @code.
+
+\def\newcodeindex #1{
+\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file
+\openout \csname#1indfile\endcsname \jobname.#1 % Open the file
+\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex
+\noexpand\docodeindex {#1}}
+}
+
+\def\defcodeindex{\parsearg\newcodeindex}
+
+% @synindex foo bar makes index foo feed into index bar.
+% Do this instead of @defindex foo if you don't want it as a separate index.
+\def\synindex #1 #2 {%
+\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname
+\expandafter\let\csname#1indfile\endcsname=\synindexfoo
+\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex
+\noexpand\doindex {#2}}%
+}
+
+% @syncodeindex foo bar similar, but put all entries made for index foo
+% inside @code.
+\def\syncodeindex #1 #2 {%
+\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname
+\expandafter\let\csname#1indfile\endcsname=\synindexfoo
+\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex
+\noexpand\docodeindex {#2}}%
+}
+
+% Define \doindex, the driver for all \fooindex macros.
+% Argument #1 is generated by the calling \fooindex macro,
+% and it is "foo", the name of the index.
+
+% \doindex just uses \parsearg; it calls \doind for the actual work.
+% This is because \doind is more useful to call from other macros.
+
+% There is also \dosubind {index}{topic}{subtopic}
+% which makes an entry in a two-level index such as the operation index.
+
+\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer}
+\def\singleindexer #1{\doind{\indexname}{#1}}
+
+% like the previous two, but they put @code around the argument.
+\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer}
+\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}}
+
+\def\indexdummies{%
+% Take care of the plain tex accent commands.
+\def\"{\realbackslash "}%
+\def\`{\realbackslash `}%
+\def\'{\realbackslash '}%
+\def\^{\realbackslash ^}%
+\def\~{\realbackslash ~}%
+\def\={\realbackslash =}%
+\def\b{\realbackslash b}%
+\def\c{\realbackslash c}%
+\def\d{\realbackslash d}%
+\def\u{\realbackslash u}%
+\def\v{\realbackslash v}%
+\def\H{\realbackslash H}%
+% Take care of the plain tex special European modified letters.
+\def\oe{\realbackslash oe}%
+\def\ae{\realbackslash ae}%
+\def\aa{\realbackslash aa}%
+\def\OE{\realbackslash OE}%
+\def\AE{\realbackslash AE}%
+\def\AA{\realbackslash AA}%
+\def\o{\realbackslash o}%
+\def\O{\realbackslash O}%
+\def\l{\realbackslash l}%
+\def\L{\realbackslash L}%
+\def\ss{\realbackslash ss}%
+% Take care of texinfo commands likely to appear in an index entry.
+\def\_{{\realbackslash _}}%
+\def\w{\realbackslash w }%
+\def\bf{\realbackslash bf }%
+\def\rm{\realbackslash rm }%
+\def\sl{\realbackslash sl }%
+\def\sf{\realbackslash sf}%
+\def\tt{\realbackslash tt}%
+\def\gtr{\realbackslash gtr}%
+\def\less{\realbackslash less}%
+\def\hat{\realbackslash hat}%
+\def\char{\realbackslash char}%
+\def\TeX{\realbackslash TeX}%
+\def\dots{\realbackslash dots }%
+\def\copyright{\realbackslash copyright }%
+\def\tclose##1{\realbackslash tclose {##1}}%
+\def\code##1{\realbackslash code {##1}}%
+\def\samp##1{\realbackslash samp {##1}}%
+\def\t##1{\realbackslash r {##1}}%
+\def\r##1{\realbackslash r {##1}}%
+\def\i##1{\realbackslash i {##1}}%
+\def\b##1{\realbackslash b {##1}}%
+\def\cite##1{\realbackslash cite {##1}}%
+\def\key##1{\realbackslash key {##1}}%
+\def\file##1{\realbackslash file {##1}}%
+\def\var##1{\realbackslash var {##1}}%
+\def\kbd##1{\realbackslash kbd {##1}}%
+\def\dfn##1{\realbackslash dfn {##1}}%
+\def\emph##1{\realbackslash emph {##1}}%
+}
+
+% \indexnofonts no-ops all font-change commands.
+% This is used when outputting the strings to sort the index by.
+\def\indexdummyfont#1{#1}
+\def\indexdummytex{TeX}
+\def\indexdummydots{...}
+
+\def\indexnofonts{%
+% Just ignore accents.
+\let\"=\indexdummyfont
+\let\`=\indexdummyfont
+\let\'=\indexdummyfont
+\let\^=\indexdummyfont
+\let\~=\indexdummyfont
+\let\==\indexdummyfont
+\let\b=\indexdummyfont
+\let\c=\indexdummyfont
+\let\d=\indexdummyfont
+\let\u=\indexdummyfont
+\let\v=\indexdummyfont
+\let\H=\indexdummyfont
+% Take care of the plain tex special European modified letters.
+\def\oe{oe}%
+\def\ae{ae}%
+\def\aa{aa}%
+\def\OE{OE}%
+\def\AE{AE}%
+\def\AA{AA}%
+\def\o{o}%
+\def\O{O}%
+\def\l{l}%
+\def\L{L}%
+\def\ss{ss}%
+\let\w=\indexdummyfont
+\let\t=\indexdummyfont
+\let\r=\indexdummyfont
+\let\i=\indexdummyfont
+\let\b=\indexdummyfont
+\let\emph=\indexdummyfont
+\let\strong=\indexdummyfont
+\let\cite=\indexdummyfont
+\let\sc=\indexdummyfont
+%Don't no-op \tt, since it isn't a user-level command
+% and is used in the definitions of the active chars like <, >, |...
+%\let\tt=\indexdummyfont
+\let\tclose=\indexdummyfont
+\let\code=\indexdummyfont
+\let\file=\indexdummyfont
+\let\samp=\indexdummyfont
+\let\kbd=\indexdummyfont
+\let\key=\indexdummyfont
+\let\var=\indexdummyfont
+\let\TeX=\indexdummytex
+\let\dots=\indexdummydots
+}
+
+% To define \realbackslash, we must make \ not be an escape.
+% We must first make another character (@) an escape
+% so we do not become unable to do a definition.
+
+{\catcode`\@=0 \catcode`\\=\other
+@gdef@realbackslash{\}}
+
+\let\indexbackslash=0 %overridden during \printindex.
+
+\def\doind #1#2{%
+{\count10=\lastpenalty %
+{\indexdummies % Must do this here, since \bf, etc expand at this stage
+\escapechar=`\\%
+{\let\folio=0% Expand all macros now EXCEPT \folio
+\def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now
+% so it will be output as is; and it will print as backslash in the indx.
+%
+% Now process the index-string once, with all font commands turned off,
+% to get the string to sort the index by.
+{\indexnofonts
+\xdef\temp1{#2}%
+}%
+% Now produce the complete index entry. We process the index-string again,
+% this time with font commands expanded, to get what to print in the index.
+\edef\temp{%
+\write \csname#1indfile\endcsname{%
+\realbackslash entry {\temp1}{\folio}{#2}}}%
+\temp }%
+}\penalty\count10}}
+
+\def\dosubind #1#2#3{%
+{\count10=\lastpenalty %
+{\indexdummies % Must do this here, since \bf, etc expand at this stage
+\escapechar=`\\%
+{\let\folio=0%
+\def\rawbackslashxx{\indexbackslash}%
+%
+% Now process the index-string once, with all font commands turned off,
+% to get the string to sort the index by.
+{\indexnofonts
+\xdef\temp1{#2 #3}%
+}%
+% Now produce the complete index entry. We process the index-string again,
+% this time with font commands expanded, to get what to print in the index.
+\edef\temp{%
+\write \csname#1indfile\endcsname{%
+\realbackslash entry {\temp1}{\folio}{#2}{#3}}}%
+\temp }%
+}\penalty\count10}}
+
+% The index entry written in the file actually looks like
+% \entry {sortstring}{page}{topic}
+% or
+% \entry {sortstring}{page}{topic}{subtopic}
+% The texindex program reads in these files and writes files
+% containing these kinds of lines:
+% \initial {c}
+% before the first topic whose initial is c
+% \entry {topic}{pagelist}
+% for a topic that is used without subtopics
+% \primary {topic}
+% for the beginning of a topic that is used with subtopics
+% \secondary {subtopic}{pagelist}
+% for each subtopic.
+
+% Define the user-accessible indexing commands
+% @findex, @vindex, @kindex, @cindex.
+
+\def\findex {\fnindex}
+\def\kindex {\kyindex}
+\def\cindex {\cpindex}
+\def\vindex {\vrindex}
+\def\tindex {\tpindex}
+\def\pindex {\pgindex}
+
+\def\cindexsub {\begingroup\obeylines\cindexsub}
+{\obeylines %
+\gdef\cindexsub "#1" #2^^M{\endgroup %
+\dosubind{cp}{#2}{#1}}}
+
+% Define the macros used in formatting output of the sorted index material.
+
+% This is what you call to cause a particular index to get printed.
+% Write
+% @unnumbered Function Index
+% @printindex fn
+
+\def\printindex{\parsearg\doprintindex}
+
+\def\doprintindex#1{%
+ \tex
+ \dobreak \chapheadingskip {10000}
+ \catcode`\%=\other\catcode`\&=\other\catcode`\#=\other
+ \catcode`\$=\other
+ \catcode`\~=\other
+ \indexbreaks
+ %
+ % The following don't help, since the chars were translated
+ % when the raw index was written, and their fonts were discarded
+ % due to \indexnofonts.
+ %\catcode`\"=\active
+ %\catcode`\^=\active
+ %\catcode`\_=\active
+ %\catcode`\|=\active
+ %\catcode`\<=\active
+ %\catcode`\>=\active
+ % %
+ \def\indexbackslash{\rawbackslashxx}
+ \indexfonts\rm \tolerance=9500 \advance\baselineskip -1pt
+ \begindoublecolumns
+ %
+ % See if the index file exists and is nonempty.
+ \openin 1 \jobname.#1s
+ \ifeof 1
+ % \enddoublecolumns gets confused if there is no text in the index,
+ % and it loses the chapter title and the aux file entries for the
+ % index. The easiest way to prevent this problem is to make sure
+ % there is some text.
+ (Index is nonexistent)
+ \else
+ %
+ % If the index file exists but is empty, then \openin leaves \ifeof
+ % false. We have to make TeX try to read something from the file, so
+ % it can discover if there is anything in it.
+ \read 1 to \temp
+ \ifeof 1
+ (Index is empty)
+ \else
+ \input \jobname.#1s
+ \fi
+ \fi
+ \closein 1
+ \enddoublecolumns
+ \Etex
+}
+
+% These macros are used by the sorted index file itself.
+% Change them to control the appearance of the index.
+
+% Same as \bigskipamount except no shrink.
+% \balancecolumns gets confused if there is any shrink.
+\newskip\initialskipamount \initialskipamount 12pt plus4pt
+
+\def\initial #1{%
+{\let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt
+\ifdim\lastskip<\initialskipamount
+\removelastskip \penalty-200 \vskip \initialskipamount\fi
+\line{\secbf#1\hfill}\kern 2pt\penalty10000}}
+
+% This typesets a paragraph consisting of #1, dot leaders, and then #2
+% flush to the right margin. It is used for index and table of contents
+% entries. The paragraph is indented by \leftskip.
+%
+\def\entry #1#2{\begingroup
+ %
+ % Start a new paragraph if necessary, so our assignments below can't
+ % affect previous text.
+ \par
+ %
+ % Do not fill out the last line with white space.
+ \parfillskip = 0in
+ %
+ % No extra space above this paragraph.
+ \parskip = 0in
+ %
+ % Do not prefer a separate line ending with a hyphen to fewer lines.
+ \finalhyphendemerits = 0
+ %
+ % \hangindent is only relevant when the entry text and page number
+ % don't both fit on one line. In that case, bob suggests starting the
+ % dots pretty far over on the line. Unfortunately, a large
+ % indentation looks wrong when the entry text itself is broken across
+ % lines. So we use a small indentation and put up with long leaders.
+ %
+ % \hangafter is reset to 1 (which is the value we want) at the start
+ % of each paragraph, so we need not do anything with that.
+ \hangindent=2em
+ %
+ % When the entry text needs to be broken, just fill out the first line
+ % with blank space.
+ \rightskip = 0pt plus1fil
+ %
+ % Start a ``paragraph'' for the index entry so the line breaking
+ % parameters we've set above will have an effect.
+ \noindent
+ %
+ % Insert the text of the index entry. TeX will do line-breaking on it.
+ #1%
+ % The following is kluged to not output a line of dots in the index if
+ % there are no page numbers. The next person who breaks this will be
+ % cursed by a Unix daemon.
+ \def\tempa{{\rm }}%
+ \def\tempb{#2}%
+ \edef\tempc{\tempa}%
+ \edef\tempd{\tempb}%
+ \ifx\tempc\tempd\ \else%
+ %
+ % If we must, put the page number on a line of its own, and fill out
+ % this line with blank space. (The \hfil is overwhelmed with the
+ % fill leaders glue in \indexdotfill if the page number does fit.)
+ \hfil\penalty50
+ \null\nobreak\indexdotfill % Have leaders before the page number.
+ %
+ % The `\ ' here is removed by the implicit \unskip that TeX does as
+ % part of (the primitive) \par. Without it, a spurious underfull
+ % \hbox ensues.
+ \ #2% The page number ends the paragraph.
+ \fi%
+ \par
+\endgroup}
+
+% Like \dotfill except takes at least 1 em.
+\def\indexdotfill{\cleaders
+ \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill}
+
+\def\primary #1{\line{#1\hfil}}
+
+\newskip\secondaryindent \secondaryindent=0.5cm
+
+\def\secondary #1#2{
+{\parfillskip=0in \parskip=0in
+\hangindent =1in \hangafter=1
+\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par
+}}
+
+%% Define two-column mode, which is used in indexes.
+%% Adapted from the TeXbook, page 416.
+\catcode `\@=11
+
+\newbox\partialpage
+
+\newdimen\doublecolumnhsize
+
+\def\begindoublecolumns{\begingroup
+ % Grab any single-column material above us.
+ \output = {\global\setbox\partialpage
+ =\vbox{\unvbox255\kern -\topskip \kern \baselineskip}}%
+ \eject
+ %
+ % Now switch to the double-column output routine.
+ \output={\doublecolumnout}%
+ %
+ % Change the page size parameters. We could do this once outside this
+ % routine, in each of @smallbook, @afourpaper, and the default 8.5x11
+ % format, but then we repeat the same computation. Repeating a couple
+ % of assignments once per index is clearly meaningless for the
+ % execution time, so we may as well do it once.
+ %
+ % First we halve the line length, less a little for the gutter between
+ % the columns. We compute the gutter based on the line length, so it
+ % changes automatically with the paper format. The magic constant
+ % below is chosen so that the gutter has the same value (well, +- <
+ % 1pt) as it did when we hard-coded it.
+ %
+ % We put the result in a separate register, \doublecolumhsize, so we
+ % can restore it in \pagesofar, after \hsize itself has (potentially)
+ % been clobbered.
+ %
+ \doublecolumnhsize = \hsize
+ \advance\doublecolumnhsize by -.04154\hsize
+ \divide\doublecolumnhsize by 2
+ \hsize = \doublecolumnhsize
+ %
+ % Double the \vsize as well. (We don't need a separate register here,
+ % since nobody clobbers \vsize.)
+ \vsize = 2\vsize
+ \doublecolumnpagegoal
+}
+
+\def\enddoublecolumns{\eject \endgroup \pagegoal=\vsize \unvbox\partialpage}
+
+\def\doublecolumnsplit{\splittopskip=\topskip \splitmaxdepth=\maxdepth
+ \global\dimen@=\pageheight \global\advance\dimen@ by-\ht\partialpage
+ \global\setbox1=\vsplit255 to\dimen@ \global\setbox0=\vbox{\unvbox1}
+ \global\setbox3=\vsplit255 to\dimen@ \global\setbox2=\vbox{\unvbox3}
+ \ifdim\ht0>\dimen@ \setbox255=\vbox{\unvbox0\unvbox2} \global\setbox255=\copy5 \fi
+ \ifdim\ht2>\dimen@ \setbox255=\vbox{\unvbox0\unvbox2} \global\setbox255=\copy5 \fi
+}
+\def\doublecolumnpagegoal{%
+ \dimen@=\vsize \advance\dimen@ by-2\ht\partialpage \global\pagegoal=\dimen@
+}
+\def\pagesofar{\unvbox\partialpage %
+ \hsize=\doublecolumnhsize % have to restore this since output routine
+ \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}}
+\def\doublecolumnout{%
+ \setbox5=\copy255
+ {\vbadness=10000 \doublecolumnsplit}
+ \ifvbox255
+ \setbox0=\vtop to\dimen@{\unvbox0}
+ \setbox2=\vtop to\dimen@{\unvbox2}
+ \onepageout\pagesofar \unvbox255 \penalty\outputpenalty
+ \else
+ \setbox0=\vbox{\unvbox5}
+ \ifvbox0
+ \dimen@=\ht0 \advance\dimen@ by\topskip \advance\dimen@ by-\baselineskip
+ \divide\dimen@ by2 \splittopskip=\topskip \splitmaxdepth=\maxdepth
+ {\vbadness=10000
+ \loop \global\setbox5=\copy0
+ \setbox1=\vsplit5 to\dimen@
+ \setbox3=\vsplit5 to\dimen@
+ \ifvbox5 \global\advance\dimen@ by1pt \repeat
+ \setbox0=\vbox to\dimen@{\unvbox1}
+ \setbox2=\vbox to\dimen@{\unvbox3}
+ \global\setbox\partialpage=\vbox{\pagesofar}
+ \doublecolumnpagegoal
+ }
+ \fi
+ \fi
+}
+
+\catcode `\@=\other
+\message{sectioning,}
+% Define chapters, sections, etc.
+
+\newcount \chapno
+\newcount \secno \secno=0
+\newcount \subsecno \subsecno=0
+\newcount \subsubsecno \subsubsecno=0
+
+% This counter is funny since it counts through charcodes of letters A, B, ...
+\newcount \appendixno \appendixno = `\@
+\def\appendixletter{\char\the\appendixno}
+
+\newwrite \contentsfile
+% This is called from \setfilename.
+\def\opencontents{\openout \contentsfile = \jobname.toc}
+
+% Each @chapter defines this as the name of the chapter.
+% page headings and footings can use it. @section does likewise
+
+\def\thischapter{} \def\thissection{}
+\def\seccheck#1{\if \pageno<0 %
+\errmessage{@#1 not allowed after generating table of contents}\fi
+%
+}
+
+\def\chapternofonts{%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\def\result{\realbackslash result}
+\def\equiv{\realbackslash equiv}
+\def\expansion{\realbackslash expansion}
+\def\print{\realbackslash print}
+\def\TeX{\realbackslash TeX}
+\def\dots{\realbackslash dots}
+\def\copyright{\realbackslash copyright}
+\def\tt{\realbackslash tt}
+\def\bf{\realbackslash bf }
+\def\w{\realbackslash w}
+\def\less{\realbackslash less}
+\def\gtr{\realbackslash gtr}
+\def\hat{\realbackslash hat}
+\def\char{\realbackslash char}
+\def\tclose##1{\realbackslash tclose {##1}}
+\def\code##1{\realbackslash code {##1}}
+\def\samp##1{\realbackslash samp {##1}}
+\def\r##1{\realbackslash r {##1}}
+\def\b##1{\realbackslash b {##1}}
+\def\key##1{\realbackslash key {##1}}
+\def\file##1{\realbackslash file {##1}}
+\def\kbd##1{\realbackslash kbd {##1}}
+% These are redefined because @smartitalic wouldn't work inside xdef.
+\def\i##1{\realbackslash i {##1}}
+\def\cite##1{\realbackslash cite {##1}}
+\def\var##1{\realbackslash var {##1}}
+\def\emph##1{\realbackslash emph {##1}}
+\def\dfn##1{\realbackslash dfn {##1}}
+}
+
+\newcount\absseclevel % used to calculate proper heading level
+\newcount\secbase\secbase=0 % @raise/lowersections modify this count
+
+% @raisesections: treat @section as chapter, @subsection as section, etc.
+\def\raisesections{\global\advance\secbase by -1}
+\let\up=\raisesections % original BFox name
+
+% @lowersections: treat @chapter as section, @section as subsection, etc.
+\def\lowersections{\global\advance\secbase by 1}
+\let\down=\lowersections % original BFox name
+
+% Choose a numbered-heading macro
+% #1 is heading level if unmodified by @raisesections or @lowersections
+% #2 is text for heading
+\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
+\ifcase\absseclevel
+ \chapterzzz{#2}
+\or
+ \seczzz{#2}
+\or
+ \numberedsubseczzz{#2}
+\or
+ \numberedsubsubseczzz{#2}
+\else
+ \ifnum \absseclevel<0
+ \chapterzzz{#2}
+ \else
+ \numberedsubsubseczzz{#2}
+ \fi
+\fi
+}
+
+% like \numhead, but chooses appendix heading levels
+\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
+\ifcase\absseclevel
+ \appendixzzz{#2}
+\or
+ \appendixsectionzzz{#2}
+\or
+ \appendixsubseczzz{#2}
+\or
+ \appendixsubsubseczzz{#2}
+\else
+ \ifnum \absseclevel<0
+ \appendixzzz{#2}
+ \else
+ \appendixsubsubseczzz{#2}
+ \fi
+\fi
+}
+
+% like \numhead, but chooses numberless heading levels
+\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
+\ifcase\absseclevel
+ \unnumberedzzz{#2}
+\or
+ \unnumberedseczzz{#2}
+\or
+ \unnumberedsubseczzz{#2}
+\or
+ \unnumberedsubsubseczzz{#2}
+\else
+ \ifnum \absseclevel<0
+ \unnumberedzzz{#2}
+ \else
+ \unnumberedsubsubseczzz{#2}
+ \fi
+\fi
+}
+
+
+\def\thischaptername{No Chapter Title}
+\outer\def\chapter{\parsearg\chapteryyy}
+\def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz
+\def\chapterzzz #1{\seccheck{chapter}%
+\secno=0 \subsecno=0 \subsubsecno=0
+\global\advance \chapno by 1 \message{Chapter \the\chapno}%
+\chapmacro {#1}{\the\chapno}%
+\gdef\thissection{#1}%
+\gdef\thischaptername{#1}%
+% We don't substitute the actual chapter name into \thischapter
+% because we don't want its macros evaluated now.
+\xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}%
+{\chapternofonts%
+\edef\temp{{\realbackslash chapentry {#1}{\the\chapno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\global\let\section = \numberedsec
+\global\let\subsection = \numberedsubsec
+\global\let\subsubsection = \numberedsubsubsec
+}}
+
+\outer\def\appendix{\parsearg\appendixyyy}
+\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz
+\def\appendixzzz #1{\seccheck{appendix}%
+\secno=0 \subsecno=0 \subsubsecno=0
+\global\advance \appendixno by 1 \message{Appendix \appendixletter}%
+\chapmacro {#1}{\putwordAppendix{} \appendixletter}%
+\gdef\thissection{#1}%
+\gdef\thischaptername{#1}%
+\xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}%
+{\chapternofonts%
+\edef\temp{{\realbackslash chapentry
+ {#1}{\putwordAppendix{} \appendixletter}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\appendixnoderef %
+\global\let\section = \appendixsec
+\global\let\subsection = \appendixsubsec
+\global\let\subsubsection = \appendixsubsubsec
+}}
+
+\outer\def\top{\parsearg\unnumberedyyy}
+\outer\def\unnumbered{\parsearg\unnumberedyyy}
+\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz
+\def\unnumberedzzz #1{\seccheck{unnumbered}%
+\secno=0 \subsecno=0 \subsubsecno=0
+%
+% This used to be simply \message{#1}, but TeX fully expands the
+% argument to \message. Therefore, if #1 contained @-commands, TeX
+% expanded them. For example, in `@unnumbered The @cite{Book}', TeX
+% expanded @cite (which turns out to cause errors because \cite is meant
+% to be executed, not expanded).
+%
+% Anyway, we don't want the fully-expanded definition of @cite to appear
+% as a result of the \message, we just want `@cite' itself. We use
+% \the<toks register> to achieve this: TeX expands \the<toks> only once,
+% simply yielding the contents of the <toks register>.
+\toks0 = {#1}\message{(\the\toks0)}%
+%
+\unnumbchapmacro {#1}%
+\gdef\thischapter{#1}\gdef\thissection{#1}%
+{\chapternofonts%
+\edef\temp{{\realbackslash unnumbchapentry {#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\global\let\section = \unnumberedsec
+\global\let\subsection = \unnumberedsubsec
+\global\let\subsubsection = \unnumberedsubsubsec
+}}
+
+\outer\def\numberedsec{\parsearg\secyyy}
+\def\secyyy #1{\numhead1{#1}} % normally calls seczzz
+\def\seczzz #1{\seccheck{section}%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash secentry %
+{#1}{\the\chapno}{\the\secno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+}}
+
+\outer\def\appenixsection{\parsearg\appendixsecyyy}
+\outer\def\appendixsec{\parsearg\appendixsecyyy}
+\def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz
+\def\appendixsectionzzz #1{\seccheck{appendixsection}%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash secentry %
+{#1}{\appendixletter}{\the\secno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\appendixnoderef %
+\penalty 10000 %
+}}
+
+\outer\def\unnumberedsec{\parsearg\unnumberedsecyyy}
+\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz
+\def\unnumberedseczzz #1{\seccheck{unnumberedsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+{\chapternofonts%
+\edef\temp{{\realbackslash unnumbsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}}
+
+\outer\def\numberedsubsec{\parsearg\numberedsubsecyyy}
+\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz
+\def\numberedsubseczzz #1{\seccheck{subsection}%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash subsecentry %
+{#1}{\the\chapno}{\the\secno}{\the\subsecno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+}}
+
+\outer\def\appendixsubsec{\parsearg\appendixsubsecyyy}
+\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz
+\def\appendixsubseczzz #1{\seccheck{appendixsubsec}%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash subsecentry %
+{#1}{\appendixletter}{\the\secno}{\the\subsecno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\appendixnoderef %
+\penalty 10000 %
+}}
+
+\outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy}
+\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz
+\def\unnumberedsubseczzz #1{\seccheck{unnumberedsubsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+{\chapternofonts%
+\edef\temp{{\realbackslash unnumbsubsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}}
+
+\outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy}
+\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz
+\def\numberedsubsubseczzz #1{\seccheck{subsubsection}%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}
+ {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash subsubsecentry %
+ {#1}
+ {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}
+ {\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+}}
+
+\outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy}
+\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz
+\def\appendixsubsubseczzz #1{\seccheck{appendixsubsubsec}%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}
+ {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash subsubsecentry{#1}%
+ {\appendixletter}
+ {\the\secno}{\the\subsecno}{\the\subsubsecno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\appendixnoderef %
+\penalty 10000 %
+}}
+
+\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy}
+\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz
+\def\unnumberedsubsubseczzz #1{\seccheck{unnumberedsubsubsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+{\chapternofonts%
+\edef\temp{{\realbackslash unnumbsubsubsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}}
+
+% These are variants which are not "outer", so they can appear in @ifinfo.
+% Actually, they should now be obsolete; ordinary section commands should work.
+\def\infotop{\parsearg\unnumberedzzz}
+\def\infounnumbered{\parsearg\unnumberedzzz}
+\def\infounnumberedsec{\parsearg\unnumberedseczzz}
+\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz}
+\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz}
+
+\def\infoappendix{\parsearg\appendixzzz}
+\def\infoappendixsec{\parsearg\appendixseczzz}
+\def\infoappendixsubsec{\parsearg\appendixsubseczzz}
+\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz}
+
+\def\infochapter{\parsearg\chapterzzz}
+\def\infosection{\parsearg\sectionzzz}
+\def\infosubsection{\parsearg\subsectionzzz}
+\def\infosubsubsection{\parsearg\subsubsectionzzz}
+
+% These macros control what the section commands do, according
+% to what kind of chapter we are in (ordinary, appendix, or unnumbered).
+% Define them by default for a numbered chapter.
+\global\let\section = \numberedsec
+\global\let\subsection = \numberedsubsec
+\global\let\subsubsection = \numberedsubsubsec
+
+% Define @majorheading, @heading and @subheading
+
+% NOTE on use of \vbox for chapter headings, section headings, and
+% such:
+% 1) We use \vbox rather than the earlier \line to permit
+% overlong headings to fold.
+% 2) \hyphenpenalty is set to 10000 because hyphenation in a
+% heading is obnoxious; this forbids it.
+% 3) Likewise, headings look best if no \parindent is used, and
+% if justification is not attempted. Hence \raggedright.
+
+
+\def\majorheading{\parsearg\majorheadingzzz}
+\def\majorheadingzzz #1{%
+{\advance\chapheadingskip by 10pt \chapbreak }%
+{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}\bigskip \par\penalty 200}
+
+\def\chapheading{\parsearg\chapheadingzzz}
+\def\chapheadingzzz #1{\chapbreak %
+{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}\bigskip \par\penalty 200}
+
+\def\heading{\parsearg\secheadingi}
+
+\def\subheading{\parsearg\subsecheadingi}
+
+\def\subsubheading{\parsearg\subsubsecheadingi}
+
+% These macros generate a chapter, section, etc. heading only
+% (including whitespace, linebreaking, etc. around it),
+% given all the information in convenient, parsed form.
+
+%%% Args are the skip and penalty (usually negative)
+\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi}
+
+\def\setchapterstyle #1 {\csname CHAPF#1\endcsname}
+
+%%% Define plain chapter starts, and page on/off switching for it
+% Parameter controlling skip before chapter headings (if needed)
+
+\newskip \chapheadingskip \chapheadingskip = 30pt plus 8pt minus 4pt
+
+\def\chapbreak{\dobreak \chapheadingskip {-4000}}
+\def\chappager{\par\vfill\supereject}
+\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi}
+
+\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname}
+
+\def\CHAPPAGoff{
+\global\let\pchapsepmacro=\chapbreak
+\global\let\pagealignmacro=\chappager}
+
+\def\CHAPPAGon{
+\global\let\pchapsepmacro=\chappager
+\global\let\pagealignmacro=\chappager
+\global\def\HEADINGSon{\HEADINGSsingle}}
+
+\def\CHAPPAGodd{
+\global\let\pchapsepmacro=\chapoddpage
+\global\let\pagealignmacro=\chapoddpage
+\global\def\HEADINGSon{\HEADINGSdouble}}
+
+\CHAPPAGon
+
+\def\CHAPFplain{
+\global\let\chapmacro=\chfplain
+\global\let\unnumbchapmacro=\unnchfplain}
+
+\def\chfplain #1#2{%
+ \pchapsepmacro
+ {%
+ \chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #2\enspace #1}%
+ }%
+ \bigskip
+ \penalty5000
+}
+
+\def\unnchfplain #1{%
+\pchapsepmacro %
+{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}\bigskip \par\penalty 10000 %
+}
+\CHAPFplain % The default
+
+\def\unnchfopen #1{%
+\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}\bigskip \par\penalty 10000 %
+}
+
+\def\chfopen #1#2{\chapoddpage {\chapfonts
+\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}%
+\par\penalty 5000 %
+}
+
+\def\CHAPFopen{
+\global\let\chapmacro=\chfopen
+\global\let\unnumbchapmacro=\unnchfopen}
+
+% Parameter controlling skip before section headings.
+
+\newskip \subsecheadingskip \subsecheadingskip = 17pt plus 8pt minus 4pt
+\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}}
+
+\newskip \secheadingskip \secheadingskip = 21pt plus 8pt minus 4pt
+\def\secheadingbreak{\dobreak \secheadingskip {-1000}}
+
+% @paragraphindent is defined for the Info formatting commands only.
+\let\paragraphindent=\comment
+
+% Section fonts are the base font at magstep2, which produces
+% a size a bit more than 14 points in the default situation.
+
+\def\secheading #1#2#3{\secheadingi {#2.#3\enspace #1}}
+\def\plainsecheading #1{\secheadingi {#1}}
+\def\secheadingi #1{{\advance \secheadingskip by \parskip %
+\secheadingbreak}%
+{\secfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 }
+
+
+% Subsection fonts are the base font at magstep1,
+% which produces a size of 12 points.
+
+\def\subsecheading #1#2#3#4{\subsecheadingi {#2.#3.#4\enspace #1}}
+\def\subsecheadingi #1{{\advance \subsecheadingskip by \parskip %
+\subsecheadingbreak}%
+{\subsecfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 }
+
+\def\subsubsecfonts{\subsecfonts} % Maybe this should change:
+ % Perhaps make sssec fonts scaled
+ % magstep half
+\def\subsubsecheading #1#2#3#4#5{\subsubsecheadingi {#2.#3.#4.#5\enspace #1}}
+\def\subsubsecheadingi #1{{\advance \subsecheadingskip by \parskip %
+\subsecheadingbreak}%
+{\subsubsecfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000}
+
+
+\message{toc printing,}
+
+% Finish up the main text and prepare to read what we've written
+% to \contentsfile.
+
+\newskip\contentsrightmargin \contentsrightmargin=1in
+\def\startcontents#1{%
+ \pagealignmacro
+ \immediate\closeout \contentsfile
+ \ifnum \pageno>0
+ \pageno = -1 % Request roman numbered pages.
+ \fi
+ % Don't need to put `Contents' or `Short Contents' in the headline.
+ % It is abundantly clear what they are.
+ \unnumbchapmacro{#1}\def\thischapter{}%
+ \begingroup % Set up to handle contents files properly.
+ \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11
+ \catcode`\^=7 % to see ^^e4 as \"a etc. juha@piuha.ydi.vtt.fi
+ \raggedbottom % Worry more about breakpoints than the bottom.
+ \advance\hsize by -\contentsrightmargin % Don't use the full line length.
+}
+
+
+% Normal (long) toc.
+\outer\def\contents{%
+ \startcontents{\putwordTableofContents}%
+ \input \jobname.toc
+ \endgroup
+ \vfill \eject
+}
+
+% And just the chapters.
+\outer\def\summarycontents{%
+ \startcontents{\putwordShortContents}%
+ %
+ \let\chapentry = \shortchapentry
+ \let\unnumbchapentry = \shortunnumberedentry
+ % We want a true roman here for the page numbers.
+ \secfonts
+ \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl
+ \rm
+ \advance\baselineskip by 1pt % Open it up a little.
+ \def\secentry ##1##2##3##4{}
+ \def\unnumbsecentry ##1##2{}
+ \def\subsecentry ##1##2##3##4##5{}
+ \def\unnumbsubsecentry ##1##2{}
+ \def\subsubsecentry ##1##2##3##4##5##6{}
+ \def\unnumbsubsubsecentry ##1##2{}
+ \input \jobname.toc
+ \endgroup
+ \vfill \eject
+}
+\let\shortcontents = \summarycontents
+
+% These macros generate individual entries in the table of contents.
+% The first argument is the chapter or section name.
+% The last argument is the page number.
+% The arguments in between are the chapter number, section number, ...
+
+% Chapter-level things, for both the long and short contents.
+\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}}
+
+% See comments in \dochapentry re vbox and related settings
+\def\shortchapentry#1#2#3{%
+ \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno{#3}}%
+}
+
+% Typeset the label for a chapter or appendix for the short contents.
+% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter.
+% We could simplify the code here by writing out an \appendixentry
+% command in the toc file for appendices, instead of using \chapentry
+% for both, but it doesn't seem worth it.
+\setbox0 = \hbox{\shortcontrm \putwordAppendix }
+\newdimen\shortappendixwidth \shortappendixwidth = \wd0
+
+\def\shortchaplabel#1{%
+ % We typeset #1 in a box of constant width, regardless of the text of
+ % #1, so the chapter titles will come out aligned.
+ \setbox0 = \hbox{#1}%
+ \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi
+ %
+ % This space should be plenty, since a single number is .5em, and the
+ % widest letter (M) is 1em, at least in the Computer Modern fonts.
+ % (This space doesn't include the extra space that gets added after
+ % the label; that gets put in in \shortchapentry above.)
+ \advance\dimen0 by 1.1em
+ \hbox to \dimen0{#1\hfil}%
+}
+
+\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}}
+\def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno{#2}}}
+
+% Sections.
+\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}}
+\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}}
+
+% Subsections.
+\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}}
+\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}}
+
+% And subsubsections.
+\def\subsubsecentry#1#2#3#4#5#6{%
+ \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}}
+\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}}
+
+
+% This parameter controls the indentation of the various levels.
+\newdimen\tocindent \tocindent = 3pc
+
+% Now for the actual typesetting. In all these, #1 is the text and #2 is the
+% page number.
+%
+% If the toc has to be broken over pages, we would want to be at chapters
+% if at all possible; hence the \penalty.
+\def\dochapentry#1#2{%
+ \penalty-300 \vskip\baselineskip
+ \begingroup
+ \chapentryfonts
+ \tocentry{#1}{\dopageno{#2}}%
+ \endgroup
+ \nobreak\vskip .25\baselineskip
+}
+
+\def\dosecentry#1#2{\begingroup
+ \secentryfonts \leftskip=\tocindent
+ \tocentry{#1}{\dopageno{#2}}%
+\endgroup}
+
+\def\dosubsecentry#1#2{\begingroup
+ \subsecentryfonts \leftskip=2\tocindent
+ \tocentry{#1}{\dopageno{#2}}%
+\endgroup}
+
+\def\dosubsubsecentry#1#2{\begingroup
+ \subsubsecentryfonts \leftskip=3\tocindent
+ \tocentry{#1}{\dopageno{#2}}%
+\endgroup}
+
+% Final typesetting of a toc entry; we use the same \entry macro as for
+% the index entries, but we want to suppress hyphenation here. (We
+% can't do that in the \entry macro, since index entries might consist
+% of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.)
+%
+\def\tocentry#1#2{\begingroup
+ \hyphenpenalty = 10000
+ \entry{#1}{#2}%
+\endgroup}
+
+% Space between chapter (or whatever) number and the title.
+\def\labelspace{\hskip1em \relax}
+
+\def\dopageno#1{{\rm #1}}
+\def\doshortpageno#1{{\rm #1}}
+
+\def\chapentryfonts{\secfonts \rm}
+\def\secentryfonts{\textfonts}
+\let\subsecentryfonts = \textfonts
+\let\subsubsecentryfonts = \textfonts
+
+
+\message{environments,}
+
+% Since these characters are used in examples, it should be an even number of
+% \tt widths. Each \tt character is 1en, so two makes it 1em.
+% Furthermore, these definitions must come after we define our fonts.
+\newbox\dblarrowbox \newbox\longdblarrowbox
+\newbox\pushcharbox \newbox\bullbox
+\newbox\equivbox \newbox\errorbox
+
+\let\ptexequiv = \equiv
+
+%{\tentt
+%\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil}
+%\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil}
+%\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil}
+%\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil}
+% Adapted from the manmac format (p.420 of TeXbook)
+%\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex
+% depth .1ex\hfil}
+%}
+
+\def\point{$\star$}
+
+\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}}
+\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}}
+\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}}
+
+\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}}
+
+% Adapted from the TeXbook's \boxit.
+{\tentt \global\dimen0 = 3em}% Width of the box.
+\dimen2 = .55pt % Thickness of rules
+% The text. (`r' is open on the right, `e' somewhat less so on the left.)
+\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt}
+
+\global\setbox\errorbox=\hbox to \dimen0{\hfil
+ \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right.
+ \advance\hsize by -2\dimen2 % Rules.
+ \vbox{
+ \hrule height\dimen2
+ \hbox{\vrule width\dimen2 \kern3pt % Space to left of text.
+ \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below.
+ \kern3pt\vrule width\dimen2}% Space to right.
+ \hrule height\dimen2}
+ \hfil}
+
+% The @error{} command.
+\def\error{\leavevmode\lower.7ex\copy\errorbox}
+
+% @tex ... @end tex escapes into raw Tex temporarily.
+% One exception: @ is still an escape character, so that @end tex works.
+% But \@ or @@ will get a plain tex @ character.
+
+\def\tex{\begingroup
+\catcode `\\=0 \catcode `\{=1 \catcode `\}=2
+\catcode `\$=3 \catcode `\&=4 \catcode `\#=6
+\catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie
+\catcode `\%=14
+\catcode 43=12
+\catcode`\"=12
+\catcode`\==12
+\catcode`\|=12
+\catcode`\<=12
+\catcode`\>=12
+\escapechar=`\\
+%
+\let\~=\ptextilde
+\let\{=\ptexlbrace
+\let\}=\ptexrbrace
+\let\.=\ptexdot
+\let\*=\ptexstar
+\let\dots=\ptexdots
+\def\@{@}%
+\let\bullet=\ptexbullet
+\let\b=\ptexb \let\c=\ptexc \let\i=\ptexi \let\t=\ptext \let\l=\ptexl
+\let\L=\ptexL
+%
+\let\Etex=\endgroup}
+
+% Define @lisp ... @endlisp.
+% @lisp does a \begingroup so it can rebind things,
+% including the definition of @endlisp (which normally is erroneous).
+
+% Amount to narrow the margins by for @lisp.
+\newskip\lispnarrowing \lispnarrowing=0.4in
+
+% This is the definition that ^^M gets inside @lisp, @example, and other
+% such environments. \null is better than a space, since it doesn't
+% have any width.
+\def\lisppar{\null\endgraf}
+
+% Make each space character in the input produce a normal interword
+% space in the output. Don't allow a line break at this space, as this
+% is used only in environments like @example, where each line of input
+% should produce a line of output anyway.
+%
+{\obeyspaces %
+\gdef\sepspaces{\obeyspaces\let =\tie}}
+
+% Define \obeyedspace to be our active space, whatever it is. This is
+% for use in \parsearg.
+{\sepspaces%
+\global\let\obeyedspace= }
+
+% This space is always present above and below environments.
+\newskip\envskipamount \envskipamount = 0pt
+
+% Make spacing and below environment symmetrical. We use \parskip here
+% to help in doing that, since in @example-like environments \parskip
+% is reset to zero; thus the \afterenvbreak inserts no space -- but the
+% start of the next paragraph will insert \parskip
+%
+\def\aboveenvbreak{{\advance\envskipamount by \parskip
+\endgraf \ifdim\lastskip<\envskipamount
+\removelastskip \penalty-50 \vskip\envskipamount \fi}}
+
+\let\afterenvbreak = \aboveenvbreak
+
+% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins.
+\let\nonarrowing=\relax
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \cartouche: draw rectangle w/rounded corners around argument
+\font\circle=lcircle10
+\newdimen\circthick
+\newdimen\cartouter\newdimen\cartinner
+\newskip\normbskip\newskip\normpskip\newskip\normlskip
+\circthick=\fontdimen8\circle
+%
+\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth
+\def\ctr{{\hskip 6pt\circle\char'010}}
+\def\cbl{{\circle\char'012\hskip -6pt}}
+\def\cbr{{\hskip 6pt\circle\char'011}}
+\def\carttop{\hbox to \cartouter{\hskip\lskip
+ \ctl\leaders\hrule height\circthick\hfil\ctr
+ \hskip\rskip}}
+\def\cartbot{\hbox to \cartouter{\hskip\lskip
+ \cbl\leaders\hrule height\circthick\hfil\cbr
+ \hskip\rskip}}
+%
+\newskip\lskip\newskip\rskip
+
+\long\def\cartouche{%
+\begingroup
+ \lskip=\leftskip \rskip=\rightskip
+ \leftskip=0pt\rightskip=0pt %we want these *outside*.
+ \cartinner=\hsize \advance\cartinner by-\lskip
+ \advance\cartinner by-\rskip
+ \cartouter=\hsize
+ \advance\cartouter by 18pt % allow for 3pt kerns on either
+% side, and for 6pt waste from
+% each corner char
+ \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip
+ % Flag to tell @lisp, etc., not to narrow margin.
+ \let\nonarrowing=\comment
+ \vbox\bgroup
+ \baselineskip=0pt\parskip=0pt\lineskip=0pt
+ \carttop
+ \hbox\bgroup
+ \hskip\lskip
+ \vrule\kern3pt
+ \vbox\bgroup
+ \hsize=\cartinner
+ \kern3pt
+ \begingroup
+ \baselineskip=\normbskip
+ \lineskip=\normlskip
+ \parskip=\normpskip
+ \vskip -\parskip
+\def\Ecartouche{%
+ \endgroup
+ \kern3pt
+ \egroup
+ \kern3pt\vrule
+ \hskip\rskip
+ \egroup
+ \cartbot
+ \egroup
+\endgroup
+}}
+
+
+% This macro is called at the beginning of all the @example variants,
+% inside a group.
+\def\nonfillstart{%
+ \aboveenvbreak
+ \inENV % This group ends at the end of the body
+ \hfuzz = 12pt % Don't be fussy
+ \sepspaces % Make spaces be word-separators rather than space tokens.
+ \singlespace
+ \let\par = \lisppar % don't ignore blank lines
+ \obeylines % each line of input is a line of output
+ \parskip = 0pt
+ \parindent = 0pt
+ \emergencystretch = 0pt % don't try to avoid overfull boxes
+ % @cartouche defines \nonarrowing to inhibit narrowing
+ % at next level down.
+ \ifx\nonarrowing\relax
+ \advance \leftskip by \lispnarrowing
+ \exdentamount=\lispnarrowing
+ \let\exdent=\nofillexdent
+ \let\nonarrowing=\relax
+ \fi
+}
+
+% To ending an @example-like environment, we first end the paragraph
+% (via \afterenvbreak's vertical glue), and then the group. That way we
+% keep the zero \parskip that the environments set -- \parskip glue
+% will be inserted at the beginning of the next paragraph in the
+% document, after the environment.
+%
+\def\nonfillfinish{\afterenvbreak\endgroup}%
+
+% This macro is
+\def\lisp{\begingroup
+ \nonfillstart
+ \let\Elisp = \nonfillfinish
+ \tt
+ \rawbackslash % have \ input char produce \ char from current font
+ \gobble
+}
+
+% Define the \E... control sequence only if we are inside the
+% environment, so the error checking in \end will work.
+%
+% We must call \lisp last in the definition, since it reads the
+% return following the @example (or whatever) command.
+%
+\def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp}
+\def\smallexample{\begingroup \def\Esmallexample{\nonfillfinish\endgroup}\lisp}
+\def\smalllisp{\begingroup \def\Esmalllisp{\nonfillfinish\endgroup}\lisp}
+
+% @smallexample and @smalllisp. This is not used unless the @smallbook
+% command is given. Originally contributed by Pavel@xerox.
+%
+\def\smalllispx{\begingroup
+ \nonfillstart
+ \let\Esmalllisp = \nonfillfinish
+ \let\Esmallexample = \nonfillfinish
+ %
+ % Smaller interline space and fonts for small examples.
+ \setleading{10pt}%
+ \indexfonts \tt
+ \rawbackslash % make \ output the \ character from the current font (tt)
+ \gobble
+}
+
+% This is @display; same as @lisp except use roman font.
+%
+\def\display{\begingroup
+ \nonfillstart
+ \let\Edisplay = \nonfillfinish
+ \gobble
+}
+
+% This is @format; same as @display except don't narrow margins.
+%
+\def\format{\begingroup
+ \let\nonarrowing = t
+ \nonfillstart
+ \let\Eformat = \nonfillfinish
+ \gobble
+}
+
+% @flushleft (same as @format) and @flushright.
+%
+\def\flushleft{\begingroup
+ \let\nonarrowing = t
+ \nonfillstart
+ \let\Eflushleft = \nonfillfinish
+ \gobble
+}
+\def\flushright{\begingroup
+ \let\nonarrowing = t
+ \nonfillstart
+ \let\Eflushright = \nonfillfinish
+ \advance\leftskip by 0pt plus 1fill
+ \gobble}
+
+% @quotation does normal linebreaking (hence we can't use \nonfillstart)
+% and narrows the margins.
+%
+\def\quotation{%
+ \begingroup\inENV %This group ends at the end of the @quotation body
+ {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip
+ \singlespace
+ \parindent=0pt
+ % We have retained a nonzero parskip for the environment, since we're
+ % doing normal filling. So to avoid extra space below the environment...
+ \def\Equotation{\parskip = 0pt \nonfillfinish}%
+ %
+ % @cartouche defines \nonarrowing to inhibit narrowing at next level down.
+ \ifx\nonarrowing\relax
+ \advance\leftskip by \lispnarrowing
+ \advance\rightskip by \lispnarrowing
+ \exdentamount = \lispnarrowing
+ \let\nonarrowing = \relax
+ \fi
+}
+
+\message{defuns,}
+% Define formatter for defuns
+% First, allow user to change definition object font (\df) internally
+\def\setdeffont #1 {\csname DEF#1\endcsname}
+
+\newskip\defbodyindent \defbodyindent=.4in
+\newskip\defargsindent \defargsindent=50pt
+\newskip\deftypemargin \deftypemargin=12pt
+\newskip\deflastargmargin \deflastargmargin=18pt
+
+\newcount\parencount
+% define \functionparens, which makes ( and ) and & do special things.
+% \functionparens affects the group it is contained in.
+\def\activeparens{%
+\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active
+\catcode`\[=\active \catcode`\]=\active}
+
+% Make control sequences which act like normal parenthesis chars.
+\let\lparen = ( \let\rparen = )
+
+{\activeparens % Now, smart parens don't turn on until &foo (see \amprm)
+
+% Be sure that we always have a definition for `(', etc. For example,
+% if the fn name has parens in it, \boldbrax will not be in effect yet,
+% so TeX would otherwise complain about undefined control sequence.
+\global\let(=\lparen \global\let)=\rparen
+\global\let[=\lbrack \global\let]=\rbrack
+
+\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 }
+\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb}
+
+% Definitions of (, ) and & used in args for functions.
+% This is the definition of ( outside of all parentheses.
+\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested %
+\global\advance\parencount by 1 }
+%
+% This is the definition of ( when already inside a level of parens.
+\gdef\opnested{\char`\(\global\advance\parencount by 1 }
+%
+\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0.
+% also in that case restore the outer-level definition of (.
+\ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi
+\global\advance \parencount by -1 }
+% If we encounter &foo, then turn on ()-hacking afterwards
+\gdef\amprm#1 {{\rm\&#1}\let(=\oprm \let)=\clrm\ }
+%
+\gdef\normalparens{\boldbrax\let&=\ampnr}
+} % End of definition inside \activeparens
+%% These parens (in \boldbrax) actually are a little bolder than the
+%% contained text. This is especially needed for [ and ]
+\def\opnr{{\sf\char`\(}} \def\clnr{{\sf\char`\)}} \def\ampnr{\&}
+\def\lbrb{{\bf\char`\[}} \def\rbrb{{\bf\char`\]}}
+
+% First, defname, which formats the header line itself.
+% #1 should be the function name.
+% #2 should be the type of definition, such as "Function".
+
+\def\defname #1#2{%
+% Get the values of \leftskip and \rightskip as they were
+% outside the @def...
+\dimen2=\leftskip
+\advance\dimen2 by -\defbodyindent
+\dimen3=\rightskip
+\advance\dimen3 by -\defbodyindent
+\noindent %
+\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}%
+\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line
+\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations
+\parshape 2 0in \dimen0 \defargsindent \dimen1 %
+% Now output arg 2 ("Function" or some such)
+% ending at \deftypemargin from the right margin,
+% but stuck inside a box of width 0 so it does not interfere with linebreaking
+{% Adjust \hsize to exclude the ambient margins,
+% so that \rightline will obey them.
+\advance \hsize by -\dimen2 \advance \hsize by -\dimen3
+\rlap{\rightline{{\rm #2}\hskip \deftypemargin}}}%
+% Make all lines underfull and no complaints:
+\tolerance=10000 \hbadness=10000
+\advance\leftskip by -\defbodyindent
+\exdentamount=\defbodyindent
+{\df #1}\enskip % Generate function name
+}
+
+% Actually process the body of a definition
+% #1 should be the terminating control sequence, such as \Edefun.
+% #2 should be the "another name" control sequence, such as \defunx.
+% #3 should be the control sequence that actually processes the header,
+% such as \defunheader.
+
+\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2{\begingroup\obeylines\activeparens\spacesplit#3}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup %
+\catcode 61=\active % 61 is `='
+\obeylines\activeparens\spacesplit#3}
+
+\def\defmethparsebody #1#2#3#4 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\activeparens\spacesplit{#3{#4}}}
+
+\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 ##2 {\def#4{##1}%
+\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\activeparens\spacesplit{#3{#5}}}
+
+% These parsing functions are similar to the preceding ones
+% except that they do not make parens into active characters.
+% These are used for "variables" since they have no arguments.
+
+\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2{\begingroup\obeylines\spacesplit#3}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup %
+\catcode 61=\active %
+\obeylines\spacesplit#3}
+
+% This is used for \def{tp,vr}parsebody. It could probably be used for
+% some of the others, too, with some judicious conditionals.
+%
+\def\parsebodycommon#1#2#3{%
+ \begingroup\inENV %
+ \medbreak %
+ % Define the end token that this defining construct specifies
+ % so that it will exit this group.
+ \def#1{\endgraf\endgroup\medbreak}%
+ \def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}%
+ \parindent=0in
+ \advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+ \exdentamount=\defbodyindent
+ \begingroup\obeylines
+}
+
+\def\defvrparsebody#1#2#3#4 {%
+ \parsebodycommon{#1}{#2}{#3}%
+ \spacesplit{#3{#4}}%
+}
+
+% This loses on `@deftp {Data Type} {struct termios}' -- it thinks the
+% type is just `struct', because we lose the braces in `{struct
+% termios}' when \spacesplit reads its undelimited argument. Sigh.
+% \let\deftpparsebody=\defvrparsebody
+%
+% So, to get around this, we put \empty in with the type name. That
+% way, TeX won't find exactly `{...}' as an undelimited argument, and
+% won't strip off the braces.
+%
+\def\deftpparsebody #1#2#3#4 {%
+ \parsebodycommon{#1}{#2}{#3}%
+ \spacesplit{\parsetpheaderline{#3{#4}}}\empty
+}
+
+% Fine, but then we have to eventually remove the \empty *and* the
+% braces (if any). That's what this does, putting the result in \tptemp.
+%
+\def\removeemptybraces\empty#1\relax{\def\tptemp{#1}}%
+
+% After \spacesplit has done its work, this is called -- #1 is the final
+% thing to call, #2 the type name (which starts with \empty), and #3
+% (which might be empty) the arguments.
+%
+\def\parsetpheaderline#1#2#3{%
+ \removeemptybraces#2\relax
+ #1{\tptemp}{#3}%
+}%
+
+\def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 ##2 {\def#4{##1}%
+\begingroup\obeylines\spacesplit{#3{##2}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\spacesplit{#3{#5}}}
+
+% Split up #2 at the first space token.
+% call #1 with two arguments:
+% the first is all of #2 before the space token,
+% the second is all of #2 after that space token.
+% If #2 contains no space token, all of it is passed as the first arg
+% and the second is passed as empty.
+
+{\obeylines
+\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}%
+\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{%
+\ifx\relax #3%
+#1{#2}{}\else #1{#2}{#3#4}\fi}}
+
+% So much for the things common to all kinds of definitions.
+
+% Define @defun.
+
+% First, define the processing that is wanted for arguments of \defun
+% Use this to expand the args and terminate the paragraph they make up
+
+\def\defunargs #1{\functionparens \sl
+% Expand, preventing hyphenation at `-' chars.
+% Note that groups don't affect changes in \hyphenchar.
+\hyphenchar\tensl=0
+#1%
+\hyphenchar\tensl=45
+\ifnum\parencount=0 \else \errmessage{unbalanced parens in @def arguments}\fi%
+\interlinepenalty=10000
+\advance\rightskip by 0pt plus 1fil
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000%
+}
+
+\def\deftypefunargs #1{%
+% Expand, preventing hyphenation at `-' chars.
+% Note that groups don't affect changes in \hyphenchar.
+\functionparens
+\tclose{#1}% avoid \code because of side effects on active chars
+\interlinepenalty=10000
+\advance\rightskip by 0pt plus 1fil
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000%
+}
+
+% Do complete processing of one @defun or @defunx line already parsed.
+
+% @deffn Command forward-char nchars
+
+\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader}
+
+\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defun == @deffn Function
+
+\def\defun{\defparsebody\Edefun\defunx\defunheader}
+
+\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Function}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @deftypefun int foobar (int @var{foo}, float @var{bar})
+
+\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader}
+
+% #1 is the data type. #2 is the name and args.
+\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax}
+% #1 is the data type, #2 the name, #3 the args.
+\def\deftypefunheaderx #1#2 #3\relax{%
+\doind {fn}{\code{#2}}% Make entry in function index
+\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Function}%
+\deftypefunargs {#3}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar})
+
+\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader}
+
+% \defheaderxcond#1\relax$$$
+% puts #1 in @code, followed by a space, but does nothing if #1 is null.
+\def\defheaderxcond#1#2$$${\ifx#1\relax\else\code{#1#2} \fi}
+
+% #1 is the classification. #2 is the data type. #3 is the name and args.
+\def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax}
+% #1 is the classification, #2 the data type, #3 the name, #4 the args.
+\def\deftypefnheaderx #1#2#3 #4\relax{%
+\doind {fn}{\code{#3}}% Make entry in function index
+\begingroup
+\normalparens % notably, turn off `&' magic, which prevents
+% at least some C++ text from working
+\defname {\defheaderxcond#2\relax$$$#3}{#1}%
+\deftypefunargs {#4}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defmac == @deffn Macro
+
+\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader}
+
+\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Macro}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defspec == @deffn Special Form
+
+\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader}
+
+\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Special Form}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% This definition is run if you use @defunx
+% anywhere other than immediately after a @defun or @defunx.
+
+\def\deffnx #1 {\errmessage{@deffnx in invalid context}}
+\def\defunx #1 {\errmessage{@defunx in invalid context}}
+\def\defmacx #1 {\errmessage{@defmacx in invalid context}}
+\def\defspecx #1 {\errmessage{@defspecx in invalid context}}
+\def\deftypefnx #1 {\errmessage{@deftypefnx in invalid context}}
+\def\deftypeunx #1 {\errmessage{@deftypeunx in invalid context}}
+
+% @defmethod, and so on
+
+% @defop {Funny Method} foo-class frobnicate argument
+
+\def\defop #1 {\def\defoptype{#1}%
+\defopparsebody\Edefop\defopx\defopheader\defoptype}
+
+\def\defopheader #1#2#3{%
+\dosubind {fn}{\code{#2}}{on #1}% Make entry in function index
+\begingroup\defname {#2}{\defoptype{} on #1}%
+\defunargs {#3}\endgroup %
+}
+
+% @defmethod == @defop Method
+
+\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader}
+
+\def\defmethodheader #1#2#3{%
+\dosubind {fn}{\code{#2}}{on #1}% entry in function index
+\begingroup\defname {#2}{Method on #1}%
+\defunargs {#3}\endgroup %
+}
+
+% @defcv {Class Option} foo-class foo-flag
+
+\def\defcv #1 {\def\defcvtype{#1}%
+\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype}
+
+\def\defcvarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index
+\begingroup\defname {#2}{\defcvtype{} of #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% @defivar == @defcv {Instance Variable}
+
+\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader}
+
+\def\defivarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index
+\begingroup\defname {#2}{Instance Variable of #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% These definitions are run if you use @defmethodx, etc.,
+% anywhere other than immediately after a @defmethod, etc.
+
+\def\defopx #1 {\errmessage{@defopx in invalid context}}
+\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}}
+\def\defcvx #1 {\errmessage{@defcvx in invalid context}}
+\def\defivarx #1 {\errmessage{@defivarx in invalid context}}
+
+% Now @defvar
+
+% First, define the processing that is wanted for arguments of @defvar.
+% This is actually simple: just print them in roman.
+% This must expand the args and terminate the paragraph they make up
+\def\defvarargs #1{\normalparens #1%
+\interlinepenalty=10000
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000}
+
+% @defvr Counter foo-count
+
+\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader}
+
+\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup}
+
+% @defvar == @defvr Variable
+
+\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader}
+
+\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{Variable}%
+\defvarargs {#2}\endgroup %
+}
+
+% @defopt == @defvr {User Option}
+
+\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader}
+
+\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{User Option}%
+\defvarargs {#2}\endgroup %
+}
+
+% @deftypevar int foobar
+
+\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader}
+
+% #1 is the data type. #2 is the name.
+\def\deftypevarheader #1#2{%
+\doind {vr}{\code{#2}}% Make entry in variables index
+\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Variable}%
+\interlinepenalty=10000
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000
+\endgroup}
+
+% @deftypevr {Global Flag} int enable
+
+\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader}
+
+\def\deftypevrheader #1#2#3{\doind {vr}{\code{#3}}%
+\begingroup\defname {\defheaderxcond#2\relax$$$#3}{#1}
+\interlinepenalty=10000
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000
+\endgroup}
+
+% This definition is run if you use @defvarx
+% anywhere other than immediately after a @defvar or @defvarx.
+
+\def\defvrx #1 {\errmessage{@defvrx in invalid context}}
+\def\defvarx #1 {\errmessage{@defvarx in invalid context}}
+\def\defoptx #1 {\errmessage{@defoptx in invalid context}}
+\def\deftypevarx #1 {\errmessage{@deftypevarx in invalid context}}
+\def\deftypevrx #1 {\errmessage{@deftypevrx in invalid context}}
+
+% Now define @deftp
+% Args are printed in bold, a slight difference from @defvar.
+
+\def\deftpargs #1{\bf \defvarargs{#1}}
+
+% @deftp Class window height width ...
+
+\def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader}
+
+\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}%
+\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup}
+
+% This definition is run if you use @deftpx, etc
+% anywhere other than immediately after a @deftp, etc.
+
+\def\deftpx #1 {\errmessage{@deftpx in invalid context}}
+
+\message{cross reference,}
+% Define cross-reference macros
+\newwrite \auxfile
+
+\newif\ifhavexrefs % True if xref values are known.
+\newif\ifwarnedxrefs % True if we warned once that they aren't known.
+
+% \setref{foo} defines a cross-reference point named foo.
+
+\def\setref#1{%
+\dosetq{#1-title}{Ytitle}%
+\dosetq{#1-pg}{Ypagenumber}%
+\dosetq{#1-snt}{Ysectionnumberandtype}}
+
+\def\unnumbsetref#1{%
+\dosetq{#1-title}{Ytitle}%
+\dosetq{#1-pg}{Ypagenumber}%
+\dosetq{#1-snt}{Ynothing}}
+
+\def\appendixsetref#1{%
+\dosetq{#1-title}{Ytitle}%
+\dosetq{#1-pg}{Ypagenumber}%
+\dosetq{#1-snt}{Yappendixletterandtype}}
+
+% \xref, \pxref, and \ref generate cross-references to specified points.
+% For \xrefX, #1 is the node name, #2 the name of the Info
+% cross-reference, #3 the printed node name, #4 the name of the Info
+% file, #5 the name of the printed manual. All but the node name can be
+% omitted.
+%
+\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]}
+\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]}
+\def\ref#1{\xrefX[#1,,,,,,,]}
+\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup
+ \def\printedmanual{\ignorespaces #5}%
+ \def\printednodename{\ignorespaces #3}%
+ \setbox1=\hbox{\printedmanual}%
+ \setbox0=\hbox{\printednodename}%
+ \ifdim \wd0 = 0pt
+ % No printed node name was explicitly given.
+ \ifx\SETxref-automatic-section-title\relax %
+ % Use the actual chapter/section title appear inside
+ % the square brackets. Use the real section title if we have it.
+ \ifdim \wd1>0pt%
+ % It is in another manual, so we don't have it.
+ \def\printednodename{\ignorespaces #1}%
+ \else
+ \ifhavexrefs
+ % We know the real title if we have the xref values.
+ \def\printednodename{\refx{#1-title}}%
+ \else
+ % Otherwise just copy the Info node name.
+ \def\printednodename{\ignorespaces #1}%
+ \fi%
+ \fi
+ \def\printednodename{#1-title}%
+ \else
+ % Use the node name inside the square brackets.
+ \def\printednodename{\ignorespaces #1}%
+ \fi
+ \fi
+ %
+ % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not
+ % insert empty discretionaries after hyphens, which means that it will
+ % not find a line break at a hyphen in a node names. Since some manuals
+ % are best written with fairly long node names, containing hyphens, this
+ % is a loss. Therefore, we give the text of the node name again, so it
+ % is as if TeX is seeing it for the first time.
+ \ifdim \wd1 > 0pt
+ \putwordsection{} ``\printednodename'' in \cite{\printedmanual}%
+ \else
+ % _ (for example) has to be the character _ for the purposes of the
+ % control sequence corresponding to the node, but it has to expand
+ % into the usual \leavevmode...\vrule stuff for purposes of
+ % printing. So we \turnoffactive for the \refx-snt, back on for the
+ % printing, back off for the \refx-pg.
+ {\turnoffactive \refx{#1-snt}{}}%
+ \space [\printednodename],\space
+ \turnoffactive \putwordpage\tie\refx{#1-pg}{}%
+ \fi
+\endgroup}
+
+% \dosetq is the interface for calls from other macros
+
+% Use \turnoffactive so that punctuation chars such as underscore
+% work in node names.
+\def\dosetq #1#2{{\let\folio=0 \turnoffactive%
+\edef\next{\write\auxfile{\internalsetq {#1}{#2}}}%
+\next}}
+
+% \internalsetq {foo}{page} expands into
+% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...}
+% When the aux file is read, ' is the escape character
+
+\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}}
+
+% Things to be expanded by \internalsetq
+
+\def\Ypagenumber{\folio}
+
+\def\Ytitle{\thissection}
+
+\def\Ynothing{}
+
+\def\Ysectionnumberandtype{%
+\ifnum\secno=0 \putwordChapter\xreftie\the\chapno %
+\else \ifnum \subsecno=0 \putwordSection\xreftie\the\chapno.\the\secno %
+\else \ifnum \subsubsecno=0 %
+\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno %
+\else %
+\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno %
+\fi \fi \fi }
+
+\def\Yappendixletterandtype{%
+\ifnum\secno=0 \putwordAppendix\xreftie'char\the\appendixno{}%
+\else \ifnum \subsecno=0 \putwordSection\xreftie'char\the\appendixno.\the\secno %
+\else \ifnum \subsubsecno=0 %
+\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno %
+\else %
+\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno %
+\fi \fi \fi }
+
+\gdef\xreftie{'tie}
+
+% Use TeX 3.0's \inputlineno to get the line number, for better error
+% messages, but if we're using an old version of TeX, don't do anything.
+%
+\ifx\inputlineno\thisisundefined
+ \let\linenumber = \empty % Non-3.0.
+\else
+ \def\linenumber{\the\inputlineno:\space}
+\fi
+
+% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME.
+% If its value is nonempty, SUFFIX is output afterward.
+
+\def\refx#1#2{%
+ \expandafter\ifx\csname X#1\endcsname\relax
+ % If not defined, say something at least.
+ $\langle$un\-de\-fined$\rangle$%
+ \ifhavexrefs
+ \message{\linenumber Undefined cross reference `#1'.}%
+ \else
+ \ifwarnedxrefs\else
+ \global\warnedxrefstrue
+ \message{Cross reference values unknown; you must run TeX again.}%
+ \fi
+ \fi
+ \else
+ % It's defined, so just use it.
+ \csname X#1\endcsname
+ \fi
+ #2% Output the suffix in any case.
+}
+
+% Read the last existing aux file, if any. No error if none exists.
+
+% This is the macro invoked by entries in the aux file.
+\def\xrdef #1#2{
+{\catcode`\'=\other\expandafter \gdef \csname X#1\endcsname {#2}}}
+
+\def\readauxfile{%
+\begingroup
+\catcode `\^^@=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\^^C=\other
+\catcode `\^^D=\other
+\catcode `\^^E=\other
+\catcode `\^^F=\other
+\catcode `\^^G=\other
+\catcode `\^^H=\other
+\catcode `\ =\other
+\catcode `\^^L=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode 26=\other
+\catcode `\^^[=\other
+\catcode `\^^\=\other
+\catcode `\^^]=\other
+\catcode `\^^^=\other
+\catcode `\^^_=\other
+\catcode `\@=\other
+\catcode `\^=\other
+\catcode `\~=\other
+\catcode `\[=\other
+\catcode `\]=\other
+\catcode`\"=\other
+\catcode`\_=\other
+\catcode`\|=\other
+\catcode`\<=\other
+\catcode`\>=\other
+\catcode `\$=\other
+\catcode `\#=\other
+\catcode `\&=\other
+% `\+ does not work, so use 43.
+\catcode 43=\other
+% Make the characters 128-255 be printing characters
+{%
+ \count 1=128
+ \def\loop{%
+ \catcode\count 1=\other
+ \advance\count 1 by 1
+ \ifnum \count 1<256 \loop \fi
+ }%
+}%
+% the aux file uses ' as the escape.
+% Turn off \ as an escape so we do not lose on
+% entries which were dumped with control sequences in their names.
+% For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^
+% Reference to such entries still does not work the way one would wish,
+% but at least they do not bomb out when the aux file is read in.
+\catcode `\{=1 \catcode `\}=2
+\catcode `\%=\other
+\catcode `\'=0
+\catcode `\\=\other
+\openin 1 \jobname.aux
+\ifeof 1 \else \closein 1 \input \jobname.aux \global\havexrefstrue
+\global\warnedobstrue
+\fi
+% Open the new aux file. Tex will close it automatically at exit.
+\openout \auxfile=\jobname.aux
+\endgroup}
+
+
+% Footnotes.
+
+\newcount \footnoteno
+
+% The trailing space in the following definition for supereject is
+% vital for proper filling; pages come out unaligned when you do a
+% pagealignmacro call if that space before the closing brace is
+% removed.
+\def\supereject{\par\penalty -20000\footnoteno =0 }
+
+% @footnotestyle is meaningful for info output only..
+\let\footnotestyle=\comment
+
+\let\ptexfootnote=\footnote
+
+{\catcode `\@=11
+%
+% Auto-number footnotes. Otherwise like plain.
+\gdef\footnote{%
+ \global\advance\footnoteno by \@ne
+ \edef\thisfootno{$^{\the\footnoteno}$}%
+ %
+ % In case the footnote comes at the end of a sentence, preserve the
+ % extra spacing after we do the footnote number.
+ \let\@sf\empty
+ \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi
+ %
+ % Remove inadvertent blank space before typesetting the footnote number.
+ \unskip
+ \thisfootno\@sf
+ \footnotezzz
+}%
+
+% Don't bother with the trickery in plain.tex to not require the
+% footnote text as a parameter. Our footnotes don't need to be so general.
+%
+\long\gdef\footnotezzz#1{\insert\footins{%
+ % We want to typeset this text as a normal paragraph, even if the
+ % footnote reference occurs in (for example) a display environment.
+ % So reset some parameters.
+ \interlinepenalty\interfootnotelinepenalty
+ \splittopskip\ht\strutbox % top baseline for broken footnotes
+ \splitmaxdepth\dp\strutbox
+ \floatingpenalty\@MM
+ \leftskip\z@skip
+ \rightskip\z@skip
+ \spaceskip\z@skip
+ \xspaceskip\z@skip
+ \parindent\defaultparindent
+ %
+ % Hang the footnote text off the number.
+ \hang
+ \textindent{\thisfootno}%
+ %
+ % Don't crash into the line above the footnote text. Since this
+ % expands into a box, it must come within the paragraph, lest it
+ % provide a place where TeX can split the footnote.
+ \footstrut
+ #1\strut}%
+}
+
+}%end \catcode `\@=11
+
+% Set the baselineskip to #1, and the lineskip and strut size
+% correspondingly. There is no deep meaning behind these magic numbers
+% used as factors; they just match (closely enough) what Knuth defined.
+%
+\def\lineskipfactor{.08333}
+\def\strutheightpercent{.70833}
+\def\strutdepthpercent {.29167}
+%
+\def\setleading#1{%
+ \normalbaselineskip = #1\relax
+ \normallineskip = \lineskipfactor\normalbaselineskip
+ \normalbaselines
+ \setbox\strutbox =\hbox{%
+ \vrule width0pt height\strutheightpercent\baselineskip
+ depth \strutdepthpercent \baselineskip
+ }%
+}
+
+% @| inserts a changebar to the left of the current line. It should
+% surround any changed text. This approach does *not* work if the
+% change spans more than two lines of output. To handle that, we would
+% have adopt a much more difficult approach (putting marks into the main
+% vertical list for the beginning and end of each change).
+%
+\def\|{%
+ % \vadjust can only be used in horizontal mode.
+ \leavevmode
+ %
+ % Append this vertical mode material after the current line in the output.
+ \vadjust{%
+ % We want to insert a rule with the height and depth of the current
+ % leading; that is exactly what \strutbox is supposed to record.
+ \vskip-\baselineskip
+ %
+ % \vadjust-items are inserted at the left edge of the type. So
+ % the \llap here moves out into the left-hand margin.
+ \llap{%
+ %
+ % For a thicker or thinner bar, change the `1pt'.
+ \vrule height\baselineskip width1pt
+ %
+ % This is the space between the bar and the text.
+ \hskip 12pt
+ }%
+ }%
+}
+
+% For a final copy, take out the rectangles
+% that mark overfull boxes (in case you have decided
+% that the text looks ok even though it passes the margin).
+%
+\def\finalout{\overfullrule=0pt}
+
+
+% End of control word definitions.
+
+\message{and turning on texinfo input format.}
+
+\def\openindices{%
+ \newindex{cp}%
+ \newcodeindex{fn}%
+ \newcodeindex{vr}%
+ \newcodeindex{tp}%
+ \newcodeindex{ky}%
+ \newcodeindex{pg}%
+}
+
+% Set some numeric style parameters, for 8.5 x 11 format.
+
+%\hsize = 6.5in
+\newdimen\defaultparindent \defaultparindent = 15pt
+\parindent = \defaultparindent
+\parskip 18pt plus 1pt
+\setleading{15pt}
+\advance\topskip by 1.2cm
+
+% Prevent underfull vbox error messages.
+\vbadness=10000
+
+% Following George Bush, just get rid of widows and orphans.
+\widowpenalty=10000
+\clubpenalty=10000
+
+% Use TeX 3.0's \emergencystretch to help line breaking, but if we're
+% using an old version of TeX, don't do anything. We want the amount of
+% stretch added to depend on the line length, hence the dependence on
+% \hsize. This makes it come to about 9pt for the 8.5x11 format.
+%
+\ifx\emergencystretch\thisisundefined
+ % Allow us to assign to \emergencystretch anyway.
+ \def\emergencystretch{\dimen0}%
+\else
+ \emergencystretch = \hsize
+ \divide\emergencystretch by 45
+\fi
+
+% Use @smallbook to reset parameters for 7x9.5 format (or else 7x9.25)
+\def\smallbook{
+
+% These values for secheadingskip and subsecheadingskip are
+% experiments. RJC 7 Aug 1992
+\global\secheadingskip = 17pt plus 6pt minus 3pt
+\global\subsecheadingskip = 14pt plus 6pt minus 3pt
+
+\global\lispnarrowing = 0.3in
+\setleading{12pt}
+\advance\topskip by -1cm
+\global\parskip 3pt plus 1pt
+\global\hsize = 5in
+\global\vsize=7.5in
+\global\tolerance=700
+\global\hfuzz=1pt
+\global\contentsrightmargin=0pt
+\global\deftypemargin=0pt
+\global\defbodyindent=.5cm
+
+\global\pagewidth=\hsize
+\global\pageheight=\vsize
+
+\global\let\smalllisp=\smalllispx
+\global\let\smallexample=\smalllispx
+\global\def\Esmallexample{\Esmalllisp}
+}
+
+% Use @afourpaper to print on European A4 paper.
+\def\afourpaper{
+\global\tolerance=700
+\global\hfuzz=1pt
+\setleading{12pt}
+\global\parskip 15pt plus 1pt
+
+\global\vsize= 53\baselineskip
+\advance\vsize by \topskip
+%\global\hsize= 5.85in % A4 wide 10pt
+\global\hsize= 6.5in
+\global\outerhsize=\hsize
+\global\advance\outerhsize by 0.5in
+\global\outervsize=\vsize
+\global\advance\outervsize by 0.6in
+
+\global\pagewidth=\hsize
+\global\pageheight=\vsize
+}
+
+% Allow control of the text dimensions. Parameters in order: textheight;
+% textwidth; \voffset; \hoffset (!); binding offset. All require a dimension;
+% header is additional; added length extends the bottom of the page.
+
+\def\changepagesizes#1#2#3#4#5
+{\global\vsize= #1
+ \advance\vsize by \topskip
+ \global\voffset= #3
+ \global\hsize= #2
+ \global\outerhsize=\hsize
+ \global\advance\outerhsize by 0.5in
+ \global\outervsize=\vsize
+ \global\advance\outervsize by 0.6in
+ \global\pagewidth=\hsize
+ \global\pageheight=\vsize
+ \global\normaloffset= #4
+ \global\bindingoffset= #5}
+
+% This layout is compatible with Latex on A4 paper.
+
+\def\afourlatex{\changepagesizes{22cm}{15cm}{7mm}{4.6mm}{5mm}}
+
+% Define macros to output various characters with catcode for normal text.
+\catcode`\"=\other
+\catcode`\~=\other
+\catcode`\^=\other
+\catcode`\_=\other
+\catcode`\|=\other
+\catcode`\<=\other
+\catcode`\>=\other
+\catcode`\+=\other
+\def\normaldoublequote{"}
+\def\normaltilde{~}
+\def\normalcaret{^}
+\def\normalunderscore{_}
+\def\normalverticalbar{|}
+\def\normalless{<}
+\def\normalgreater{>}
+\def\normalplus{+}
+
+% This macro is used to make a character print one way in ttfont
+% where it can probably just be output, and another way in other fonts,
+% where something hairier probably needs to be done.
+%
+% #1 is what to print if we are indeed using \tt; #2 is what to print
+% otherwise. Since all the Computer Modern typewriter fonts have zero
+% interword stretch (and shrink), and it is reasonable to expect all
+% typewriter fonts to have this, we can check that font parameter.
+%
+\def\ifusingtt#1#2{\ifdim \fontdimen3\the\font=0pt #1\else #2\fi}
+
+% Turn off all special characters except @
+% (and those which the user can use as if they were ordinary).
+% Most of these we simply print from the \tt font, but for some, we can
+% use math or other variants that look better in normal text.
+
+\catcode`\"=\active
+\def\activedoublequote{{\tt \char '042}}
+\let"=\activedoublequote
+\catcode`\~=\active
+\def~{{\tt \char '176}}
+\chardef\hat=`\^
+\catcode`\^=\active
+\def^{{\tt \hat}}
+
+\catcode`\_=\active
+\def_{\ifusingtt\normalunderscore\_}
+% Subroutine for the previous macro.
+\def\_{\lvvmode \kern.06em \vbox{\hrule width.3em height.1ex}}
+
+% \lvvmode is equivalent in function to \leavevmode.
+% Using \leavevmode runs into trouble when written out to
+% an index file due to the expansion of \leavevmode into ``\unhbox
+% \voidb@x'' ---which looks to TeX like ``\unhbox \voidb\x'' due to our
+% magic tricks with @.
+\def\lvvmode{\vbox to 0pt{}}
+
+\catcode`\|=\active
+\def|{{\tt \char '174}}
+\chardef \less=`\<
+\catcode`\<=\active
+\def<{{\tt \less}}
+\chardef \gtr=`\>
+\catcode`\>=\active
+\def>{{\tt \gtr}}
+\catcode`\+=\active
+\def+{{\tt \char 43}}
+%\catcode 27=\active
+%\def^^[{$\diamondsuit$}
+
+% Set up an active definition for =, but don't enable it most of the time.
+{\catcode`\==\active
+\global\def={{\tt \char 61}}}
+
+\catcode`\@=0
+
+% \rawbackslashxx output one backslash character in current font
+\global\chardef\rawbackslashxx=`\\
+%{\catcode`\\=\other
+%@gdef@rawbackslashxx{\}}
+
+% \rawbackslash redefines \ as input to do \rawbackslashxx.
+{\catcode`\\=\active
+@gdef@rawbackslash{@let\=@rawbackslashxx }}
+
+% \normalbackslash outputs one backslash in fixed width font.
+\def\normalbackslash{{\tt\rawbackslashxx}}
+
+% Say @foo, not \foo, in error messages.
+\escapechar=`\@
+
+% \catcode 17=0 % Define control-q
+\catcode`\\=\active
+
+% Used sometimes to turn off (effectively) the active characters
+% even after parsing them.
+@def@turnoffactive{@let"=@normaldoublequote
+@let\=@realbackslash
+@let~=@normaltilde
+@let^=@normalcaret
+@let_=@normalunderscore
+@let|=@normalverticalbar
+@let<=@normalless
+@let>=@normalgreater
+@let+=@normalplus}
+
+@def@normalturnoffactive{@let"=@normaldoublequote
+@let\=@normalbackslash
+@let~=@normaltilde
+@let^=@normalcaret
+@let_=@normalunderscore
+@let|=@normalverticalbar
+@let<=@normalless
+@let>=@normalgreater
+@let+=@normalplus}
+
+% If a .fmt file is being used, we don't want the `\input texinfo' to show up.
+% That is what \eatinput is for; after that, the `\' should revert to printing
+% a backslash.
+%
+@gdef@eatinput input texinfo{@fixbackslash}
+@global@let\ = @eatinput
+
+% On the other hand, perhaps the file did not have a `\input texinfo'. Then
+% the first `\{ in the file would cause an error. This macro tries to fix
+% that, assuming it is called before the first `\' could plausibly occur.
+%
+@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi}
+
+%% These look ok in all fonts, so just make them not special. The @rm below
+%% makes sure that the current font starts out as the newly loaded cmr10
+@catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other
+
+@textfonts
+@rm
+
+@c Local variables:
+@c page-delimiter: "^\\\\message"
+@c End:
diff --git a/find/Makefile.am b/find/Makefile.am
index b0015098..d8096cde 100644
--- a/find/Makefile.am
+++ b/find/Makefile.am
@@ -1,38 +1,14 @@
-AUTOMAKE_OPTIONS = std-options
-localedir = $(datadir)/locale
-# noinst_PROGRAMS = regexprops
-# regexprops_SOURCES = regexprops.c
-
-noinst_LIBRARIES = libfindtools.a
-libfindtools_a_SOURCES = finddata.c fstype.c parser.c pred.c tree.c util.c
-
-
-# We always build two versions of find, one with fts, one without.
-# Their names depend on whether the user specified --with-fts.
-#
-# --with-fts find extra binary
-# yes with fts 'oldfind', without fts
-# no without fts 'ftsfind', with fts
-#
-if WITH_FTS
-bin_PROGRAMS = find oldfind
-find_SOURCES = ftsfind.c
-oldfind_SOURCES = find.c
-else
-bin_PROGRAMS = find ftsfind
-find_SOURCES = find.c
-ftsfind_SOURCES = ftsfind.c
-endif
-
-EXTRA_DIST = defs.h $(man_MANS)
-INCLUDES = -I../gnulib/lib -I$(top_srcdir)/lib -I$(top_srcdir)/gnulib/lib -I../intl -DLOCALEDIR=\"$(localedir)\"
-LDADD = ./libfindtools.a ../lib/libfind.a ../gnulib/lib/libgnulib.a @INTLLIBS@ @LIB_CLOCK_GETTIME@ @FINDLIBS@
-man_MANS = find.1
-SUBDIRS = . testsuite
-
-#$(PROGRAMS): ../lib/libfind.a
-
-dist-hook: findutils-check-manpages
-
-findutils-check-manpages:
- $(top_srcdir)/build-aux/man-lint.sh $(srcdir) $(man_MANS)
+PROGRAMS = find
+find_SOURCES = find.c fstype.c parser.c pred.c tree.c util.c version.c
+DIST_OTHER = defs.h
+INCLUDES = -I.. -I$(top_srcdir)/lib
+LDADD = ../lib/libfind.a
+MANS = find.1
+CONFIG_HEADER = ../config.h
+
+$(PROGRAMS): ../lib/libfind.a
+
+parser.o: ../lib/modechange.h
+find.o fstype.o parser.o pred.o: ../lib/modetype.h
+find.o fstype.o parser.o pred.o tree.o util.o: defs.h
+pred.o: ../lib/wait.h
diff --git a/find/Makefile.in b/find/Makefile.in
new file mode 100644
index 00000000..1f658cb0
--- /dev/null
+++ b/find/Makefile.in
@@ -0,0 +1,160 @@
+# Makefile.in generated automatically by automake from Makefile.am.
+# Copyright (C) 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = $(exec_prefix)/bin
+sbindir = $(exec_prefix)/sbin
+libexecdir = $(exec_prefix)/libexec
+datadir = $(prefix)/share
+sysconfdir = $(prefix)/etc
+sharedstatedir = $(prefix)/com
+localstatedir = $(prefix)/var
+libdir = $(exec_prefix)/lib
+infodir = $(prefix)/info
+mandir = $(prefix)/man
+includedir = $(prefix)/include
+oldincludedir = /usr/include
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+transform = @program_transform_name@
+
+ALL = ${PROGRAMS} ${LIBPROGRAMS} ${SCRIPTS} ${LIBSCRIPTS} ${LIBFILES}
+CC = @CC@
+LEX = @LEX@
+YACC = @YACC@
+ANSI2KNR = ./ansi2knr
+
+DEFS = @DEFS@
+CPPFLAGS = @CPPFLAGS@
+CFLAGS = @CFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+
+find_OBJECTS = find.o fstype.o parser.o pred.o tree.o util.o version.o
+NROFF = nroff
+
+SOURCES = ${find_SOURCES}
+DIST_CONF = Makefile.am Makefile.in
+DIST_FILES = $(DIST_CONF) $(SOURCES) $(TEXINFOS) $(INFOS) $(MANS) $(DIST_OTHER)
+
+PROGRAMS = find
+find_SOURCES = find.c fstype.c parser.c pred.c tree.c util.c version.c
+DIST_OTHER = defs.h
+INCLUDES = -I.. -I$(top_srcdir)/lib
+LDADD = ../lib/libfind.a
+MANS = find.1
+CONFIG_HEADER = ../config.h
+
+all:: ${ALL}
+
+.c.o:
+ $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $<
+
+$(find_OBJECTS): ../config.h
+install:: install-programs
+
+install-programs: $(PROGRAMS) $(SCRIPTS)
+ $(top_srcdir)/mkinstalldirs $(bindir)
+ for p in $(PROGRAMS) $(SCRIPTS); do \
+ $(INSTALL_PROGRAM) $$p $(bindir)/`echo $$p|sed '$(transform)'`; \
+ done
+
+uninstall:: uninstall-programs
+
+uninstall-programs:
+ for p in $(PROGRAMS) $(SCRIPTS); do \
+ rm -f $(bindir)/`echo $$p|sed '$(transform)'`; \
+ done
+
+find: $(find_OBJECTS)
+ $(CC) -o $@ $(find_OBJECTS) $(LDADD) $(LDFLAGS) $(LIBS)
+
+install:: install-man
+
+install-man:
+ for man in $(MANS); do \
+ sect=`echo $$man|sed 's%.*\.\([0-9][a-z]*\)$$%\1%'`; \
+ inst=`basename $$man $$sect|sed '$(transform)'`$$sect; \
+ mdir=$(mandir)/man$$sect; \
+ $(top_srcdir)/mkinstalldirs $$mdir; \
+ echo installing $$man as $$mdir/$$inst; \
+ $(INSTALL_DATA) $(srcdir)/$$man $$mdir/$$inst; \
+ cdir=$(mandir)/cat$$sect; \
+ if test -d $$cdir; then \
+ echo formatting $$man as $$cdir/$$inst; \
+ $(NROFF) -man $(srcdir)/$$man > $$cdir/$$inst; \
+ fi; \
+ done
+
+uninstall:: uninstall-man
+
+uninstall-man:
+ for man in $(MANS); do \
+ sect=`echo $$man|sed 's%.*\(\.[0-9][a-z]*\)$$%\1%'; \
+ inst=`basename $$man $sect|sed '$(transform)'`.$$sect; \
+ mdir=$(mandir)/man$$sect; \
+ cdir=$(mandir)/cat$$sect; \
+ rm -f $$mdir/$$inst $$cdir/$$inst; \
+ done
+
+mostlyclean:
+ rm -f *.o core
+
+clean: mostlyclean
+ rm -f $(PROGRAMS) $(LIBPROGRAMS) $(LIBFILES) $(TEXFILES) $(CLEANFILES)
+
+distclean: clean
+ rm -f Makefile *.tab.c $(DISTCLEANFILES)
+ rm -f config.cache config.log config.status ${CONFIG_HEADER} stamp-h
+
+realclean: distclean
+ rm -f TAGS $(INFOS)
+
+dist: $(DIST_FILES) $(DIST_DIRS)
+ -mkdir ../`cat ../distname`/$(subdir)
+ @for file in $(DIST_FILES); do \
+ echo linking $$file; \
+ ln $(srcdir)/$$file ../`cat ../distname`/$(subdir)/$$file || \
+ { echo copying $$file instead; cp -p $(srcdir)/$$file ../`cat ../distname`/$(subdir)/$$file;}; \
+ done
+
+check dvi info install uninstall::
+
+tags:: TAGS
+
+TAGS::
+ cd $(srcdir); etags $(SOURCES)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
+
+$(PROGRAMS): ../lib/libfind.a
+
+parser.o: ../lib/modechange.h
+find.o fstype.o parser.o pred.o: ../lib/modetype.h
+find.o fstype.o parser.o pred.o tree.o util.o: defs.h
+pred.o: ../lib/wait.h
diff --git a/find/defs.h b/find/defs.h
index d076aa9b..ec029de1 100644
--- a/find/defs.h
+++ b/find/defs.h
@@ -1,101 +1,62 @@
/* defs.h -- data types and declarations.
- Copyright (C) 1990, 91, 92, 93, 94, 2000, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
+ 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 3 of the License, or
- (at your option) any later version.
-
+ 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, see <http://www.gnu.org/licenses/>.
-*/
-
-
-#ifndef INC_DEFS_H
-#define INC_DEFS_H 1
-
-#if !defined(ALREADY_INCLUDED_CONFIG_H)
-/*
- * Savannah bug #20128: if we include some system header and it
- * includes some othersecond system header, the second system header
- * may in fact turn out to be a file provided by gnulib. For that
- * situation, we need to have already included <config.h> so that the
- * Gnulib files have access to the information probed by their
- * configure script fragments. So <config.h> should be the first
- * thing included.
- */
-#error "<config.h> should be #included before defs.h, and indeed before any other header"
-Please stop compiling the program now
-#endif
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-#include <sys/types.h>
-
-/* XXX: some of these includes probably don't belong in a common header file */
-#include <sys/stat.h>
-#include <stdio.h> /* for FILE* */
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <time.h>
-#include <limits.h> /* for CHAR_BIT */
-#include <stdbool.h> /* for bool/boolean */
-#include <stdint.h> /* for uintmax_t */
-#include <sys/stat.h> /* S_ISUID etc. */
-
-
-
-#ifndef CHAR_BIT
-# define CHAR_BIT 8
+#else
+#include <strings.h>
+#ifndef strchr
+#define strchr index
+#endif
+#ifndef strrchr
+#define strrchr rindex
#endif
-
-#if HAVE_INTTYPES_H
-# include <inttypes.h>
#endif
-typedef bool boolean;
-#include "regex.h"
-#include "timespec.h"
-#include "buildcmd.h"
-#include "quotearg.h"
-
-/* These days we will assume ANSI/ISO C protootypes work on our compiler. */
-#define PARAMS(Args) Args
-
-#ifndef ATTRIBUTE_NORETURN
-# if HAVE_ATTRIBUTE_NORETURN
-# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
-# else
-# define ATTRIBUTE_NORETURN /* nothing */
-# endif
+#include <errno.h>
+#ifndef errno
+extern int errno;
#endif
-int optionl_stat PARAMS((const char *name, struct stat *p));
-int optionp_stat PARAMS((const char *name, struct stat *p));
-int optionh_stat PARAMS((const char *name, struct stat *p));
-int debug_stat PARAMS((const char *file, struct stat *bufp));
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
-void set_stat_placeholders PARAMS((struct stat *p));
-int get_statinfo PARAMS((const char *pathname, const char *name, struct stat *p));
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <time.h>
-#define MODE_WXUSR (S_IWUSR | S_IXUSR)
-#define MODE_R (S_IRUSR | S_IRGRP | S_IROTH)
-#define MODE_RW (S_IWUSR | S_IWGRP | S_IWOTH | MODE_R)
-#define MODE_RWX (S_IXUSR | S_IXGRP | S_IXOTH | MODE_RW)
-#define MODE_ALL (S_ISUID | S_ISGID | S_ISVTX | MODE_RWX)
+#include "regex.h"
+#if __STDC__
+# define P_(s) s
+#else
+# define P_(s) ()
+#endif
-struct predicate;
-struct options;
+/* Not char because of type promotion; NeXT gcc can't handle it. */
+typedef int boolean;
+#define true 1
+#define false 0
-/* Pointer to a predicate function. */
-typedef boolean (*PRED_FUNC)(const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr);
+/* Pointer to function returning boolean. */
+typedef boolean (*PFB)();
/* The number of seconds in a day. */
#define DAYSECS 86400
@@ -109,13 +70,6 @@ enum comparison_type
COMP_EQ
};
-enum permissions_type
-{
- PERM_AT_LEAST,
- PERM_ANY,
- PERM_EXACT
-};
-
enum predicate_type
{
NO_TYPE,
@@ -139,64 +93,27 @@ enum predicate_precedence
struct long_val
{
enum comparison_type kind;
- boolean negative; /* Defined only when representing time_t. */
- uintmax_t l_val;
-};
-
-struct perm_val
-{
- enum permissions_type kind;
- mode_t val[2];
-};
-
-/* dir_id is used to support loop detection in find.c
- */
-struct dir_id
-{
- ino_t ino;
- dev_t dev;
-};
-
-/* samefile_file_id is used to support the -samefile test.
- */
-struct samefile_file_id
-{
- ino_t ino;
- dev_t dev;
- int fd;
+ unsigned long l_val;
};
struct size_val
{
enum comparison_type kind;
int blocksize;
- uintmax_t size;
+ unsigned long size;
};
-
-enum xval
- {
- XVAL_ATIME, XVAL_BIRTHTIME, XVAL_CTIME, XVAL_MTIME, XVAL_TIME
- };
-
-struct time_val
+struct path_arg
{
- enum xval xval;
- enum comparison_type kind;
- struct timespec ts;
+ short offset; /* Offset in `vec' of this arg. */
+ short count; /* Number of path replacements in this arg. */
+ char *origarg; /* Arg with "{}" intact. */
};
-
struct exec_val
{
- boolean multiple; /* -exec {} \+ denotes multiple argument. */
- struct buildcmd_control ctl;
- struct buildcmd_state state;
- char **replace_vec; /* Command arguments (for ";" style) */
- int num_args;
- boolean use_current_dir; /* If nonzero, don't chdir to start dir */
- boolean close_stdin; /* If true, close stdin in the child. */
- int dirfd; /* The directory to do the exec in. */
+ struct path_arg *paths; /* Array of args with path replacements. */
+ char **vec; /* Array of args to pass to program. */
};
/* The format string for a -printf or -fprintf is chopped into one or
@@ -205,17 +122,12 @@ struct exec_val
each \c and `%' conversion is a segment. */
/* Special values for the `kind' field of `struct segment'. */
-enum SegmentKind
- {
- KIND_PLAIN=0, /* Segment containing just plain text. */
- KIND_STOP=1, /* \c -- stop printing and flush output. */
- KIND_FORMAT, /* Regular format */
- };
+#define KIND_PLAIN 0 /* Segment containing just plain text. */
+#define KIND_STOP 1 /* \c -- stop printing and flush output. */
struct segment
{
- enum SegmentKind segkind; /* KIND_FORMAT, KIND_PLAIN, KIND_STOP */
- char format_char[2]; /* Format chars if kind is KIND_FORMAT */
+ int kind; /* Format chars or KIND_{PLAIN,STOP}. */
char *text; /* Plain text or `%' format string. */
int text_len; /* Length of `text'. */
struct segment *next; /* Next segment for this predicate. */
@@ -225,38 +137,12 @@ struct format_val
{
struct segment *segment; /* Linked list of segments. */
FILE *stream; /* Output stream to print on. */
- const char *filename; /* We need the filename for error messages. */
- boolean dest_is_tty; /* True if the destination is a terminal. */
- struct quoting_options *quote_opts;
-};
-
-/* Profiling information for a predicate */
-struct predicate_performance_info
-{
- unsigned long visits;
- unsigned long successes;
};
-/* evaluation cost of a predicate */
-enum EvaluationCost
-{
- NeedsNothing,
- NeedsType,
- NeedsStatInfo,
- NeedsLinkName,
- NeedsAccessInfo,
- NeedsSyncDiskHit,
- NeedsEventualExec,
- NeedsImmediateExec,
- NeedsUserInteraction,
- NeedsUnknown,
- NumEvaluationCosts
-};
-
struct predicate
{
/* Pointer to the function that implements this predicate. */
- PRED_FUNC pred_func;
+ PFB pred_func;
/* Only used for debugging, but defined unconditionally so individual
modules can be compiled with -DDEBUG. */
@@ -270,54 +156,32 @@ struct predicate
/* The precedence of this node. Only has meaning for operators. */
enum predicate_precedence p_prec;
- /* True if this predicate node produces side effects.
- If side_effects are produced
- then optimization will not be performed */
+ /* True if this predicate node produces side effects. */
boolean side_effects;
- /* True if this predicate node requires default print be turned off. */
- boolean no_default_print;
-
/* True if this predicate node requires a stat system call to execute. */
boolean need_stat;
- /* True if this predicate node requires knowledge of the file type. */
- boolean need_type;
-
- enum EvaluationCost p_cost;
-
- /* est_success_rate is a number between 0.0 and 1.0 */
- float est_success_rate;
-
- /* True if this predicate should display control characters literally */
- boolean literal_control_chars;
-
- /* True if this predicate didn't originate from the user. */
- boolean artificial;
-
- /* The raw text of the argument of this predicate. */
- char *arg_text;
-
/* Information needed by the predicate processor.
Next to each member are listed the predicates that use it. */
union
{
- const char *str; /* fstype [i]lname [i]name [i]path */
+ char *str; /* fstype [i]lname [i]name [i]path */
struct re_pattern_buffer *regex; /* regex */
struct exec_val exec_vec; /* exec ok */
- struct long_val numinfo; /* gid inum links uid */
+ struct long_val info; /* atime ctime mtime inum links */
struct size_val size; /* size */
uid_t uid; /* user */
gid_t gid; /* group */
- struct time_val reftime; /* newer newerXY anewer cnewer mtime atime ctime mmin amin cmin */
- struct perm_val perm; /* perm */
- struct samefile_file_id samefileid; /* samefile */
- mode_t type; /* type */
- struct format_val printf_vec; /* printf fprintf fprint ls fls print0 fprint0 print */
+ time_t time; /* newer */
+ unsigned long perm; /* perm */
+ unsigned long type; /* type */
+ FILE *stream; /* fprint fprint0 */
+ struct format_val printf_vec; /* printf fprintf */
} args;
/* The next predicate in the user input sequence,
- which represents the order in which the user supplied the
+ which repesents the order in which the user supplied the
predicates on the command line. */
struct predicate *pred_next;
@@ -326,334 +190,143 @@ struct predicate
processed. */
struct predicate *pred_left;
struct predicate *pred_right;
-
- struct predicate_performance_info perf;
-
- const struct parser_table* parser_entry;
};
-/* find.c, ftsfind.c */
-boolean is_fts_enabled(int *ftsoptions);
-int get_start_dirfd(void);
-int get_current_dirfd(void);
-
/* find library function declarations. */
-/* find global function declarations. */
-
-/* find.c */
-/* SymlinkOption represents the choice of
- * -P, -L or -P (default) on the command line.
- */
-enum SymlinkOption
- {
- SYMLINK_NEVER_DEREF, /* Option -P */
- SYMLINK_ALWAYS_DEREF, /* Option -L */
- SYMLINK_DEREF_ARGSONLY /* Option -H */
- };
-extern enum SymlinkOption symlink_handling; /* defined in find.c. */
-
-void set_follow_state PARAMS((enum SymlinkOption opt));
-void cleanup(void);
-
-/* fstype.c */
-char *filesystem_type PARAMS((const struct stat *statp, const char *path));
-char * get_mounted_filesystems (void);
-dev_t * get_mounted_devices PARAMS((size_t *));
+/* dirname.c */
+char *dirname P_((char *path));
+/* error.c */
+void error P_((int status, int errnum, char *message, ...));
+/* listfile.c */
+void list_file P_((char *name, char *relname, struct stat *statp, FILE *stream));
+char *get_link_name P_((char *name, char *relname));
-enum arg_type
- {
- ARG_OPTION, /* regular options like -maxdepth */
- ARG_NOOP, /* does nothing, returns true, internal use only */
- ARG_POSITIONAL_OPTION, /* options whose position is important (-follow) */
- ARG_TEST, /* a like -name */
- ARG_SPECIAL_PARSE, /* complex to parse, don't eat the test name before calling parse_xx(). */
- ARG_PUNCTUATION, /* like -o or ( */
- ARG_ACTION /* like -print */
- };
-
-
-struct parser_table;
-/* Pointer to a parser function. */
-typedef boolean (*PARSE_FUNC)(const struct parser_table *p,
- char *argv[], int *arg_ptr);
-struct parser_table
-{
- enum arg_type type;
- char *parser_name;
- PARSE_FUNC parser_func;
- PRED_FUNC pred_func;
-};
-
-/* parser.c */
-const struct parser_table* find_parser PARAMS((char *search_name));
-boolean parse_print PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-void pred_sanity_check PARAMS((const struct predicate *predicates));
-void check_option_combinations (const struct predicate *p);
-void parse_begin_user_args PARAMS((char **args, int argno, const struct predicate *last, const struct predicate *predicates));
-void parse_end_user_args PARAMS((char **args, int argno, const struct predicate *last, const struct predicate *predicates));
-boolean parse_openparen PARAMS((const struct parser_table* entry, char *argv[], int *arg_ptr));
-boolean parse_closeparen PARAMS((const struct parser_table* entry, char *argv[], int *arg_ptr));
-
-/* pred.c */
-
-typedef boolean PREDICATEFUNCTION(const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr);
-PREDICATEFUNCTION pred_amin;
-PREDICATEFUNCTION pred_and;
-PREDICATEFUNCTION pred_anewer;
-PREDICATEFUNCTION pred_atime;
-PREDICATEFUNCTION pred_closeparen;
-PREDICATEFUNCTION pred_cmin;
-PREDICATEFUNCTION pred_cnewer;
-PREDICATEFUNCTION pred_comma;
-PREDICATEFUNCTION pred_ctime;
-PREDICATEFUNCTION pred_delete;
-PREDICATEFUNCTION pred_empty;
-PREDICATEFUNCTION pred_exec;
-PREDICATEFUNCTION pred_execdir;
-PREDICATEFUNCTION pred_executable;
-PREDICATEFUNCTION pred_false;
-PREDICATEFUNCTION pred_fls;
-PREDICATEFUNCTION pred_fprint;
-PREDICATEFUNCTION pred_fprint0;
-PREDICATEFUNCTION pred_fprintf;
-PREDICATEFUNCTION pred_fstype;
-PREDICATEFUNCTION pred_gid;
-PREDICATEFUNCTION pred_group;
-PREDICATEFUNCTION pred_ilname;
-PREDICATEFUNCTION pred_iname;
-PREDICATEFUNCTION pred_inum;
-PREDICATEFUNCTION pred_ipath;
-PREDICATEFUNCTION pred_links;
-PREDICATEFUNCTION pred_lname;
-PREDICATEFUNCTION pred_ls;
-PREDICATEFUNCTION pred_mmin;
-PREDICATEFUNCTION pred_mtime;
-PREDICATEFUNCTION pred_name;
-PREDICATEFUNCTION pred_negate;
-PREDICATEFUNCTION pred_newer;
-PREDICATEFUNCTION pred_newerXY;
-PREDICATEFUNCTION pred_nogroup;
-PREDICATEFUNCTION pred_nouser;
-PREDICATEFUNCTION pred_ok;
-PREDICATEFUNCTION pred_okdir;
-PREDICATEFUNCTION pred_openparen;
-PREDICATEFUNCTION pred_or;
-PREDICATEFUNCTION pred_path;
-PREDICATEFUNCTION pred_perm;
-PREDICATEFUNCTION pred_print;
-PREDICATEFUNCTION pred_print0;
-PREDICATEFUNCTION pred_prune;
-PREDICATEFUNCTION pred_quit;
-PREDICATEFUNCTION pred_readable;
-PREDICATEFUNCTION pred_regex;
-PREDICATEFUNCTION pred_samefile;
-PREDICATEFUNCTION pred_size;
-PREDICATEFUNCTION pred_true;
-PREDICATEFUNCTION pred_type;
-PREDICATEFUNCTION pred_uid;
-PREDICATEFUNCTION pred_used;
-PREDICATEFUNCTION pred_user;
-PREDICATEFUNCTION pred_writable;
-PREDICATEFUNCTION pred_xtype;
-
-
-
-int launch PARAMS((const struct buildcmd_control *ctl,
- struct buildcmd_state *buildstate));
-
-
-char *find_pred_name PARAMS((PRED_FUNC pred_func));
-
-
-
-void print_predicate PARAMS((FILE *fp, const struct predicate *p));
-void print_tree PARAMS((FILE*, struct predicate *node, int indent));
-void print_list PARAMS((FILE*, struct predicate *node));
-void print_optlist PARAMS((FILE *fp, const struct predicate *node));
-void show_success_rates(const struct predicate *node);
+/* savedir.c */
+char *savedir P_((char *dir, unsigned name_size));
+/* stpcpy.c */
+#if !HAVE_STPCPY
+char *stpcpy P_((char *dest, const char *src));
+#endif
-/* tree.c */
-struct predicate * build_expression_tree PARAMS((int argc, char *argv[], int end_of_leading_options));
-struct predicate * get_eval_tree PARAMS((void));
-struct predicate *get_new_pred PARAMS((const struct parser_table *entry));
-struct predicate *get_new_pred_chk_op PARAMS((const struct parser_table *entry));
-float calculate_derived_rates PARAMS((struct predicate *p));
+/* xgetcwd.c */
+char *xgetcwd P_((void));
-/* util.c */
-struct predicate *insert_primary PARAMS((const struct parser_table *entry));
-struct predicate *insert_primary_withpred PARAMS((const struct parser_table *entry, PRED_FUNC fptr));
-void usage PARAMS((FILE *fp, int status, char *msg));
-extern boolean check_nofollow(void);
-void complete_pending_execs(struct predicate *p);
-void complete_pending_execdirs(int dirfd); /* Passing dirfd is an unpleasant CodeSmell. */
-const char *safely_quote_err_filename (int n, char const *arg);
-void fatal_file_error(const char *name) ATTRIBUTE_NORETURN;
-void nonfatal_file_error(const char *name);
-
-int process_leading_options PARAMS((int argc, char *argv[]));
-void set_option_defaults PARAMS((struct options *p));
-
-#if 0
-#define apply_predicate(pathname, stat_buf_ptr, node) \
- (*(node)->pred_func)((pathname), (stat_buf_ptr), (node))
+/* xmalloc.c */
+#if __STDC__
+#define VOID void
#else
-boolean apply_predicate(const char *pathname, struct stat *stat_buf, struct predicate *p);
+#define VOID char
#endif
-#define pred_is(node, fn) ( ((node)->pred_func) == (fn) )
-
+VOID *xmalloc P_((size_t n));
+VOID *xrealloc P_((VOID *p, size_t n));
-/* find.c. */
-int get_info PARAMS((const char *pathname, struct stat *p, struct predicate *pred_ptr));
-int following_links PARAMS((void));
-int digest_mode PARAMS((mode_t mode, const char *pathname, const char *name, struct stat *pstat, boolean leaf));
-boolean default_prints PARAMS((struct predicate *pred));
-boolean looks_like_expression PARAMS((const char *arg, boolean leading));
+/* xstrdup.c */
+char *xstrdup P_((char *string));
+/* find global function declarations. */
-enum DebugOption
- {
- DebugNone = 0,
- DebugExpressionTree = 1,
- DebugStat = 2,
- DebugSearch = 4,
- DebugTreeOpt = 8,
- DebugHelp = 16,
- DebugExec = 32,
- DebugSuccessRates = 64
- };
-
-struct options
-{
- /* If true, process directory before contents. True unless -depth given. */
- boolean do_dir_first;
- /* If true, -depth was EXPLICITLY set (as opposed to having been turned
- * on by -delete, for example).
- */
- boolean explicit_depth;
-
- /* If >=0, don't descend more than this many levels of subdirectories. */
- int maxdepth;
-
- /* If >=0, don't process files above this level. */
- int mindepth;
-
- /* If true, do not assume that files in directories with nlink == 2
- are non-directories. */
- boolean no_leaf_check;
-
- /* If true, don't cross filesystem boundaries. */
- boolean stay_on_filesystem;
-
- /* If true, we ignore the problem where we find that a directory entry
- * no longer exists by the time we get around to processing it.
- */
- boolean ignore_readdir_race;
-
- /* If true, pass control characters through. If false, escape them
- * or turn them into harmless things.
- */
- boolean literal_control_chars;
-
- /* If true, we issue warning messages
- */
- boolean warnings;
-
- /* If true, avoid POSIX-incompatible behaviours
- * (this functionality is currently incomplete
- * and at the moment affects mainly warning messages).
- */
- boolean posixly_correct;
-
- struct timespec start_time; /* Time at start of execution. */
-
- /* Either one day before now (the default), or the start of today (if -daystart is given). */
- struct timespec cur_day_start;
-
- /* If true, cur_day_start has been adjusted to the start of the day. */
- boolean full_days;
-
- int output_block_size; /* Output block size. */
-
- /* bitmask for debug options */
- unsigned long debug_options;
-
- enum SymlinkOption symlink_handling;
-
-
- /* Pointer to the function used to stat files. */
- int (*xstat) (const char *name, struct stat *statbuf);
-
-
- /* Indicate if we can implement safely_chdir() using the O_NOFOLLOW
- * flag to open(2).
- */
- boolean open_nofollow_available;
-
- /* The variety of regular expression that we support.
- * The default is POSIX Basic Regular Expressions, but this
- * can be changed with the positional option, -regextype.
- */
- int regex_options;
-
- /* Optimisation level. One is the default.
- */
- unsigned short optimisation_level;
-
-
- /* How should we quote filenames in error messages and so forth?
- */
- enum quoting_style err_quoting_style;
-};
-extern struct options options;
+/* fstype.c */
+char *filesystem_type P_((char *path, char *relpath, struct stat *statp));
+/* parser.c */
+PFB find_parser P_((char *search_name));
+boolean parse_close P_((char *argv[], int *arg_ptr));
+boolean parse_open P_((char *argv[], int *arg_ptr));
+boolean parse_print P_((char *argv[], int *arg_ptr));
-struct state
-{
- /* Current depth; 0 means current path is a command line arg. */
- int curdepth;
-
- /* If true, we have called stat on the current path. */
- boolean have_stat;
-
- /* If true, we know the type of the current path. */
- boolean have_type;
- mode_t type; /* this is the actual type */
-
- /* The file being operated on, relative to the current directory.
- Used for stat, readlink, remove, and opendir. */
- char *rel_pathname;
- /* The directory fd to which rel_pathname is relative. Thsi is relevant
- * when we're navigating the hierarchy with fts() and using FTS_CWDFD.
- */
- int cwd_dir_fd;
-
- /* Length of starting path. */
- int starting_path_length;
-
- /* If true, don't descend past current directory.
- Can be set by -prune, -maxdepth, and -xdev/-mount. */
- boolean stop_at_current_level;
-
- /* Status value to return to system. */
- int exit_status;
-
- /* True if there are any execdirs. This saves us a pair of fchdir()
- * calls for every directory we leave if it is false. This is just
- * an optimisation. Set to true if you want to be conservative.
- */
- boolean execdirs_outstanding;
-};
+/* pred.c */
+boolean pred_amin P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_and P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_anewer P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_atime P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_close P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_cmin P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_cnewer P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_comma P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_ctime P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_empty P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_exec P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_false P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_fls P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_fprint P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_fprint0 P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_fprintf P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_fstype P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_gid P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_group P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_ilname P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_iname P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_inum P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_ipath P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_links P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_lname P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_ls P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_mmin P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_mtime P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_name P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_negate P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_newer P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_nogroup P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_nouser P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_ok P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_open P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_or P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_path P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_perm P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_print P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_print0 P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_prune P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_regex P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_size P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_true P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_type P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_uid P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_used P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_user P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+boolean pred_xtype P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr));
+char *find_pred_name P_((PFB pred_func));
+#ifdef DEBUG
+void print_tree P_((struct predicate *node, int indent));
+void print_list P_((struct predicate *node));
+#endif /* DEBUG */
-/* finddata.c */
-extern struct state state;
-extern char const *starting_dir;
-extern int starting_desc;
-extern char *program_name;
+/* tree.c */
+struct predicate *get_expr P_((struct predicate **input, int prev_prec));
+boolean opt_expr P_((struct predicate **eval_treep));
+boolean mark_stat P_((struct predicate *tree));
+/* util.c */
+char *basename P_((char *fname));
+struct predicate *get_new_pred P_((void));
+struct predicate *get_new_pred_chk_op P_((void));
+struct predicate *insert_primary P_((boolean (*pred_func )()));
+void usage P_((char *msg));
+extern char *program_name;
+extern struct predicate *predicates;
+extern struct predicate *last_pred;
+extern boolean do_dir_first;
+extern int maxdepth;
+extern int mindepth;
+extern int curdepth;
+extern time_t cur_day_start;
+extern boolean full_days;
+extern boolean no_leaf_check;
+extern boolean stay_on_filesystem;
+extern boolean stop_at_current_level;
+extern boolean have_stat;
+extern char *rel_pathname;
+#ifndef HAVE_FCHDIR
+extern char *starting_dir;
+#else
+extern int starting_desc;
#endif
+extern int exit_status;
+extern int path_length;
+extern int (*xstat) ();
+extern boolean dereference;
diff --git a/find/find.1 b/find/find.1
index d7f40cf9..d6280d40 100644
--- a/find/find.1
+++ b/find/find.1
@@ -1,14 +1,13 @@
-.TH FIND 1 \" -*- nroff -*-
+.TH FIND 1L \" -*- nroff -*-
.SH NAME
find \- search for files in a directory hierarchy
.SH SYNOPSIS
-.B find
-[\-H] [\-L] [\-P] [\-D debugopts] [\-Olevel] [path...] [expression]
+.B find
+[path...] [expression]
.SH DESCRIPTION
This manual page
documents the GNU version of
.BR find .
-GNU
.B find
searches the directory tree rooted at each given file name by
evaluating the given expression from left to right, according to the
@@ -18,400 +17,53 @@ known (the left hand side is false for \fIand\fR operations, true for
.B find
moves on to the next file name.
.PP
-If you are using
-.B find
-in an environment where security is important (for example if you are
-using it to seach directories that are writable by other users), you
-should read the "Security Considerations" chapter of the findutils
-documentation, which is called \fBFinding Files\fP and comes with
-findutils. That document also includes a lot more detail
-and discussion than this manual page, so you may find it a more useful
-source of information.
-.SH OPTIONS
-The
-.BR \-H ,
-.B \-L
-and
-.B \-P
-options control the treatment of symbolic
-links. Command-line arguments following these are taken to be names
-of files or directories to be examined, up to the first argument that
-begins with `\-', or the argument `(' or `!'. That argument and any
-following arguments are taken to be the expression describing what is
-to be searched for. If no paths are given, the current directory is
-used. If no expression is given, the expression
-.B \-print
-is used
-(but you should probably consider using
-.B \-print0
-instead, anyway).
+The first argument that begins with `\-', `(', `)', `,', or `!' is taken
+to be the beginning of the expression; any arguments before it are
+paths to search, and any arguments after it are the rest of the
+expression. If no paths are given, the current directory is used. If
+no expression is given, the expression `\-print' is used.
.PP
-This manual page talks about `options' within the expression list.
-These options control the behaviour of
-.B find
-but are specified immediately after the last path name. The five
-`real' options
-.BR \-H ,
-.BR \-L ,
-.BR \-P ,
-.B \-D
-and
-.B \-O
-must appear before
-the first path name, if at all. A double dash
-.B \-\-
-can also be used
-to signal that any remaining arguments are not options (though
-ensuring that all start points begin with either `./' or `/' is
-generally safer if you use wildcards in the list of start points).
-.IP \-P
-Never follow symbolic links. This is the default behaviour. When
-.B find
-examines or prints information a file, and the file is a symbolic
-link, the information used shall be taken from the properties of the
-symbolic link itself.
-
-.IP \-L
-Follow symbolic links. When
.B find
-examines or prints information about files, the information used shall
-be taken from the properties of the file to which the link points, not
-from the link itself (unless it is a broken symbolic link or
-.B find
-is unable to examine the file to which the link points). Use of this
-option implies
-.BR \-noleaf .
-If you later use the
-.B \-P
-option,
-.B \-noleaf
-will still be in effect. If
-.B \-L
-is in effect and
-.B find
-discovers a symbolic link to a subdirectory during its search,
-the subdirectory pointed to by the symbolic link will be searched.
-.IP
-When the
-.B \-L
-option is in effect, the
-.B \-type
-predicate will always
-match against the type of the file that a symbolic link points to
-rather than the link itself (unless the symbolic link is broken).
-Using
-.B \-L
-causes the
-.B \-lname
-and
-.B \-ilname
-predicates always to return
-false.
-
-.IP \-H
-Do not follow symbolic links, except while processing the command
-line arguments. When
-.B find
-examines or prints information about files, the information used
-shall be taken from the properties of the symbolic link itself. The
-only exception to this behaviour is when a file specified on the
-command line is a symbolic link, and the link can be resolved. For
-that situation, the information used is taken from whatever the link
-points to (that is, the link is followed). The information about the
-link itself is used as a fallback if the file pointed to by the
-symbolic link cannot be examined. If
-.B \-H
-is in effect and one of the
-paths specified on the command line is a symbolic link to a directory,
-the contents of that directory will be examined (though of course
-\-maxdepth 0 would prevent this).
-.P
-If more than one of
-.BR \-H ,
-.B \-L
-and
-.B \-P
-is specified, each overrides the
-others; the last one appearing on the command line takes effect.
-Since it is the default, the
-.B \-P
-option should be considered to be in
-effect unless either
-.B \-H
-or
-.B \-L
-is specified.
-
-GNU
-.B find
-frequently stats files during the processing of the command line
-itself, before any searching has begun. These options also affect how
-those arguments are processed. Specifically, there are a number of
-tests that compare files listed on the command line against a file we
-are currently considering. In each case, the file specified on the
-command line will have been examined and some of its properties will
-have been saved. If the named file is in fact a symbolic link, and
-the
-.B \-P
-option is in effect (or if neither
-.B \-H
-nor
-.B \-L
-were specified), the information used for the comparison will be taken from
-the properties of the symbolic link. Otherwise, it will be taken from
-the properties of the file the link points to. If
-.B find
-cannot follow the link (for example because it has insufficient
-privileges or the link points to a nonexistent file) the properties of
-the link itself will be used.
-.P
-When the
-.B \-H
-or
-.B \-L options are in effect, any symbolic links listed
-as the argument of
-.B \-newer
-will be dereferenced, and the timestamp
-will be taken from the file to which the symbolic link points. The
-same consideration applies to
-.BR \-newerXY ,
-.B \-anewer
-and
-.BR \-cnewer .
-
-The
-.B \-follow
-option has a similar effect to
-.BR \-L ,
-though it takes
-effect at the point where it appears (that is, if
-.B \-L
-is not used but
-.B \-follow
-is, any symbolic links appearing after
-.B \-follow
-on the
-command line will be dereferenced, and those before it will not).
-
-.IP "\-D debugoptions"
-Print diagnostic information; this can be helpful to diagnose problems
-with why
-.B find
-is not doing what you want. The list of debug options should be comma
-separated. Compatibility of the debug options is not guaranteed
-between releases of findutils. For a complete list of valid debug
-options, see the output of
-.B find \-D
-.BR help .
-Valid debug options include
-.RS
-.IP help
-Explain the debugging options
-.IP tree
-Show the expression tree in its original and optimised form.
-.IP stat
-Print messages as files are examined with the
-.B stat
-and
-.B lstat
-system calls. The
-.B find
-program tries to minimise such calls.
-.IP opt
-Prints diagnostic information relating to the optimisation of the
-expression tree; see the \-O option.
-.IP rates
-Prints a summary indicating how often each predicate succeeded or
-failed.
-.RE
-.IP \-Olevel
-Enables query optimisation. The
-.B find
-program reorders tests to speed up execution while preserving the
-overall effect; that is, predicates with side effects are not
-reordered relative to each other. The optimisations performed at each
-optimisation level are as follows.
-.RS
-.IP 0
-Equivalent to optimisation level 1.
-.IP 1
-This is the default optimisation level and corresponds to the
-traditional behaviour. Expressions are reordered so that tests based
-only on the names of files (for example
-.B \-name
-and
-.BR \-regex )
-are performed first.
-.IP 2
-Any
-.B \-type
-or
-.B \-xtype
-tests are performed after any tests based only on the names of files,
-but before any tests that require information from the inode. On many
-modern versions of Unix, file types are returned by
-.B readdir()
-and so these predicates are faster to evaluate than predicates which
-need to stat the file first.
-.IP 3
-At this optimisation level, the full cost-based query optimiser is
-enabled. The order of tests is modified so that cheap (i.e. fast)
-tests are performed first and more expensive ones are performed later,
-if necessary. Within each cost band, predicates are evaluated earlier
-or later according to whether they are likely to succeed or not. For
-.BR \-o ,
-predicates which are likely to succeed are evaluated earlier, and for
-.BR \-a ,
-predicates which are likely to fail are evaluated earlier.
-.RE
-.IP
-The cost-based optimiser has a fixed idea of how likely any given test
-is to succeed. In some cases the probability takes account of the
-specific nature of the test (for example,
-.B \-type f
-is assumed to be more likely to succeed than
-.BR "\-type c" ).
-The cost-based optimiser is currently being evaluated. If it does
-not actually improve the performance of
-.BR find ,
-it will be removed again. Conversely, optimisations that prove to be
-reliable, robust and effective may be enabled at lower optimisation
-levels over time. However, the default behaviour (i.e. optimisation
-level 1) will not be changed in the 4.3.x release series. The
-findutils test suite runs all the tests on
-.B find
-at each optimisation level and ensures that the result is the same.
-.P
+exits with status 0 if all files are processed successfully, greater
+than 0 if errors occur.
.SH EXPRESSIONS
+.P
The expression is made up of options (which affect overall operation
-rather than the processing of a specific file, and always return
-true), tests (which return a true or false value), and actions (which
-have side effects and return a true or false value), all separated by
-operators.
-.B \-and
-is assumed where the operator is omitted.
-
-If the expression contains no actions other than
-.BR \-prune ,
-.B \-print
-is
-performed on all files for which the expression is true.
-
+rather than the processing of a specific file, and always return true),
+tests (which return a true or false value), and actions (which have side
+effects and return a true or false value), all separated by operators.
+\-and is assumed where the operator is omitted. If the expression contains
+no actions other than \-prune, \-print is performed on all files
+for which the expression is true.
.SS OPTIONS
.P
-All options always return true. Except for
-.BR \-daystart ,
-.B \-follow
-and
-.BR \-regextype ,
-the options affect all tests, including tests specified
-before the option. This is because the options are processed when the
-command line is parsed, while the tests don't do anything until files
-are examined. The
-.BR \-daystart ,
-.B \-follow
-and
-.B \-regextype
-options are different in this respect, and have an effect only on tests which
-appear later in the command line. Therefore, for clarity, it is best
-to place them at the beginning of the expression. A warning is issued
-if you don't do this.
-
-.IP \-d
-A synonym for \-depth, for compatibility with FreeBSD, NetBSD, MacOS X and OpenBSD.
-
+All options always return true. They always take effect, rather than
+being processed only when their place in the expression is reached.
+Therefore, for clarity, it is best to place them at the beginning of
+the expression.
.IP \-daystart
-Measure times (for
-.BR \-amin ,
-.BR \-atime ,
-.BR \-cmin ,
-.BR \-ctime ,
-.BR \-mmin ,
-and
-.BR \-mtime )
-from the beginning of today rather than from 24 hours ago. This
-option only affects tests which appear later on the command line.
-
+Measure times (for \-amin, \-atime, \-cmin, \-ctime, \-mmin, and \-mtime)
+from the beginning of today rather than from 24 hours ago.
.IP \-depth
-Process each directory's contents before the directory itself. The
-\-delete action also implies
-.BR \-depth .
-
+Process each directory's contents before the directory itself.
.IP \-follow
-Deprecated; use the
-.B \-L
-option instead. Dereference symbolic links.
-Implies
-.BR \-noleaf .
-The
-.B \-follow
-option affects only those tests which
-appear after it on the command line. Unless the
-.B \-H
-or
-.B \-L
-option has
-been specified, the position of the
-.B \-follow
-option changes the behaviour of the
-.B \-newer
-predicate; any files listed as the argument
-of
-.B \-newer
-will be dereferenced if they are symbolic links. The same
-consideration applies to
-.BR \-newerXY ,
-.B \-anewer
-and
-.BR \-cnewer .
-Similarly, the
-.B \-type
-predicate will always match against the type of the file
-that a symbolic link points to rather than the link itself. Using
-.B \-follow
-causes the
-.B \-lname and
-.B \-ilname
-predicates always to return false.
-
+Dereference symbolic links. Implies \-noleaf.
.IP "\-help, \-\-help"
Print a summary of the command-line usage of
.B find
and exit.
-
-.IP \-ignore_readdir_race
-Normally, \fBfind\fR will emit an error message when it fails to stat a file.
-If you give this option and a file is deleted between the time \fBfind\fR
-reads the name of the file from the directory and the time it tries to stat
-the file, no error message will be issued. This also applies to files
-or directories whose names are given on the command line. This option takes
-effect at the time the command line is read, which means that you cannot search
-one part of the filesystem with this option on and part of it with this option
-off (if you need to do that, you will need to issue two \fBfind\fR commands
-instead, one with the option and one without it).
-
.IP "\-maxdepth \fIlevels\fR"
Descend at most \fIlevels\fR (a non-negative integer) levels of
-directories below the command line arguments.
-.B \-maxdepth 0
- means only apply the tests and actions to the command line arguments.
-
+directories below the command line arguments. `\-maxdepth 0' means
+only apply the tests and actions to the command line arguments.
.IP "\-mindepth \fIlevels\fR"
Do not apply any tests or actions at levels less than \fIlevels\fR (a
-non-negative integer).
-.B \-mindepth 1
-means process all files except the command line arguments.
-
+non-negative integer). `\-mindepth 1' means process all files except
+the command line arguments.
.IP \-mount
Don't descend directories on other filesystems. An alternate name for
-.BR \-xdev ,
-for compatibility with some other versions of
+\-xdev, for compatibility with some other versions of
.BR find .
-
-.IP \-noignore_readdir_race
-Turns off the effect of
-.BR \-ignore_readdir_race .
-
.IP "\-noleaf"
Do not optimize by assuming that directories contain 2 fewer
subdirectories than their hard link count. This option is needed when
@@ -427,55 +79,11 @@ than the directory's link count, it knows that the rest of the entries
in the directory are non-directories (`leaf' files in the directory
tree). If only the files' names need to be examined, there is no need
to stat them; this gives a significant increase in search speed.
-
-.IP "\-regextype \fItype\fR"
-Changes the regular expression syntax understood by
-.B \-regex
-and
-.B \-iregex
-tests which occur later on the command line. Currently-implemented
-types are emacs (this is the default), posix-awk, posix-basic,
-posix-egrep and posix-extended.
-
.IP "\-version, \-\-version"
Print the \fBfind\fR version number and exit.
-
-.IP "\-warn, \-nowarn"
-Turn warning messages on or off. These warnings apply only to the
-command line usage, not to any conditions that
-.B find
-might encounter when it searches directories. The default behaviour
-corresponds to
-.B \-warn
-if standard input is a tty, and to
-.B \-nowarn
-otherwise.
-
.IP \-xdev
Don't descend directories on other filesystems.
-
.SS TESTS
-Some tests, for example
-.B \-newerXY
-and
-.BR -samefile ,
-allow comparison between the file currently being examined and some
-reference file specified on the command line. When these tests are
-used, the interpretation of the reference file is determined by the
-options
-.BR \-H ,
-.B \-L
-and
-.B \-P
-and any previous
-.BR \-follow ,
-but the reference file is only examined once, at the time the command
-line is parsed. If the reference file cannot be examined (for
-example, the
-.BR stat (2)
-system call fails for it), an error message is issued, and
-.B find
-exits with a nonzero status.
.P
Numeric arguments can be specified as
.IP \fI+n\fP
@@ -487,383 +95,109 @@ for less than
.IP \fIn\fP
for exactly
.IR n .
-.P
-
.IP "\-amin \fIn\fR"
File was last accessed \fIn\fR minutes ago.
-
.IP "\-anewer \fIfile\fR"
-File was last accessed more recently than \fIfile\fR was modified. If
-\fIfile\fR is a symbolic link and the
-.B \-H
-option or the
-.B \-L
-option is in effect, the access time of the file it points to is
-always used.
-
+File was last accessed more recently than \fIfile\fR was modified.
+\-anewer is affected by \-follow only if \-follow comes before
+\-anewer on the command line.
.IP "\-atime \fIn\fR"
-File was last accessed \fIn\fR*24 hours ago.
-When find figures out how many 24-hour periods ago the file
-was last accessed, any fractional part is ignored, so to match
-.B \-atime
-.BR +1 ,
-a file has to have been accessed at least
-.I two
-days ago.
-
+File was last accessed \fIn\fR*24 hours ago.
.IP "\-cmin \fIn\fR"
File's status was last changed \fIn\fR minutes ago.
-
.IP "\-cnewer \fIfile\fR"
-File's status was last changed more recently than \fIfile\fR was
-modified. If \fIfile\fR is a symbolic link and the
-.B \-H
-option or the
-.B \-L
-option is in effect, the status-change time of the file it points
-to is always used.
-
+File's status was last changed more recently than \fIfile\fR was modified.
+\-cnewer is affected by \-follow only if \-follow comes before
+\-cnewer on the command line.
.IP "\-ctime \fIn\fR"
File's status was last changed \fIn\fR*24 hours ago.
-See the comments for
-.B \-atime
-to understand how rounding affects the interpretation of file status
-change times.
-
.IP \-empty
File is empty and is either a regular file or a directory.
-
-.IP \-executable
-Matches files which are executable and directories which are
-searchable (in a file name resolution sense). This takes into account
-access control lists and other permissions artefacts which the
-.B \-perm
-test ignores. This test makes use of the
-.BR access (2)
-system call, and so can be fooled by NFS servers which do UID
-mapping (or root-squashing), since many systems implement
-.BR access (2)
-in the client's kernel and so cannot make use of the UID mapping
-information held on the server. Because this test is based only on
-the result of the
-.BR access (2)
-system call, there is no guarantee that a file for which this test
-succeeds can actually be executed.
-
.IP \-false
Always false.
-
.IP "\-fstype \fItype\fR"
File is on a filesystem of type \fItype\fR. The valid filesystem
types vary among different versions of Unix; an incomplete list of
filesystem types that are accepted on some version of Unix or another
-is: ufs, 4.2, 4.3, nfs, tmp, mfs, S51K, S52K. You can use
-.B \-printf
+is: ufs, 4.2, 4.3, nfs, tmp, mfs, S51K, S52K. You can use \-printf
with the %F directive to see the types of your filesystems.
-
.IP "\-gid \fIn\fR"
File's numeric group ID is \fIn\fR.
-
.IP "\-group \fIgname\fR"
File belongs to group \fIgname\fR (numeric group ID allowed).
-
.IP "\-ilname \fIpattern\fR"
-Like
-.BR \-lname ,
-but the match is case insensitive.
-If the
-.B \-L
-option or the
-.B \-follow
-option is in effect, this test returns false unless the symbolic link
-is broken.
-
+Like \-lname, but the match is case insensitive.
.IP "\-iname \fIpattern\fR"
-Like
-.BR \-name ,
-but the match is case insensitive. For example, the
+Like \-name, but the match is case insensitive. For example, the
patterns `fo*' and `F??' match the file names `Foo', `FOO', `foo',
-`fOo', etc. In these patterns, unlike filename expansion by the
-shell, an initial '.' can be matched by `*'. That is,
-.B find \-name *bar
-will match the file `.foobar'. Please note that you should quote
-patterns as a matter of course, otherwise the shell will expand any
-wildcard characters in them.
-
+`fOo', etc.
.IP "\-inum \fIn\fR"
-File has inode number \fIn\fR. It is normally easier to use the
-.B \-samefile
-test instead.
-
+File has inode number \fIn\fR.
.IP "\-ipath \fIpattern\fR"
-Behaves in the same way as
-.BR \-iwholename .
-This option is deprecated, so please do not use it.
-
+Like \-path, but the match is case insensitive.
.IP "\-iregex \fIpattern\fR"
-Like
-.BR \-regex ,
-but the match is case insensitive.
-
-.IP "\-iwholename \fIpattern\fR"
-Like
-.BR \-wholename ,
-but the match is case insensitive.
-
+Like \-regex, but the match is case insensitive.
.IP "\-links \fIn\fR"
File has \fIn\fR links.
-
.IP "\-lname \fIpattern\fR"
File is a symbolic link whose contents match shell pattern
\fIpattern\fR. The metacharacters do not treat `/' or `.' specially.
-If the
-.B \-L
-option or the
-.B \-follow
-option is in effect, this test returns false unless the symbolic link
-is broken.
-
.IP "\-mmin \fIn\fR"
File's data was last modified \fIn\fR minutes ago.
-
.IP "\-mtime \fIn\fR"
File's data was last modified \fIn\fR*24 hours ago.
-See the comments for
-.B \-atime
-to understand how rounding affects the interpretation of file
-modification times.
-
.IP "\-name \fIpattern\fR"
Base of file name (the path with the leading directories removed)
matches shell pattern \fIpattern\fR. The metacharacters (`*', `?',
-and `[]') match a `.' at the start of the base name (this is a change
-in findutils-4.2.2; see section STANDARDS CONFORMANCE below). To ignore a
-directory and the files under it, use
-.BR \-prune ;
-see an example in the
-description of
-.BR \-path .
-Braces are not recognised as being
-special, despite the fact that some shells including Bash imbue braces
-with a special meaning in shell patterns. The filename matching is
-performed with the use of the
-.BR fnmatch (3)
-library function. Don't forget to enclose the pattern in quotes
-in order to protect it from expansion by the shell.
-
+and `[]') do not match a `.' at the start of the base name. To ignore
+a directory and the files under it, use \-prune; see an example in the
+description of \-path.
.IP "\-newer \fIfile\fR"
-File was modified more recently than \fIfile\fR. If \fIfile\fR is a
-symbolic link and the
-.B \-H
-option or the
-.B \-L
-option is in effect, the
-modification time of the file it points to is always used.
-
-.IP "\-newerXY \fIreference\fR"
-Compares the timestamp of the current file with \fIreference\fR.
-The
-.I reference
-argument is normally the name of a file (and one of its timestamps is
-used for the comparison) but it may also be a string describing an
-absolute time.
-.I X
-and
-.I Y
-are placeholders for other letters, and these letters select which
-time belonging to
-how
-.I reference
-is used for the comparison.
-.TS
-ll
-ll
-ll
-ll
-llw(2i).
-a The access time of the file \fIreference\fR
-B The birth time of the file \fIreference\fR
-c The inode status change time of \fIreference\fR
-m The modification time of the file \fIreference\fR
-t \fIreference\fR is interpreted directly as a time
-.TE
-
-Some combinations are invalid; for example, it is invalid for
-.I X
-to be
-.IR t .
-Some combinations are not implemented on all systems; for example
-.I B
-is not supported on all systems. If an invalid or unsupported
-combination of
-.I XY
-is specified, a fatal error results. Time specifications are
-interpreted as for the argument to the
-.B \-d
-option of GNU
-.BR date .
-If you try to use the birth time of a reference file, and the birth
-time cannot be determined, a fatal error message results. If you
-specify a test which refers to the birth time of files being examined,
-this test will fail for any files where the birth time is unknown.
-
-.IP \-nogroup
-No group corresponds to file's numeric group ID.
-
+File was modified more recently than \fIfile\fR.
+\-newer is affected by \-follow only if \-follow comes before
+\-newer on the command line.
.IP \-nouser
No user corresponds to file's numeric user ID.
-
+.IP \-nogroup
+No group corresponds to file's numeric group ID.
.IP "\-path \fIpattern\fR"
File name matches shell pattern \fIpattern\fR. The metacharacters do
not treat `/' or `.' specially; so, for example,
.br
.in +1i
-find . \-path "./sr*sc"
+find . \-path './sr*sc'
.br
.in -1i
-will print an entry for a directory called `./src/misc' (if one
-exists). To ignore a whole directory tree, use
-.B \-prune
-rather than
+will print an entry for a directory called './src/misc' (if one
+exists). To ignore a whole directory tree, use \-prune rather than
checking every file in the tree. For example, to skip the
directory `src/emacs' and all files and directories under it, and
print the names of the other files found, do something like this:
.br
.in +1i
-find . \-path ./src/emacs \-prune \-o \-print
-.br
-.in -1i
-Note that the pattern match test applies to the whole file name,
-starting from one of the start points named on the command line. It
-would only make sense to use an absolute path name here if the
-relevant start point is also an absolute path. This means that this
-command will never match anything:
-.br
-.in +1i
-find bar \-path /foo/bar/myfile \-print
+find . \-path './src/emacs' -prune -o -print
.br
.in -1i
-The predicate
-.B \-path
-is also supported by HP-UX
-.B find
-and will be in a forthcoming version of the POSIX standard.
-
.IP "\-perm \fImode\fR"
File's permission bits are exactly \fImode\fR (octal or symbolic).
-Since an exact match is required, if you want to use this form for
-symbolic modes, you may have to specify a rather complex mode string.
-For example
-.B \-perm g=w
-will only match files which have mode 0020
-(that is, ones for which group write permission is the only permission
-set). It is more likely that you will want to use the `/' or `-'
-forms, for example
-.BR "\-perm \-g=w" ,
-which matches any file with group write permission. See the
-.B EXAMPLES
-section for some illustrative examples.
-
+Symbolic modes use mode 0 as a point of departure.
.IP "\-perm \-\fImode\fR"
All of the permission bits \fImode\fR are set for the file.
-Symbolic modes are accepted in this form, and this is usually the way
-in which would want to use them. You must specify `u', `g' or `o' if
-you use a symbolic mode. See the
-.B EXAMPLES
-section for some illustrative examples.
-
-.IP "\-perm /\fImode\fR"
-Any of the permission bits \fImode\fR are set for the file. Symbolic
-modes are accepted in this form. You must specify `u', `g' or `o' if
-you use a symbolic mode. See the
-.B EXAMPLES
-section for some illustrative examples. If no permission bits in
-.I mode
-are set, this test currently matches no files. However, it will soon
-be changed to match any file (the idea is to be more consistent with
-the behaviour of
-.B \-perm
-.BR \-000 ).
-
.IP "\-perm +\fImode\fR"
-Deprecated, old way of searching for files with any of the permission
-bits in \fImode\fR set. You should use
-.B \-perm \fI/mode\fR
-instead. Trying to use the `+' syntax with symbolic modes will yield
-surprising results. For example, `+u+x' is a valid symbolic mode
-(equivalent to +u,+x, i.e. 0111) and will therefore not be evaluated
-as
-.B \-perm +\fImode\fR
-but instead as the exact mode specifier
-.B \-perm \fImode\fR
-and so it matches files with exact permissions 0111 instead of files with any
-execute bit set. If you found this paragraph confusing, you're not
-alone - just use
-.B \-perm /\fImode\fR.
-This form of the
-.B \-perm
-test is deprecated because the POSIX specification requires the
-interpretation of a leading `+' as being part of a symbolic mode, and
-so we switched to using `/' instead.
-
-.IP \-readable
-Matches files which are readable. This takes into account access
-control lists and other permissions artefacts which the
-.B \-perm
-test ignores. This test makes use of the
-.BR access (2)
-system call, and so can be fooled by NFS servers which do UID
-mapping (or root-squashing), since many systems implement
-.BR access (2)
-in the client's kernel and so cannot make use of the UID mapping
-information held on the server.
-
+Any of the permission bits \fImode\fR are set for the file.
.IP "\-regex \fIpattern\fR"
File name matches regular expression \fIpattern\fR. This is a match
on the whole path, not a search. For example, to match a file named
`./fubar3', you can use the regular expression `.*bar.' or `.*b.*3',
-but not `f.*r3'. The regular expressions understood by
-.B find
-are by default Emacs Regular Expressions, but this can be
-changed with the
-.B \-regextype
-option.
-
-.IP "\-samefile \fIname\fR"
-File refers to the same inode as \fIname\fR. When
-.B \-L
-is in effect, this can include symbolic links.
-
-.IP "\-size \fIn\fR[cwbkMG]"
-File uses \fIn\fP units of space. The following suffixes
-can be used:
-.RS
-.IP `b'
-for 512-byte blocks (this is the default if no suffix is used)
-.IP `c'
-for bytes
-.IP `w'
-for two-byte words
-.IP `k'
-for Kilobytes (units of 1024 bytes)
-.IP `M'
-for Megabytes (units of 1048576 bytes)
-.IP `G'
-for Gigabytes (units of 1073741824 bytes)
-.RE
-.IP
+but not `b.*r3'.
+.IP "\-size \fIn\fR[bckw]"
+File uses \fIn\fP units of space. The units are 512-byte blocks by
+default or if `b' follows \fIn\fP, bytes if `c' follows \fIn\fP,
+kilobytes if `k' follows \fIn\fP, or 2-byte words if `w' follows \fIn\fP.
The size does not count indirect blocks, but it does count blocks in
-sparse files that are not actually allocated. Bear in mind that the
-`%k' and `%b' format specifiers of
-.B \-printf
-handle sparse files
-differently. The `b' suffix always denotes 512-byte blocks and never
-1 Kilobyte blocks, which is different to the behaviour of
-.BR \-ls .
-
+sparse files that are not actually allocated.
.IP \-true
Always true.
-
.IP "\-type \fIc\fR"
File is of type \fIc\fR:
.RS
@@ -878,102 +212,23 @@ named pipe (FIFO)
.IP f
regular file
.IP l
-symbolic link; this is never true if the
-.B \-L
-option or the
-.B \-follow
-option is in effect, unless the symbolic link is broken. If you want
-to search for symbolic links when
-.B \-L
-is in effect, use
-.BR \-xtype .
+symbolic link
.IP s
socket
-.IP D
-door (Solaris)
.RE
.IP "\-uid \fIn\fR"
File's numeric user ID is \fIn\fR.
-
.IP "\-used \fIn\fR"
File was last accessed \fIn\fR days after its status was last changed.
-
.IP "\-user \fIuname\fR"
File is owned by user \fIuname\fR (numeric user ID allowed).
-
-.IP "\-wholename \fIpattern\fR"
-See \-path. This alternative is less portable than
-.BR \-path .
-
-.IP "\-writable"
-Matches files which are writable. This takes into account access
-control lists and other permissions artefacts which the
-.B \-perm
-test ignores. This test makes use of the
-.BR access (2)
-system call, and so can be fooled by NFS servers which do UID
-mapping (or root-squashing), since many systems implement
-.BR access (2)
-in the client's kernel and so cannot make use of the UID mapping
-information held on the server.
-
.IP "\-xtype \fIc\fR"
-The same as
-.B \-type
-unless the file is a symbolic link. For symbolic
-links: if the
-.B \-H
-or
-.B \-P
-option was specified, true if the file is a
-link to a file of type \fIc\fR; if the
-.B \-L
-option has been given, true
-if \fIc\fR is `l'. In other words, for symbolic links,
-.B \-xtype
-checks the type of the file that
-.B \-type
-does not check.
-
+The same as \-type unless the file is a symbolic link. For symbolic
+links: if \-follow has not been given, true if the file is a link to a
+file of type \fIc\fR; if \-follow has been given, true if \fIc\fR is
+`l'. In other words, for symbolic links, \-xtype checks the type of
+the file that \-type does not check.
.SS ACTIONS
-.IP "\-delete\fR"
-Delete files; true if removal succeeded. If the removal failed, an
-error message is issued.
-If
-.B \-delete
-fails,
-.BR find 's
-exit status will be nonzero
-(when it eventually exits).
-Use of
-.B \-delete
-automatically turns on the
-.B \-depth
-option.
-
-.BR Warnings :
-Don't forget that the find command line is
-evaluated as an expression, so putting
-.B \-delete
-first will make
-.B find
-try to delete everything below the starting points you specified.
-When testing a
-.B find
-command line that you later intend to use with
-.BR \-delete ,
-you should explicitly specify
-.B \-depth
-in order to avoid later surprises. Because
-.B \-delete
-implies
-.BR \-depth ,
-you cannot usefully use
-.B \-prune
-and
-.B \-delete
-together.
-
.IP "\-exec \fIcommand\fR ;"
Execute \fIcommand\fR; true if 0 status is returned. All following
arguments to
@@ -985,168 +240,36 @@ command, not just in arguments where it is alone, as in some versions
of
.BR find .
Both of these constructions might need to be escaped (with a `\e') or
-quoted to protect them from expansion by the shell. See the
-.B EXAMPLES
-section for examples of the use of the
-.B \-exec
-option. The specified
-command is run once for each matched file.
-The command is executed in the starting directory. There are
-unavoidable security problems surrounding use of the
-.B \-exec
-action;
-you should use the
-.B \-execdir
-option instead.
-
-.IP "\-exec \fIcommand\fR {} +"
-This variant of the
-.B \-exec
-action runs the specified command on the
-selected files, but the command line is built by appending each
-selected file name at the end; the total number of invocations of the
-command will be much less than the number of matched files. The
-command line is built in much the same way that
-.B xargs
-builds its command lines. Only one instance of `{}' is allowed within
-the command. The command is executed in the starting directory.
-
-.IP "\-execdir \fIcommand\fR ;"
-.IP "\-execdir \fIcommand\fR {} +"
-Like
-.BR \-exec ,
-but the specified command is run from the subdirectory
-containing the matched file, which is not normally the directory in
-which you started
-.BR find .
-This a much more secure method for invoking commands, as it avoids
-race conditions during resolution of the paths to the matched files.
-As with the
-.B \-exec
-action, the `+' form of
-.B \-execdir
-will build a
-command line to process more than one matched file, but any given
-invocation of
-.I command
-will only list files that exist in the same subdirectory. If you use
-this option, you must ensure that your
-.B $PATH
-environment variable does not reference `.';
-otherwise, an attacker can run any commands they like by leaving an
-appropriately-named file in a directory in which you will run
-.BR \-execdir .
-The same applies to having entries in
-.B $PATH
-which are empty or which are not absolute directory names.
-
+quoted to protect them from expansion by the shell. The command is
+executed in the starting directory.
.IP "\-fls \fIfile\fR"
-True; like
-.B \-ls
-but write to \fIfile\fR like
-.BR \-fprint .
-The output file is always created, even if the predicate is never
-matched.
-See the
-.B UNUSUAL FILENAMES
-section for information about how unusual characters in filenames are handled.
-
+True; like \-ls but write to \fIfile\fR like \-fprint.
.IP "\-fprint \fIfile\fR"
True; print the full file name into file \fIfile\fR. If \fIfile\fR
does not exist when \fBfind\fR is run, it is created; if it does
exist, it is truncated. The file names ``/dev/stdout'' and
``/dev/stderr'' are handled specially; they refer to the standard
output and standard error output, respectively.
-The output file is always created, even if the predicate is never matched.
-See the
-.B UNUSUAL FILENAMES
-section for information about how unusual characters in filenames are handled.
-
.IP "\-fprint0 \fIfile\fR"
-True; like
-.B \-print0
-but write to \fIfile\fR like
-.BR \-fprint .
-The output file is always created, even if the predicate is never matched.
-See the
-.B UNUSUAL FILENAMES
-section for information about how unusual characters in filenames are handled.
-
+True; like \-print0 but write to \fIfile\fR like \-fprint.
.IP "\-fprintf \fIfile\fR \fIformat\fR"
-True; like
-.B \-printf
-but write to \fIfile\fR like
-.BR \-fprint .
-The output file is always created, even if the predicate is never matched.
-See the
-.B UNUSUAL FILENAMES
-section for information about how unusual characters in filenames are handled.
-
-.IP \-ls
-True; list current file in
-.B ls \-dils
-format on standard output.
-The block counts are of 1K blocks, unless the environment variable
-POSIXLY_CORRECT is set, in which case 512-byte blocks are used.
-See the
-.B UNUSUAL FILENAMES
-section for information about how unusual characters in filenames are handled.
-
+True; like \-printf but write to \fIfile\fR like \-fprint.
.IP "\-ok \fIcommand\fR ;"
-Like
-.B \-exec
-but ask the user first (on the standard input); if the
+Like \-exec but ask the user first (on the standard input); if the
response does not start with `y' or `Y', do not run the command, and
-return false. If the command is run, its standard input is redirected
-from
-.BR /dev/null .
-
-.IP "\-okdir \fIcommand\fR ;"
-Like
-.B \-execdir
-but ask the user first (on the standard input); if the
-response does not start with `y' or `Y', do not run the command, and
-return false. If the command is run, its standard input is redirected
-from
-.BR /dev/null .
-
+return false.
.IP \-print
-True; print the full file name on the standard output, followed by a
-newline. If you are piping the output of
-.B find
-into another program and there is the faintest possibility that the files
-which you are searching for might contain a newline, then you should
-seriously consider using the
-.B \-print0
-option instead of
-.BR \-print .
-See the
-.B UNUSUAL FILENAMES
-section for information about how unusual characters in filenames are handled.
-
+True; print the full file name on the standard output, followed by a newline.
.IP \-print0
True; print the full file name on the standard output, followed by a
-null character (instead of the newline character that
-.B \-print
-uses).
-This allows file names that contain newlines or other types of white
-space to be correctly interpreted by programs that process the
-\fBfind\fR output. This option corresponds to the
-.B \-0
-option of
-.BR xargs .
-
+null character. This allows file names that contain newlines to be
+correctly interpreted by programs that process the \fBfind\fR output.
.IP "\-printf \fIformat\fR"
True; print \fIformat\fR on the standard output, interpreting `\e'
escapes and `%' directives. Field widths and precisions can be
-specified as with the `printf' C function. Please note that many of
-the fields are printed as %s rather than %d, and this may mean that
-flags don't work as you might expect. This also means that the `\-'
-flag does work (it forces fields to be left-aligned). Unlike
-.BR \-print ,
-.B \-printf
-does not add a newline at the end of the string. The escapes
-and directives are:
+specified as with the `printf' C function. Unlike \-print, \-printf
+does not add a newline at the end of the string. The escapes and
+directives are:
.RS
.IP \ea
Alarm bell.
@@ -1164,12 +287,8 @@ Carriage return.
Horizontal tab.
.IP \ev
Vertical tab.
-.IP \e\0
-ASCII NUL.
.IP \e\e
A literal backslash (`\e').
-.IP \eNNN
-The character whose ASCII code is NNN (octal).
.PP
A `\e' character followed by any other character is treated as an
ordinary character, so they both are printed.
@@ -1182,10 +301,10 @@ File's last access time in the format specified by \fIk\fR, which is
either `@' or a directive for the C `strftime' function. The possible
values for \fIk\fR are listed below; some of them might not be
available on all systems, due to differences in `strftime' between
-systems.
+systems.
.RS
.IP @
-seconds since Jan. 1, 1970, 00:00 GMT, with fractional part.
+seconds since Jan. 1, 1970, 00:00 GMT.
.PP
Time fields:
.IP H
@@ -1203,14 +322,9 @@ locale's AM or PM
.IP r
time, 12-hour (hh:mm:ss [AP]M)
.IP S
-Second (00.00 .. 61.00). There is a fractional part.
+second (00..61)
.IP T
time, 24-hour (hh:mm:ss)
-.IP +
-Date and time, separated by `+', for example
-`2004\-04\-28+22:22:05.0'. This is a GNU extension. The time is
-given in the current timezone (which may be affected by setting the TZ
-environment variable). The seconds field includes a fractional part.
.IP X
locale's time representation (H:M:S)
.IP Z
@@ -1226,11 +340,7 @@ locale's abbreviated month name (Jan..Dec)
.IP B
locale's full month name, variable length (January..December)
.IP c
-locale's date and time (Sat Nov 04 12:02:33 EST 1989). The format is
-the same as for
-.BR ctime (3)
-and so to preserve compatibility with that format, there is no fractional part
-in the seconds field.
+locale's date and time (Sat Nov 04 12:02:33 EST 1989)
.IP d
day of month (01..31)
.IP D
@@ -1255,9 +365,7 @@ last two digits of year (00..99)
year (1970...)
.RE
.IP %b
-The amount of disk space used for this file in 512-byte blocks. Since disk
-space is allocated in multiples of the filesystem block size this is usually
-greater than %s/512, but it can also be smaller if the file is a sparse file.
+File's size in 512-byte blocks (rounded up).
.IP %c
File's last status change time in the format returned by the C `ctime'
function.
@@ -1267,9 +375,6 @@ which is the same as for %A.
.IP %d
File's depth in the directory tree; 0 means the file is a command line
argument.
-.IP %D
-The device number on which the file exists (the st_dev field of struct
-stat), in decimal.
.IP %f
File's name with any leading directories removed (only the last element).
.IP %F
@@ -1281,31 +386,16 @@ File's group name, or numeric group ID if the group has no name.
File's numeric group ID.
.IP %h
Leading directories of file's name (all but the last element).
-If the file name contains no slashes (since it is in the current
-directory) the %h specifier expands to ".".
.IP %H
Command line argument under which file was found.
.IP %i
File's inode number (in decimal).
.IP %k
-The amount of disk space used for this file in 1K blocks. Since disk space is
-allocated in multiples of the filesystem block size this is usually greater
-than %s/1024, but it can also be smaller if the file is a sparse file.
+File's size in 1K blocks (rounded up).
.IP %l
Object of symbolic link (empty string if file is not a symbolic link).
.IP %m
-File's permission bits (in octal). This option uses the `traditional'
-numbers which most Unix implementations use, but if your particular
-implementation uses an unusual ordering of octal permissions bits, you
-will see a difference between the actual value of the file's mode and
-the output of %m. Normally you will want to have a leading
-zero on this number, and to do this, you should use the
-.B #
-flag (as in, for example, `%#m').
-.IP %M
-File's permissions (in symbolic form, as for
-.BR ls ).
-This directive is supported in findutils 4.2.5 and later.
+File's permission bits (in octal).
.IP %n
Number of hard links to file.
.IP %p
@@ -1315,15 +405,6 @@ File's name with the name of the command line argument under which
it was found removed.
.IP %s
File's size in bytes.
-.IP %S
-File's sparseness. This is calculated as (BLOCKSIZE*st_blocks /
-st_size). The exact value you will get for an ordinary file of a
-certain length is system-dependent. However, normally sparse files
-will have values less than 1.0, and files which use indirect blocks
-may have a value which is greater than 1.0. The value used for
-BLOCKSIZE is system-dependent, but is usually 512 bytes. If the file
-size is zero, the value printed is undefined. On systems which lack
-support for st_blocks, a file's sparseness is assumed to be 1.0.
.IP %t
File's last modification time in the format returned by the C `ctime'
function.
@@ -1334,694 +415,41 @@ which is the same as for %A.
File's user name, or numeric user ID if the user has no name.
.IP %U
File's numeric user ID.
-.IP %y
-File's type (like in
-.BR "ls \-l" ),
-U=unknown type (shouldn't happen)
-.IP %Y
-File's type (like %y), plus follow symlinks: L=loop, N=nonexistent
-.PP
-A `%' character followed by any other character is discarded, but the
-other character is printed (don't rely on this, as further format
-characters may be introduced). A `%' at the end of the format
-argument causes undefined behaviour since there is no following
-character. In some locales, it may hide your door keys, while in
-others it may remove the final page from the novel you are reading.
-
-The %m and %d directives support the
-.B #
-,
-.B 0
-and
-.B +
-flags, but the other directives do not, even if they
-print numbers. Numeric directives that do not support these flags
-include
-.BR G ,
-.BR U ,
-.BR b ,
-.BR D ,
-.B k
-and
-.BR n .
-The `\-' format flag is supported and changes the alignment of a field
-from right-justified (which is the default) to left-justified.
.PP
-See the
-.B UNUSUAL FILENAMES
-section for information about how unusual characters in filenames are handled.
-
-
+A `%' character followed by any other character is discarded (but the
+other character is printed).
.RE
.IP \-prune
-True; if the file is a directory, do not descend into it. If
-.B \-depth
-is given, false; no effect. Because
-.B \-delete
-implies
-.BR \-depth ,
-you cannot usefully use
-.B \-prune
-and
-.B \-delete together.
-
-.IP "\-quit"
-Exit immediately. No child processes will be left running, but no more
-paths specified on the command line will be processed. For example,
-.B find /tmp/foo /tmp/bar \-print \-quit
-will print only
-.BR /tmp/foo .
-Any command lines which have been built up with
-.B \-execdir ... {} +
-will be invoked before
-.B find
-exits. The exit status may or may not be zero, depending on whether
-an error has already occurred.
-
-.SS UNUSUAL FILENAMES
-Many of the actions of
-.B find
-result in the printing of data which is under the control of other
-users. This includes file names, sizes, modification times and so
-forth. File names are a potential problem since they can contain any
-character except `\e0' and `/'. Unusual characters in file names can
-do unexpected and often undesirable things to your terminal (for
-example, changing the settings of your function keys on some
-terminals). Unusual characters are handled differently by various
-actions, as described below.
-
-.IP "\-print0, \-fprint0\"
-Always print the exact filename, unchanged, even if the output is
-going to a terminal.
-
-.IP "\-ls, \-fls"
-Unusual characters are always escaped. White space, backslash, and
-double quote characters are printed using C-style escaping (for
-example `\ef', `\e"'). Other unusual characters are printed using an
-octal escape. Other printable characters (for
-.B \-ls
-and
-.B \-fls
-these are the characters between octal 041 and 0176) are printed as-is.
-
-.IP "\-printf, \-fprintf"
-If the output is not going to a terminal, it is printed as-is.
-Otherwise, the result depends on which directive is in use. The
-directives %D, %F, %g, %G, %H, %Y, and %y expand to values which are
-not under control of files' owners, and so are printed as-is. The
-directives %a, %b, %c, %d, %i, %k, %m, %M, %n, %s, %t, %u and %U have
-values which are under the control of files' owners but which cannot
-be used to send arbitrary data to the terminal, and so these are
-printed as-is. The directives %f, %h, %l, %p and %P are quoted. This
-quoting is performed in the same way as for GNU
-.BR ls .
-This is not the same quoting mechanism as the one used for
-.B \-ls
-and
-.BR \-fls .
-If you are able to decide what format to use for the output of
-.B find
-then it is normally better to use `\e0' as a terminator
-than to use newline, as file names can contain white space and newline
-characters.
-
-.IP "\-print, \-fprint"
-Quoting is handled in the same way as for
-.B \-printf
-and
-.BR \-fprintf .
-If you are using
-.B find
-in a script or in a situation where the matched files might have
-arbitrary names, you should consider using
-.B \-print0
-instead of
-.BR \-print .
-.P
-The
-.B \-ok
-and
-.B \-okdir
-actions print the current filename as-is. This may change in a future release.
+If \-depth is not given, true; do not descend the current directory.
+.br
+If \-depth is given, false; no effect.
+.IP \-ls
+True; list current file in `ls \-dils' format on standard output.
+The block counts are of 1K blocks, unless the environment variable
+POSIXLY_CORRECT is set, in which case 512-byte blocks are used.
.SS OPERATORS
.P
Listed in order of decreasing precedence:
-
.IP "( \fIexpr\fR )"
-Force precedence. Since parentheses are special to the shell, you
-will normally need to quote them. Many of the examples in this manual
-page use backslashes for this purpose: `\e(...\e)' instead of `(...)'.
-
+Force precedence.
.IP "! \fIexpr\fR"
-True if \fIexpr\fR is false. This character will also usually need
-protection from interpretation by the shell.
-
+True if \fIexpr\fR is false.
.IP "\-not \fIexpr\fR"
-Same as ! \fIexpr\fR, but not POSIX compliant.
-
+Same as ! \fIexpr\fR.
.IP "\fIexpr1 expr2\fR"
-Two expressions in a row are taken to be joined with an
-implied "and"; \fIexpr2\fR is not evaluated if \fIexpr1\fR is false.
-
+And (implied); \fIexpr2\fR is not evaluated if \fIexpr1\fR is false.
.IP "\fIexpr1\fR \-a \fIexpr2\fR"
Same as \fIexpr1 expr2\fR.
-
.IP "\fIexpr1\fR \-and \fIexpr2\fR"
-Same as \fIexpr1 expr2\fR, but not POSIX compliant.
-
+Same as \fIexpr1 expr2\fR.
.IP "\fIexpr1\fR \-o \fIexpr2\fR"
Or; \fIexpr2\fR is not evaluated if \fIexpr1\fR is true.
-
.IP "\fIexpr1\fR \-or \fIexpr2\fR"
-Same as \fIexpr1\fR
-.B \-o
-\fIexpr2\fR, but not POSIX compliant.
-
+Same as \fIexpr1\fR \-o \fIexpr2\fR.
.IP "\fIexpr1\fR , \fIexpr2\fR"
-List; both \fIexpr1\fR and \fIexpr2\fR are always evaluated. The
-value of \fIexpr1\fR is discarded; the value of the list is the value
-of \fIexpr2\fR. The comma operator can be useful for searching for
-several different types of thing, but traversing the filesystem
-hierarchy only once. The
-.B \-fprintf
-action can be used to list the various matched items into several
-different output files.
-
-
-.SH "STANDARDS CONFORMANCE"
-For closest compliance to the POSIX standard, you should set the
-POSIXLY_CORRECT environment variable. The following options are
-specified in the POSIX standard (IEEE Std 1003.1, 2003 Edition):
-
-.IP \fB\-H\fR
-This option is supported.
-
-.IP \fB\-L\fR
-This option is supported.
-
-.IP \fB\-name\fR
-This option is supported, but POSIX conformance depends on the
-POSIX conformance of the system's
-.BR fnmatch (3)
-library function. As of findutils-4.2.2, shell metacharacters
-(`*', `?' or `[]' for example) will match a leading `.', because
-IEEE PASC interpretation 126 requires this. This is a change from
-previous versions of findutils.
-
-.IP \fB\-type\fR
-Supported. POSIX specifies `b', `c', `d', `l', `p', `f' and `s'.
-GNU find also supports `D', representing a Door, where the OS provides these.
-
-.IP \fB\-ok\fR
-Supported. Interpretation of the response is not locale-dependent
-(see ENVIRONMENT VARIABLES).
-
-.IP \fB\-newer\fR
-Supported. If the file specified is a symbolic link, it is always
-dereferenced. This is a change from previous behaviour, which used to
-take the relevant time from the symbolic link; see the HISTORY section
-below.
-
-.IP \fB\-perm\fR
-Supported. If the POSIXLY_CORRECT environment variable is not set,
-some mode arguments (for example +a+x) which are not valid in POSIX
-are supported for backward-compatibility.
-
-.IP "Other predicates"
-The predicates
-.BR \-atime ,
-.BR \-ctime ,
-.BR \-depth ,
-.BR \-group ,
-.BR \-links ,
-.BR \-mtime ,
-.BR \-nogroup ,
-.BR \-nouser ,
-.BR \-print ,
-.BR \-prune ,
-.BR \-size ,
-.BR \-user
-and
-.B \-xdev
-are all supported.
-
-.P
-The POSIX standard specifies parentheses `(', `)', negation `!' and the
-`and' and `or' operators (
-.BR \-a ,
-.BR \-o ).
-.P
-All other options, predicates, expressions and so forth are extensions
-beyond the POSIX standard. Many of these extensions are not unique to
-GNU find, however.
-.P
-The POSIX standard requires that
-.B find
-detects loops:
-.IP
-The
-.B find
-utility shall detect infinite loops; that is, entering a
-previously visited directory that is an ancestor of the last file
-encountered. When it detects an infinite loop, find shall write a
-diagnostic message to standard error and shall either recover its
-position in the hierarchy or terminate.
-.P
-GNU
-.B find
-complies with these requirements. The link count of
-directories which contain entries which are hard links to an ancestor
-will often be lower than they otherwise should be. This can mean that
-GNU find will sometimes optimise away the visiting of a subdirectory
-which is actually a link to an ancestor. Since
-.B find
-does not actually enter such a subdirectory, it is allowed to avoid
-emitting a diagnostic message. Although this behaviour may be
-somewhat confusing, it is unlikely that anybody actually depends on
-this behaviour. If the leaf optimisation has been turned off with
-.BR \-noleaf ,
-the directory entry will always be examined and the diagnostic message
-will be issued where it is appropriate. Symbolic links cannot be used
-to create filesystem cycles as such, but if the
-.B \-L
-option or the
-.B \-follow
-option is in use, a diagnostic message is issued when
-.B find
-encounters a loop of symbolic links. As with loops containing hard
-links, the leaf optimisation will often mean that
-.B find
-knows that it doesn't need to call
-.I stat()
-or
-.I chdir()
-on the symbolic link, so this diagnostic is frequently not necessary.
-.P
-The
-.B \-d
-option is supported for compatibility with various BSD systems,
-but you should use the POSIX-compliant option
-.B \-depth
-instead.
-.P
-The POSIXLY_CORRECT environment variable does not affect the behaviour
-of the
-.B \-regex
-or
-.B \-iregex
-tests because those tests aren't specified in the POSIX standard.
-.SH "ENVIRONMENT VARIABLES"
-
-.IP LANG
-Provides a default value for the internationalization variables that
-are unset or null.
-
-.IP LC_ALL
-If set to a non-empty string value, override the values of all the
-other internationalization variables.
-
-.IP LC_COLLATE
-The POSIX standard specifies that this variable affects the pattern
-matching to be used for the
-.B \-name
-option. GNU find uses the
-.BR fnmatch (3)
-library function, and so support for `LC_COLLATE' depends on the
-system library.
-
-.IP
-POSIX also specifies that the `LC_COLLATE' environment
-variable affects the interpretation of the user's response to the
-query issued by
-.BR \-ok' ,
-but this is not the case for GNU find.
-
-.IP LC_CTYPE
-This variable affects the treatment of character classes used with
-the
-.B \-name
-test, if the system's
-.BR fnmatch (3)
-library function supports this. It has no effect on the behaviour
-of the
-.B \-ok
-expression.
-
-.IP LC_MESSAGES
-Determines the locale to be used for internationalised messages.
-
-.IP NLSPATH
-Determines the location of the internationalisation message catalogues.
-
-.IP PATH
-Affects the directories which are searched to find the executables
-invoked by
-.BR \-exec ,
-.BR \-execdir ,
-.B \-ok
-and
-.BR \-okdir .
-
-.IP POSIXLY_CORRECT
-Determines the block size used by
-.B \-ls
-and
-.BR \-fls .
-If
-.B POSIXLY_CORRECT
-is set, blocks are units of 512 bytes. Otherwise
-they are units of 1024 bytes.
-.IP
-Setting this variable also turns off
-warning messages (that is, implies
-.BR \-nowarn )
-by default, because POSIX requires that apart from
-the output for
-.BR \-ok ,
-all messages printed on stderr are diagnositcs and must result in a
-non-zero exit status.
-.IP
-When POSIXLY_CORRECT is not set,
-.B \-perm
-+zzz
-is treated just like
-.B \-perm
-/zzz
-if
-+zzz is not a valid symbolic mode. When POSIXLY_CORRECT is set, such
-constructs are treated as an error.
-
-.IP TZ
-Affects the time zone used for some of the time-related format
-directives of
-.B \-printf
-and
-.BR \-fprintf .
-.SH "EXAMPLES"
-.nf
-.B find /tmp \-name core \-type f \-print | xargs /bin/rm \-f
-
-.fi
-Find files named
-.B core
-in or below the directory
-.B /tmp
-and delete them. Note that this will work incorrectly if there are
-any filenames containing newlines, single or double quotes, or spaces.
-.P
-.B find /tmp \-name core \-type f \-print0 | xargs \-0 /bin/rm \-f
-
-.fi
-Find files named
-.B core
-in or below the directory
-.B /tmp
-and delete them, processing filenames in such a way that file or
-directory names containing single or double quotes, spaces or newlines
-are correctly handled. The
-.B \-name
-test comes before the
-.B \-type
-test in order to avoid having to call
-.B stat(2)
-on every file.
-
-.P
-.nf
-.B find . \-type f \-exec file \(aq{}\(aq \e\;
-
-.fi
-Runs `file' on every file in or below the current directory. Notice
-that the braces are enclosed in single quote marks to protect them
-from interpretation as shell script punctuation. The semicolon is
-similarly protected by the use of a backslash, though single quotes
-could have been used in that case also.
-
-.P
-.nf
-.B find / \e
-.B \e( \-perm \-4000 \-fprintf /root/suid.txt "%#m %u %p\en" \e) , \e
-.B \e( \-size +100M \-fprintf /root/big.txt "%\-10s %p\en" \e)
-
-.fi
-Traverse the filesystem just once, listing setuid files and
-directories into
-.B /root/suid.txt
-and large files into
-.BR /root/big.txt .
-
-.P
-.nf
-.B find $HOME \-mtime 0
-
-.fi
-Search for files in your home directory which have been modified in
-the last twenty-four hours. This command works this way because the
-time since each file was last modified is divided by 24 hours and any
-remainder is discarded. That means that to match
-.B \-mtime
-.BR 0 ,
-a file will have to have a modification in the past which is less than
-24 hours ago.
-
-.P
-.nf
-.B find /sbin /usr/sbin -executable \e! -readable \-print
-
-.fi
-Search for files which are executable but not readable.
-
-.P
-.nf
-.B find . \-perm 664
-
-.fi
-Search for files which have read and write permission for their owner,
-and group, but which other users can read but not write to. Files
-which meet these criteria but have other permissions bits set (for
-example if someone can execute the file) will not be matched.
-
-.P
-.nf
-.B find . \-perm \-664
-
-.fi
-Search for files which have read and write permission for their owner
-and group, and which other users can read, without regard to the
-presence of any extra permission bits (for example the executable
-bit). This will match a file which has mode 0777, for example.
-
-.P
-.nf
-.B find . \-perm /222
-
-.fi
-Search for files which are writable by somebody (their owner, or
-their group, or anybody else).
-
-.P
-.nf
-.B find . \-perm /220
-.B find . \-perm /u+w,g+w
-.B find . \-perm /u=w,g=w
-
-.fi
-All three of these commands do the same thing, but the first one uses
-the octal representation of the file mode, and the other two use the
-symbolic form. These commands all search for files which are
-writable by either their owner or their group. The files don't have
-to be writable by both the owner and group to be matched; either will
-do.
-
-.P
-.nf
-.B find . \-perm \-220
-.B find . \-perm \-g+w,u+w
-
-.fi
-Both these commands do the same thing; search for files which are
-writable by both their owner and their group.
-
-.P
-.nf
-.B find . \-perm \-444 \-perm /222 ! \-perm /111
-.B find . \-perm \-a+r \-perm /a+w ! \-perm /a+x
-
-.fi
-These two commands both search for files that are readable for
-everybody (
-.B \-perm \-444
-or
-.BR "\-perm \-a+r" ),
-have at least one write bit
-set (
-.B \-perm /222
-or
-.BR "\-perm /a+w" )
-but are not executable for anybody (
-.B ! \-perm /111
-and
-.B ! \-perm /a+x
-respectively).
-
-.P
-.nf
-.B cd /source-dir
-.B find . \-name .snapshot \-prune \-o \e( \e! \-name "*~" \-print0 \e)|
-.B cpio \-pmd0 /dest-dir
-
-.fi
-This command copies the contents of
-.B /source-dir
-to
-.BR /dest-dir ,
-but omits files and directories named
-.B .snapshot
-(and anything in them). It also omits files or directories whose name
-ends in
-.BR ~ ,
-but not their contents. The construct
-.B \-prune \-o \e( ... \-print0 \e)
-is quite common. The idea here is that the expression before
-.B \-prune
-matches things which are to be pruned. However, the
-.B \-prune
-action itself returns true, so the following
-.B \-o
-ensures that the right hand side is evaluated only for those
-directories which didn't get pruned (the contents of the pruned
-directories are not even visited, so their contents are irrelevant).
-The expression on the right hand side of the
-.B \-o
-is in parentheses only for clarity. It emphasises that the
-.B \-print0
-action takes place only for things that didn't have
-.B \-prune
-applied to them. Because the default `and' condition between tests
-binds more tightly than
-.BR \-o ,
-this is the default anyway, but the parentheses help to show
-what is going on.
-
-.SH EXIT STATUS
-.PP
-.B find
-exits with status 0 if all files are processed successfully, greater
-than 0 if errors occur. This is deliberately a very broad
-description, but if the return value is non-zero, you should not rely
-on the correctness of the results of
-.BR find .
-
+List; both \fIexpr1\fR and \fIexpr2\fR are always evaluated.
+The value of \fIexpr1\fR is discarded; the value of the list is the
+value of \fIexpr2\fR.
.SH "SEE ALSO"
-\fBlocate\fP(1), \fBlocatedb\fP(5), \fBupdatedb\fP(1), \fBxargs\fP(1),
-\fBchmod\fP(1), \fBfnmatch\fP(3), \fBregex\fP(7), \fBstat\fP(2),
-\fBlstat\fP(2), \fBls\fP(1), \fBprintf\fP(3), \fBstrftime\fP(3),
-\fBctime\fP(3), \fBFinding Files\fP (on-line in Info, or printed).
-.SH "HISTORY"
-As of findutils-4.2.2, shell metacharacters (`*', `?' or `[]' for
-example) used in filename patterns will match a leading `.', because
-IEEE POSIX interpretation 126 requires this.
-.P
-The syntax
-\.B \-perm +MODE
-was deprecated in findutils-4.2.21, in favour of
-\.B \-perm
-.BR /MODE .
-As of findutils-4.3.3,
-.B \-perm /000
-now matches all files instead of none.
-.P
-Nanosecond-resolution
-timestamps were implemented in findutils-4.3.3.
-.P
-As of findutils-4.3.11, the
-.B \-delete
-action sets
-.BR find 's
-exit status to a nonzero value when it fails.
-However,
-.B find
-will not exit immediately. Previously,
-.BR find 's
-exit status was unaffected by the failure of
-.BR \-delete .
-.TS
-l l l .
-Feature Added in Also occurs in
-\-newerXY 4.3.3 BSD
-\-D 4.3.1
-\-O 4.3.1
-\-readable 4.3.0
-\-writable 4.3.0
-\-executable 4.3.0
-\-regextype 4.2.24
-\-exec ... + 4.2.12 POSIX
-\-execdir 4.2.12 BSD
-\-okdir 4.2.12
-\-samefile 4.2.11
-\-H 4.2.5 POSIX
-\-L 4.2.5 POSIX
-\-P 4.2.5 BSD
-\-delete 4.2.3
-\-quit 4.2.3
-\-d 4.2.3 BSD
-\-wholename 4.2.0
-\-iwholename 4.2.0
-\-ignore_readdir_race 4.2.0
-\-fls 4.0
-\-ilname 3.8
-\-iname 3.8
-\-ipath 3.8
-\-iregex 3.8
-.TE
-.SH "NON-BUGS"
-.nf
-.B $ find . \-name *.c \-print
-find: paths must precede expression
-Usage: find [\-H] [\-L] [\-P] [\-Olevel] [\-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
-.fi
-.P
-This happens because
-.I *.c
-has been expanded by the shell
-resulting in
-.B find
-actually receiving a command line like this:
-.nf
-
-.B find . \-name bigram.c code.c frcode.c locate.c \-print
-
-.fi
-That command is of course not going to work. Instead of doing things
-this way, you should enclose the pattern in quotes or escape the wildcard:
-.nf
-.B $ find . \-name \e*.c \-print
-.fi
-
-.SH "BUGS"
-.P
-There are security problems inherent in the behaviour that the POSIX
-standard specifies for
-.BR find ,
-which therefore cannot be fixed. For example, the
-.B \-exec
-action is
-inherently insecure, and
-.B \-execdir
-should be used instead.
-Please see \fBFinding Files\fP for more information.
-.P
-The environment variable
-.B LC_COLLATE
-has no effect on the
-.B \-ok
-action.
-.P
-The best way to report a bug is to use the form at
-http://savannah.gnu.org/bugs/?group=findutils.
-The reason for this is that you will then be able to track progress in
-fixing the problem. Other comments about \fBfind\fP(1) and about
-the findutils package in general can be sent to the
-.I bug\-findutils
-mailing list. To join the list, send email to
-.IR bug\-findutils\-request@gnu.org .
+\fBlocate\fP(1L), \fBlocatedb\fP(5L), \fBupdatedb\fP(1L), \fBxargs\fP(1L)
+\fBFinding Files\fP (on-line in Info, or printed)
diff --git a/find/find.c b/find/find.c
index 66ee07e7..361f2c41 100644
--- a/find/find.c
+++ b/find/find.c
@@ -1,1078 +1,304 @@
/* find -- search for files in a directory hierarchy
- Copyright (C) 1990, 91, 92, 93, 94, 2000,
- 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+ Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
+ 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 3 of the License, or
- (at your option) any later version.
-
+ 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, see <http://www.gnu.org/licenses/>.
-*/
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
/* GNU find was written by Eric Decker <cire@cisco.com>,
- with enhancements by David MacKenzie <djm@gnu.org>,
+ with enhancements by David MacKenzie <djm@gnu.ai.mit.edu>,
Jay Plett <jay@silence.princeton.nj.us>,
and Tim Wood <axolotl!tim@toad.com>.
The idea for -print0 and xargs -0 came from
- Dan Bernstein <brnstnd@kramden.acf.nyu.edu>.
- Improvements have been made by James Youngman <jay@gnu.org>.
-*/
-
+ Dan Bernstein <brnstnd@kramden.acf.nyu.edu>. */
#include <config.h>
-#include "defs.h"
-
-#define USE_SAFE_CHDIR 1
-#undef STAT_MOUNTPOINTS
-
-
-#include <errno.h>
-#include <assert.h>
-
+#include <sys/types.h>
#include <sys/stat.h>
+#include <stdio.h>
+#ifdef HAVE_FCNTL_H
#include <fcntl.h>
-#include <openat.h>
-
-#include "xalloc.h"
-#include "human.h"
-#include "canonicalize.h"
-#include <modetype.h>
-
-#include "closein.h"
-#include "savedirinfo.h"
-#include "buildcmd.h"
-#include "dirname.h"
-#include "quote.h"
-#include "quotearg.h"
-#include "xgetcwd.h"
-#include "error.h"
-
-#ifdef HAVE_LOCALE_H
-#include <locale.h>
-#endif
-
-#if ENABLE_NLS
-# include <libintl.h>
-# define _(Text) gettext (Text)
-#else
-# define _(Text) Text
-#define textdomain(Domain)
-#define bindtextdomain(Package, Directory)
-#define ngettext(singular,plural,n) ((1==n) ? singular : plural)
-#endif
-#ifdef gettext_noop
-# define N_(String) gettext_noop (String)
#else
-/* See locate.c for explanation as to why not use (String) */
-# define N_(String) String
+#include <sys/file.h>
#endif
+#include "defs.h"
+#include "modetype.h"
-#ifdef STAT_MOUNTPOINTS
-static void init_mounted_dev_list(int mandatory);
+#ifndef S_IFLNK
+#define lstat stat
#endif
-static void process_top_path PARAMS((char *pathname, mode_t mode));
-static int process_path PARAMS((char *pathname, char *name, boolean leaf, char *parent, mode_t type));
-static void process_dir PARAMS((char *pathname, char *name, int pathlen, const struct stat *statp, char *parent));
+int lstat ();
+int stat ();
+#define apply_predicate(pathname, stat_buf_ptr, node) \
+ (*(node)->pred_func)((pathname), (stat_buf_ptr), (node))
+static void process_top_path P_((char *pathname));
+static int process_path P_((char *pathname, char *name, boolean leaf, char *parent));
+static void process_dir P_((char *pathname, char *name, int pathlen, struct stat *statp, char *parent));
+static boolean no_side_effects P_((struct predicate *pred));
/* Name this program was run with. */
-extern char *program_name;
-
-/* A file descriptor open to the initial working directory.
- Doing it this way allows us to work when the i.w.d. has
- unreadable parents. */
-extern int starting_desc;
-
-/* The stat buffer of the initial working directory. */
-static struct stat starting_stat_buf;
+char *program_name;
-enum ChdirSymlinkHandling
- {
- SymlinkHandleDefault, /* Normally the right choice */
- SymlinkFollowOk /* see comment in process_top_path() */
- };
+/* All predicates for each path to process. */
+struct predicate *predicates;
+/* The last predicate allocated. */
+struct predicate *last_pred;
-enum TraversalDirection
- {
- TraversingUp,
- TraversingDown
- };
+/* The root of the evaluation tree. */
+static struct predicate *eval_tree;
-enum WdSanityCheckFatality
- {
- FATAL_IF_SANITY_CHECK_FAILS,
- RETRY_IF_SANITY_CHECK_FAILS,
- NON_FATAL_IF_SANITY_CHECK_FAILS
- };
+/* If true, process directory before contents. True unless -depth given. */
+boolean do_dir_first;
+/* If >=0, don't descend more than this many levels of subdirectories. */
+int maxdepth;
-int get_current_dirfd(void)
-{
- return AT_FDCWD;
-}
-
-
-int
-main (int argc, char **argv)
-{
- int i;
- int end_of_leading_options = 0; /* First arg after any -H/-L etc. */
- struct predicate *eval_tree;
+/* If >=0, don't process files above this level. */
+int mindepth;
- program_name = argv[0];
- state.exit_status = 0;
+/* Current depth; 0 means current path is a command line arg. */
+int curdepth;
- /* Set the option defaults before we do the locale
- * initialisation as check_nofollow() needs to be executed in the
- * POSIX locale.
- */
- set_option_defaults(&options);
+/* Seconds between 00:00 1/1/70 and either one day before now
+ (the default), or the start of today (if -daystart is given). */
+time_t cur_day_start;
-#ifdef HAVE_SETLOCALE
- setlocale (LC_ALL, "");
-#endif
- bindtextdomain (PACKAGE, LOCALEDIR);
- textdomain (PACKAGE);
- atexit (close_stdin);
+/* If true, cur_day_start has been adjusted to the start of the day. */
+boolean full_days;
- /* Check for -P, -H or -L options. */
- end_of_leading_options = process_leading_options(argc, argv);
+/* If true, do not assume that files in directories with nlink == 2
+ are non-directories. */
+boolean no_leaf_check;
- if (options.debug_options & DebugStat)
- options.xstat = debug_stat;
+/* If true, don't cross filesystem boundaries. */
+boolean stay_on_filesystem;
-#ifdef DEBUG
- fprintf (stderr, "cur_day_start = %s", ctime (&options.cur_day_start));
-#endif /* DEBUG */
+/* If true, don't descend past current directory.
+ Can be set by -prune, -maxdepth, and -xdev/-mount. */
+boolean stop_at_current_level;
- /* state.cwd_dir_fd has to be initialised before we call build_expression_tree()
- * because command-line parsing may lead us to stat some files.
- */
- state.cwd_dir_fd = AT_FDCWD;
-
- /* We are now processing the part of the "find" command line
- * after the -H/-L options (if any).
- */
- eval_tree = build_expression_tree(argc, argv, end_of_leading_options);
-
-
- /* safely_chdir() needs to check that it has ended up in the right place.
- * To avoid bailing out when something gets automounted, it checks if
- * the target directory appears to have had a directory mounted on it as
- * we chdir()ed. The problem with this is that in order to notice that
- * a file system was mounted, we would need to lstat() all the mount points.
- * That strategy loses if our machine is a client of a dead NFS server.
- *
- * Hence if safely_chdir() and wd_sanity_check() can manage without needing
- * to know the mounted device list, we do that.
- */
- if (!options.open_nofollow_available)
- {
-#ifdef STAT_MOUNTPOINTS
- init_mounted_dev_list(0);
-#endif
- }
-
-
- starting_desc = open (".", O_RDONLY
-#if defined O_LARGEFILE
- |O_LARGEFILE
+#ifndef HAVE_FCHDIR
+/* The full path of the initial working directory. */
+char *starting_dir;
+#else
+/* A file descriptor open to the initial working directory.
+ Doing it this way allows us to work when the i.w.d. has
+ unreadable parents. */
+int starting_desc;
#endif
- );
- if (0 <= starting_desc && fchdir (starting_desc) != 0)
- {
- close (starting_desc);
- starting_desc = -1;
- }
-
- if (starting_desc < 0)
- {
- starting_dir = xgetcwd ();
- if (! starting_dir)
- error (1, errno, _("cannot get current directory"));
- }
- set_stat_placeholders(&starting_stat_buf);
- if ((*options.xstat) (".", &starting_stat_buf) != 0)
- error (1, errno, _("cannot stat current directory"));
-
- /* If no paths are given, default to ".". */
- for (i = end_of_leading_options; i < argc && !looks_like_expression(argv[i], true); i++)
- {
- process_top_path (argv[i], 0);
- }
-
- /* If there were no path arguments, default to ".". */
- if (i == end_of_leading_options)
- {
- /*
- * We use a temporary variable here because some actions modify
- * the path temporarily. Hence if we use a string constant,
- * we get a coredump. The best example of this is if we say
- * "find -printf %H" (note, not "find . -printf %H").
- */
- char defaultpath[2] = ".";
- process_top_path (defaultpath, 0);
- }
-
- /* If "-exec ... {} +" has been used, there may be some
- * partially-full command lines which have been built,
- * but which are not yet complete. Execute those now.
- */
- show_success_rates(eval_tree);
- cleanup();
- return state.exit_status;
-}
-
-boolean is_fts_enabled(int *ftsoptions)
-{
- /* this version of find (i.e. this main()) does not use fts. */
- *ftsoptions = 0;
- return false;
-}
-
-
-static char *
-specific_dirname(const char *dir)
-{
- char dirbuf[1024];
-
- if (0 == strcmp(".", dir))
- {
- /* OK, what's '.'? */
- if (NULL != getcwd(dirbuf, sizeof(dirbuf)))
- {
- return strdup(dirbuf);
- }
- else
- {
- return strdup(dir);
- }
- }
- else
- {
- char *result = canonicalize_filename_mode(dir, CAN_EXISTING);
- if (NULL == result)
- return strdup(dir);
- else
- return result;
- }
-}
-
-
-
-/* Return non-zero if FS is the name of a file system that is likely to
- * be automounted
- */
-static int
-fs_likely_to_be_automounted(const char *fs)
-{
- return ( (0==strcmp(fs, "nfs")) || (0==strcmp(fs, "autofs")) || (0==strcmp(fs, "subfs")));
-}
+/* If true, we have called stat on the current path. */
+boolean have_stat;
+/* The file being operated on, relative to the current directory.
+ Used for stat, readlink, and opendir. */
+char *rel_pathname;
-#ifdef STAT_MOUNTPOINTS
-static dev_t *mounted_devices = NULL;
-static size_t num_mounted_devices = 0u;
+/* Length of current path. */
+int path_length;
+/* true if following symlinks. Should be consistent with xstat. */
+boolean dereference;
-static void
-init_mounted_dev_list(int mandatory)
-{
- assert (NULL == mounted_devices);
- assert (0 == num_mounted_devices);
- mounted_devices = get_mounted_devices(&num_mounted_devices);
- if (mandatory && (NULL == mounted_devices))
- {
- error(1, 0, "Cannot read list of mounted devices.");
- }
-}
-
-static void
-refresh_mounted_dev_list(void)
-{
- if (mounted_devices)
- {
- free(mounted_devices);
- mounted_devices = 0;
- }
- num_mounted_devices = 0u;
- init_mounted_dev_list(1);
-}
+/* Pointer to the function used to stat files. */
+int (*xstat) ();
+/* Status value to return to system. */
+int exit_status;
-/* Search for device DEV in the array LIST, which is of size N. */
+#ifdef DEBUG_STAT
static int
-dev_present(dev_t dev, const dev_t *list, size_t n)
-{
- if (list)
- {
- while (n-- > 0u)
- {
- if ( (*list++) == dev )
- return 1;
- }
- }
- return 0;
-}
-
-enum MountPointStateChange
- {
- MountPointRecentlyMounted,
- MountPointRecentlyUnmounted,
- MountPointStateUnchanged
- };
-
-
-
-static enum MountPointStateChange
-get_mount_state(dev_t newdev)
+debug_stat (file, bufp)
+ char *file;
+ struct stat *bufp;
{
- int new_is_present, new_was_present;
-
- new_was_present = dev_present(newdev, mounted_devices, num_mounted_devices);
- refresh_mounted_dev_list();
- new_is_present = dev_present(newdev, mounted_devices, num_mounted_devices);
-
- if (new_was_present == new_is_present)
- return MountPointStateUnchanged;
- else if (new_is_present)
- return MountPointRecentlyMounted;
- else
- return MountPointRecentlyUnmounted;
+ fprintf (stderr, "debug_stat (%s)\n", file);
+ return lstat (file, bufp);
}
-
-
-
-/* We stat()ed a directory, chdir()ed into it (we know this
- * since direction is TraversingDown), stat()ed it again,
- * and noticed that the device numbers are different. Check
- * if the file system was recently mounted.
- *
- * If it was, it looks like chdir()ing into the directory
- * caused a file system to be mounted. Maybe automount is
- * running. Anyway, that's probably OK - but it happens
- * only when we are moving downward.
- *
- * We also allow for the possibility that a similar thing
- * has happened with the unmounting of a file system. This
- * is much rarer, as it relies on an automounter timeout
- * occurring at exactly the wrong moment.
- */
-static enum WdSanityCheckFatality
-dirchange_is_fatal(const char *specific_what,
- enum WdSanityCheckFatality isfatal,
- int silent,
- struct stat *newinfo)
+#endif /* DEBUG_STAT */
+
+void
+main (argc, argv)
+ int argc;
+ char *argv[];
{
- enum MountPointStateChange transition = get_mount_state(newinfo->st_dev);
- switch (transition)
- {
- case MountPointRecentlyUnmounted:
- isfatal = NON_FATAL_IF_SANITY_CHECK_FAILS;
- if (!silent)
- {
- error (0, 0,
- _("Warning: file system %s has recently been unmounted."),
- safely_quote_err_filename(0, specific_what));
- }
- break;
-
- case MountPointRecentlyMounted:
- isfatal = NON_FATAL_IF_SANITY_CHECK_FAILS;
- if (!silent)
- {
- error (0, 0,
- _("Warning: file system %s has recently been mounted."),
- safely_quote_err_filename(0, specific_what));
- }
- break;
-
- case MountPointStateUnchanged:
- /* leave isfatal as it is */
- break;
- }
-
- return isfatal;
-}
-
-
-#endif
+ int i;
+ PFB parse_function; /* Pointer to who is to do the parsing. */
+ struct predicate *cur_pred;
+ char *predicate_name; /* Name of predicate being parsed. */
+ program_name = argv[0];
+ predicates = NULL;
+ last_pred = NULL;
+ do_dir_first = true;
+ maxdepth = mindepth = -1;
+ cur_day_start = time ((time_t *) 0) - DAYSECS;
+ full_days = false;
+ no_leaf_check = false;
+ stay_on_filesystem = false;
+ exit_status = 0;
+ dereference = false;
+#ifdef DEBUG_STAT
+ xstat = debug_stat;
+#else /* !DEBUG_STAT */
+ xstat = lstat;
+#endif /* !DEBUG_STAT */
-/* Examine the results of the stat() of a directory from before we
- * entered or left it, with the results of stat()ing it afterward. If
- * these are different, the file system tree has been modified while we
- * were traversing it. That might be an attempt to use a race
- * condition to persuade find to do something it didn't intend
- * (e.g. an attempt by an ordinary user to exploit the fact that root
- * sometimes runs find on the whole file system). However, this can
- * also happen if automount is running (certainly on Solaris). With
- * automount, moving into a directory can cause a file system to be
- * mounted there.
- *
- * To cope sensibly with this, we will raise an error if we see the
- * device number change unless we are chdir()ing into a subdirectory,
- * and the directory we moved into has been mounted or unmounted "recently".
- * Here "recently" means since we started "find" or we last re-read
- * the /etc/mnttab file.
- *
- * If the device number does not change but the inode does, that is a
- * problem.
- *
- * If the device number and inode are both the same, we are happy.
- *
- * If a file system is (un)mounted as we chdir() into the directory, that
- * may mean that we're now examining a section of the file system that might
- * have been excluded from consideration (via -prune or -quit for example).
- * Hence we print a warning message to indicate that the output of find
- * might be inconsistent due to the change in the file system.
- */
-static boolean
-wd_sanity_check(const char *thing_to_stat,
- const char *progname,
- const char *what,
- dev_t old_dev,
- ino_t old_ino,
- struct stat *newinfo,
- int parent,
- int line_no,
- enum TraversalDirection direction,
- enum WdSanityCheckFatality isfatal,
- boolean *changed) /* output parameter */
-{
- const char *fstype;
- char *specific_what = NULL;
- int silent = 0;
- const char *current_dir = ".";
-
- *changed = false;
-
- set_stat_placeholders(newinfo);
- if ((*options.xstat) (current_dir, newinfo) != 0)
- fatal_file_error(thing_to_stat);
-
- if (old_dev != newinfo->st_dev)
- {
- *changed = true;
- specific_what = specific_dirname(what);
- fstype = filesystem_type(newinfo, current_dir);
- silent = fs_likely_to_be_automounted(fstype);
-
- /* This condition is rare, so once we are here it is
- * reasonable to perform an expensive computation to
- * determine if we should continue or fail.
- */
- if (TraversingDown == direction)
- {
-#ifdef STAT_MOUNTPOINTS
- isfatal = dirchange_is_fatal(specific_what,isfatal,silent,newinfo);
-#else
- isfatal = RETRY_IF_SANITY_CHECK_FAILS;
-#endif
- }
+#ifdef DEBUG
+ printf ("cur_day_start = %s", ctime (&cur_day_start));
+#endif /* DEBUG */
- switch (isfatal)
+ /* Find where in ARGV the predicates begin. */
+ for (i = 1; i < argc && strchr ("-!(),", argv[i][0]) == NULL; i++)
+ /* Do nothing. */ ;
+
+ /* Enclose the expression in `( ... )' so a default -print will
+ apply to the whole expression. */
+ parse_open (argv, &argc);
+ /* Build the input order list. */
+ while (i < argc)
+ {
+ if (strchr ("-!(),", argv[i][0]) == NULL)
+ usage ("paths must precede expression");
+ predicate_name = argv[i];
+ parse_function = find_parser (predicate_name);
+ if (parse_function == NULL)
+ error (1, 0, "invalid predicate `%s'", predicate_name);
+ i++;
+ if (!(*parse_function) (argv, &i))
{
- case FATAL_IF_SANITY_CHECK_FAILS:
- {
- fstype = filesystem_type(newinfo, current_dir);
- error (1, 0,
- _("%s%s changed during execution of %s (old device number %ld, new device number %ld, file system type is %s) [ref %ld]"),
- safely_quote_err_filename(0, specific_what),
- parent ? "/.." : "",
- safely_quote_err_filename(1, progname),
- (long) old_dev,
- (long) newinfo->st_dev,
- fstype,
- (long)line_no);
- /*NOTREACHED*/
- return false;
- }
-
- case NON_FATAL_IF_SANITY_CHECK_FAILS:
- {
- /* Since the device has changed under us, the inode number
- * will almost certainly also be different. However, we have
- * already decided that this is not a problem. Hence we return
- * without checking the inode number.
- */
- free(specific_what);
- return true;
- }
-
- case RETRY_IF_SANITY_CHECK_FAILS:
- return false;
+ if (argv[i] == NULL)
+ error (1, 0, "missing argument to `%s'", predicate_name);
+ else
+ error (1, 0, "invalid argument `%s' to `%s'",
+ argv[i], predicate_name);
}
}
-
- /* Device number was the same, check if the inode has changed. */
- if (old_ino != newinfo->st_ino)
+ if (predicates->pred_next == NULL)
{
- *changed = true;
- specific_what = specific_dirname(what);
- fstype = filesystem_type(newinfo, current_dir);
-
- error ((isfatal == FATAL_IF_SANITY_CHECK_FAILS) ? 1 : 0,
- 0, /* no relevant errno value */
- _("%s%s changed during execution of %s "
- "(old inode number %ld, new inode number %ld, file system type is %s) [ref %ld]"),
- safely_quote_err_filename(0, specific_what),
- parent ? "/.." : "",
- safely_quote_err_filename(1, progname),
- (long) old_ino,
- (long) newinfo->st_ino,
- fstype,
- (long)line_no);
- free(specific_what);
- return false;
+ /* No predicates that do something other than set a global variable
+ were given; remove the unneeded initial `(' and add `-print'. */
+ cur_pred = predicates;
+ predicates = last_pred = predicates->pred_next;
+ free ((char *) cur_pred);
+ parse_print (argv, &argc);
}
-
- return true;
-}
-
-enum SafeChdirStatus
- {
- SafeChdirOK,
- SafeChdirFailSymlink,
- SafeChdirFailNotDir,
- SafeChdirFailStat,
- SafeChdirFailWouldBeUnableToReturn,
- SafeChdirFailChdirFailed,
- SafeChdirFailNonexistent,
- SafeChdirFailDestUnreadable
- };
-
-/* Safely perform a change in directory. We do this by calling
- * lstat() on the subdirectory, using chdir() to move into it, and
- * then lstat()ing ".". We compare the results of the two stat calls
- * to see if they are consistent. If not, we sound the alarm.
- *
- * If following_links() is true, we do follow symbolic links.
- */
-static enum SafeChdirStatus
-safely_chdir_lstat(const char *dest,
- enum TraversalDirection direction,
- struct stat *statbuf_dest,
- enum ChdirSymlinkHandling symlink_follow_option,
- boolean *did_stat)
-{
- struct stat statbuf_arrived;
- int rv, dotfd=-1;
- int saved_errno; /* specific_dirname() changes errno. */
- boolean rv_set = false;
- boolean statflag = false;
- int tries = 0;
- enum WdSanityCheckFatality isfatal = RETRY_IF_SANITY_CHECK_FAILS;
-
- saved_errno = errno = 0;
-
- dotfd = open(".", O_RDONLY
-#if defined O_LARGEFILE
- |O_LARGEFILE
-#endif
- );
-
- /* We jump back to here if wd_sanity_check()
- * recoverably triggers an alert.
- */
- retry:
- ++tries;
-
- if (dotfd >= 0)
+ else if (!no_side_effects (predicates->pred_next))
{
- /* Stat the directory we're going to. */
- set_stat_placeholders(statbuf_dest);
- if (0 == options.xstat(dest, statbuf_dest))
- {
- statflag = true;
-
-#ifdef S_ISLNK
- /* symlink_follow_option might be set to SymlinkFollowOk, which
- * would allow us to chdir() into a symbolic link. This is
- * only useful for the case where the directory we're
- * chdir()ing into is the basename of a command line
- * argument, for example where "foo/bar/baz" is specified on
- * the command line. When -P is in effect (the default),
- * baz will not be followed if it is a symlink, but if bar
- * is a symlink, it _should_ be followed. Hence we need the
- * ability to override the policy set by following_links().
- */
- if (!following_links() && S_ISLNK(statbuf_dest->st_mode))
- {
- /* We're not supposed to be following links, but this is
- * a link. Check symlink_follow_option to see if we should
- * make a special exception.
- */
- if (symlink_follow_option == SymlinkFollowOk)
- {
- /* We need to re-stat() the file so that the
- * sanity check can pass.
- */
- if (0 != stat(dest, statbuf_dest))
- {
- rv = SafeChdirFailNonexistent;
- rv_set = true;
- saved_errno = errno;
- goto fail;
- }
- statflag = true;
- }
- else
- {
- /* Not following symlinks, so the attempt to
- * chdir() into a symlink should be prevented.
- */
- rv = SafeChdirFailSymlink;
- rv_set = true;
- saved_errno = 0; /* silence the error message */
- goto fail;
- }
- }
-#endif
-#ifdef S_ISDIR
- /* Although the immediately following chdir() would detect
- * the fact that this is not a directory for us, this would
- * result in an extra system call that fails. Anybody
- * examining the system-call trace should ideally not be
- * concerned that something is actually failing.
- */
- if (!S_ISDIR(statbuf_dest->st_mode))
- {
- rv = SafeChdirFailNotDir;
- rv_set = true;
- saved_errno = 0; /* silence the error message */
- goto fail;
- }
-#endif
-
- if (options.debug_options & DebugSearch)
- fprintf(stderr, "safely_chdir(): chdir(\"%s\")\n", dest);
-
- if (0 == chdir(dest))
- {
- /* check we ended up where we wanted to go */
- boolean changed = false;
- if (!wd_sanity_check(".", program_name, ".",
- statbuf_dest->st_dev,
- statbuf_dest->st_ino,
- &statbuf_arrived,
- 0, __LINE__, direction,
- isfatal,
- &changed))
- {
- /* Only allow one failure. */
- if (RETRY_IF_SANITY_CHECK_FAILS == isfatal)
- {
- if (0 == fchdir(dotfd))
- {
- isfatal = FATAL_IF_SANITY_CHECK_FAILS;
- goto retry;
- }
- else
- {
- /* Failed to return to original directory,
- * but we know that the current working
- * directory is not the one that we intend
- * to be in. Since fchdir() failed, we
- * can't recover from this and so this error
- * is fatal.
- */
- error(1, errno,
- "failed to return to parent directory");
- }
- }
- else
- {
- /* XXX: not sure what to use as an excuse here. */
- rv = SafeChdirFailNonexistent;
- rv_set = true;
- saved_errno = 0;
- goto fail;
- }
- }
-
- close(dotfd);
- return SafeChdirOK;
- }
- else
- {
- saved_errno = errno;
- if (ENOENT == saved_errno)
- {
- rv = SafeChdirFailNonexistent;
- rv_set = true;
- if (options.ignore_readdir_race)
- errno = 0; /* don't issue err msg */
- }
- else if (ENOTDIR == saved_errno)
- {
- /* This can happen if the we stat a directory,
- * and then file system activity changes it into
- * a non-directory.
- */
- saved_errno = 0; /* don't issue err msg */
- rv = SafeChdirFailNotDir;
- rv_set = true;
- }
- else
- {
- rv = SafeChdirFailChdirFailed;
- rv_set = true;
- }
- goto fail;
- }
- }
- else
- {
- saved_errno = errno;
- rv = SafeChdirFailStat;
- rv_set = true;
-
- if ( (ENOENT == saved_errno) || (0 == state.curdepth))
- saved_errno = 0; /* don't issue err msg */
- goto fail;
- }
+ /* One or more predicates that produce output were given;
+ remove the unneeded initial `('. */
+ cur_pred = predicates;
+ predicates = predicates->pred_next;
+ free ((char *) cur_pred);
}
else
{
- /* We do not have read permissions on "." */
- rv = SafeChdirFailWouldBeUnableToReturn;
- rv_set = true;
- goto fail;
+ /* `( user-supplied-expression ) -print'. */
+ parse_close (argv, &argc);
+ parse_print (argv, &argc);
}
- /* This is the success path, so we clear errno. The caller probably
- * won't be calling error() anyway.
- */
- saved_errno = 0;
-
- /* We use the same exit path for success or failure.
- * which has occurred is recorded in RV.
- */
- fail:
- /* We do not call error() as this would result in a duplicate error
- * message when the caller does the same thing.
- */
- if (saved_errno)
- errno = saved_errno;
-
- if (dotfd >= 0)
- {
- close(dotfd);
- dotfd = -1;
- }
-
- *did_stat = statflag;
- assert (rv_set);
- return rv;
-}
+#ifdef DEBUG
+ printf ("Predicate List:\n");
+ print_list (predicates);
+#endif /* DEBUG */
-#if defined O_NOFOLLOW
-/* Safely change working directory to the specified subdirectory. If
- * we are not allowed to follow symbolic links, we use open() with
- * O_NOFOLLOW, followed by fchdir(). This ensures that we don't
- * follow symbolic links (of course, we do follow them if the -L
- * option is in effect).
- */
-static enum SafeChdirStatus
-safely_chdir_nofollow(const char *dest,
- enum TraversalDirection direction,
- struct stat *statbuf_dest,
- enum ChdirSymlinkHandling symlink_follow_option,
- boolean *did_stat)
-{
- int extraflags, fd;
-
- (void) direction;
- (void) statbuf_dest;
-
- extraflags = 0;
- *did_stat = false;
-
- switch (symlink_follow_option)
- {
- case SymlinkFollowOk:
- extraflags = 0;
- break;
-
- case SymlinkHandleDefault:
- if (following_links())
- extraflags = 0;
- else
- extraflags = O_NOFOLLOW;
- break;
- }
-
- errno = 0;
- fd = open(dest, O_RDONLY
-#if defined O_LARGEFILE
- |O_LARGEFILE
-#endif
- |extraflags);
- if (fd < 0)
- {
- switch (errno)
- {
- case ELOOP:
- return SafeChdirFailSymlink; /* This is why we use O_NOFOLLOW */
- case ENOENT:
- return SafeChdirFailNonexistent;
- default:
- return SafeChdirFailDestUnreadable;
- }
- }
-
- errno = 0;
- if (0 == fchdir(fd))
- {
- close(fd);
- return SafeChdirOK;
- }
- else
- {
- int saved_errno = errno;
- close(fd);
- errno = saved_errno;
-
- switch (errno)
- {
- case ENOTDIR:
- return SafeChdirFailNotDir;
-
- case EACCES:
- case EBADF: /* Shouldn't happen */
- case EINTR:
- case EIO:
- default:
- return SafeChdirFailChdirFailed;
- }
- }
-}
-#endif
+ /* Done parsing the predicates. Build the evaluation tree. */
+ cur_pred = predicates;
+ eval_tree = get_expr (&cur_pred, NO_PREC);
+#ifdef DEBUG
+ printf ("Eval Tree:\n");
+ print_tree (eval_tree, 0);
+#endif /* DEBUG */
-static enum SafeChdirStatus
-safely_chdir(const char *dest,
- enum TraversalDirection direction,
- struct stat *statbuf_dest,
- enum ChdirSymlinkHandling symlink_follow_option,
- boolean *did_stat)
-{
- enum SafeChdirStatus result;
-
- /* We're about to leave a directory. If there are any -execdir
- * argument lists which have been built but have not yet been
- * processed, do them now because they must be done in the same
- * directory.
- */
- complete_pending_execdirs(get_current_dirfd());
-
-#if !defined(O_NOFOLLOW)
- options.open_nofollow_available = false;
-#endif
- if (options.open_nofollow_available)
- {
- result = safely_chdir_nofollow(dest, direction, statbuf_dest,
- symlink_follow_option, did_stat);
- if (SafeChdirFailDestUnreadable != result)
- {
- return result;
- }
- else
- {
- /* Savannah bug #15384: fall through to use safely_chdir_lstat
- * if the directory is not readable.
- */
- /* Do nothing. */
- }
- }
- /* Even if O_NOFOLLOW is available, we may need to use the alternative
- * method, since parent of the start point may be executable but not
- * readable.
- */
- return safely_chdir_lstat(dest, direction, statbuf_dest,
- symlink_follow_option, did_stat);
-}
+ /* Rearrange the eval tree in optimal-predicate order. */
+ opt_expr (&eval_tree);
+ /* Determine the point, if any, at which to stat the file. */
+ mark_stat (eval_tree);
-
-/* Safely go back to the starting directory. */
-static void
-chdir_back (void)
-{
- struct stat stat_buf;
- boolean dummy;
-
+#ifdef DEBUG
+ printf ("Optimized Eval Tree:\n");
+ print_tree (eval_tree, 0);
+#endif /* DEBUG */
+
+#ifndef HAVE_FCHDIR
+ starting_dir = xgetcwd ();
+ if (starting_dir == NULL)
+ error (1, errno, "cannot get current directory");
+#else
+ starting_desc = open (".", O_RDONLY);
if (starting_desc < 0)
- {
- if (options.debug_options & DebugSearch)
- fprintf(stderr, "chdir_back(): chdir(\"%s\")\n", starting_dir);
-
-#ifdef STAT_MOUNTPOINTS
- /* We will need the mounted device list. Get it now if we don't
- * already have it.
- */
- if (NULL == mounted_devices)
- init_mounted_dev_list(1);
+ error (1, errno, "cannot open current directory");
#endif
-
- if (chdir (starting_dir) != 0)
- fatal_file_error(starting_dir);
-
- wd_sanity_check(starting_dir,
- program_name,
- starting_dir,
- starting_stat_buf.st_dev,
- starting_stat_buf.st_ino,
- &stat_buf, 0, __LINE__,
- TraversingUp,
- FATAL_IF_SANITY_CHECK_FAILS,
- &dummy);
- }
- else
- {
- if (options.debug_options & DebugSearch)
- fprintf(stderr, "chdir_back(): chdir(<starting-point>)\n");
- if (fchdir (starting_desc) != 0)
- {
- fatal_file_error(starting_dir);
- }
- }
+ /* If no paths are given, default to ".". */
+ for (i = 1; i < argc && strchr ("-!(),", argv[i][0]) == NULL; i++)
+ process_top_path (argv[i]);
+ if (i == 1)
+ process_top_path (".");
+
+ exit (exit_status);
}
-/* Move to the parent of a given directory and then call a function,
- * restoring the cwd. Don't bother changing directory if the
- * specified directory is a child of "." or is the root directory.
- */
+/* Descend PATHNAME, which is a command-line argument. */
+
static void
-at_top (char *pathname,
- mode_t mode,
- struct stat *pstat,
- void (*action)(char *pathname,
- char *basename,
- int mode,
- struct stat *pstat))
+process_top_path (pathname)
+ char *pathname;
{
- int dirchange;
- char *parent_dir = dir_name (pathname);
- char *base = last_component (pathname);
+ struct stat stat_buf;
- state.curdepth = 0;
- state.starting_path_length = strlen (pathname);
+ curdepth = 0;
+ path_length = strlen (pathname);
- if (0 == *base
- || 0 == strcmp(parent_dir, "."))
+ /* We stat each pathname given on the command-line twice --
+ once here and once in process_path. It's not too bad, though,
+ since the kernel can read the stat information out of its inode
+ cache the second time. */
+ if ((*xstat) (pathname, &stat_buf) == 0 && S_ISDIR (stat_buf.st_mode))
{
- dirchange = 0;
- base = pathname;
- }
- else
- {
- enum TraversalDirection direction;
- enum SafeChdirStatus chdir_status;
- struct stat st;
- boolean did_stat = false;
-
- dirchange = 1;
- if (0 == strcmp(base, ".."))
- direction = TraversingUp;
- else
- direction = TraversingDown;
-
- /* We pass SymlinkFollowOk to safely_chdir(), which allows it to
- * chdir() into a symbolic link. This is only useful for the
- * case where the directory we're chdir()ing into is the
- * basename of a command line argument, for example where
- * "foo/bar/baz" is specified on the command line. When -P is
- * in effect (the default), baz will not be followed if it is a
- * symlink, but if bar is a symlink, it _should_ be followed.
- * Hence we need the ability to override the policy set by
- * following_links().
- */
- chdir_status = safely_chdir(parent_dir, direction, &st, SymlinkFollowOk, &did_stat);
- if (SafeChdirOK != chdir_status)
+ if (chdir (pathname) < 0)
{
- const char *what = (SafeChdirFailWouldBeUnableToReturn == chdir_status) ? "." : parent_dir;
- if (errno)
- error (0, errno, "%s",
- safely_quote_err_filename(0, what));
- else
- error (0, 0, _("Failed to safely change directory into %s"),
- safely_quote_err_filename(0, parent_dir));
-
- /* We can't process this command-line argument. */
- state.exit_status = 1;
+ error (0, errno, "%s", pathname);
+ exit_status = 1;
return;
}
+ process_path (pathname, ".", false, ".");
+#ifndef HAVE_FCHDIR
+ if (chdir (starting_dir) < 0)
+ error (1, errno, "%s", starting_dir);
+#else
+ if (fchdir (starting_desc))
+ error (1, errno, "cannot return to starting directory");
+#endif
}
-
- free (parent_dir);
- parent_dir = NULL;
-
- action(pathname, base, mode, pstat);
-
- if (dirchange)
- {
- chdir_back();
- }
-}
-
-
-static void do_process_top_dir(char *pathname,
- char *base,
- int mode,
- struct stat *pstat)
-{
- (void) pstat;
-
- process_path (pathname, base, false, ".", mode);
- complete_pending_execdirs(get_current_dirfd());
-}
-
-static void do_process_predicate(char *pathname,
- char *base,
- int mode,
- struct stat *pstat)
-{
- (void) mode;
-
- state.rel_pathname = base; /* cwd_dir_fd was already set by safely_chdir */
- apply_predicate (pathname, pstat, get_eval_tree());
-}
-
-
-
-
-/* Descend PATHNAME, which is a command-line argument.
-
- Actions like -execdir assume that we are in the
- parent directory of the file we're examining,
- and on entry to this function our working directory
- is whatever it was when find was invoked. Therefore
- If PATHNAME is "." we just leave things as they are.
- Otherwise, we figure out what the parent directory is,
- and move to that.
-*/
-static void
-process_top_path (char *pathname, mode_t mode)
-{
- at_top(pathname, mode, NULL, do_process_top_dir);
+ else
+ process_path (pathname, pathname, false, ".");
}
-
/* Info on each directory in the current tree branch, to avoid
getting stuck in symbolic link loops. */
+struct dir_id
+{
+ ino_t ino;
+ dev_t dev;
+};
static struct dir_id *dir_ids = NULL;
/* Entries allocated in `dir_ids'. */
static int dir_alloc = 0;
@@ -1082,60 +308,6 @@ static int dir_curr = -1;
/* (Arbitrary) number of entries to grow `dir_ids' by. */
#define DIR_ALLOC_STEP 32
-
-
-/* We've detected a file system loop. This is caused by one of
- * two things:
- *
- * 1. Option -L is in effect and we've hit a symbolic link that
- * points to an ancestor. This is harmless. We won't traverse the
- * symbolic link.
- *
- * 2. We have hit a real cycle in the directory hierarchy. In this
- * case, we issue a diagnostic message (POSIX requires this) and we
- * skip that directory entry.
- */
-static void
-issue_loop_warning(const char *name, const char *pathname, int level)
-{
- struct stat stbuf_link;
- if (lstat(name, &stbuf_link) != 0)
- stbuf_link.st_mode = S_IFREG;
-
- if (S_ISLNK(stbuf_link.st_mode))
- {
- error(0, 0,
- _("Symbolic link %s is part of a loop in the directory hierarchy; we have already visited the directory to which it points."),
- safely_quote_err_filename(0, pathname));
- /* XXX: POSIX appears to require that the exit status be non-zero if a
- * diagnostic is issued.
- */
- }
- else
- {
- int distance = 1 + (dir_curr-level);
- /* We have found an infinite loop. POSIX requires us to
- * issue a diagnostic. Usually we won't get to here
- * because when the leaf optimisation is on, it will cause
- * the subdirectory to be skipped. If /a/b/c/d is a hard
- * link to /a/b, then the link count of /a/b/c is 2,
- * because the ".." entry of /b/b/c/d points to /a, not
- * to /a/b/c.
- */
- error(0, 0,
- ngettext(
- "Filesystem loop detected; %s has the same device number and inode as "
- "a directory which is %d level higher in the file system hierarchy",
- "Filesystem loop detected; %s has the same device number and inode as "
- "a directory which is %d levels higher in the file system hierarchy",
- (long)distance),
- safely_quote_err_filename(0, pathname),
- distance);
- }
-}
-
-
-
/* Recursively descend path PATHNAME, applying the predicates.
LEAF is true if PATHNAME is known to be in a directory that has no
more unexamined subdirectories, and therefore it is not a directory.
@@ -1151,57 +323,52 @@ issue_loop_warning(const char *name, const char *pathname, int level)
Return nonzero iff PATHNAME is a directory. */
static int
-process_path (char *pathname, char *name, boolean leaf, char *parent,
- mode_t mode)
+process_path (pathname, name, leaf, parent)
+ char *pathname;
+ char *name;
+ boolean leaf;
+ char *parent;
{
struct stat stat_buf;
static dev_t root_dev; /* Device ID of current argument pathname. */
int i;
- struct predicate *eval_tree;
- eval_tree = get_eval_tree();
/* Assume it is a non-directory initially. */
stat_buf.st_mode = 0;
- state.rel_pathname = name;
- state.type = 0;
- state.have_stat = false;
- state.have_type = false;
-
- if (!digest_mode(mode, pathname, name, &stat_buf, leaf))
- return 0;
-
- if (!S_ISDIR (state.type))
+
+ rel_pathname = name;
+
+ if (leaf)
+ have_stat = false;
+ else
+ {
+ if ((*xstat) (name, &stat_buf) != 0)
+ {
+ error (0, errno, "%s", pathname);
+ exit_status = 1;
+ return 0;
+ }
+ have_stat = true;
+ }
+
+ if (!S_ISDIR (stat_buf.st_mode))
{
- if (state.curdepth >= options.mindepth)
+ if (curdepth >= mindepth)
apply_predicate (pathname, &stat_buf, eval_tree);
return 0;
}
/* From here on, we're working on a directory. */
-
- /* Now we really need to stat the directory, even if we know the
- * type, because we need information like struct stat.st_rdev.
- */
- if (get_statinfo(pathname, name, &stat_buf) != 0)
- return 0;
-
- state.have_stat = true;
- mode = state.type = stat_buf.st_mode; /* use full info now that we have it. */
- state.stop_at_current_level =
- options.maxdepth >= 0
- && state.curdepth >= options.maxdepth;
+ stop_at_current_level = maxdepth >= 0 && curdepth >= maxdepth;
/* If we've already seen this directory on this branch,
don't descend it again. */
for (i = 0; i <= dir_curr; i++)
if (stat_buf.st_ino == dir_ids[i].ino &&
stat_buf.st_dev == dir_ids[i].dev)
- {
- state.stop_at_current_level = true;
- issue_loop_warning(name, pathname, i);
- }
-
+ stop_at_current_level = true;
+
if (dir_alloc <= ++dir_curr)
{
dir_alloc += DIR_ALLOC_STEP;
@@ -1211,49 +378,28 @@ process_path (char *pathname, char *name, boolean leaf, char *parent,
dir_ids[dir_curr].ino = stat_buf.st_ino;
dir_ids[dir_curr].dev = stat_buf.st_dev;
- if (options.stay_on_filesystem)
+ if (stay_on_filesystem)
{
- if (state.curdepth == 0)
+ if (curdepth == 0)
root_dev = stat_buf.st_dev;
else if (stat_buf.st_dev != root_dev)
- state.stop_at_current_level = true;
+ stop_at_current_level = true;
}
- if (options.do_dir_first && state.curdepth >= options.mindepth)
+ if (do_dir_first && curdepth >= mindepth)
apply_predicate (pathname, &stat_buf, eval_tree);
- if (options.debug_options & DebugSearch)
- fprintf(stderr, "pathname = %s, stop_at_current_level = %d\n",
- pathname, state.stop_at_current_level);
-
- if (state.stop_at_current_level == false)
- {
- /* Scan directory on disk. */
- process_dir (pathname, name, strlen (pathname), &stat_buf, parent);
- }
+ if (stop_at_current_level == false)
+ /* Scan directory on disk. */
+ process_dir (pathname, name, strlen (pathname), &stat_buf, parent);
- if (options.do_dir_first == false && state.curdepth >= options.mindepth)
- {
- /* The fields in 'state' are now out of date. Correct them.
- */
- if (!digest_mode(mode, pathname, name, &stat_buf, leaf))
- return 0;
-
- if (0 == dir_curr)
- {
- at_top(pathname, mode, &stat_buf, do_process_predicate);
- }
- else
- {
- do_process_predicate(pathname, name, mode, &stat_buf);
- }
- }
+ if (do_dir_first == false && curdepth >= mindepth)
+ apply_predicate (pathname, &stat_buf, eval_tree);
dir_curr--;
return 1;
}
-
/* Scan directory PATHNAME and recurse through process_path for each entry.
@@ -1261,47 +407,36 @@ process_path (char *pathname, char *name, boolean leaf, char *parent,
NAME is PATHNAME relative to the current directory.
- STATP is the results of *options.xstat on it.
+ STATP is the results of *xstat on it.
PARENT is the path of the parent of NAME, relative to find's
starting directory. */
static void
-process_dir (char *pathname, char *name, int pathlen, const struct stat *statp, char *parent)
+process_dir (pathname, name, pathlen, statp, parent)
+ char *pathname;
+ char *name;
+ int pathlen;
+ struct stat *statp;
+ char *parent;
{
+ char *name_space; /* Names of files in PATHNAME. */
int subdirs_left; /* Number of unexamined subdirs in PATHNAME. */
- boolean subdirs_unreliable; /* if true, cannot use dir link count as subdir limif (if false, it may STILL be unreliable) */
- unsigned int idx; /* Which entry are we on? */
- struct stat stat_buf;
- size_t dircount = 0u;
- struct savedir_dirinfo *dirinfo;
-#if 0
- printf("process_dir: pathname=%s name=%s statp->st_nlink=%d st_ino=%d\n",
- pathname,
- name,
- (int)statp->st_nlink,
- (int)statp->st_ino);
-#endif
- if (statp->st_nlink < 2)
- {
- subdirs_unreliable = true;
- subdirs_left = 0;
- }
- else
- {
- subdirs_unreliable = false; /* not necessarily right */
- subdirs_left = statp->st_nlink - 2; /* Account for name and ".". */
- }
-
- errno = 0;
- dirinfo = xsavedir(name, 0);
-
- if (dirinfo == NULL)
+ subdirs_left = statp->st_nlink - 2; /* Account for name and ".". */
+
+ errno = 0;
+ /* On some systems (VAX 4.3BSD+NFS), NFS mount points have st_size < 0. */
+ name_space = savedir (name, statp->st_size > 0 ? statp->st_size : 512);
+ if (name_space == NULL)
{
- assert (errno != 0);
- error (0, errno, "%s", safely_quote_err_filename(0, pathname));
- state.exit_status = 1;
+ if (errno)
+ {
+ error (0, errno, "%s", pathname);
+ exit_status = 1;
+ }
+ else
+ error (1, 0, "virtual memory exhausted");
}
else
{
@@ -1311,8 +446,7 @@ process_dir (char *pathname, char *name, int pathlen, const struct stat *statp,
unsigned cur_path_size; /* Bytes allocated for `cur_path'. */
register unsigned file_len; /* Length of each path to process. */
register unsigned pathname_len; /* PATHLEN plus trailing '/'. */
- boolean did_stat = false;
-
+
if (pathname[pathlen - 1] == '/')
pathname_len = pathlen + 1; /* For '\0'; already have '/'. */
else
@@ -1320,77 +454,15 @@ process_dir (char *pathname, char *name, int pathlen, const struct stat *statp,
cur_path_size = 0;
cur_path = NULL;
- /* We're about to leave the directory. If there are any
- * -execdir argument lists which have been built but have not
- * yet been processed, do them now because they must be done in
- * the same directory.
- */
- complete_pending_execdirs(get_current_dirfd());
-
- if (strcmp (name, "."))
+ if (strcmp (name, ".") && chdir (name) < 0)
{
- enum SafeChdirStatus status = safely_chdir (name, TraversingDown, &stat_buf, SymlinkHandleDefault, &did_stat);
- switch (status)
- {
- case SafeChdirOK:
- /* If there had been a change but wd_sanity_check()
- * accepted it, we need to accept that on the
- * way back up as well, so modify our record
- * of what we think we should see later.
- * If there was no change, the assignments are a no-op.
- *
- * However, before performing the assignment, we need to
- * check that we have the stat information. If O_NOFOLLOW
- * is available, safely_chdir() will not have needed to use
- * stat(), and so stat_buf will just contain random data.
- */
- if (!did_stat)
- {
- /* If there is a link we need to follow it. Hence
- * the direct call to stat() not through (options.xstat)
- */
- set_stat_placeholders(&stat_buf);
- if (0 != stat(".", &stat_buf))
- break; /* skip the assignment. */
- }
- dir_ids[dir_curr].dev = stat_buf.st_dev;
- dir_ids[dir_curr].ino = stat_buf.st_ino;
-
- break;
-
- case SafeChdirFailWouldBeUnableToReturn:
- error (0, errno, ".");
- state.exit_status = 1;
- break;
-
- case SafeChdirFailNonexistent:
- case SafeChdirFailDestUnreadable:
- case SafeChdirFailStat:
- case SafeChdirFailNotDir:
- case SafeChdirFailChdirFailed:
- error (0, errno, "%s",
- safely_quote_err_filename(0, pathname));
- state.exit_status = 1;
- return;
-
- case SafeChdirFailSymlink:
- error (0, 0,
- _("warning: not following the symbolic link %s"),
- safely_quote_err_filename(0, pathname));
- state.exit_status = 1;
- return;
- }
+ error (0, errno, "%s", pathname);
+ exit_status = 1;
+ return;
}
- for (idx=0; idx < dirinfo->size; ++idx)
+ for (namep = name_space; *namep; namep += file_len - pathname_len + 1)
{
- /* savedirinfo() may return dirinfo=NULL if extended information
- * is not available.
- */
- mode_t mode = (dirinfo->entries[idx].flags & SavedirHaveFileType) ?
- dirinfo->entries[idx].type_info : 0;
- namep = dirinfo->entries[idx].name;
-
/* Append this directory entry's name to the path being searched. */
file_len = pathname_len + strlen (namep);
if (file_len > cur_path_size)
@@ -1406,126 +478,64 @@ process_dir (char *pathname, char *name, int pathlen, const struct stat *statp,
cur_name = cur_path + pathname_len - 1;
strcpy (cur_name, namep);
- state.curdepth++;
- if (!options.no_leaf_check && !subdirs_unreliable)
- {
- if (mode && S_ISDIR(mode) && (subdirs_left == 0))
- {
- /* This is a subdirectory, but the number of directories we
- * have found now exceeds the number we would expect given
- * the hard link count on the parent. This is likely to be
- * a bug in the file system driver (e.g. Linux's
- * /proc file system) or may just be a fact that the OS
- * doesn't really handle hard links with Unix semantics.
- * In the latter case, -noleaf should be used routinely.
- */
- error(0, 0, _("WARNING: Hard link count is wrong for %s (saw only st_nlink=%d but we already saw %d subdirectories): this may be a bug in your file system driver. Automatically turning on find's -noleaf option. Earlier results may have failed to include directories that should have been searched."),
- safely_quote_err_filename(0, pathname),
- statp->st_nlink,
- dircount);
- state.exit_status = 1; /* We know the result is wrong, now */
- options.no_leaf_check = true; /* Don't make same
- mistake again */
- subdirs_unreliable = 1;
- subdirs_left = 1; /* band-aid for this iteration. */
- }
-
- /* Normal case optimization. On normal Unix
- file systems, a directory that has no subdirectories
- has two links: its name, and ".". Any additional
- links are to the ".." entries of its subdirectories.
- Once we have processed as many subdirectories as
- there are additional links, we know that the rest of
- the entries are non-directories -- in other words,
- leaf files. */
- {
- int count;
- count = process_path (cur_path, cur_name,
- subdirs_left == 0, pathname,
- mode);
- subdirs_left -= count;
- dircount += count;
- }
- }
+ curdepth++;
+ if (!no_leaf_check)
+ /* Normal case optimization.
+ On normal Unix filesystems, a directory that has no
+ subdirectories has two links: its name, and ".". Any
+ additional links are to the ".." entries of its
+ subdirectories. Once we have processed as many
+ subdirectories as there are additional links, we know
+ that the rest of the entries are non-directories --
+ in other words, leaf files. */
+ subdirs_left -= process_path (cur_path, cur_name,
+ subdirs_left == 0, pathname);
else
- {
- /* There might be weird (e.g., CD-ROM or MS-DOS) file systems
- mounted, which don't have Unix-like directory link counts. */
- process_path (cur_path, cur_name, false, pathname, mode);
- }
-
- state.curdepth--;
+ /* There might be weird (e.g., CD-ROM or MS-DOS) filesystems
+ mounted, which don't have Unix-like directory link counts. */
+ process_path (cur_path, cur_name, false, pathname);
+ curdepth--;
}
-
- /* We're about to leave the directory. If there are any
- * -execdir argument lists which have been built but have not
- * yet been processed, do them now because they must be done in
- * the same directory.
- */
- complete_pending_execdirs(get_current_dirfd());
-
if (strcmp (name, "."))
{
- enum SafeChdirStatus status;
- struct dir_id did;
-
- /* We could go back and do the next command-line arg
- instead, maybe using longjmp. */
- char const *dir;
- boolean deref = following_links() ? true : false;
-
- if ( (state.curdepth>0) && !deref)
- dir = "..";
- else
- {
- chdir_back ();
- dir = parent;
- }
-
- did_stat = false;
- status = safely_chdir (dir, TraversingUp, &stat_buf, SymlinkHandleDefault, &did_stat);
- switch (status)
+ if (!dereference)
{
- case SafeChdirOK:
- break;
-
- case SafeChdirFailWouldBeUnableToReturn:
- error (1, errno, ".");
- return;
-
- case SafeChdirFailNonexistent:
- case SafeChdirFailDestUnreadable:
- case SafeChdirFailStat:
- case SafeChdirFailSymlink:
- case SafeChdirFailNotDir:
- case SafeChdirFailChdirFailed:
- error (1, errno, "%s", safely_quote_err_filename(0, pathname));
- return;
- }
-
- if (dir_curr > 0)
- {
- did.dev = dir_ids[dir_curr-1].dev;
- did.ino = dir_ids[dir_curr-1].ino;
+ if (chdir ("..") < 0)
+ /* We could go back and do the next command-line arg instead,
+ maybe using longjmp. */
+ error (1, errno, "%s", parent);
}
else
{
- did.dev = starting_stat_buf.st_dev;
- did.ino = starting_stat_buf.st_ino;
+#ifndef HAVE_FCHDIR
+ if (chdir (starting_dir) || chdir (parent))
+ error (1, errno, "%s", parent);
+#else
+ if (fchdir (starting_desc) || chdir (parent))
+ error (1, errno, "%s", parent);
+#endif
}
}
if (cur_path)
free (cur_path);
- free_dirinfo(dirinfo);
+ free (name_space);
}
+}
+
+/* Return true if there are no side effects in any of the predicates in
+ predicate list PRED, false if there are any. */
- if (subdirs_unreliable)
+static boolean
+no_side_effects (pred)
+ struct predicate *pred;
+{
+ while (pred != NULL)
{
- /* Make sure we hasn't used the variable subdirs_left if we knew
- * we shouldn't do so.
- */
- assert (0 == subdirs_left || options.no_leaf_check);
+ if (pred->side_effects)
+ return (false);
+ pred = pred->pred_next;
}
+ return (true);
}
diff --git a/find/fstype.c b/find/fstype.c
index 75b33713..56492a50 100644
--- a/find/fstype.c
+++ b/find/fstype.c
@@ -1,9 +1,10 @@
-/* fstype.c -- determine type of file systems that files are on
- Copyright (C) 1990, 91, 92, 93, 94, 2000, 2004 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
+/* fstype.c -- determine type of filesystems that files are on
+ Copyright (C) 1990, 91, 92, 93, 94 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 3 of the License, or
- (at your option) any later version.
+ 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
@@ -11,108 +12,144 @@
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, see <http://www.gnu.org/licenses/>.
-*/
-
-/* Written by David MacKenzie <djm@gnu.org>.
- *
- * Converted to use gnulib's read_file_system_list()
- * by James Youngman <jay@gnu.org> (which saves a lot
- * of manual hacking of configure.in).
- */
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
#include <config.h>
-#include <errno.h>
-#include <stdbool.h>
-
-#ifdef HAVE_SYS_TYPES_H
+#include <stdio.h>
#include <sys/types.h>
-#endif
#include <sys/stat.h>
-
-/* The presence of unistd.h is assumed by gnulib these days, so we
- * might as well assume it too.
- */
-#include <unistd.h>
-
-#include <fcntl.h>
-#ifdef HAVE_SYS_MNTIO_H
-#include <sys/mntio.h>
-#endif
-#ifdef HAVE_SYS_MKDEV_H
-#include <sys/mkdev.h>
-#endif
-
+#include "defs.h"
+#include "modetype.h"
+#include <errno.h>
#ifdef STDC_HEADERS
#include <stdlib.h>
#else
extern int errno;
#endif
-#include "defs.h"
-#include "../gnulib/lib/dirname.h"
-#include "xalloc.h"
-#include "modetype.h"
+char *strdup ();
+char *strstr ();
+
+static char *filesystem_type_uncached P_((char *path, char *relpath, struct stat *statp));
+static int xatoi P_((char *cp));
+
+#ifdef FSTYPE_MNTENT /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
+#include <mntent.h>
+#if !defined(MOUNTED)
+# if defined(MNT_MNTTAB) /* HP-UX. */
+# define MOUNTED MNT_MNTTAB
+# endif
+# if defined(MNTTABNAME) /* Dynix. */
+# define MOUNTED MNTTABNAME
+# endif
+#endif
+#endif
-/* Need declaration of function `xstrtoumax' */
-#include "../gnulib/lib/xstrtol.h"
+#ifdef FSTYPE_GETMNT /* Ultrix. */
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/fs_types.h>
+#endif
-#include "extendbuf.h"
-#include "mountlist.h"
-#include "error.h"
+#ifdef FSTYPE_USG_STATFS /* SVR3. */
+#include <sys/statfs.h>
+#include <sys/fstyp.h>
+#endif
+#ifdef FSTYPE_STATVFS /* SVR4. */
+#include <sys/statvfs.h>
+#include <sys/fstyp.h>
+#endif
+#ifdef FSTYPE_STATFS /* 4.4BSD. */
+#include <sys/param.h> /* NetBSD needs this. */
+#include <sys/mount.h>
-#if ENABLE_NLS
-# include <libintl.h>
-# define _(Text) gettext (Text)
-#else
-# define _(Text) Text
+#ifndef MFSNAMELEN /* NetBSD defines this. */
+static char *
+fstype_to_string (t)
+ short t;
+{
+#ifdef INITMOUNTNAMES /* Defined in 4.4BSD, not in NET/2. */
+ static char *mn[] = INITMOUNTNAMES;
+ if (t >= 0 && t <= MOUNT_MAXTYPE)
+ return mn[t];
+ else
+ return "?";
+#else /* !INITMOUNTNAMES */
+ switch (t)
+ {
+ case MOUNT_UFS:
+ return "ufs";
+ case MOUNT_NFS:
+ return "nfs";
+#ifdef MOUNT_PC
+ case MOUNT_PC:
+ return "pc";
#endif
-#ifdef gettext_noop
-# define N_(String) gettext_noop (String)
-#else
-/* See locate.c for explanation as to why not use (String) */
-# define N_(String) String
+#ifdef MOUNT_MFS
+ case MOUNT_MFS:
+ return "mfs";
#endif
-
-static char *file_system_type_uncached PARAMS((const struct stat *statp, const char *path));
-
-
-/* Get MNTTYPE_IGNORE if it is available. */
-#if HAVE_MNTENT_H
-# include <mntent.h>
+#ifdef MOUNT_LO
+ case MOUNT_LO:
+ return "lofs";
#endif
-#if HAVE_SYS_MNTTAB_H
-# include <stdio.h>
-# include <sys/mnttab.h>
+#ifdef MOUNT_TFS
+ case MOUNT_TFS:
+ return "tfs";
#endif
+#ifdef MOUNT_TMP
+ case MOUNT_TMP:
+ return "tmp";
+#endif
+#ifdef MOUNT_MSDOS
+ case MOUNT_MSDOS:
+ return "msdos";
+#endif
+#ifdef MOUNT_ISO9660
+ case MOUNT_ISO9660:
+ return "iso9660fs";
+#endif
+ default:
+ return "?";
+ }
+#endif /* !INITMOUNTNAMES */
+}
+#endif /* !MFSNAMELEN */
+#endif /* FSTYPE_STATFS */
+#ifdef FSTYPE_AIX_STATFS /* AIX. */
+#include <sys/vmount.h>
+#include <sys/statfs.h>
+#define FSTYPE_STATFS /* Otherwise like 4.4BSD. */
+#define f_type f_vfstype
-
-
-static void
-free_file_system_list(struct mount_entry *p)
+static char *
+fstype_to_string (t)
+ short t;
{
- while (p)
+ switch (t)
{
- struct mount_entry *pnext = p->me_next;
-
- free(p->me_devname);
- free(p->me_mountdir);
-
- if(p->me_type_malloced)
- free(p->me_type);
- p->me_next = NULL;
- free(p);
- p = pnext;
+ case MNT_AIX:
+#if 0 /* NFS filesystems are actually MNT_AIX. */
+ return "aix";
+#endif
+ case MNT_NFS:
+ return "nfs";
+ case MNT_JFS:
+ return "jfs";
+ case MNT_CDROM:
+ return "cdrom";
+ default:
+ return "?";
}
}
-
-
-
+#endif /* FSTYPE_AIX_STATFS */
#ifdef AFS
#include <netinet/in.h>
@@ -128,7 +165,8 @@ free_file_system_list(struct mount_entry *p)
#endif
static int
-in_afs (char *path)
+in_afs (path)
+ char *path;
{
static char space[2048];
struct ViceIoctl vi;
@@ -144,16 +182,19 @@ in_afs (char *path)
}
#endif /* AFS */
-/* Nonzero if the current file system's type is known. */
+/* Nonzero if the current filesystem's type is known. */
static int fstype_known = 0;
-/* Return a static string naming the type of file system that the file PATH,
+/* Return a static string naming the type of filesystem that the file PATH,
described by STATP, is on.
RELPATH is the file name relative to the current directory.
- Return "unknown" if its file system type is unknown. */
+ Return "unknown" if its filesystem type is unknown. */
char *
-filesystem_type (const struct stat *statp, const char *path)
+filesystem_type (path, relpath, statp)
+ char *path;
+ char *relpath;
+ struct stat *statp;
{
static char *current_fstype = NULL;
static dev_t current_dev;
@@ -165,149 +206,181 @@ filesystem_type (const struct stat *statp, const char *path)
free (current_fstype);
}
current_dev = statp->st_dev;
- current_fstype = file_system_type_uncached (statp, path);
+ current_fstype = filesystem_type_uncached (path, relpath, statp);
return current_fstype;
}
-static int
-set_fstype_devno(struct mount_entry *p)
+/* Return a newly allocated string naming the type of filesystem that the
+ file PATH, described by STATP, is on.
+ RELPATH is the file name relative to the current directory.
+ Return "unknown" if its filesystem type is unknown. */
+
+static char *
+filesystem_type_uncached (path, relpath, statp)
+ char *path;
+ char *relpath;
+ struct stat *statp;
{
- struct stat stbuf;
-
- if (p->me_dev == (dev_t)-1)
+ char *type = NULL;
+
+#ifdef FSTYPE_MNTENT /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
+ char *table = MOUNTED;
+ FILE *mfp;
+ struct mntent *mnt;
+
+ mfp = setmntent (table, "r");
+ if (mfp == NULL)
+ error (1, errno, "%s", table);
+
+ /* Find the entry with the same device number as STATP, and return
+ that entry's fstype. */
+ while (type == NULL && (mnt = getmntent (mfp)))
{
- set_stat_placeholders(&stbuf);
- if (0 == (options.xstat)(p->me_mountdir, &stbuf))
+ char *devopt;
+ dev_t dev;
+ struct stat disk_stats;
+
+#ifdef MNTTYPE_IGNORE
+ if (!strcmp (mnt->mnt_type, MNTTYPE_IGNORE))
+ continue;
+#endif
+
+ /* Newer systems like SunOS 4.1 keep the dev number in the mtab,
+ in the options string. For older systems, we need to stat the
+ directory that the filesystem is mounted on to get it.
+
+ Unfortunately, the HPUX 9.x mnttab entries created by automountq
+ contain a dev= option but the option value does not match the
+ st_dev value of the file (maybe the lower 16 bits match?). */
+
+#if !defined(hpux) && !defined(__hpux__)
+ devopt = strstr (mnt->mnt_opts, "dev=");
+ if (devopt)
{
- p->me_dev = stbuf.st_dev;
- return 0;
+ if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
+ dev = xatoi (devopt + 6);
+ else
+ dev = xatoi (devopt + 4);
}
else
+#endif /* not hpux */
{
- return -1;
+ if (stat (mnt->mnt_dir, &disk_stats) == -1)
+ error (1, errno, "error in %s: %s", table, mnt->mnt_dir);
+ dev = disk_stats.st_dev;
}
- }
- return 0; /* not needed */
-}
-static struct mount_entry *
-must_read_fs_list(bool need_fs_type)
-{
- struct mount_entry *entries = read_file_system_list(need_fs_type);
- if (NULL == entries)
- {
- /* We cannot determine for sure which file we were trying to
- * use because gnulib has extracted all that stuff away.
- * Hence we cannot issue a specific error message here.
- */
- error(1, 0, "Cannot read mounted file system list");
+ if (dev == statp->st_dev)
+ type = mnt->mnt_type;
}
- return entries;
-}
+ if (endmntent (mfp) == 0)
+ error (0, errno, "%s", table);
+#endif
+#ifdef FSTYPE_GETMNT /* Ultrix. */
+ int offset = 0;
+ struct fs_data fsd;
-/* Return a newly allocated string naming the type of file system that the
- file PATH, described by STATP, is on.
- RELPATH is the file name relative to the current directory.
- Return "unknown" if its file system type is unknown. */
+ while (type == NULL
+ && getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, 0) > 0)
+ {
+ if (fsd.fd_req.dev == statp->st_dev)
+ type = gt_names[fsd.fd_req.fstype];
+ }
+#endif
-static char *
-file_system_type_uncached (const struct stat *statp, const char *path)
-{
- struct mount_entry *entries, *entry;
- char *type;
+#ifdef FSTYPE_USG_STATFS /* SVR3. */
+ struct statfs fss;
+ char typebuf[FSTYPSZ];
- (void) path;
-
-#ifdef AFS
- if (in_afs(path))
+ if (statfs (relpath, &fss, sizeof (struct statfs), 0) == -1)
{
- fstype_known = 1;
- return xstrdup("afs");
+ /* Don't die if a file was just removed. */
+ if (errno != ENOENT)
+ error (1, errno, "%s", path);
}
-#endif
-
- entries = must_read_fs_list(true);
- for (type=NULL, entry=entries; entry; entry=entry->me_next)
- {
-#ifdef MNTTYPE_IGNORE
- if (!strcmp (entry->me_type, MNTTYPE_IGNORE))
- continue;
+ else if (!sysfs (GETFSTYP, fss.f_fstyp, typebuf))
+ type = typebuf;
#endif
- set_fstype_devno(entry);
- if (entry->me_dev == statp->st_dev)
- {
- type = xstrdup(entry->me_type);
- break;
- }
+
+#ifdef FSTYPE_STATVFS /* SVR4. */
+ struct statvfs fss;
+
+ if (statvfs (relpath, &fss) == -1)
+ {
+ /* Don't die if a file was just removed. */
+ if (errno != ENOENT)
+ error (1, errno, "%s", path);
}
- free_file_system_list(entries);
+ else
+ type = fss.f_basetype;
+#endif
- /* Don't cache unknown values. */
- fstype_known = (type != NULL);
-
- return type ? type : xstrdup(_("unknown"));
-}
+#ifdef FSTYPE_STATFS /* 4.4BSD. */
+ struct statfs fss;
+ char *p;
+ if (S_ISLNK (statp->st_mode))
+ p = dirname (relpath);
+ else
+ p = relpath;
-char *
-get_mounted_filesystems (void)
-{
- char *result = NULL;
- size_t alloc_size = 0u;
- size_t used = 0u;
- struct mount_entry *entries, *entry;
-
- entries = must_read_fs_list(false);
- for (entry=entries; entry; entry=entry->me_next)
+ if (statfs (p, &fss) == -1)
{
- size_t len;
-
-#ifdef MNTTYPE_IGNORE
- if (!strcmp (entry->me_type, MNTTYPE_IGNORE))
- continue;
+ /* Don't die if symlink to nonexisting file, or a file that was
+ just removed. */
+ if (errno != ENOENT)
+ error (1, errno, "%s", path);
+ }
+ else
+ {
+#ifdef MFSNAMELEN /* NetBSD. */
+ type = xstrdup (fss.f_fstypename);
+#else
+ type = fstype_to_string (fss.f_type);
#endif
- set_fstype_devno(entry);
-
- len = strlen(entry->me_mountdir) + 1;
- result = extendbuf(result, used+len, &alloc_size);
- strcpy(&result[used], entry->me_mountdir);
- used += len; /* len already includes one for the \0 */
}
+ if (p != relpath)
+ free (p);
+#endif
+
+#ifdef AFS
+ if ((!type || !strcmp (type, "xx")) && in_afs (relpath))
+ type = "afs";
+#endif
- free_file_system_list(entries);
- return result;
+ /* An unknown value can be caused by an ENOENT error condition.
+ Don't cache those values. */
+ fstype_known = (type != NULL);
+
+ return xstrdup (type ? type : "unknown");
}
+#ifdef FSTYPE_MNTENT /* 4.3BSD etc. */
+/* Return the value of the hexadecimal number represented by CP.
+ No prefix (like '0x') or suffix (like 'h') is expected to be
+ part of CP. */
-dev_t *
-get_mounted_devices (size_t *n)
+static int
+xatoi (cp)
+ char *cp;
{
- size_t alloc_size = 0u;
- size_t used = 0u;
- struct mount_entry *entries, *entry;
- dev_t *result = NULL;
-
- /* Use read_file_system_list() rather than must_read_fs_list()
- * because on some system this is always called at startup,
- * and find should only exit fatally if it needs to use the
- * result of this operation. If we can't get the fs list
- * but we never need the information, there is no need to fail.
- */
- for (entry = entries = read_file_system_list(false);
- entry;
- entry = entry->me_next)
+ int val;
+
+ val = 0;
+ while (*cp)
{
- result = extendbuf(result, sizeof(dev_t)*(used+1), &alloc_size);
- set_fstype_devno(entry);
- result[used] = entry->me_dev;
- ++used;
+ if (*cp >= 'a' && *cp <= 'f')
+ val = val * 16 + *cp - 'a' + 10;
+ else if (*cp >= 'A' && *cp <= 'F')
+ val = val * 16 + *cp - 'A' + 10;
+ else if (*cp >= '0' && *cp <= '9')
+ val = val * 16 + *cp - '0';
+ else
+ break;
+ cp++;
}
- free_file_system_list(entries);
- *n = used;
- return result;
+ return val;
}
-
-
-
+#endif
diff --git a/find/parser.c b/find/parser.c
index b7ef88f8..3d85a9a3 100644
--- a/find/parser.c
+++ b/find/parser.c
@@ -1,11 +1,10 @@
/* parser.c -- convert the command line args into an expression tree.
- Copyright (C) 1990, 1991, 1992, 1993, 1994, 2000, 2001, 2003,
- 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
+ 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 3 of the License, or
- (at your option) any later version.
+ 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
@@ -13,58 +12,19 @@
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, see <http://www.gnu.org/licenses/>.
-*/
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <config.h>
-
-#include "defs.h"
+#include <sys/types.h>
+#include <sys/stat.h>
#include <ctype.h>
-#include <math.h>
-#include <assert.h>
+#include <stdio.h>
#include <pwd.h>
-#include <errno.h>
#include <grp.h>
-#include <fnmatch.h>
#include "modechange.h"
+#include "defs.h"
#include "modetype.h"
-#include "xstrtol.h"
-#include "xalloc.h"
-#include "quote.h"
-#include "quotearg.h"
-#include "buildcmd.h"
-#include "nextelem.h"
-#include "stdio-safer.h"
-#include "regextype.h"
-#include "stat-time.h"
-#include "xstrtod.h"
-#include "fts_.h"
-#include "getdate.h"
-#include "error.h"
-#include "findutils-version.h"
-
-#include <fcntl.h>
-
-
-/* The presence of unistd.h is assumed by gnulib these days, so we
- * might as well assume it too.
- */
-/* We need <unistd.h> for isatty(). */
-#include <unistd.h>
-#include <sys/stat.h>
-
-#if ENABLE_NLS
-# include <libintl.h>
-# define _(Text) gettext (Text)
-#else
-# define _(Text) Text
-#endif
-#ifdef gettext_noop
-# define N_(String) gettext_noop (String)
-#else
-/* See locate.c for explanation as to why not use (String) */
-# define N_(String) String
-#endif
#if !defined (isascii) || defined (STDC_HEADERS)
#ifdef isascii
@@ -73,594 +33,225 @@
#define isascii(c) 1
#endif
-#define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
-#define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c))
+#define ISDIGIT(c) (isascii (c) && isdigit (c))
+#define ISUPPER(c) (isascii (c) && isupper (c))
-#ifndef HAVE_ENDGRENT
-#define endgrent()
+#ifndef _POSIX_VERSION
+/* POSIX.1 header files should declare these. */
+struct group *getgrnam ();
+struct passwd *getpwnam ();
+#endif
+
+#ifdef CACHE_IDS
+/* These two aren't specified by POSIX.1. */
+struct group *getgrent ();
+struct passwd *getpwent ();
+#endif
+
+#ifndef S_IFLNK
+#define lstat stat
+#endif
+
+char *strstr ();
+int lstat ();
+int stat ();
+#ifndef atol /* for Linux */
+long atol ();
#endif
-#ifndef HAVE_ENDPWENT
+struct tm *localtime ();
+
+#ifdef _POSIX_SOURCE
+#define endgrent()
#define endpwent()
+#else
+void endgrent ();
+void endpwent ();
#endif
-static boolean parse_accesscheck PARAMS((const struct parser_table* entry, char **argv, int *arg_ptr));
-static boolean parse_amin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_and PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_anewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_cmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_cnewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_comma PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_daystart PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_delete PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_d PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_depth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_empty PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_exec PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_execdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_false PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_fls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_fprintf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_follow PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_fprint PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_fprint0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_fstype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_gid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_group PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_help PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_ilname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_iname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_inum PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_ipath PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_iregex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_iwholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_links PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_lname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_ls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_maxdepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_mindepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_mmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_name PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_negate PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_newer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_newerXY PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_noleaf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_nogroup PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_nouser PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_nowarn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_ok PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_okdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_or PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_path PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_perm PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_print0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_printf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_prune PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_regex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_regextype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_samefile PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-#if 0
-static boolean parse_show_control_chars PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-#endif
-static boolean parse_size PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_time PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_true PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_type PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_uid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_used PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_user PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_version PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_wholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_xdev PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_ignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_noignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_warn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_xtype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_quit PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-
-boolean parse_print PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-
-
-static boolean insert_type PARAMS((char **argv, int *arg_ptr,
- const struct parser_table *entry,
- PRED_FUNC which_pred));
-static boolean insert_regex PARAMS((char *argv[], int *arg_ptr,
- const struct parser_table *entry,
- int regex_options));
-static boolean insert_fprintf (struct format_val *vec,
- const struct parser_table *entry,
- PRED_FUNC func,
- const char *format);
-
-static struct segment **make_segment PARAMS((struct segment **segment,
- char *format, int len,
- int kind, char format_char,
- char aux_format_char,
- struct predicate *pred));
-static boolean insert_exec_ok PARAMS((const char *action,
- const struct parser_table *entry,
- int dirfd,
- char *argv[],
- int *arg_ptr));
-static boolean get_comp_type PARAMS((const char **str,
- enum comparison_type *comp_type));
-static boolean get_relative_timestamp PARAMS((const char *str,
- struct time_val *tval,
- struct timespec origin,
- double sec_per_unit,
- const char *overflowmessage));
-static boolean get_num PARAMS((const char *str,
- uintmax_t *num,
- enum comparison_type *comp_type));
-static struct predicate* insert_num PARAMS((char *argv[], int *arg_ptr,
- const struct parser_table *entry));
-static void open_output_file (const char *path, struct format_val *p);
-static void open_stdout (struct format_val *p);
-static boolean stream_is_tty(FILE *fp);
-static boolean parse_noop PARAMS((const struct parser_table* entry,
- char **argv, int *arg_ptr));
-
-#define PASTE(x,y) x##y
-#define STRINGIFY(s) #s
-
-#define PARSE_OPTION(what,suffix) \
- { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
-
-#define PARSE_POSOPT(what,suffix) \
- { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
-
-#define PARSE_TEST(what,suffix) \
- { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
-
-#define PARSE_TEST_NP(what,suffix) \
- { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
-
-#define PARSE_ACTION(what,suffix) \
- { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
-
-#define PARSE_ACTION_NP(what,suffix) \
- { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL }
-
-#define PARSE_PUNCTUATION(what,suffix) \
- { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
-
-
-/* Predicates we cannot handle in the usual way. If you add an entry
- * to this table, double-check the switch statement in
- * pred_sanity_check() to make sure that the new case is being
- * correctly handled.
- */
-static struct parser_table const parse_entry_newerXY =
- {
- ARG_SPECIAL_PARSE, "newerXY", parse_newerXY, pred_newerXY /* BSD */
- };
+static boolean parse_amin P_((char *argv[], int *arg_ptr));
+static boolean parse_and P_((char *argv[], int *arg_ptr));
+static boolean parse_anewer P_((char *argv[], int *arg_ptr));
+static boolean parse_atime P_((char *argv[], int *arg_ptr));
+boolean parse_close P_((char *argv[], int *arg_ptr));
+static boolean parse_cmin P_((char *argv[], int *arg_ptr));
+static boolean parse_cnewer P_((char *argv[], int *arg_ptr));
+static boolean parse_comma P_((char *argv[], int *arg_ptr));
+static boolean parse_ctime P_((char *argv[], int *arg_ptr));
+static boolean parse_daystart P_((char *argv[], int *arg_ptr));
+static boolean parse_depth P_((char *argv[], int *arg_ptr));
+static boolean parse_empty P_((char *argv[], int *arg_ptr));
+static boolean parse_exec P_((char *argv[], int *arg_ptr));
+static boolean parse_false P_((char *argv[], int *arg_ptr));
+static boolean parse_fls P_((char *argv[], int *arg_ptr));
+static boolean parse_fprintf P_((char *argv[], int *arg_ptr));
+static boolean parse_follow P_((char *argv[], int *arg_ptr));
+static boolean parse_fprint P_((char *argv[], int *arg_ptr));
+static boolean parse_fprint0 P_((char *argv[], int *arg_ptr));
+static boolean parse_fstype P_((char *argv[], int *arg_ptr));
+static boolean parse_gid P_((char *argv[], int *arg_ptr));
+static boolean parse_group P_((char *argv[], int *arg_ptr));
+static boolean parse_help P_((char *argv[], int *arg_ptr));
+static boolean parse_ilname P_((char *argv[], int *arg_ptr));
+static boolean parse_iname P_((char *argv[], int *arg_ptr));
+static boolean parse_inum P_((char *argv[], int *arg_ptr));
+static boolean parse_ipath P_((char *argv[], int *arg_ptr));
+static boolean parse_iregex P_((char *argv[], int *arg_ptr));
+static boolean parse_links P_((char *argv[], int *arg_ptr));
+static boolean parse_lname P_((char *argv[], int *arg_ptr));
+static boolean parse_ls P_((char *argv[], int *arg_ptr));
+static boolean parse_maxdepth P_((char *argv[], int *arg_ptr));
+static boolean parse_mindepth P_((char *argv[], int *arg_ptr));
+static boolean parse_mmin P_((char *argv[], int *arg_ptr));
+static boolean parse_mtime P_((char *argv[], int *arg_ptr));
+static boolean parse_name P_((char *argv[], int *arg_ptr));
+static boolean parse_negate P_((char *argv[], int *arg_ptr));
+static boolean parse_newer P_((char *argv[], int *arg_ptr));
+static boolean parse_noleaf P_((char *argv[], int *arg_ptr));
+static boolean parse_nogroup P_((char *argv[], int *arg_ptr));
+static boolean parse_nouser P_((char *argv[], int *arg_ptr));
+static boolean parse_ok P_((char *argv[], int *arg_ptr));
+boolean parse_open P_((char *argv[], int *arg_ptr));
+static boolean parse_or P_((char *argv[], int *arg_ptr));
+static boolean parse_path P_((char *argv[], int *arg_ptr));
+static boolean parse_perm P_((char *argv[], int *arg_ptr));
+boolean parse_print P_((char *argv[], int *arg_ptr));
+static boolean parse_print0 P_((char *argv[], int *arg_ptr));
+static boolean parse_printf P_((char *argv[], int *arg_ptr));
+static boolean parse_prune P_((char *argv[], int *arg_ptr));
+static boolean parse_regex P_((char *argv[], int *arg_ptr));
+static boolean insert_regex P_((char *argv[], int *arg_ptr, boolean ignore_case));
+static boolean parse_size P_((char *argv[], int *arg_ptr));
+static boolean parse_true P_((char *argv[], int *arg_ptr));
+static boolean parse_type P_((char *argv[], int *arg_ptr));
+static boolean parse_uid P_((char *argv[], int *arg_ptr));
+static boolean parse_used P_((char *argv[], int *arg_ptr));
+static boolean parse_user P_((char *argv[], int *arg_ptr));
+static boolean parse_version P_((char *argv[], int *arg_ptr));
+static boolean parse_xdev P_((char *argv[], int *arg_ptr));
+static boolean parse_xtype P_((char *argv[], int *arg_ptr));
+
+static boolean insert_regex P_((char *argv[], int *arg_ptr, boolean ignore_case));
+static boolean insert_type P_((char *argv[], int *arg_ptr, boolean (*which_pred )()));
+static boolean insert_fprintf P_((FILE *fp, boolean (*func )(), char *argv[], int *arg_ptr));
+static struct segment **make_segment P_((struct segment **segment, char *format, int len, int kind));
+static boolean insert_exec_ok P_((boolean (*func )(), char *argv[], int *arg_ptr));
+static boolean get_num_days P_((char *str, unsigned long *num_days, enum comparison_type *comp_type));
+static boolean insert_time P_((char *argv[], int *arg_ptr, PFB pred));
+static boolean get_num P_((char *str, unsigned long *num, enum comparison_type *comp_type));
+static boolean insert_num P_((char *argv[], int *arg_ptr, PFB pred));
+static FILE *open_output_file P_((char *path));
+
+#ifdef DEBUG
+char *find_pred_name _P((PFB pred_func));
+#endif /* DEBUG */
+
+struct parser_table
+{
+ char *parser_name;
+ PFB parser_func;
+};
/* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
If they are in some Unix versions of find, they are marked `Unix'. */
static struct parser_table const parse_table[] =
{
- PARSE_PUNCTUATION("!", negate), /* POSIX */
- PARSE_PUNCTUATION("not", negate), /* GNU */
- PARSE_PUNCTUATION("(", openparen), /* POSIX */
- PARSE_PUNCTUATION(")", closeparen), /* POSIX */
- PARSE_PUNCTUATION(",", comma), /* GNU */
- PARSE_PUNCTUATION("a", and), /* POSIX */
- PARSE_TEST ("amin", amin), /* GNU */
- PARSE_PUNCTUATION("and", and), /* GNU */
- PARSE_TEST ("anewer", anewer), /* GNU */
- {ARG_TEST, "atime", parse_time, pred_atime}, /* POSIX */
- PARSE_TEST ("cmin", cmin), /* GNU */
- PARSE_TEST ("cnewer", cnewer), /* GNU */
- {ARG_TEST, "ctime", parse_time, pred_ctime}, /* POSIX */
- PARSE_POSOPT ("daystart", daystart), /* GNU */
- PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
- PARSE_OPTION ("d", d), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
- PARSE_OPTION ("depth", depth), /* POSIX */
- PARSE_TEST ("empty", empty), /* GNU */
- {ARG_ACTION, "exec", parse_exec, pred_exec}, /* POSIX */
- {ARG_TEST, "executable", parse_accesscheck, pred_executable}, /* GNU, 4.3.0+ */
- PARSE_ACTION ("execdir", execdir), /* *BSD, GNU */
- PARSE_ACTION ("fls", fls), /* GNU */
- PARSE_POSOPT ("follow", follow), /* GNU, Unix */
- PARSE_ACTION ("fprint", fprint), /* GNU */
- PARSE_ACTION ("fprint0", fprint0), /* GNU */
- {ARG_ACTION, "fprintf", parse_fprintf, pred_fprintf}, /* GNU */
- PARSE_TEST ("fstype", fstype), /* GNU, Unix */
- PARSE_TEST ("gid", gid), /* GNU */
- PARSE_TEST ("group", group), /* POSIX */
- PARSE_OPTION ("ignore_readdir_race", ignore_race), /* GNU */
- PARSE_TEST ("ilname", ilname), /* GNU */
- PARSE_TEST ("iname", iname), /* GNU */
- PARSE_TEST ("inum", inum), /* GNU, Unix */
- PARSE_TEST ("ipath", ipath), /* GNU, deprecated in favour of iwholename */
- PARSE_TEST_NP ("iregex", iregex), /* GNU */
- PARSE_TEST_NP ("iwholename", iwholename), /* GNU */
- PARSE_TEST ("links", links), /* POSIX */
- PARSE_TEST ("lname", lname), /* GNU */
- PARSE_ACTION ("ls", ls), /* GNU, Unix */
- PARSE_OPTION ("maxdepth", maxdepth), /* GNU */
- PARSE_OPTION ("mindepth", mindepth), /* GNU */
- PARSE_TEST ("mmin", mmin), /* GNU */
- PARSE_OPTION ("mount", xdev), /* Unix */
- {ARG_TEST, "mtime", parse_time, pred_mtime}, /* POSIX */
- PARSE_TEST ("name", name),
-#ifdef UNIMPLEMENTED_UNIX
- PARSE(ARG_UNIMPLEMENTED, "ncpio", ncpio), /* Unix */
-#endif
- PARSE_TEST ("newer", newer), /* POSIX */
- {ARG_TEST, "atime", parse_time, pred_atime}, /* POSIX */
- PARSE_OPTION ("noleaf", noleaf), /* GNU */
- PARSE_TEST ("nogroup", nogroup), /* POSIX */
- PARSE_TEST ("nouser", nouser), /* POSIX */
- PARSE_OPTION ("noignore_readdir_race", noignore_race), /* GNU */
- PARSE_POSOPT ("nowarn", nowarn), /* GNU */
- PARSE_PUNCTUATION("o", or), /* POSIX */
- PARSE_PUNCTUATION("or", or), /* GNU */
- PARSE_ACTION ("ok", ok), /* POSIX */
- PARSE_ACTION ("okdir", okdir), /* GNU (-execdir is BSD) */
- PARSE_TEST ("path", path), /* GNU, HP-UX, RMS prefers wholename, but anyway soon POSIX */
- PARSE_TEST ("perm", perm), /* POSIX */
- PARSE_ACTION ("print", print), /* POSIX */
- PARSE_ACTION ("print0", print0), /* GNU */
- {ARG_ACTION, "printf", parse_printf, NULL}, /* GNU */
- PARSE_ACTION ("prune", prune), /* POSIX */
- PARSE_ACTION ("quit", quit), /* GNU */
- {ARG_TEST, "readable", parse_accesscheck, pred_readable}, /* GNU, 4.3.0+ */
- PARSE_TEST ("regex", regex), /* GNU */
- PARSE_OPTION ("regextype", regextype), /* GNU */
- PARSE_TEST ("samefile", samefile), /* GNU */
-#if 0
- PARSE_OPTION ("show-control-chars", show_control_chars), /* GNU, 4.3.0+ */
-#endif
- PARSE_TEST ("size", size), /* POSIX */
- PARSE_TEST ("type", type), /* POSIX */
- PARSE_TEST ("uid", uid), /* GNU */
- PARSE_TEST ("used", used), /* GNU */
- PARSE_TEST ("user", user), /* POSIX */
- PARSE_OPTION ("warn", warn), /* GNU */
- PARSE_TEST_NP ("wholename", wholename), /* GNU, replaced -path, but anyway -path will soon be in POSIX */
- {ARG_TEST, "writable", parse_accesscheck, pred_writable}, /* GNU, 4.3.0+ */
- PARSE_OPTION ("xdev", xdev), /* POSIX */
- PARSE_TEST ("xtype", xtype), /* GNU */
+ {"!", parse_negate},
+ {"not", parse_negate}, /* GNU */
+ {"(", parse_open},
+ {")", parse_close},
+ {",", parse_comma}, /* GNU */
+ {"a", parse_and},
+ {"amin", parse_amin}, /* GNU */
+ {"and", parse_and}, /* GNU */
+ {"anewer", parse_anewer}, /* GNU */
+ {"atime", parse_atime},
+ {"cmin", parse_cmin}, /* GNU */
+ {"cnewer", parse_cnewer}, /* GNU */
#ifdef UNIMPLEMENTED_UNIX
/* It's pretty ugly for find to know about archive formats.
Plus what it could do with cpio archives is very limited.
Better to leave it out. */
- PARSE(ARG_UNIMPLEMENTED, "cpio", cpio), /* Unix */
+ {"cpio", parse_cpio}, /* Unix */
+#endif
+ {"ctime", parse_ctime},
+ {"daystart", parse_daystart}, /* GNU */
+ {"depth", parse_depth},
+ {"empty", parse_empty}, /* GNU */
+ {"exec", parse_exec},
+ {"false", parse_false}, /* GNU */
+ {"fls", parse_fls}, /* GNU */
+ {"follow", parse_follow}, /* GNU, Unix */
+ {"fprint", parse_fprint}, /* GNU */
+ {"fprint0", parse_fprint0}, /* GNU */
+ {"fprintf", parse_fprintf}, /* GNU */
+ {"fstype", parse_fstype}, /* GNU, Unix */
+ {"gid", parse_gid}, /* GNU */
+ {"group", parse_group},
+ {"help", parse_help}, /* GNU */
+ {"-help", parse_help}, /* GNU */
+ {"ilname", parse_ilname}, /* GNU */
+ {"iname", parse_iname}, /* GNU */
+ {"inum", parse_inum}, /* GNU, Unix */
+ {"ipath", parse_ipath}, /* GNU */
+ {"iregex", parse_iregex}, /* GNU */
+ {"links", parse_links},
+ {"lname", parse_lname}, /* GNU */
+ {"ls", parse_ls}, /* GNU, Unix */
+ {"maxdepth", parse_maxdepth}, /* GNU */
+ {"mindepth", parse_mindepth}, /* GNU */
+ {"mmin", parse_mmin}, /* GNU */
+ {"mount", parse_xdev}, /* Unix */
+ {"mtime", parse_mtime},
+ {"name", parse_name},
+#ifdef UNIMPLEMENTED_UNIX
+ {"ncpio", parse_ncpio}, /* Unix */
#endif
- /* gnulib's stdbool.h might have made true and false into macros,
- * so we can't leave named 'true' and 'false' tokens, so we have
- * to expeant the relevant entries longhand.
- */
- {ARG_TEST, "false", parse_false, pred_false}, /* GNU */
- {ARG_TEST, "true", parse_true, pred_true }, /* GNU */
- {ARG_NOOP, "noop", NULL, pred_true }, /* GNU, internal use only */
-
- /* Various other cases that don't fit neatly into our macro scheme. */
- {ARG_TEST, "help", parse_help, NULL}, /* GNU */
- {ARG_TEST, "-help", parse_help, NULL}, /* GNU */
- {ARG_TEST, "version", parse_version, NULL}, /* GNU */
- {ARG_TEST, "-version", parse_version, NULL}, /* GNU */
- {0, 0, 0, 0}
+ {"newer", parse_newer},
+ {"noleaf", parse_noleaf}, /* GNU */
+ {"nogroup", parse_nogroup},
+ {"nouser", parse_nouser},
+ {"o", parse_or},
+ {"or", parse_or}, /* GNU */
+ {"ok", parse_ok},
+ {"path", parse_path}, /* GNU, HP-UX */
+ {"perm", parse_perm},
+ {"print", parse_print},
+ {"print0", parse_print0}, /* GNU */
+ {"printf", parse_printf}, /* GNU */
+ {"prune", parse_prune},
+ {"regex", parse_regex}, /* GNU */
+ {"size", parse_size},
+ {"true", parse_true}, /* GNU */
+ {"type", parse_type},
+ {"uid", parse_uid}, /* GNU */
+ {"used", parse_used}, /* GNU */
+ {"user", parse_user},
+ {"version", parse_version}, /* GNU */
+ {"-version", parse_version}, /* GNU */
+ {"xdev", parse_xdev},
+ {"xtype", parse_xtype}, /* GNU */
+ {0, 0}
};
-
-static const char *first_nonoption_arg = NULL;
-static const struct parser_table *noop = NULL;
-
-
-void
-check_option_combinations(const struct predicate *p)
-{
- enum { seen_delete=1u, seen_prune=2u };
- unsigned int predicates = 0u;
-
- while (p)
- {
- if (p->pred_func == pred_delete)
- predicates |= seen_delete;
- else if (p->pred_func == pred_prune)
- predicates |= seen_prune;
- p = p->pred_next;
- }
-
- if ((predicates & seen_prune) && (predicates & seen_delete))
- {
- /* The user specified both -delete and -prune. One might test
- * this by first doing
- * find dirs .... -prune ..... -print
- * to fnd out what's going to get deleted, and then switch to
- * find dirs .... -prune ..... -delete
- * once we are happy. Unfortunately, the -delete action also
- * implicitly turns on -depth, which will affect the behaviour
- * of -prune (in fact, it makes it a no-op). In this case we
- * would like to prevent unfortunate accidents, so we require
- * the user to have explicitly used -depth.
- *
- * We only get away with this because the -delete predicate is not
- * in POSIX. If it was, we couldn't issue a fatal error here.
- */
- if (!options.explicit_depth)
- {
- /* This fixes Savannah bug #20865. */
- error (1, 0, _("The -delete action atomatically turns on -depth, "
- "but -prune does nothing when -depth is in effect. "
- "If you want to carry on anyway, just explicitly use "
- "the -depth option."));
- }
- }
-}
-
-
-static const struct parser_table*
-get_noop(void)
-{
- int i;
- if (NULL == noop)
- {
- for (i = 0; parse_table[i].parser_name != 0; i++)
- {
- if (ARG_NOOP ==parse_table[i].type)
- {
- noop = &(parse_table[i]);
- break;
- }
- }
- }
- return noop;
-}
-
-static int
-get_stat_Ytime(const struct stat *p,
- char what,
- struct timespec *ret)
-{
- switch (what)
- {
- case 'a':
- *ret = get_stat_atime(p);
- return 1;
- case 'B':
- *ret = get_stat_birthtime(p);
- return (ret->tv_nsec >= 0);
- case 'c':
- *ret = get_stat_ctime(p);
- return 1;
- case 'm':
- *ret = get_stat_mtime(p);
- return 1;
- default:
- assert (0);
- abort();
- }
-}
-
-void
-set_follow_state(enum SymlinkOption opt)
-{
- if (options.debug_options & DebugStat)
- {
- /* For DebugStat, the choice is made at runtime within debug_stat()
- * by checking the contents of the symlink_handling variable.
- */
- options.xstat = debug_stat;
- }
- else
- {
- switch (opt)
- {
- case SYMLINK_ALWAYS_DEREF: /* -L */
- options.xstat = optionl_stat;
- options.no_leaf_check = true;
- break;
-
- case SYMLINK_NEVER_DEREF: /* -P (default) */
- options.xstat = optionp_stat;
- /* Can't turn no_leaf_check off because the user might have specified
- * -noleaf anyway
- */
- break;
-
- case SYMLINK_DEREF_ARGSONLY: /* -H */
- options.xstat = optionh_stat;
- options.no_leaf_check = true;
- }
- }
- options.symlink_handling = opt;
-}
-
-
-void
-parse_begin_user_args (char **args, int argno,
- const struct predicate *last,
- const struct predicate *predicates)
-{
- (void) args;
- (void) argno;
- (void) last;
- (void) predicates;
- first_nonoption_arg = NULL;
-}
-
-void
-parse_end_user_args (char **args, int argno,
- const struct predicate *last,
- const struct predicate *predicates)
-{
- /* does nothing */
- (void) args;
- (void) argno;
- (void) last;
- (void) predicates;
-}
-
-
-/* Check that it is legal to fid the given primary in its
- * position and return it.
- */
-const struct parser_table*
-found_parser(const char *original_arg, const struct parser_table *entry)
-{
- /* If this is an option, but we have already had a
- * non-option argument, the user may be under the
- * impression that the behaviour of the option
- * argument is conditional on some preceding
- * tests. This might typically be the case with,
- * for example, -maxdepth.
- *
- * The options -daystart and -follow are exempt
- * from this treatment, since their positioning
- * in the command line does have an effect on
- * subsequent tests but not previous ones. That
- * might be intentional on the part of the user.
- */
- if (entry->type != ARG_POSITIONAL_OPTION)
- {
- /* Something other than -follow/-daystart.
- * If this is an option, check if it followed
- * a non-option and if so, issue a warning.
- */
- if (entry->type == ARG_OPTION)
- {
- if ((first_nonoption_arg != NULL)
- && options.warnings )
- {
- /* option which follows a non-option */
- error (0, 0,
- _("warning: you have specified the %s "
- "option after a non-option argument %s, "
- "but options are not positional (%s affects "
- "tests specified before it as well as those "
- "specified after it). Please specify options "
- "before other arguments.\n"),
- original_arg,
- first_nonoption_arg,
- original_arg);
- }
- }
- else
- {
- /* Not an option or a positional option,
- * so remember we've seen it in order to
- * use it in a possible future warning message.
- */
- if (first_nonoption_arg == NULL)
- {
- first_nonoption_arg = original_arg;
- }
- }
- }
-
- return entry;
-}
-
-
/* Return a pointer to the parser function to invoke for predicate
SEARCH_NAME.
Return NULL if SEARCH_NAME is not a valid predicate name. */
-const struct parser_table*
-find_parser (char *search_name)
+PFB
+find_parser (search_name)
+ char *search_name;
{
int i;
- const char *original_arg = search_name;
-
- /* Ugh. Special case -newerXY. */
- if (0 == strncmp("-newer", search_name, 6)
- && (8 == strlen(search_name)))
- {
- return found_parser(original_arg, &parse_entry_newerXY);
- }
-
+
if (*search_name == '-')
search_name++;
-
for (i = 0; parse_table[i].parser_name != 0; i++)
- {
- if (strcmp (parse_table[i].parser_name, search_name) == 0)
- {
- return found_parser(original_arg, &parse_table[i]);
- }
- }
- return NULL;
-}
-
-static float
-estimate_file_age_success_rate(float num_days)
-{
- if (num_days < 0.1)
- {
- /* Assume 1% of files have timestamps in the future */
- return 0.01f;
- }
- else if (num_days < 1)
- {
- /* Assume 30% of files have timestamps today */
- return 0.3f;
- }
- else if (num_days > 100)
- {
- /* Assume 30% of files are very old */
- return 0.3f;
- }
- else
- {
- /* Assume 39% of files are between 1 and 100 days old. */
- return 0.39f;
- }
+ if (strcmp (parse_table[i].parser_name, search_name) == 0)
+ return (parse_table[i].parser_func);
+ return (NULL);
}
-static float
-estimate_timestamp_success_rate(time_t when)
-{
- /* This calculation ignores the nanoseconds field of the
- * origin, but I don't think that makes much difference
- * to our estimate.
- */
- int num_days = (options.cur_day_start.tv_sec - when) / 86400;
- return estimate_file_age_success_rate(num_days);
-}
-
-/* Collect an argument from the argument list, or
- * return false.
- */
-static boolean
-collect_arg(char **argv, int *arg_ptr, const char **collected_arg)
-{
- if ((argv == NULL) || (argv[*arg_ptr] == NULL))
- {
- *collected_arg = NULL;
- return false;
- }
- else
- {
- *collected_arg = argv[*arg_ptr];
- (*arg_ptr)++;
- return true;
- }
-}
-
-static boolean
-collect_arg_stat_info(char **argv, int *arg_ptr, struct stat *p)
-{
- const char *filename;
- if (collect_arg(argv, arg_ptr, &filename))
- {
- if (0 == (options.xstat)(filename, p))
- {
- return true;
- }
- else
- {
- fatal_file_error(filename);
- }
- }
- else
- {
- return false;
- }
-}
-
/* The parsers are responsible to continue scanning ARGV for
their arguments. Each parser knows what is and isn't
allowed for itself.
@@ -671,925 +262,595 @@ collect_arg_stat_info(char **argv, int *arg_ptr, struct stat *p)
The predicate structure is updated with the new information. */
-
static boolean
-parse_and (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_amin (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
+{
+ struct predicate *our_pred;
+ unsigned long num;
+ enum comparison_type c_type;
+
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ if (!get_num_days (argv[*arg_ptr], &num, &c_type))
+ return (false);
+ our_pred = insert_primary (pred_amin);
+ our_pred->args.info.kind = c_type;
+ our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60;
+ (*arg_ptr)++;
+ return (true);
+}
+
+static boolean
+parse_and (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
- (void) argv;
- (void) arg_ptr;
-
- our_pred = get_new_pred (entry);
+ our_pred = get_new_pred ();
our_pred->pred_func = pred_and;
+#ifdef DEBUG
+ our_pred->p_name = find_pred_name (pred_and);
+#endif /* DEBUG */
our_pred->p_type = BI_OP;
our_pred->p_prec = AND_PREC;
- our_pred->need_stat = our_pred->need_type = false;
- return true;
+ our_pred->need_stat = false;
+ return (true);
}
static boolean
-parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_anewer (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
+ struct predicate *our_pred;
struct stat stat_newer;
- set_stat_placeholders(&stat_newer);
- if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
- {
- struct predicate *our_pred = insert_primary (entry);
- our_pred->args.reftime.xval = XVAL_ATIME;
- our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
- our_pred->args.reftime.kind = COMP_GT;
- our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
- return true;
- }
- return false;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ if ((*xstat) (argv[*arg_ptr], &stat_newer))
+ error (1, errno, "%s", argv[*arg_ptr]);
+ our_pred = insert_primary (pred_anewer);
+ our_pred->args.time = stat_newer.st_mtime;
+ (*arg_ptr)++;
+ return (true);
+}
+
+static boolean
+parse_atime (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
+{
+ return (insert_time (argv, arg_ptr, pred_atime));
}
boolean
-parse_closeparen (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_close (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
- (void) argv;
- (void) arg_ptr;
-
- our_pred = get_new_pred (entry);
- our_pred->pred_func = pred_closeparen;
+ our_pred = get_new_pred ();
+ our_pred->pred_func = pred_close;
+#ifdef DEBUG
+ our_pred->p_name = find_pred_name (pred_close);
+#endif /* DEBUG */
our_pred->p_type = CLOSE_PAREN;
our_pred->p_prec = NO_PREC;
- our_pred->need_stat = our_pred->need_type = false;
- return true;
+ our_pred->need_stat = false;
+ return (true);
}
static boolean
-parse_cnewer (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_cmin (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- struct stat stat_newer;
+ struct predicate *our_pred;
+ unsigned long num;
+ enum comparison_type c_type;
- set_stat_placeholders(&stat_newer);
- if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
- {
- struct predicate *our_pred = insert_primary (entry);
- our_pred->args.reftime.xval = XVAL_CTIME; /* like -newercm */
- our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
- our_pred->args.reftime.kind = COMP_GT;
- our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
- return true;
- }
- return false;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ if (!get_num_days (argv[*arg_ptr], &num, &c_type))
+ return (false);
+ our_pred = insert_primary (pred_cmin);
+ our_pred->args.info.kind = c_type;
+ our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60;
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_comma (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_cnewer (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
+ struct stat stat_newer;
- (void) argv;
- (void) arg_ptr;
-
- our_pred = get_new_pred (entry);
- our_pred->pred_func = pred_comma;
- our_pred->p_type = BI_OP;
- our_pred->p_prec = COMMA_PREC;
- our_pred->need_stat = our_pred->need_type = false;
- our_pred->est_success_rate = 1.0f;
- return true;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ if ((*xstat) (argv[*arg_ptr], &stat_newer))
+ error (1, errno, "%s", argv[*arg_ptr]);
+ our_pred = insert_primary (pred_cnewer);
+ our_pred->args.time = stat_newer.st_mtime;
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_daystart (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_comma (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- struct tm *local;
-
- (void) entry;
- (void) argv;
- (void) arg_ptr;
+ struct predicate *our_pred;
- if (options.full_days == false)
- {
- options.cur_day_start.tv_sec += DAYSECS;
- options.cur_day_start.tv_nsec = 0;
- local = localtime (&options.cur_day_start.tv_sec);
- options.cur_day_start.tv_sec -= (local
- ? (local->tm_sec + local->tm_min * 60
- + local->tm_hour * 3600)
- : options.cur_day_start.tv_sec % DAYSECS);
- options.full_days = true;
- }
- return true;
+ our_pred = get_new_pred ();
+ our_pred->pred_func = pred_comma;
+#ifdef DEBUG
+ our_pred->p_name = find_pred_name (pred_comma);
+#endif /* DEBUG */
+ our_pred->p_type = BI_OP;
+ our_pred->p_prec = COMMA_PREC;
+ our_pred->need_stat = false;
+ return (true);
}
static boolean
-parse_delete (const struct parser_table* entry, char *argv[], int *arg_ptr)
+parse_ctime (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- struct predicate *our_pred;
- (void) argv;
- (void) arg_ptr;
-
- our_pred = insert_primary (entry);
- our_pred->side_effects = our_pred->no_default_print = true;
- /* -delete implies -depth */
- options.do_dir_first = false;
-
- /* We do not need stat information because we check for the case
- * (errno==EISDIR) in pred_delete.
- */
- our_pred->need_stat = our_pred->need_type = false;
-
- our_pred->est_success_rate = 1.0f;
- return true;
+ return (insert_time (argv, arg_ptr, pred_ctime));
}
static boolean
-parse_depth (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_daystart (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- (void) entry;
- (void) argv;
+ struct tm *local;
- options.do_dir_first = false;
- options.explicit_depth = true;
- return parse_noop(entry, argv, arg_ptr);
-}
-
-static boolean
-parse_d (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- if (options.warnings)
+ if (full_days == false)
{
- error (0, 0,
- _("warning: the -d option is deprecated; please use "
- "-depth instead, because the latter is a "
- "POSIX-compliant feature."));
+ cur_day_start += DAYSECS;
+ local = localtime (&cur_day_start);
+ cur_day_start -= local->tm_sec + local->tm_min * 60
+ + local->tm_hour * 3600;
+ full_days = true;
}
- return parse_depth(entry, argv, arg_ptr);
+ return (true);
}
-
+
static boolean
-parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_depth (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- struct predicate *our_pred;
- (void) argv;
- (void) arg_ptr;
-
- our_pred = insert_primary (entry);
- our_pred->est_success_rate = 0.01f; /* assume 1% of files are empty. */
- return true;
+ do_dir_first = false;
+ return (true);
}
-
+
static boolean
-parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_empty (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- return insert_exec_ok ("-exec", entry, get_start_dirfd(), argv, arg_ptr);
+ insert_primary (pred_empty);
+ return (true);
}
static boolean
-parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_exec (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- return insert_exec_ok ("-execdir", entry, -1, argv, arg_ptr);
+ return (insert_exec_ok (pred_exec, argv, arg_ptr));
}
static boolean
-parse_false (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_false (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
-
- (void) argv;
- (void) arg_ptr;
-
- our_pred = insert_primary (entry);
- our_pred->need_stat = our_pred->need_type = false;
- our_pred->side_effects = our_pred->no_default_print = false;
- our_pred->est_success_rate = 0.0f;
- return true;
-}
-static boolean
-insert_fls (const struct parser_table* entry, const char *filename)
-{
- struct predicate *our_pred = insert_primary (entry);
- if (filename)
- open_output_file (filename, &our_pred->args.printf_vec);
- else
- open_stdout (&our_pred->args.printf_vec);
- our_pred->side_effects = our_pred->no_default_print = true;
- our_pred->est_success_rate = 1.0f;
- return true;
+ our_pred = insert_primary (pred_false);
+ our_pred->need_stat = false;
+ return (true);
}
-
static boolean
-parse_fls (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_fls (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- const char *filename;
- return collect_arg(argv, arg_ptr, &filename)
- && insert_fls(entry, filename);
-}
+ struct predicate *our_pred;
-static boolean
-parse_follow (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- set_follow_state(SYMLINK_ALWAYS_DEREF);
- return parse_noop(entry, argv, arg_ptr);
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ our_pred = insert_primary (pred_fls);
+ our_pred->args.stream = open_output_file (argv[*arg_ptr]);
+ our_pred->side_effects = true;
+ (*arg_ptr)++;
+ return (true);
}
-static boolean
-parse_fprint (const struct parser_table* entry, char **argv, int *arg_ptr)
+static boolean
+parse_fprintf (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- struct predicate *our_pred;
- const char *filename;
- if (collect_arg(argv, arg_ptr, &filename))
- {
- our_pred = insert_primary (entry);
- open_output_file (filename, &our_pred->args.printf_vec);
- our_pred->side_effects = our_pred->no_default_print = true;
- our_pred->need_stat = our_pred->need_type = false;
- our_pred->est_success_rate = 1.0f;
- return true;
- }
- else
+ FILE *fp;
+
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ if (argv[*arg_ptr + 1] == NULL)
{
- return false;
+ /* Ensure we get "missing arg" message, not "invalid arg". */
+ (*arg_ptr)++;
+ return (false);
}
+ fp = open_output_file (argv[*arg_ptr]);
+ (*arg_ptr)++;
+ return (insert_fprintf (fp, pred_fprintf, argv, arg_ptr));
}
-static boolean
-insert_fprint(const struct parser_table* entry, const char *filename)
+static boolean
+parse_follow (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- struct predicate *our_pred = insert_primary (entry);
- if (filename)
- open_output_file (filename, &our_pred->args.printf_vec);
- else
- open_stdout (&our_pred->args.printf_vec);
- our_pred->side_effects = our_pred->no_default_print = true;
- our_pred->need_stat = our_pred->need_type = false;
- our_pred->est_success_rate = 1.0f;
- return true;
+ dereference = true;
+ xstat = stat;
+ no_leaf_check = true;
+ return (true);
}
-
static boolean
-parse_fprint0 (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_fprint (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- const char *filename;
- if (collect_arg(argv, arg_ptr, &filename))
- return insert_fprint(entry, filename);
- else
- return false;
-}
+ struct predicate *our_pred;
-static float estimate_fstype_success_rate(const char *fsname)
-{
- struct stat dir_stat;
- const char *dir = "/";
- if (0 == stat(dir, &dir_stat))
- {
- const char *fstype = filesystem_type(&dir_stat, dir);
- /* Assume most files are on the same file system type as the root fs. */
- if (0 == strcmp(fsname, fstype))
- return 0.7f;
- else
- return 0.3f;
- }
- return 1.0f;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ our_pred = insert_primary (pred_fprint);
+ our_pred->args.stream = open_output_file (argv[*arg_ptr]);
+ our_pred->side_effects = true;
+ our_pred->need_stat = false;
+ (*arg_ptr)++;
+ return (true);
}
-
static boolean
-parse_fstype (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_fprint0 (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- const char *typename;
- if (collect_arg(argv, arg_ptr, &typename))
- {
- struct predicate *our_pred = insert_primary (entry);
- our_pred->args.str = typename;
-
- /* This is an expensive operation, so although there are
- * circumstances where it is selective, we ignore this fact
- * because we probably don't want to promote this test to the
- * front anyway.
- */
- our_pred->est_success_rate = estimate_fstype_success_rate(typename);
- return true;
- }
- else
- {
- return false;
- }
+ struct predicate *our_pred;
+
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ our_pred = insert_primary (pred_fprint0);
+ our_pred->args.stream = open_output_file (argv[*arg_ptr]);
+ our_pred->side_effects = true;
+ our_pred->need_stat = false;
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_gid (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_fstype (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- struct predicate *p = insert_num (argv, arg_ptr, entry);
- if (p)
- {
- p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
- return true;
- }
- else
- {
- return false;
- }
-}
+ struct predicate *our_pred;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ our_pred = insert_primary (pred_fstype);
+ our_pred->args.str = argv[*arg_ptr];
+ (*arg_ptr)++;
+ return (true);
+}
-static int
-safe_atoi (const char *s)
+static boolean
+parse_gid (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- long lval;
- char *end;
-
- errno = 0;
- lval = strtol(s, &end, 10);
- if ( (LONG_MAX == lval) || (LONG_MIN == lval) )
- {
- /* max/min possible value, or an error. */
- if (errno == ERANGE)
- {
- /* too big, or too small. */
- error(1, errno, "%s", s);
- }
- else
- {
- /* not a valid number */
- error(1, errno, "%s", s);
- }
- /* Otherwise, we do a range chack against INT_MAX and INT_MIN
- * below.
- */
- }
-
- if (lval > INT_MAX || lval < INT_MIN)
- {
- /* The number was in range for long, but not int. */
- errno = ERANGE;
- error(1, errno, "%s", s);
- }
- else if (*end)
- {
- error(1, errno, "Unexpected suffix %s on %s",
- quotearg_n_style(0, options.err_quoting_style, end),
- quotearg_n_style(1, options.err_quoting_style, s));
- }
- else if (end == s)
- {
- error(1, errno, "Expected an integer: %s",
- quotearg_n_style(0, options.err_quoting_style, s));
- }
- return (int)lval;
+ return (insert_num (argv, arg_ptr, pred_gid));
}
-
static boolean
-parse_group (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_group (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- const char *groupname;
+ struct group *cur_gr;
+ struct predicate *our_pred;
+ gid_t gid;
+ int gid_len;
- if (collect_arg(argv, arg_ptr, &groupname))
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ cur_gr = getgrnam (argv[*arg_ptr]);
+ endgrent ();
+ if (cur_gr != NULL)
+ gid = cur_gr->gr_gid;
+ else
{
- gid_t gid;
- struct predicate *our_pred;
- struct group *cur_gr = getgrnam(groupname);
- endgrent();
- if (cur_gr)
- {
- gid = cur_gr->gr_gid;
- }
- else
- {
- const int gid_len = strspn (groupname, "0123456789");
- if (gid_len)
- {
- if (groupname[gid_len] == 0)
- {
- gid = safe_atoi (groupname);
- }
- else
- {
- /* XXX: no test in test suite for this */
- error(1, 0, _("%s is not the name of an existing group and"
- " it does not look like a numeric group ID "
- "because it has the unexpected suffix %s"),
- quotearg_n_style(0, options.err_quoting_style, groupname),
- quotearg_n_style(1, options.err_quoting_style, groupname+gid_len));
- return false;
- }
- }
- else
- {
- if (*groupname)
- {
- /* XXX: no test in test suite for this */
- error(1, 0, _("%s is not the name of an existing group"),
- quotearg_n_style(0, options.err_quoting_style, groupname));
- }
- else
- {
- error(1, 0, _("argument to -group is empty, but should be a group name"));
- }
- return false;
- }
- }
- our_pred = insert_primary (entry);
- our_pred->args.gid = gid;
- our_pred->est_success_rate = (our_pred->args.numinfo.l_val < 100) ? 0.99 : 0.2;
- return true;
+ gid_len = strspn (argv[*arg_ptr], "0123456789");
+ if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
+ return (false);
+ gid = atoi (argv[*arg_ptr]);
}
- return false;
+ our_pred = insert_primary (pred_group);
+ our_pred->args.gid = gid;
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_help (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_help (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- (void) entry;
- (void) argv;
- (void) arg_ptr;
-
- usage(stdout, 0, NULL);
- puts (_("\n\
+ printf ("\
+Usage: %s [path...] [expression]\n", program_name);
+ printf ("\
default path is the current directory; default expression is -print\n\
-expression may consist of: operators, options, tests, and actions:\n"));
- puts (_("\
+expression may consist of:\n\
operators (decreasing precedence; -and is implicit where no others are given):\n\
- ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
- EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
- puts (_("\
-positional options (always true): -daystart -follow -regextype\n\n\
-normal options (always true, specified before other expressions):\n\
- -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
- --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
- puts (_("\
-tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
+ ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n");
+ printf ("\
+ EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n\
+options (always true): -daystart -depth -follow --help\n\
+ -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev\n\
+tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n");
+ printf ("\
-cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
- -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
- -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
- puts (_("\
+ -ilname PATTERN -iname PATTERN -inum N -ipath PATTERN -iregex PATTERN\n\
+ -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE\n");
+ printf ("\
-nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
- -readable -writable -executable\n\
- -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
- -used N -user NAME -xtype [bcdpfls]\n"));
- puts (_("\
-actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
- -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
- -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
- -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
-"));
- puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
-page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
-email to <bug-findutils@gnu.org>."));
+ -size N[bckw] -true -type [bcdpfls] -uid N -used N -user NAME\n\
+ -xtype [bcdpfls]\n");
+ printf ("\
+actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
+ -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls\n");
exit (0);
}
-static float
-estimate_pattern_match_rate(const char *pattern, int is_regex)
-{
- if (strpbrk(pattern, "*?[") || (is_regex && strpbrk(pattern, ".")))
- {
- /* A wildcard; assume the pattern matches most files. */
- return 0.8f;
- }
- else
- {
- return 0.1f;
- }
-}
-
static boolean
-parse_ilname (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_ilname (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- const char *name;
- if (collect_arg(argv, arg_ptr, &name))
- {
- struct predicate *our_pred = insert_primary (entry);
- our_pred->args.str = name;
- /* Use the generic glob pattern estimator to figure out how many
- * links will match, but bear in mind that most files won't be links.
- */
- our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(name, 0);
- return true;
- }
- else
- {
- return false;
- }
-}
-
+ struct predicate *our_pred;
-/* sanity check the fnmatch() function to make sure that case folding
- * is supported (as opposed to just having the flag ignored).
- */
-static boolean
-fnmatch_sanitycheck(void)
-{
- static boolean checked = false;
- if (!checked)
- {
- if (0 != fnmatch("foo", "foo", 0)
- || 0 == fnmatch("Foo", "foo", 0)
- || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
- {
- error (1, 0, _("sanity check of the fnmatch() library function failed."));
- return false;
- }
- checked = true;
- }
- return checked;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ our_pred = insert_primary (pred_ilname);
+ our_pred->args.str = argv[*arg_ptr];
+ (*arg_ptr)++;
+ return (true);
}
-
static boolean
-check_name_arg(const char *pred, const char *arg)
+parse_iname (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- if (options.warnings && strchr(arg, '/'))
- {
- error(0, 0,_("warning: Unix filenames usually don't contain slashes "
- "(though pathnames do). That means that '%s %s' will "
- "probably evaluate to false all the time on this system. "
- "You might find the '-wholename' test more useful, or "
- "perhaps '-samefile'. Alternatively, if you are using "
- "GNU grep, you could "
- "use 'find ... -print0 | grep -FzZ %s'."),
- pred,
- safely_quote_err_filename(0, arg),
- safely_quote_err_filename(1, arg));
- }
- return true; /* allow it anyway */
-}
-
-
+ struct predicate *our_pred;
-static boolean
-parse_iname (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- const char *name;
- fnmatch_sanitycheck();
- if (collect_arg(argv, arg_ptr, &name))
- {
- if (check_name_arg("-iname", name))
- {
- struct predicate *our_pred = insert_primary (entry);
- our_pred->need_stat = our_pred->need_type = false;
- our_pred->args.str = name;
- our_pred->est_success_rate = estimate_pattern_match_rate(name, 0);
- return true;
- }
- }
- return false;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ our_pred = insert_primary (pred_iname);
+ our_pred->need_stat = false;
+ our_pred->args.str = argv[*arg_ptr];
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_inum (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_inum (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- struct predicate *p = insert_num (argv, arg_ptr, entry);
- if (p)
- {
- /* inode number is exact match only, so very low proportions of
- * files match
- */
- p->est_success_rate = 1e-6;
- return true;
- }
- else
- {
- return false;
- }
+ return (insert_num (argv, arg_ptr, pred_inum));
}
-/* -ipath is deprecated (at RMS's request) in favour of
- * -iwholename. See the node "GNU Manuals" in standards.texi
- * for the rationale for this (basically, GNU prefers the use
- * of the phrase "file name" to "path name"
- */
static boolean
-parse_ipath (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_ipath (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- const char *name;
+ struct predicate *our_pred;
- fnmatch_sanitycheck ();
- if (collect_arg (argv, arg_ptr, &name))
- {
- struct predicate *our_pred = insert_primary_withpred (entry, pred_ipath);
- our_pred->need_stat = our_pred->need_type = false;
- our_pred->args.str = name;
- our_pred->est_success_rate = estimate_pattern_match_rate (name, 0);
- return true;
- }
- return false;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ our_pred = insert_primary (pred_ipath);
+ our_pred->need_stat = false;
+ our_pred->args.str = argv[*arg_ptr];
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_iwholename (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_iregex (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- return parse_ipath (entry, argv, arg_ptr);
+ return insert_regex (argv, arg_ptr, true);
}
static boolean
-parse_iregex (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_links (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- return insert_regex (argv, arg_ptr, entry, RE_ICASE|options.regex_options);
+ return (insert_num (argv, arg_ptr, pred_links));
}
static boolean
-parse_links (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_lname (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- struct predicate *p = insert_num (argv, arg_ptr, entry);
- if (p)
- {
- if (p->args.numinfo.l_val == 1)
- p->est_success_rate = 0.99;
- else if (p->args.numinfo.l_val == 2)
- p->est_success_rate = 0.01;
- else
- p->est_success_rate = 1e-3;
- return true;
- }
- else
- {
- return false;
- }
-}
+ struct predicate *our_pred;
-static boolean
-parse_lname (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- const char *name;
- fnmatch_sanitycheck();
- if (collect_arg(argv, arg_ptr, &name))
- {
- struct predicate *our_pred = insert_primary (entry);
- our_pred->args.str = name;
- our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(name, 0);
- return true;
- }
- return false;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ our_pred = insert_primary (pred_lname);
+ our_pred->args.str = argv[*arg_ptr];
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_ls (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_ls (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- (void) &argv;
- (void) &arg_ptr;
- return insert_fls(entry, NULL);
+ struct predicate *our_pred;
+
+ our_pred = insert_primary (pred_ls);
+ our_pred->side_effects = true;
+ return (true);
}
static boolean
-insert_depthspec(const struct parser_table* entry, char **argv, int *arg_ptr,
- int *limitptr)
+parse_maxdepth (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- const char *depthstr;
int depth_len;
- const char *predicate = argv[(*arg_ptr)-1];
- if (collect_arg(argv, arg_ptr, &depthstr))
- {
- depth_len = strspn (depthstr, "0123456789");
- if ((depth_len > 0) && (depthstr[depth_len] == 0))
- {
- (*limitptr) = safe_atoi (depthstr);
- if (*limitptr >= 0)
- {
- return parse_noop(entry, argv, arg_ptr);
- }
- }
- error(1, 0, _("Expected a positive decimal integer argument to %s, but got %s"),
- predicate,
- quotearg_n_style(0, options.err_quoting_style, depthstr));
- return false;
- }
- /* missing argument */
- return false;
-}
-
-static boolean
-parse_maxdepth (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- return insert_depthspec(entry, argv, arg_ptr, &options.maxdepth);
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ depth_len = strspn (argv[*arg_ptr], "0123456789");
+ if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
+ return (false);
+ maxdepth = atoi (argv[*arg_ptr]);
+ if (maxdepth < 0)
+ return (false);
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_mindepth (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_mindepth (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- return insert_depthspec(entry, argv, arg_ptr, &options.mindepth);
+ int depth_len;
+
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ depth_len = strspn (argv[*arg_ptr], "0123456789");
+ if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
+ return (false);
+ mindepth = atoi (argv[*arg_ptr]);
+ if (mindepth < 0)
+ return (false);
+ (*arg_ptr)++;
+ return (true);
}
-
static boolean
-do_parse_xmin (const struct parser_table* entry,
- char **argv,
- int *arg_ptr,
- enum xval xv)
+parse_mmin (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- const char *minutes;
+ struct predicate *our_pred;
+ unsigned long num;
+ enum comparison_type c_type;
- if (collect_arg(argv, arg_ptr, &minutes))
- {
- struct time_val tval;
- tval.xval = xv;
- struct timespec origin = options.cur_day_start;
- origin.tv_sec += DAYSECS;
- if (get_relative_timestamp(minutes, &tval, origin, 60,
- "arithmetic overflow while converting %s "
- "minutes to a number of seconds"))
- {
- struct predicate *our_pred = insert_primary (entry);
- our_pred->args.reftime = tval;
- our_pred->est_success_rate = estimate_timestamp_success_rate(tval.ts.tv_sec);
- return true;
- }
- }
- return false;
-}
-static boolean
-parse_amin (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- return do_parse_xmin(entry, argv, arg_ptr, XVAL_ATIME);
-}
-
-static boolean
-parse_cmin (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- return do_parse_xmin(entry, argv, arg_ptr, XVAL_CTIME);
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ if (!get_num_days (argv[*arg_ptr], &num, &c_type))
+ return (false);
+ our_pred = insert_primary (pred_mmin);
+ our_pred->args.info.kind = c_type;
+ our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60;
+ (*arg_ptr)++;
+ return (true);
}
-
static boolean
-parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_mtime (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- return do_parse_xmin(entry, argv, arg_ptr, XVAL_MTIME);
+ return (insert_time (argv, arg_ptr, pred_mtime));
}
static boolean
-parse_name (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_name (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- const char *name;
- if (collect_arg(argv, arg_ptr, &name))
- {
- fnmatch_sanitycheck();
- if (check_name_arg("-name", name))
- {
- struct predicate *our_pred = insert_primary (entry);
- our_pred->need_stat = our_pred->need_type = false;
- our_pred->args.str = name;
- our_pred->est_success_rate = estimate_pattern_match_rate(name, 0);
- return true;
- }
- }
- return false;
+ struct predicate *our_pred;
+
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ our_pred = insert_primary (pred_name);
+ our_pred->need_stat = false;
+ our_pred->args.str = argv[*arg_ptr];
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_negate (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_negate (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
- (void) &argv;
- (void) &arg_ptr;
-
- our_pred = get_new_pred_chk_op (entry);
+ our_pred = get_new_pred_chk_op ();
our_pred->pred_func = pred_negate;
+#ifdef DEBUG
+ our_pred->p_name = find_pred_name (pred_negate);
+#endif /* DEBUG */
our_pred->p_type = UNI_OP;
our_pred->p_prec = NEGATE_PREC;
- our_pred->need_stat = our_pred->need_type = false;
- return true;
+ our_pred->need_stat = false;
+ return (true);
}
static boolean
-parse_newer (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_newer (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
struct stat stat_newer;
- set_stat_placeholders(&stat_newer);
- if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
- {
- our_pred = insert_primary (entry);
- our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
- our_pred->args.reftime.xval = XVAL_MTIME;
- our_pred->args.reftime.kind = COMP_GT;
- our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
- return true;
- }
- return false;
-}
-
-
-static boolean
-parse_newerXY (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- (void) argv;
- (void) arg_ptr;
-
if ((argv == NULL) || (argv[*arg_ptr] == NULL))
- {
- return false;
- }
- else if (8u != strlen(argv[*arg_ptr]))
- {
- return false;
- }
- else
- {
- char x, y;
- const char validchars[] = "aBcmt";
-
- assert (0 == strncmp("-newer", argv[*arg_ptr], 6));
- x = argv[*arg_ptr][6];
- y = argv[*arg_ptr][7];
-
-
-#if !defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) && !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC) && !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
- if ('B' == x || 'B' == y)
- {
- error(0, 0,
- _("This system does not provide a way to find the birth time of a file."));
- return 0;
- }
-#endif
-
- /* -newertY (for any Y) is invalid. */
- if (x == 't'
- || 0 == strchr(validchars, x)
- || 0 == strchr( validchars, y))
- {
- return false;
- }
- else
- {
- struct predicate *our_pred;
-
- /* Because this item is ARG_SPECIAL_PARSE, we have to advance arg_ptr
- * past the test name (for most other tests, this is already done)
- */
- (*arg_ptr)++;
-
- our_pred = insert_primary (entry);
-
-
- switch (x)
- {
- case 'a':
- our_pred->args.reftime.xval = XVAL_ATIME;
- break;
- case 'B':
- our_pred->args.reftime.xval = XVAL_BIRTHTIME;
- break;
- case 'c':
- our_pred->args.reftime.xval = XVAL_CTIME;
- break;
- case 'm':
- our_pred->args.reftime.xval = XVAL_MTIME;
- break;
- default:
- assert (strchr(validchars, x));
- assert (0);
- }
-
- if ('t' == y)
- {
- if (!get_date(&our_pred->args.reftime.ts,
- argv[*arg_ptr],
- &options.start_time))
- {
- error(1, 0,
- _("I cannot figure out how to interpret %s as a date or time"),
- quotearg_n_style(0, options.err_quoting_style, argv[*arg_ptr]));
- }
- }
- else
- {
- struct stat stat_newer;
-
- /* Stat the named file. */
- set_stat_placeholders(&stat_newer);
- if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
- fatal_file_error(argv[*arg_ptr]);
-
- if (!get_stat_Ytime(&stat_newer, y, &our_pred->args.reftime.ts))
- {
- /* We cannot extract a timestamp from the struct stat. */
- error(1, 0, _("Cannot obtain birth time of file %s"),
- safely_quote_err_filename(0, argv[*arg_ptr]));
- }
- }
- our_pred->args.reftime.kind = COMP_GT;
- our_pred->est_success_rate = estimate_timestamp_success_rate(our_pred->args.reftime.ts.tv_sec);
- (*arg_ptr)++;
-
- assert (our_pred->pred_func != NULL);
- assert (our_pred->pred_func == pred_newerXY);
- assert (our_pred->need_stat);
- return true;
- }
- }
+ return (false);
+ if ((*xstat) (argv[*arg_ptr], &stat_newer))
+ error (1, errno, "%s", argv[*arg_ptr]);
+ our_pred = insert_primary (pred_newer);
+ our_pred->args.time = stat_newer.st_mtime;
+ (*arg_ptr)++;
+ return (true);
}
-
static boolean
-parse_noleaf (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_noleaf (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- options.no_leaf_check = true;
- return parse_noop(entry, argv, arg_ptr);
+ no_leaf_check = true;
+ return true;
}
#ifdef CACHE_IDS
@@ -1609,15 +870,13 @@ unsigned gid_allocated;
#endif
static boolean
-parse_nogroup (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_nogroup (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
- (void) &argv;
- (void) &arg_ptr;
-
- our_pred = insert_primary (entry);
- our_pred->est_success_rate = 1e-4;
+ our_pred = insert_primary (pred_nogroup);
#ifdef CACHE_IDS
if (gid_unused == NULL)
{
@@ -1642,19 +901,17 @@ parse_nogroup (const struct parser_table* entry, char **argv, int *arg_ptr)
endgrent ();
}
#endif
- return true;
+ return (true);
}
static boolean
-parse_nouser (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_nouser (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
- (void) argv;
- (void) arg_ptr;
-
- our_pred = insert_primary (entry);
- our_pred->est_success_rate = 1e-3;
+ our_pred = insert_primary (pred_nouser);
#ifdef CACHE_IDS
if (uid_unused == NULL)
{
@@ -1679,399 +936,242 @@ parse_nouser (const struct parser_table* entry, char **argv, int *arg_ptr)
endpwent ();
}
#endif
- return true;
-}
-
-static boolean
-parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- options.warnings = false;
- return parse_noop(entry, argv, arg_ptr);
+ return (true);
}
static boolean
-parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_ok (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- return insert_exec_ok ("-ok", entry, get_start_dirfd(), argv, arg_ptr);
-}
-
-static boolean
-parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- return insert_exec_ok ("-okdir", entry, -1, argv, arg_ptr);
+ return (insert_exec_ok (pred_ok, argv, arg_ptr));
}
boolean
-parse_openparen (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_open (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
- (void) argv;
- (void) arg_ptr;
-
- our_pred = get_new_pred_chk_op (entry);
- our_pred->pred_func = pred_openparen;
+ our_pred = get_new_pred_chk_op ();
+ our_pred->pred_func = pred_open;
+#ifdef DEBUG
+ our_pred->p_name = find_pred_name (pred_open);
+#endif /* DEBUG */
our_pred->p_type = OPEN_PAREN;
our_pred->p_prec = NO_PREC;
- our_pred->need_stat = our_pred->need_type = false;
- return true;
+ our_pred->need_stat = false;
+ return (true);
}
static boolean
-parse_or (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_or (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
- (void) argv;
- (void) arg_ptr;
-
- our_pred = get_new_pred (entry);
+ our_pred = get_new_pred ();
our_pred->pred_func = pred_or;
+#ifdef DEBUG
+ our_pred->p_name = find_pred_name (pred_or);
+#endif /* DEBUG */
our_pred->p_type = BI_OP;
our_pred->p_prec = OR_PREC;
- our_pred->need_stat = our_pred->need_type = false;
- return true;
-}
-
-/* For some time, -path was deprecated (at RMS's request) in favour of
- * -iwholename. See the node "GNU Manuals" in standards.texi for the
- * rationale for this (basically, GNU prefers the use of the phrase
- * "file name" to "path name".
- *
- * We do not issue a warning that this usage is deprecated
- * since
- * (a) HPUX find supports this predicate also and
- * (b) it will soon be in POSIX anyway.
- */
-static boolean
-parse_path (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- const char *name;
- if (collect_arg(argv, arg_ptr, &name))
- {
- struct predicate *our_pred = insert_primary_withpred (entry, pred_path);
- our_pred->need_stat = our_pred->need_type = false;
- our_pred->args.str = name;
- our_pred->est_success_rate = estimate_pattern_match_rate (name, 0);
- return true;
- }
- return false;
+ our_pred->need_stat = false;
+ return (true);
}
static boolean
-parse_wholename (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_path (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- return parse_path (entry, argv, arg_ptr);
-}
+ struct predicate *our_pred;
-static void
-non_posix_mode(const char *mode)
-{
- if (options.posixly_correct)
- {
- error (1, 0, _("Mode %s is not valid when POSIXLY_CORRECT is on."),
- quotearg_n_style(0, options.err_quoting_style, mode));
- }
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ our_pred = insert_primary (pred_path);
+ our_pred->need_stat = false;
+ our_pred->args.str = argv[*arg_ptr];
+ (*arg_ptr)++;
+ return (true);
}
-
static boolean
-parse_perm (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_perm (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- mode_t perm_val[2];
- float rate;
+ unsigned long perm_val;
int mode_start = 0;
- boolean havekind = false;
- enum permissions_type kind = PERM_EXACT;
- struct mode_change *change = NULL;
+ struct mode_change *change;
struct predicate *our_pred;
- const char *perm_expr;
- if (!collect_arg(argv, arg_ptr, &perm_expr))
- return false;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
- switch (perm_expr[0])
+ switch (argv[*arg_ptr][0])
{
case '-':
+ case '+':
mode_start = 1;
- kind = PERM_AT_LEAST;
- havekind = true;
- rate = 0.2;
- break;
-
- case '+':
- change = mode_compile (perm_expr);
- if (NULL == change)
- {
- /* Most likely the caller is an old script that is still
- * using the obsolete GNU syntax '-perm +MODE'. This old
- * syntax was withdrawn in favor of '-perm /MODE' because
- * it is incompatible with POSIX in some cases, but we
- * still support uses of it that are not incompatible with
- * POSIX.
- *
- * Example: POSIXLY_CORRECT=y find -perm +a+x
- */
- non_posix_mode(perm_expr);
-
- /* support the previous behaviour. */
- mode_start = 1;
- kind = PERM_ANY;
- rate = 0.3;
- }
- else
- {
- /* This is a POSIX-compatible usage */
- mode_start = 0;
- kind = PERM_EXACT;
- rate = 0.1;
- }
- havekind = true;
- break;
-
- case '/': /* GNU extension */
- non_posix_mode(perm_expr);
- mode_start = 1;
- kind = PERM_ANY;
- havekind = true;
- rate = 0.3;
break;
-
default:
- /* For example, '-perm 0644', which is valid and matches
- * only files whose mode is exactly 0644.
- */
- mode_start = 0;
- kind = PERM_EXACT;
- havekind = true;
- rate = 0.01;
+ /* empty */
break;
}
- if (NULL == change)
- {
- change = mode_compile (perm_expr + mode_start);
- if (NULL == change)
- error (1, 0, _("invalid mode %s"),
- quotearg_n_style(0, options.err_quoting_style, perm_expr));
- }
- perm_val[0] = mode_adjust (0, false, 0, change, NULL);
- perm_val[1] = mode_adjust (0, true, 0, change, NULL);
- free (change);
-
- if (('/' == perm_expr[0]) && (0 == perm_val[0]) && (0 == perm_val[1]))
- {
- /* The meaning of -perm /000 will change in the future. It
- * currently matches no files, but like -perm -000 it should
- * match all files.
- *
- * Starting in 2005, we used to issue a warning message
- * informing the user that the behaviour would change in the
- * future. We have now changed the behaviour and issue a
- * warning message that the behaviour recently changed.
- */
- error (0, 0,
- _("warning: you have specified a mode pattern %s (which is "
- "equivalent to /000). The meaning of -perm /000 has now been "
- "changed to be consistent with -perm -000; that is, while it "
- "used to match no files, it now matches all files."),
- perm_expr);
-
- kind = PERM_AT_LEAST;
- havekind = true;
-
- /* The "magic" number below is just the fraction of files on my
- * own system that "-type l -xtype l" fails for (i.e. unbroken symlinks).
- * Actual totals are 1472 and 1073833.
- */
- rate = 0.9986; /* probably matches anything but a broken symlink */
- }
-
- our_pred = insert_primary (entry);
- our_pred->est_success_rate = rate;
- if (havekind)
- {
- our_pred->args.perm.kind = kind;
- }
- else
+ change = mode_compile (argv[*arg_ptr] + mode_start, MODE_MASK_PLUS);
+ if (change == MODE_INVALID)
+ error (1, 0, "invalid mode `%s'", argv[*arg_ptr]);
+ else if (change == MODE_MEMORY_EXHAUSTED)
+ error (1, 0, "virtual memory exhausted");
+ perm_val = mode_adjust (0, change);
+ mode_free (change);
+
+ our_pred = insert_primary (pred_perm);
+
+ switch (argv[*arg_ptr][0])
{
-
- switch (perm_expr[0])
- {
- case '-':
- our_pred->args.perm.kind = PERM_AT_LEAST;
- break;
- case '+':
- our_pred->args.perm.kind = PERM_ANY;
- break;
- default:
- our_pred->args.perm.kind = PERM_EXACT;
- break;
- }
+ case '-':
+ /* Set magic flag to indicate true if at least the given bits are set. */
+ our_pred->args.perm = (perm_val & 07777) | 010000;
+ break;
+ case '+':
+ /* Set magic flag to indicate true if any of the given bits are set. */
+ our_pred->args.perm = (perm_val & 07777) | 020000;
+ break;
+ default:
+ /* True if exactly the given bits are set. */
+ our_pred->args.perm = (perm_val & 07777);
+ break;
}
- memcpy (our_pred->args.perm.val, perm_val, sizeof perm_val);
- return true;
+ (*arg_ptr)++;
+ return (true);
}
boolean
-parse_print (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_print (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
- (void) argv;
- (void) arg_ptr;
-
- our_pred = insert_primary (entry);
+ our_pred = insert_primary (pred_print);
/* -print has the side effect of printing. This prevents us
from doing undesired multiple printing when the user has
already specified -print. */
- our_pred->side_effects = our_pred->no_default_print = true;
- our_pred->need_stat = our_pred->need_type = false;
- open_stdout(&our_pred->args.printf_vec);
- return true;
+ our_pred->side_effects = true;
+ our_pred->need_stat = false;
+ return (true);
}
static boolean
-parse_print0 (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_print0 (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- return insert_fprint(entry, NULL);
-}
+ struct predicate *our_pred;
-static boolean
-parse_printf (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- const char *format;
- if (collect_arg(argv, arg_ptr, &format))
- {
- struct format_val fmt;
- open_stdout(&fmt);
- return insert_fprintf (&fmt, entry, pred_fprintf, format);
- }
- return false;
+ our_pred = insert_primary (pred_print0);
+ /* -print0 has the side effect of printing. This prevents us
+ from doing undesired multiple printing when the user has
+ already specified -print0. */
+ our_pred->side_effects = true;
+ our_pred->need_stat = false;
+ return (true);
}
-static boolean
-parse_fprintf (const struct parser_table* entry, char **argv, int *arg_ptr)
+static boolean
+parse_printf (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- const char *format, *filename;
- if (collect_arg(argv, arg_ptr, &filename))
- {
- if (collect_arg(argv, arg_ptr, &format))
- {
- struct format_val fmt;
- open_output_file (filename, &fmt);
- return insert_fprintf (&fmt, entry, pred_fprintf, format);
- }
- }
- return false;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ return (insert_fprintf (stdout, pred_fprintf, argv, arg_ptr));
}
static boolean
-parse_prune (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_prune (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
- (void) argv;
- (void) arg_ptr;
-
- our_pred = insert_primary (entry);
- our_pred->need_stat = our_pred->need_type = false;
- /* -prune has a side effect that it does not descend into
- the current directory. */
- our_pred->side_effects = true;
- our_pred->no_default_print = false;
- return true;
-}
-
-static boolean
-parse_quit (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- struct predicate *our_pred = insert_primary (entry);
- (void) argv;
- (void) arg_ptr;
- our_pred->need_stat = our_pred->need_type = false;
- our_pred->side_effects = true; /* Exiting is a side effect... */
- our_pred->no_default_print = false; /* Don't inhibit the default print, though. */
- our_pred->est_success_rate = 1.0f;
- return true;
-}
-
-
-static boolean
-parse_regextype (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- const char *type_name;
- if (collect_arg(argv, arg_ptr, &type_name))
- {
- /* collect the regex type name */
- options.regex_options = get_regex_type(type_name);
- return parse_noop(entry, argv, arg_ptr);
- }
- return false;
+ our_pred = insert_primary (pred_prune);
+ our_pred->need_stat = false;
+ return (true);
}
-
static boolean
-parse_regex (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_regex (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- return insert_regex (argv, arg_ptr, entry, options.regex_options);
+ return insert_regex (argv, arg_ptr, false);
}
static boolean
-insert_regex (char **argv,
- int *arg_ptr,
- const struct parser_table *entry,
- int regex_options)
+insert_regex (argv, arg_ptr, ignore_case)
+ char *argv[];
+ int *arg_ptr;
+ boolean ignore_case;
{
- const char *rx;
- if (collect_arg(argv, arg_ptr, &rx))
+ struct predicate *our_pred;
+ struct re_pattern_buffer *re;
+ const char *error_message;
+
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ our_pred = insert_primary (pred_regex);
+ our_pred->need_stat = false;
+ re = (struct re_pattern_buffer *)
+ xmalloc (sizeof (struct re_pattern_buffer));
+ our_pred->args.regex = re;
+ re->allocated = 100;
+ re->buffer = (unsigned char *) xmalloc (re->allocated);
+ re->fastmap = NULL;
+
+ if (ignore_case)
{
- struct re_pattern_buffer *re;
- const char *error_message;
- struct predicate *our_pred = insert_primary_withpred (entry, pred_regex);
- our_pred->need_stat = our_pred->need_type = false;
- re = xmalloc (sizeof (struct re_pattern_buffer));
- our_pred->args.regex = re;
- re->allocated = 100;
- re->buffer = xmalloc (re->allocated);
- re->fastmap = NULL;
+ unsigned i;
- re_set_syntax(regex_options);
- re->syntax = regex_options;
- re->translate = NULL;
-
- error_message = re_compile_pattern (rx, strlen(rx), re);
- if (error_message)
- error (1, 0, "%s", error_message);
- our_pred->est_success_rate = estimate_pattern_match_rate(rx, 1);
- return true;
+ re->translate = xmalloc (256);
+ /* Map uppercase characters to corresponding lowercase ones. */
+ for (i = 0; i < 256; i++)
+ re->translate[i] = ISUPPER (i) ? tolower (i) : i;
}
- return false;
+ else
+ re->translate = NULL;
+
+ error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
+ re);
+ if (error_message)
+ error (1, 0, "%s", error_message);
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_size (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
- uintmax_t num;
- char suffix;
+ unsigned long num;
enum comparison_type c_type;
-
int blksize = 512;
int len;
- /* XXX: cannot (yet) convert to ue collect_arg() as this
- * function modifies the args in-place.
- */
if ((argv == NULL) || (argv[*arg_ptr] == NULL))
- return false;
-
+ return (false);
len = strlen (argv[*arg_ptr]);
if (len == 0)
- error (1, 0, _("invalid null argument to -size"));
-
- suffix = argv[*arg_ptr][len - 1];
- switch (suffix)
+ error (1, 0, "invalid null argument to -size");
+ switch (argv[*arg_ptr][len - 1])
{
case 'b':
blksize = 512;
@@ -2088,16 +1188,6 @@ parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
argv[*arg_ptr][len - 1] = '\0';
break;
- case 'M': /* Megabytes */
- blksize = 1024*1024;
- argv[*arg_ptr][len - 1] = '\0';
- break;
-
- case 'G': /* Gigabytes */
- blksize = 1024*1024*1024;
- argv[*arg_ptr][len - 1] = '\0';
- break;
-
case 'w':
blksize = 2;
argv[*arg_ptr][len - 1] = '\0';
@@ -2116,577 +1206,198 @@ parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
break;
default:
- error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
+ error (1, 0, "invalid -size type `%c'", argv[*arg_ptr][len - 1]);
}
- /* TODO: accept fractional megabytes etc. ? */
if (!get_num (argv[*arg_ptr], &num, &c_type))
- {
- error(1, 0,
- _("Invalid argument `%s%c' to -size"),
- argv[*arg_ptr], (int)suffix);
- return false;
- }
- our_pred = insert_primary (entry);
+ return (false);
+ our_pred = insert_primary (pred_size);
our_pred->args.size.kind = c_type;
our_pred->args.size.blocksize = blksize;
our_pred->args.size.size = num;
- our_pred->need_stat = true;
- our_pred->need_type = false;
-
- if (COMP_GT == c_type)
- our_pred->est_success_rate = (num*blksize > 20480) ? 0.1 : 0.9;
- else if (COMP_LT == c_type)
- our_pred->est_success_rate = (num*blksize > 20480) ? 0.9 : 0.1;
- else
- our_pred->est_success_rate = 0.01;
-
(*arg_ptr)++;
- return true;
+ return (true);
}
-
static boolean
-parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_true (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- /* General idea: stat the file, remember device and inode numbers.
- * If a candidate file matches those, it's the same file.
- */
struct predicate *our_pred;
- struct stat st, fst;
- int fd, openflags;
-
- set_stat_placeholders(&st);
- if (!collect_arg_stat_info(argv, arg_ptr, &st))
- return false;
-
- set_stat_placeholders(&fst);
- /* POSIX systems are free to re-use the inode number of a deleted
- * file. To ensure that we are not fooled by inode reuse, we hold
- * the file open if we can. This would prevent the system reusing
- * the file.
- */
- fd = -3; /* means, uninitialised */
- openflags = O_RDONLY;
-
- if (options.symlink_handling == SYMLINK_NEVER_DEREF)
- {
- if (options.open_nofollow_available)
- {
- assert (O_NOFOLLOW != 0);
- openflags |= O_NOFOLLOW;
- fd = -1; /* safe to open it. */
- }
- else
- {
- if (S_ISLNK(st.st_mode))
- {
- /* no way to ensure that a symlink will not be followed
- * by open(2), so fall back on using lstat(). Accept
- * the risk that the named file will be deleted and
- * replaced with another having the same inode.
- *
- * Avoid opening the file.
- */
- fd = -2; /* Do not open it */
- }
- else
- {
- fd = -1;
- /* Race condition here: the file might become a symlink here. */
- }
- }
- }
- else
- {
- /* We want to dereference the symlink anyway */
- fd = -1; /* safe to open it without O_NOFOLLOW */
- }
- assert (fd != -3); /* check we made a decision */
- if (fd == -1)
- {
- /* Race condition here. The file might become a
- * symbolic link in between out call to stat and
- * the call to open.
- */
- fd = open(argv[*arg_ptr], openflags);
-
- if (fd >= 0)
- {
- /* We stat the file again here to prevent a race condition
- * between the first stat and the call to open(2).
- */
- if (0 != fstat(fd, &fst))
- {
- fatal_file_error(argv[*arg_ptr]);
- }
- else
- {
- /* Worry about the race condition. If the file became a
- * symlink after our first stat and before our call to
- * open, fst may contain the stat information for the
- * destination of the link, not the link itself.
- */
- if ((*options.xstat) (argv[*arg_ptr], &st))
- fatal_file_error(argv[*arg_ptr]);
-
- if ((options.symlink_handling == SYMLINK_NEVER_DEREF)
- && (!options.open_nofollow_available))
- {
- if (S_ISLNK(st.st_mode))
- {
- /* We lost the race. Leave the data in st. The
- * file descriptor points to the wrong thing.
- */
- close(fd);
- fd = -1;
- }
- else
- {
- /* Several possibilities here:
- * 1. There was no race
- * 2. The file changed into a symlink after the stat and
- * before the open, and then back into a non-symlink
- * before the second stat.
- *
- * In case (1) there is no problem. In case (2),
- * the stat() and fstat() calls will have returned
- * different data. O_NOFOLLOW was not available,
- * so the open() call may have followed a symlink
- * even if the -P option is in effect.
- */
- if ((st.st_dev == fst.st_dev)
- && (st.st_ino == fst.st_ino))
- {
- /* No race. No need to copy fst to st,
- * since they should be identical (modulo
- * differences in padding bytes).
- */
- }
- else
- {
- /* We lost the race. Leave the data in st. The
- * file descriptor points to the wrong thing.
- */
- close(fd);
- fd = -1;
- }
- }
- }
- else
- {
- st = fst;
- }
- }
- }
- }
-
- our_pred = insert_primary (entry);
- our_pred->args.samefileid.ino = st.st_ino;
- our_pred->args.samefileid.dev = st.st_dev;
- our_pred->args.samefileid.fd = fd;
- our_pred->need_type = false;
- our_pred->need_stat = true;
- our_pred->est_success_rate = 0.01f;
- return true;
+ our_pred = insert_primary (pred_true);
+ our_pred->need_stat = false;
+ return (true);
}
-#if 0
-/* This function is commented out partly because support for it is
- * uneven.
- */
static boolean
-parse_show_control_chars (const struct parser_table* entry,
- char **argv,
- int *arg_ptr)
+parse_type (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- const char *arg;
- const char *errmsg = _("The -show-control-chars option takes "
- "a single argument which "
- "must be 'literal' or 'safe'");
-
- if ((argv == NULL) || (argv[*arg_ptr] == NULL))
- {
- error (1, errno, "%s", errmsg);
- return false;
- }
- else
- {
- arg = argv[*arg_ptr];
-
- if (0 == strcmp("literal", arg))
- {
- options.literal_control_chars = true;
- }
- else if (0 == strcmp("safe", arg))
- {
- options.literal_control_chars = false;
- }
- else
- {
- error (1, errno, "%s", errmsg);
- return false;
- }
- (*arg_ptr)++; /* consume the argument. */
- return true;
- }
+ return insert_type (argv, arg_ptr, pred_type);
}
-#endif
-
static boolean
-parse_true (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_uid (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- struct predicate *our_pred;
-
- (void) argv;
- (void) arg_ptr;
-
- our_pred = insert_primary (entry);
- our_pred->need_stat = our_pred->need_type = false;
- our_pred->est_success_rate = 1.0f;
- return true;
+ return (insert_num (argv, arg_ptr, pred_uid));
}
static boolean
-parse_noop (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- (void) entry;
- return parse_true(get_noop(), argv, arg_ptr);
-}
+parse_used (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
-static boolean
-parse_accesscheck (const struct parser_table* entry, char **argv, int *arg_ptr)
{
struct predicate *our_pred;
- (void) argv;
- (void) arg_ptr;
- our_pred = insert_primary (entry);
- our_pred->need_stat = our_pred->need_type = false;
- our_pred->side_effects = our_pred->no_default_print = false;
- if (pred_is(our_pred, pred_executable))
- our_pred->est_success_rate = 0.2;
- else
- our_pred->est_success_rate = 0.9;
- return true;
-}
-
-static boolean
-parse_type (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- return insert_type (argv, arg_ptr, entry, pred_type);
-}
+ unsigned long num_days;
+ enum comparison_type c_type;
-static boolean
-parse_uid (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- struct predicate *p = insert_num (argv, arg_ptr, entry);
- if (p)
- {
- p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
- return true;
- }
- else
- {
- return false;
- }
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ if (!get_num (argv[*arg_ptr], &num_days, &c_type))
+ return (false);
+ our_pred = insert_primary (pred_used);
+ our_pred->args.info.kind = c_type;
+ our_pred->args.info.l_val = num_days * DAYSECS;
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_used (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_user (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
+ struct passwd *cur_pwd;
struct predicate *our_pred;
- struct time_val tval;
- const char *offset_str;
- const char *errmsg = "arithmetic overflow while converting %s days to a number of seconds";
+ uid_t uid;
+ int uid_len;
- if (collect_arg(argv, arg_ptr, &offset_str))
- {
- /* The timespec is actually a delta value, so we use an origin of 0. */
- struct timespec zero = {0,0};
- if (get_relative_timestamp(offset_str, &tval, zero, DAYSECS, errmsg))
- {
- our_pred = insert_primary (entry);
- our_pred->args.reftime = tval;
- our_pred->est_success_rate = estimate_file_age_success_rate(tval.ts.tv_sec / DAYSECS);
- return true;
- }
- else
- {
- error(1, 0, _("Invalid argument %s to -used"), offset_str);
- return false;
- }
- }
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ cur_pwd = getpwnam (argv[*arg_ptr]);
+ endpwent ();
+ if (cur_pwd != NULL)
+ uid = cur_pwd->pw_uid;
else
{
- return false; /* missing argument */
+ uid_len = strspn (argv[*arg_ptr], "0123456789");
+ if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
+ return (false);
+ uid = atoi (argv[*arg_ptr]);
}
+ our_pred = insert_primary (pred_user);
+ our_pred->args.uid = uid;
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_user (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- const char *username;
-
- if (collect_arg(argv, arg_ptr, &username))
- {
- struct predicate *our_pred;
- uid_t uid;
- struct passwd *cur_pwd = getpwnam(username);
- endpwent();
- if (cur_pwd != NULL)
- {
- uid = cur_pwd->pw_uid;
- }
- else
- {
- int uid_len = strspn (username, "0123456789");
- if (uid_len && (username[uid_len]==0))
- uid = safe_atoi (username);
- else
- return false;
- }
- our_pred = insert_primary (entry);
- our_pred->args.uid = uid;
- our_pred->est_success_rate = (our_pred->args.uid < 100) ? 0.99 : 0.2;
- return true;
- }
- return false;
-}
-
-static boolean
-parse_version (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_version (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- int features = 0;
- int flags;
-
- (void) argv;
- (void) arg_ptr;
- (void) entry;
-
- display_findutils_version("find");
- printf (_("Features enabled: "));
-
-#if CACHE_IDS
- printf("CACHE_IDS ");
- ++features;
-#endif
-#if DEBUG
- printf("DEBUG ");
- ++features;
-#endif
-#if DEBUG_STAT
- printf("DEBUG_STAT ");
- ++features;
-#endif
-#if defined USE_STRUCT_DIRENT_D_TYPE && defined HAVE_STRUCT_DIRENT_D_TYPE
- printf("D_TYPE ");
- ++features;
-#endif
-#if defined O_NOFOLLOW
- printf("O_NOFOLLOW(%s) ",
- (options.open_nofollow_available ? "enabled" : "disabled"));
- ++features;
-#endif
-#if defined LEAF_OPTIMISATION
- printf("LEAF_OPTIMISATION ");
- ++features;
-#endif
+ extern char *version_string;
- flags = 0;
- if (is_fts_enabled(&flags))
- {
- int nflags = 0;
- printf("FTS(");
- ++features;
-
- if (flags & FTS_CWDFD)
- {
- if (nflags)
- {
- printf(",");
- }
- printf("FTS_CWDFD");
- ++nflags;
- }
- printf(") ");
- }
-
- printf("CBO(level=%d) ", (int)(options.optimisation_level));
- ++features;
-
- if (0 == features)
- {
- /* For the moment, leave this as English in case someone wants
- to parse these strings. */
- printf("none");
- }
- printf("\n");
-
+ fflush (stderr);
+ printf ("GNU find version %s\n", version_string);
exit (0);
}
static boolean
-parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_xdev (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- options.stay_on_filesystem = true;
- return parse_noop(entry, argv, arg_ptr);
-}
-
-static boolean
-parse_ignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- options.ignore_readdir_race = true;
- return parse_noop(entry, argv, arg_ptr);
-}
-
-static boolean
-parse_noignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- options.ignore_readdir_race = false;
- return parse_noop(entry, argv, arg_ptr);
-}
-
-static boolean
-parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- options.warnings = true;
- return parse_noop(entry, argv, arg_ptr);
+ stay_on_filesystem = true;
+ return true;
}
static boolean
-parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_xtype (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- return insert_type (argv, arg_ptr, entry, pred_xtype);
+ return insert_type (argv, arg_ptr, pred_xtype);
}
static boolean
-insert_type (char **argv, int *arg_ptr,
- const struct parser_table *entry,
- PRED_FUNC which_pred)
+insert_type (argv, arg_ptr, which_pred)
+ char *argv[];
+ int *arg_ptr;
+ boolean (*which_pred) ();
{
- mode_t type_cell;
+ unsigned long type_cell;
struct predicate *our_pred;
- float rate = 0.5;
- const char *typeletter;
- if (collect_arg(argv, arg_ptr, &typeletter))
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL)
+ || (strlen (argv[*arg_ptr]) != 1))
+ return (false);
+ switch (argv[*arg_ptr][0])
{
- if (strlen(typeletter) != 1u)
- {
- error(1, 0, _("Arguments to -type should contain only one letter"));
- return false;
- }
-
- switch (typeletter[0])
- {
- case 'b': /* block special */
- type_cell = S_IFBLK;
- rate = 0.01f;
- break;
- case 'c': /* character special */
- type_cell = S_IFCHR;
- rate = 0.01f;
- break;
- case 'd': /* directory */
- type_cell = S_IFDIR;
- rate = 0.4f;
- break;
- case 'f': /* regular file */
- type_cell = S_IFREG;
- rate = 0.95f;
- break;
+ case 'b': /* block special */
+ type_cell = S_IFBLK;
+ break;
+ case 'c': /* character special */
+ type_cell = S_IFCHR;
+ break;
+ case 'd': /* directory */
+ type_cell = S_IFDIR;
+ break;
+ case 'f': /* regular file */
+ type_cell = S_IFREG;
+ break;
#ifdef S_IFLNK
- case 'l': /* symbolic link */
- type_cell = S_IFLNK;
- rate = 0.1f;
- break;
+ case 'l': /* symbolic link */
+ type_cell = S_IFLNK;
+ break;
#endif
#ifdef S_IFIFO
- case 'p': /* pipe */
- type_cell = S_IFIFO;
- rate = 0.01f;
- break;
+ case 'p': /* pipe */
+ type_cell = S_IFIFO;
+ break;
#endif
#ifdef S_IFSOCK
- case 's': /* socket */
- type_cell = S_IFSOCK;
- rate = 0.01f;
- break;
-#endif
-#ifdef S_IFDOOR
- case 'D': /* Solaris door */
- type_cell = S_IFDOOR;
- rate = 0.01f;
- break;
+ case 's': /* socket */
+ type_cell = S_IFSOCK;
+ break;
#endif
- default: /* None of the above ... nuke 'em. */
- error(1, 0, _("Unknown argument to -type: %c"), (*typeletter));
- return false;
- }
- our_pred = insert_primary_withpred (entry, which_pred);
- our_pred->est_success_rate = rate;
-
- /* Figure out if we will need to stat the file, because if we don't
- * need to follow symlinks, we can avoid a stat call by using
- * struct dirent.d_type.
- */
- if (which_pred == pred_xtype)
- {
- our_pred->need_stat = true;
- our_pred->need_type = false;
- }
- else
- {
- our_pred->need_stat = false; /* struct dirent is enough */
- our_pred->need_type = true;
- }
- our_pred->args.type = type_cell;
- return true;
+ default: /* None of the above ... nuke 'em. */
+ return (false);
}
- return false;
+ our_pred = insert_primary (which_pred);
+ our_pred->args.type = type_cell;
+ (*arg_ptr)++; /* Move on to next argument. */
+ return (true);
}
+/* If true, we've determined that the current fprintf predicate
+ uses stat information. */
+static boolean fprintf_stat_needed;
-/* Return true if the file accessed via FP is a terminal.
- */
-static boolean
-stream_is_tty(FILE *fp)
-{
- int fd = fileno(fp);
- if (-1 == fd)
- {
- return false; /* not a valid stream */
- }
- else
- {
- return isatty(fd) ? true : false;
- }
-
-}
-
-
-
-
-/* XXX: do we need to pass FUNC to this function? */
static boolean
-insert_fprintf (struct format_val *vec,
- const struct parser_table *entry, PRED_FUNC func,
- const char *format_const)
+insert_fprintf (fp, func, argv, arg_ptr)
+ FILE *fp;
+ boolean (*func) ();
+ char *argv[];
+ int *arg_ptr;
{
- char *format = (char*)format_const; /* XXX: casting away constness */
+ char *format; /* Beginning of unprocessed format string. */
register char *scan; /* Current address in scanning `format'. */
register char *scan2; /* Address inside of element being scanned. */
struct segment **segmentp; /* Address of current segment. */
struct predicate *our_pred;
- our_pred = insert_primary_withpred (entry, func);
- our_pred->side_effects = our_pred->no_default_print = true;
- our_pred->args.printf_vec = *vec;
- our_pred->need_type = false;
- our_pred->need_stat = false;
- our_pred->p_cost = NeedsNothing;
+ format = argv[(*arg_ptr)++];
+ fprintf_stat_needed = false; /* Might be overridden later. */
+ our_pred = insert_primary (func);
+ our_pred->side_effects = true;
+ our_pred->args.printf_vec.stream = fp;
segmentp = &our_pred->args.printf_vec.segment;
*segmentp = NULL;
@@ -2716,12 +1427,9 @@ insert_fprintf (struct format_val *vec,
*scan = '\b';
break;
case 'c':
- make_segment (segmentp, format, scan - format,
- KIND_STOP, 0, 0,
- our_pred);
- if (our_pred->need_stat && (our_pred->p_cost < NeedsStatInfo))
- our_pred->p_cost = NeedsStatInfo;
- return true;
+ make_segment (segmentp, format, scan - format, KIND_STOP);
+ our_pred->need_stat = fprintf_stat_needed;
+ return (true);
case 'f':
*scan = '\f';
break;
@@ -2741,30 +1449,22 @@ insert_fprintf (struct format_val *vec,
/* *scan = '\\'; * it already is */
break;
default:
- error (0, 0,
- _("warning: unrecognized escape `\\%c'"), *scan2);
+ error (0, 0, "warning: unrecognized escape `\\%c'", *scan2);
scan++;
continue;
}
}
segmentp = make_segment (segmentp, format, scan - format + 1,
- KIND_PLAIN, 0, 0,
- our_pred);
+ KIND_PLAIN);
format = scan2 + 1; /* Move past the escape. */
scan = scan2; /* Incremented immediately by `for'. */
}
else if (*scan == '%')
{
- if (scan[1] == 0)
- {
- /* Trailing %. We don't like those. */
- error (1, 0, _("error: %s at end of format string"), scan);
- }
- else if (scan[1] == '%')
+ if (scan[1] == '%')
{
segmentp = make_segment (segmentp, format, scan - format + 1,
- KIND_PLAIN, 0, 0,
- our_pred);
+ KIND_PLAIN);
scan++;
format = scan + 1;
continue;
@@ -2777,19 +1477,17 @@ insert_fprintf (struct format_val *vec,
if (*scan2 == '.')
for (scan2++; ISDIGIT (*scan2); scan2++)
/* Do nothing. */ ;
- if (strchr ("abcdDfFgGhHiklmMnpPsStuUyY", *scan2))
+ if (strchr ("abcdfFgGhHiklmnpPstuU", *scan2))
{
segmentp = make_segment (segmentp, format, scan2 - format,
- KIND_FORMAT, *scan2, 0,
- our_pred);
+ (int) *scan2);
scan = scan2;
format = scan + 1;
}
- else if (strchr ("ABCT", *scan2) && scan2[1])
+ else if (strchr ("ACT", *scan2) && scan2[1])
{
segmentp = make_segment (segmentp, format, scan2 - format,
- KIND_FORMAT, scan2[0], scan2[1],
- our_pred);
+ *scan2 | (scan2[1] << 8));
scan = scan2 + 1;
format = scan + 1;
continue;
@@ -2797,11 +1495,10 @@ insert_fprintf (struct format_val *vec,
else
{
/* An unrecognized % escape. Print the char after the %. */
- error (0, 0, _("warning: unrecognized format directive `%%%c'"),
+ error (0, 0, "warning: unrecognized format directive `%%%c'",
*scan2);
segmentp = make_segment (segmentp, format, scan - format,
- KIND_PLAIN, 0, 0,
- our_pred);
+ KIND_PLAIN);
format = scan + 1;
continue;
}
@@ -2809,9 +1506,9 @@ insert_fprintf (struct format_val *vec,
}
if (scan > format)
- make_segment (segmentp, format, scan - format, KIND_PLAIN, 0, 0,
- our_pred);
- return true;
+ make_segment (segmentp, format, scan - format, KIND_PLAIN);
+ our_pred->need_stat = fprintf_stat_needed;
+ return (true);
}
/* Create a new fprintf segment in *SEGMENT, with type KIND,
@@ -2819,476 +1516,208 @@ insert_fprintf (struct format_val *vec,
Return the address of the `next' pointer of the new segment. */
static struct segment **
-make_segment (struct segment **segment,
- char *format,
- int len,
- int kind,
- char format_char,
- char aux_format_char,
- struct predicate *pred)
-{
- enum EvaluationCost mycost = NeedsNothing;
+make_segment (segment, format, len, kind)
+ struct segment **segment;
+ char *format;
+ int len, kind;
+{
char *fmt;
- *segment = xmalloc (sizeof (struct segment));
+ *segment = (struct segment *) xmalloc (sizeof (struct segment));
- (*segment)->segkind = kind;
- (*segment)->format_char[0] = format_char;
- (*segment)->format_char[1] = aux_format_char;
+ (*segment)->kind = kind;
(*segment)->next = NULL;
(*segment)->text_len = len;
- fmt = (*segment)->text = xmalloc (len + sizeof "d");
+ fmt = (*segment)->text = xmalloc (len + 3); /* room for "ld\0" */
strncpy (fmt, format, len);
fmt += len;
- switch (kind)
+ switch (kind & 0xff)
{
case KIND_PLAIN: /* Plain text string, no % conversion. */
case KIND_STOP: /* Terminate argument, no newline. */
- assert (0 == format_char);
- assert (0 == aux_format_char);
- *fmt = '\0';
- if (mycost > pred->p_cost)
- pred->p_cost = NeedsNothing;
- return &(*segment)->next;
break;
- }
- assert (kind == KIND_FORMAT);
- switch (format_char)
- {
- case 'l': /* object of symlink */
- pred->need_stat = true;
- mycost = NeedsLinkName;
- *fmt++ = 's';
- break;
-
- case 'y': /* file type */
- pred->need_type = true;
- mycost = NeedsType;
- *fmt++ = 's';
- break;
-
case 'a': /* atime in `ctime' format */
- case 'A': /* atime in user-specified strftime format */
- case 'B': /* birth time in user-specified strftime format */
case 'c': /* ctime in `ctime' format */
- case 'C': /* ctime in user-specified strftime format */
- case 'F': /* file system type */
+ case 'F': /* filesystem type */
case 'g': /* group name */
- case 'i': /* inode number */
- case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
- case 's': /* size in bytes */
+ case 'l': /* object of symlink */
case 't': /* mtime in `ctime' format */
- case 'T': /* mtime in user-specified strftime format */
case 'u': /* user name */
- pred->need_stat = true;
- mycost = NeedsStatInfo;
- *fmt++ = 's';
- break;
-
- case 'S': /* sparseness */
- pred->need_stat = true;
- mycost = NeedsStatInfo;
- *fmt++ = 'g';
- break;
-
- case 'Y': /* symlink pointed file type */
- pred->need_stat = true;
- mycost = NeedsType; /* true for amortised effect */
- *fmt++ = 's';
- break;
-
+ case 'A': /* atime in user-specified strftime format */
+ case 'C': /* ctime in user-specified strftime format */
+ case 'T': /* mtime in user-specified strftime format */
+ fprintf_stat_needed = true;
+ /* FALLTHROUGH */
case 'f': /* basename of path */
case 'h': /* leading directories part of path */
+ case 'H': /* ARGV element file was found under */
case 'p': /* pathname */
case 'P': /* pathname with ARGV element stripped */
*fmt++ = 's';
break;
- case 'H': /* ARGV element file was found under */
- *fmt++ = 's';
- break;
-
- /* Numeric items that one might expect to honour
- * #, 0, + flags but which do not.
- */
- case 'G': /* GID number */
- case 'U': /* UID number */
- case 'b': /* size in 512-byte blocks (NOT birthtime in ctime fmt)*/
- case 'D': /* Filesystem device on which the file exits */
+ case 'b': /* size in 512-byte blocks */
case 'k': /* size in 1K blocks */
+ case 's': /* size in bytes */
+ *fmt++ = 'l';
+ /*FALLTHROUGH*/
case 'n': /* number of links */
- pred->need_stat = true;
- mycost = NeedsStatInfo;
- *fmt++ = 's';
- break;
-
- /* Numeric items that DO honour #, 0, + flags.
- */
+ fprintf_stat_needed = true;
+ /* FALLTHROUGH */
case 'd': /* depth in search tree (0 = ARGV element) */
*fmt++ = 'd';
break;
- case 'm': /* mode as octal number (perms only) */
- *fmt++ = 'o';
- pred->need_stat = true;
- mycost = NeedsStatInfo;
+ case 'i': /* inode number */
+ *fmt++ = 'l';
+ /*FALLTHROUGH*/
+ case 'G': /* GID number */
+ case 'U': /* UID number */
+ *fmt++ = 'u';
+ fprintf_stat_needed = true;
break;
- case '{':
- case '[':
- case '(':
- error (1, 0,
- _("error: the format directive `%%%c' is reserved for future use"),
- (int)kind);
- /*NOTREACHED*/
+ case 'm': /* mode as octal number (perms only) */
+ *fmt++ = 'o';
+ fprintf_stat_needed = true;
break;
}
*fmt = '\0';
- if (mycost > pred->p_cost)
- pred->p_cost = mycost;
- return &(*segment)->next;
-}
-
-static void
-check_path_safety(const char *action, char **argv)
-{
- char *s;
- const char *path = getenv("PATH");
- if (NULL == path)
- {
- /* $PATH is not set. Assume the OS default is safe.
- * That may not be true on Windows, but I'm not aware
- * of a way to get Windows to avoid searching the
- * current directory anyway.
- */
- return;
- }
-
- (void)argv;
-
- s = next_element(path, 1);
- while ((s = next_element ((char *) NULL, 1)) != NULL)
- {
- if (0 == strcmp(s, "."))
- {
- error(1, 0, _("The current directory is included in the PATH "
- "environment variable, which is insecure in "
- "combination with the %s action of find. "
- "Please remove the current directory from your "
- "$PATH (that is, remove \".\" or leading or trailing "
- "colons)"),
- action);
- }
- else if ('/' != s[0])
- {
- /* Relative paths are also dangerous in $PATH. */
- error(1, 0, _("The relative path %s is included in the PATH "
- "environment variable, which is insecure in "
- "combination with the %s action of find. "
- "Please remove that entry from $PATH"),
- safely_quote_err_filename(0, s),
- action);
- }
- }
+ return (&(*segment)->next);
}
-
-/* handles both exec and ok predicate */
static boolean
-new_insert_exec_ok (const char *action,
- const struct parser_table *entry,
- int dirfd,
- char **argv,
- int *arg_ptr)
+insert_exec_ok (func, argv, arg_ptr)
+ boolean (*func) ();
+ char *argv[];
+ int *arg_ptr;
{
int start, end; /* Indexes in ARGV of start & end of cmd. */
- int i; /* Index into cmd args */
- int saw_braces; /* True if previous arg was '{}'. */
- boolean allow_plus; /* True if + is a valid terminator */
- int brace_count; /* Number of instances of {}. */
- PRED_FUNC func = entry->pred_func;
- enum BC_INIT_STATUS bcstatus;
-
+ int num_paths; /* Number of args with path replacements. */
+ int path_pos; /* Index in array of path replacements. */
+ int vec_pos; /* Index in array of args. */
struct predicate *our_pred;
struct exec_val *execp; /* Pointer for efficiency. */
if ((argv == NULL) || (argv[*arg_ptr] == NULL))
- return false;
+ return (false);
- our_pred = insert_primary_withpred (entry, func);
- our_pred->side_effects = our_pred->no_default_print = true;
- our_pred->need_type = our_pred->need_stat = false;
-
- execp = &our_pred->args.exec_vec;
-
- if ((func != pred_okdir) && (func != pred_ok))
- {
- allow_plus = true;
- execp->close_stdin = false;
- }
- else
- {
- allow_plus = false;
- /* If find reads stdin (i.e. for -ok and similar), close stdin
- * in the child to prevent some script from consiming the output
- * intended for find.
- */
- execp->close_stdin = true;
- }
-
-
- if ((func == pred_execdir) || (func == pred_okdir))
- {
- options.ignore_readdir_race = false;
- check_path_safety(action, argv);
- execp->use_current_dir = true;
- }
- else
- {
- execp->use_current_dir = false;
- }
-
- our_pred->args.exec_vec.multiple = 0;
-
- /* Count the number of args with path replacements, up until the ';'.
- * Also figure out if the command is terminated by ";" or by "+".
- */
+ /* Count the number of args with path replacements, up until the ';'. */
start = *arg_ptr;
- for (end = start, saw_braces=0, brace_count=0;
+ for (end = start, num_paths = 0;
(argv[end] != NULL)
&& ((argv[end][0] != ';') || (argv[end][1] != '\0'));
end++)
- {
- /* For -exec and -execdir, "{} +" can terminate the command. */
- if ( allow_plus
- && argv[end][0] == '+' && argv[end][1] == 0
- && saw_braces)
- {
- our_pred->args.exec_vec.multiple = 1;
- break;
- }
-
- saw_braces = 0;
- if (mbsstr (argv[end], "{}"))
- {
- saw_braces = 1;
- ++brace_count;
-
- if (0 == end && (func == pred_execdir || func == pred_okdir))
- {
- /* The POSIX standard says that {} replacement should
- * occur even in the utility name. This is insecure
- * since it means we will be executing a command whose
- * name is chosen according to whatever find finds in
- * the file system. That can be influenced by an
- * attacker. Hence for -execdir and -okdir this is not
- * allowed. We can specify this as those options are
- * not defined by POSIX.
- */
- error(1, 0, _("You may not use {} within the utility name for "
- "-execdir and -okdir, because this is a potential "
- "security problem."));
- }
- }
- }
-
+ if (strstr (argv[end], "{}"))
+ num_paths++;
/* Fail if no command given or no semicolon found. */
if ((end == start) || (argv[end] == NULL))
{
*arg_ptr = end;
- free(our_pred);
- return false;
- }
-
- if (our_pred->args.exec_vec.multiple && brace_count > 1)
- {
-
- const char *suffix;
- if (func == pred_execdir)
- suffix = "dir";
- else
- suffix = "";
-
- error(1, 0,
- _("Only one instance of {} is supported with -exec%s ... +"),
- suffix);
- }
-
- /* We use a switch statement here so that the compiler warns us when
- * we forget to handle a newly invented enum value.
- *
- * Like xargs, we allow 2KiB of headroom for the launched utility to
- * export its own environment variables before calling something
- * else.
- */
- bcstatus = bc_init_controlinfo(&execp->ctl, 2048u);
- switch (bcstatus)
- {
- case BC_INIT_ENV_TOO_BIG:
- case BC_INIT_CANNOT_ACCOMODATE_HEADROOM:
- error(1, 0,
- _("The environment is too large for exec()."));
- break;
- case BC_INIT_OK:
- /* Good news. Carry on. */
- break;
+ return (false);
}
- bc_use_sensible_arg_max(&execp->ctl);
-
- execp->ctl.exec_callback = launch;
-
- if (our_pred->args.exec_vec.multiple)
+ our_pred = insert_primary (func);
+ our_pred->side_effects = true;
+ execp = &our_pred->args.exec_vec;
+ execp->paths =
+ (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1));
+ execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1));
+ /* Record the positions of all args, and the args with path replacements. */
+ for (end = start, path_pos = vec_pos = 0;
+ (argv[end] != NULL)
+ && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
+ end++)
{
- /* "+" terminator, so we can just append our arguments after the
- * command and initial arguments.
- */
- execp->replace_vec = NULL;
- execp->ctl.replace_pat = NULL;
- execp->ctl.rplen = 0;
- execp->ctl.lines_per_exec = 0; /* no limit */
- execp->ctl.args_per_exec = 0; /* no limit */
+ register char *p;
- /* remember how many arguments there are */
- execp->ctl.initial_argc = (end-start) - 1;
-
- /* execp->state = xmalloc(sizeof struct buildcmd_state); */
- bc_init_state(&execp->ctl, &execp->state, execp);
-
- /* Gather the initial arguments. Skip the {}. */
- for (i=start; i<end-1; ++i)
+ execp->paths[path_pos].count = 0;
+ for (p = argv[end]; *p; ++p)
+ if (p[0] == '{' && p[1] == '}')
+ {
+ execp->paths[path_pos].count++;
+ ++p;
+ }
+ if (execp->paths[path_pos].count)
{
- bc_push_arg(&execp->ctl, &execp->state,
- argv[i], strlen(argv[i])+1,
- NULL, 0,
- 1);
+ execp->paths[path_pos].offset = vec_pos;
+ execp->paths[path_pos].origarg = argv[end];
+ path_pos++;
}
+ execp->vec[vec_pos++] = argv[end];
}
- else
- {
- /* Semicolon terminator - more than one {} is supported, so we
- * have to do brace-replacement.
- */
- execp->num_args = end - start;
-
- execp->ctl.replace_pat = "{}";
- execp->ctl.rplen = strlen(execp->ctl.replace_pat);
- execp->ctl.lines_per_exec = 0; /* no limit */
- execp->ctl.args_per_exec = 0; /* no limit */
- execp->replace_vec = xmalloc(sizeof(char*)*execp->num_args);
+ execp->paths[path_pos].offset = -1;
+ execp->vec[vec_pos] = NULL;
-
- /* execp->state = xmalloc(sizeof(*(execp->state))); */
- bc_init_state(&execp->ctl, &execp->state, execp);
-
- /* Remember the (pre-replacement) arguments for later. */
- for (i=0; i<execp->num_args; ++i)
- {
- execp->replace_vec[i] = argv[i+start];
- }
- }
-
if (argv[end] == NULL)
*arg_ptr = end;
else
*arg_ptr = end + 1;
-
- return true;
-}
-
-
-
-static boolean
-insert_exec_ok (const char *action,
- const struct parser_table *entry,
- int dirfd,
- char **argv,
- int *arg_ptr)
-{
- return new_insert_exec_ok(action, entry, dirfd, argv, arg_ptr);
+ return (true);
}
-
-
-/* Get a timestamp and comparison type.
-
+/* Get a number of days and comparison type.
STR is the ASCII representation.
- Set *NUM_DAYS to the number of days/minutes/whatever, taken as being
- relative to ORIGIN (usually the current moment or midnight).
- Thus the sense of the comparison type appears to be reversed.
+ Set *NUM_DAYS to the number of days, taken as being from
+ the current moment (or possibly midnight). Thus the sense of the
+ comparison type appears to be reversed.
Set *COMP_TYPE to the kind of comparison that is requested.
- Issue OVERFLOWMESSAGE if overflow occurs.
+
Return true if all okay, false if input error.
Used by -atime, -ctime and -mtime (parsers) to
get the appropriate information for a time predicate processor. */
static boolean
-get_relative_timestamp (const char *str,
- struct time_val *result,
- struct timespec origin,
- double sec_per_unit,
- const char *overflowmessage)
+get_num_days (str, num_days, comp_type)
+ char *str;
+ unsigned long *num_days;
+ enum comparison_type *comp_type;
{
- uintmax_t checkval;
- double offset, seconds, nanosec;
-
- if (get_comp_type(&str, &result->kind))
- {
- /* Invert the sense of the comparison */
- switch (result->kind)
- {
- case COMP_LT: result->kind = COMP_GT; break;
- case COMP_GT: result->kind = COMP_LT; break;
- default: break;
- }
+ int len_days; /* length of field */
- /* Convert the ASCII number into floating-point. */
- if (xstrtod(str, NULL, &offset, strtod))
- {
- /* Separate the floating point number the user specified
- * (which is a number of days, or minutes, etc) into an
- * integral number of seconds (SECONDS) and a fraction (NANOSEC).
- */
- nanosec = modf(offset * sec_per_unit, &seconds);
- nanosec *= 1.0e9; /* convert from fractional seconds to ns. */
-
- result->ts.tv_sec = origin.tv_sec - seconds;
- result->ts.tv_nsec = origin.tv_nsec - nanosec;
- checkval = (uintmax_t)origin.tv_sec - seconds;
-
- if (origin.tv_nsec < nanosec)
- {
- /* Perform a carry operation */
- result->ts.tv_nsec += 1000000000;
- result->ts.tv_sec -= 1;
- checkval -= 1;
- }
- /* Check for overflow. */
- if (checkval != result->ts.tv_sec)
- {
- /* an overflow has occurred. */
- error (1, 0, overflowmessage, str);
- }
- return true;
- }
- else
- {
- /* Conversion from ASCII to double failed. */
- return false;
- }
- }
- else
+ if (str == NULL)
+ return (false);
+ switch (str[0])
{
- return false;
+ case '+':
+ *comp_type = COMP_LT;
+ str++;
+ break;
+ case '-':
+ *comp_type = COMP_GT;
+ str++;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ *comp_type = COMP_EQ;
+ break;
+ default:
+ return (false);
}
+
+ /* We know the first char has been reasonable. Find the
+ number of days to play with. */
+ len_days = strspn (str, "0123456789");
+ if ((len_days == 0) || (str[len_days] != '\0'))
+ return (false);
+ *num_days = (unsigned long) atol (str);
+ return (true);
}
-/* Insert a time predicate based on the information in ENTRY.
+/* Insert a time predicate PRED.
ARGV is a pointer to the argument array.
ARG_PTR is a pointer to an index into the array, incremented if
all went well.
@@ -3300,137 +1729,100 @@ get_relative_timestamp (const char *str,
Used by -atime, -ctime, and -mtime parsers. */
-static boolean
-parse_time (const struct parser_table* entry, char *argv[], int *arg_ptr)
+static boolean
+insert_time (argv, arg_ptr, pred)
+ char *argv[];
+ int *arg_ptr;
+ PFB pred;
{
struct predicate *our_pred;
- struct time_val tval;
- enum comparison_type comp;
- const char *timearg, *orig_timearg;
- const char *errmsg = "arithmetic overflow while converting %s "
- "days to a number of seconds";
- struct timespec origin;
-
- if (!collect_arg(argv, arg_ptr, &timearg))
- return false;
- orig_timearg = timearg;
-
- /* Decide the origin by previewing the comparison type. */
- origin = options.cur_day_start;
-
- if (get_comp_type(&timearg, &comp))
- {
- /* Remember, we invert the sense of the comparison, so this tests
- * against COMP_LT instead of COMP_GT...
- */
- if (COMP_LT == comp)
- {
- uintmax_t expected = origin.tv_sec + (DAYSECS-1);
- origin.tv_sec += (DAYSECS-1);
- if (origin.tv_sec != expected)
- {
- error(1, 0,
- _("arithmetic overflow when trying to calculate the end of today"));
- }
- }
- }
- /* We discard the value of comp here, as get_relative_timestamp
- * will set tval.kind. For that to work, we have to restore
- * timearg so that it points to the +/- prefix, if any. get_comp_type()
- * will have advanced timearg, so we restore it.
- */
- timearg = orig_timearg;
-
- if (!get_relative_timestamp(timearg, &tval, origin, DAYSECS, errmsg))
- return false;
-
- our_pred = insert_primary (entry);
- our_pred->args.reftime = tval;
- our_pred->est_success_rate = estimate_timestamp_success_rate(tval.ts.tv_sec);
+ unsigned long num_days;
+ enum comparison_type c_type;
- if (options.debug_options & DebugExpressionTree)
- {
- time_t t;
-
- fprintf (stderr, "inserting %s\n", our_pred->p_name);
- fprintf (stderr, " type: %s %s ",
- (tval.kind == COMP_GT) ? "gt" :
- ((tval.kind == COMP_LT) ? "lt" : ((tval.kind == COMP_EQ) ? "eq" : "?")),
- (tval.kind == COMP_GT) ? " >" :
- ((tval.kind == COMP_LT) ? " <" : ((tval.kind == COMP_EQ) ? ">=" : " ?")));
- t = our_pred->args.reftime.ts.tv_sec;
- fprintf (stderr, "%ju %s",
- (uintmax_t) our_pred->args.reftime.ts.tv_sec,
- ctime (&t));
- if (tval.kind == COMP_EQ)
- {
- t = our_pred->args.reftime.ts.tv_sec + DAYSECS;
- fprintf (stderr, " < %ju %s",
- (uintmax_t) t, ctime (&t));
- }
- }
-
- return true;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
+ return (false);
+ our_pred = insert_primary (pred);
+ our_pred->args.info.kind = c_type;
+ our_pred->args.info.l_val = cur_day_start - num_days * DAYSECS
+ + ((c_type == COMP_GT) ? DAYSECS - 1 : 0);
+ (*arg_ptr)++;
+#ifdef DEBUG
+ printf ("inserting %s\n", our_pred->p_name);
+ printf (" type: %s %s ",
+ (c_type == COMP_GT) ? "gt" :
+ ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
+ (c_type == COMP_GT) ? " >" :
+ ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
+ printf ("%ld %s", our_pred->args.info.l_val,
+ ctime (&our_pred->args.info.l_val));
+ if (c_type == COMP_EQ)
+ {
+ our_pred->args.info.l_val += DAYSECS;
+ printf (" < %ld %s", our_pred->args.info.l_val,
+ ctime (&our_pred->args.info.l_val));
+ our_pred->args.info.l_val -= DAYSECS;
+ }
+#endif /* DEBUG */
+ return (true);
}
-/* Get the comparison type prefix (if any) from a number argument.
- The prefix is at *STR.
+/* Get a number with comparision information.
+ The sense of the comparision information is 'normal'; that is,
+ '+' looks for inums or links > than the number and '-' less than.
+
+ STR is the ASCII representation of the number.
+ Set *NUM to the number.
Set *COMP_TYPE to the kind of comparison that is requested.
- Advance *STR beyond any initial comparison prefix.
+
+ Return true if all okay, false if input error.
+
+ Used by the -inum and -links predicate parsers. */
- Return true if all okay, false if input error. */
static boolean
-get_comp_type(const char **str, enum comparison_type *comp_type)
+get_num (str, num, comp_type)
+ char *str;
+ unsigned long *num;
+ enum comparison_type *comp_type;
{
- switch (**str)
+ int len_num; /* Length of field. */
+
+ if (str == NULL)
+ return (false);
+ switch (str[0])
{
case '+':
*comp_type = COMP_GT;
- (*str)++;
+ str++;
break;
case '-':
*comp_type = COMP_LT;
- (*str)++;
+ str++;
break;
- default:
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
*comp_type = COMP_EQ;
break;
+ default:
+ return (false);
}
- return true;
-}
-
-
-
-
-
-/* Get a number with comparison information.
- The sense of the comparison information is 'normal'; that is,
- '+' looks for a count > than the number and '-' less than.
-
- STR is the ASCII representation of the number.
- Set *NUM to the number.
- Set *COMP_TYPE to the kind of comparison that is requested.
-
- Return true if all okay, false if input error. */
-
-static boolean
-get_num (const char *str,
- uintmax_t *num,
- enum comparison_type *comp_type)
-{
- char *pend;
-
- if (str == NULL)
- return false;
- /* Figure out the comparison type if the caller accepts one. */
- if (comp_type)
- {
- if (!get_comp_type(&str, comp_type))
- return false;
- }
-
- return xstrtoumax (str, &pend, 10, num, "") == LONGINT_OK;
+ /* We know the first char has been reasonable. Find the number of
+ days to play with. */
+ len_num = strspn (str, "0123456789");
+ if ((len_num == 0) || (str[len_num] != '\0'))
+ return (false);
+ *num = (unsigned long) atol (str);
+ return (true);
}
/* Insert a number predicate.
@@ -3445,70 +1837,48 @@ get_num (const char *str,
Used by -inum and -links parsers. */
-static struct predicate *
-insert_num (char **argv, int *arg_ptr, const struct parser_table *entry)
+static boolean
+insert_num (argv, arg_ptr, pred)
+ char *argv[];
+ int *arg_ptr;
+ PFB pred;
{
- const char *numstr;
-
- if (collect_arg(argv, arg_ptr, &numstr))
- {
- uintmax_t num;
- enum comparison_type c_type;
+ struct predicate *our_pred;
+ unsigned long num;
+ enum comparison_type c_type;
- if (get_num (numstr, &num, &c_type))
- {
- struct predicate *our_pred = insert_primary (entry);
- our_pred->args.numinfo.kind = c_type;
- our_pred->args.numinfo.l_val = num;
-
- if (options.debug_options & DebugExpressionTree)
- {
- fprintf (stderr, "inserting %s\n", our_pred->p_name);
- fprintf (stderr, " type: %s %s ",
- (c_type == COMP_GT) ? "gt" :
- ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
- (c_type == COMP_GT) ? " >" :
- ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
- fprintf (stderr, "%ju\n", our_pred->args.numinfo.l_val);
- }
- return our_pred;
- }
- }
- return NULL;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ if (!get_num (argv[*arg_ptr], &num, &c_type))
+ return (false);
+ our_pred = insert_primary (pred);
+ our_pred->args.info.kind = c_type;
+ our_pred->args.info.l_val = num;
+ (*arg_ptr)++;
+#ifdef DEBUG
+ printf ("inserting %s\n", our_pred->p_name);
+ printf (" type: %s %s ",
+ (c_type == COMP_GT) ? "gt" :
+ ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
+ (c_type == COMP_GT) ? " >" :
+ ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
+ printf ("%ld\n", our_pred->args.info.l_val);
+#endif /* DEBUG */
+ return (true);
}
-static void
-open_output_file (const char *path, struct format_val *p)
+static FILE *
+open_output_file (path)
+ char *path;
{
- p->segment = NULL;
- p->quote_opts = clone_quoting_options (NULL);
-
+ FILE *f;
+
if (!strcmp (path, "/dev/stderr"))
- {
- p->stream = stderr;
- p->filename = _("standard error");
- }
+ return (stderr);
else if (!strcmp (path, "/dev/stdout"))
- {
- p->stream = stdout;
- p->filename = _("standard output");
- }
- else
- {
- p->stream = fopen_safer (path, "w");
- p->filename = path;
-
- if (p->stream == NULL)
- {
- fatal_file_error(path);
- }
- }
-
- p->dest_is_tty = stream_is_tty(p->stream);
-}
-
-static void
-open_stdout (struct format_val *p)
-{
- open_output_file("/dev/stdout", p);
+ return (stdout);
+ f = fopen (path, "w");
+ if (f == NULL)
+ error (1, errno, "%s", path);
+ return (f);
}
diff --git a/find/pred.c b/find/pred.c
index 75e6774a..9c8c6828 100644
--- a/find/pred.c
+++ b/find/pred.c
@@ -1,70 +1,40 @@
/* pred.c -- execute the expression tree.
- Copyright (C) 1990, 1991, 1992, 1993, 1994, 2000, 2003,
- 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+ Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
+ 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 3 of the License, or
- (at your option) any later version.
-
+ 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, see <http://www.gnu.org/licenses/>.
-*/
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <config.h>
-#include "defs.h"
-
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
#include <fnmatch.h>
#include <signal.h>
-#include <math.h>
#include <pwd.h>
#include <grp.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <assert.h>
-#include <stdarg.h>
-#include <fcntl.h>
-#include <locale.h>
-#include <openat.h>
-#include "xalloc.h"
-#include "dirname.h"
-#include "human.h"
+#include "defs.h"
#include "modetype.h"
-#include "filemode.h"
#include "wait.h"
-#include "printquoted.h"
-#include "buildcmd.h"
-#include "yesno.h"
-#include "listfile.h"
-#include "stat-time.h"
-#include "dircallback.h"
-#include "error.h"
-#include "verify.h"
-
-#if ENABLE_NLS
-# include <libintl.h>
-# define _(Text) gettext (Text)
-#else
-# define _(Text) Text
-#endif
-#ifdef gettext_noop
-# define N_(String) gettext_noop (String)
-#else
-/* See locate.c for explanation as to why not use (String) */
-# define N_(String) String
-#endif
#if !defined(SIGCHLD) && defined(SIGCLD)
#define SIGCHLD SIGCLD
#endif
-
+#ifndef _POSIX_VERSION
+struct passwd *getpwuid ();
+struct group *getgrgid ();
+#endif
#if HAVE_DIRENT_H
# include <dirent.h>
@@ -90,83 +60,40 @@
#define CLOSEDIR(d) closedir (d)
#endif
-
-
-
-/* Get or fake the disk device blocksize.
- Usually defined by sys/param.h (if at all). */
-#ifndef DEV_BSIZE
-# ifdef BSIZE
-# define DEV_BSIZE BSIZE
-# else /* !BSIZE */
-# define DEV_BSIZE 4096
-# endif /* !BSIZE */
-#endif /* !DEV_BSIZE */
-
-/* Extract or fake data from a `struct stat'.
- ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes.
- ST_NBLOCKS: Number of blocks in the file, including indirect blocks.
- ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */
-#ifndef HAVE_STRUCT_STAT_ST_BLOCKS
-# define ST_BLKSIZE(statbuf) DEV_BSIZE
-# if defined _POSIX_SOURCE || !defined BSIZE /* fileblocks.c uses BSIZE. */
-# define ST_NBLOCKS(statbuf) \
- (S_ISREG ((statbuf).st_mode) \
- || S_ISDIR ((statbuf).st_mode) \
- ? (statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0) : 0)
-# else /* !_POSIX_SOURCE && BSIZE */
-# define ST_NBLOCKS(statbuf) \
- (S_ISREG ((statbuf).st_mode) \
- || S_ISDIR ((statbuf).st_mode) \
- ? st_blocks ((statbuf).st_size) : 0)
-# endif /* !_POSIX_SOURCE && BSIZE */
-#else /* HAVE_STRUCT_STAT_ST_BLOCKS */
-/* Some systems, like Sequents, return st_blksize of 0 on pipes. */
-# define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \
- ? (statbuf).st_blksize : DEV_BSIZE)
-# if defined hpux || defined __hpux__ || defined __hpux
-/* HP-UX counts st_blocks in 1024-byte units.
- This loses when mixing HP-UX and BSD file systems with NFS. */
-# define ST_NBLOCKSIZE 1024
-# else /* !hpux */
-# if defined _AIX && defined _I386
-/* AIX PS/2 counts st_blocks in 4K units. */
-# define ST_NBLOCKSIZE (4 * 1024)
-# else /* not AIX PS/2 */
-# if defined _CRAY
-# define ST_NBLOCKS(statbuf) \
- (S_ISREG ((statbuf).st_mode) \
- || S_ISDIR ((statbuf).st_mode) \
- ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0)
-# endif /* _CRAY */
-# endif /* not AIX PS/2 */
-# endif /* !hpux */
-#endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
-
-#ifndef ST_NBLOCKS
-# define ST_NBLOCKS(statbuf) \
- (S_ISREG ((statbuf).st_mode) \
- || S_ISDIR ((statbuf).st_mode) \
- ? (statbuf).st_blocks : 0)
+#ifndef S_IFLNK
+#define lstat stat
#endif
-#ifndef ST_NBLOCKSIZE
-# define ST_NBLOCKSIZE 512
+/* Extract or fake data from a `struct stat'.
+ ST_NBLOCKS: Number of 512-byte blocks in the file
+ (including indirect blocks).
+ HP-UX, perhaps uniquely, counts st_blocks in 1024-byte units.
+ This workaround loses when mixing HP-UX and 4BSD filesystems, though. */
+#ifdef _POSIX_SOURCE
+# define ST_NBLOCKS(statp) (((statp)->st_size + 512 - 1) / 512)
+#else
+# ifndef HAVE_ST_BLOCKS
+# define ST_NBLOCKS(statp) (st_blocks ((statp)->st_size))
+# else
+# if defined(hpux) || defined(__hpux__)
+# define ST_NBLOCKS(statp) ((statp)->st_blocks * 2)
+# else
+# define ST_NBLOCKS(statp) ((statp)->st_blocks)
+# endif
+# endif
#endif
+int lstat ();
+int stat ();
-#undef MAX
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
-
-static boolean match_lname PARAMS((const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, boolean ignore_case));
-
-static char *format_date PARAMS((struct timespec ts, int kind));
-static char *ctime_format PARAMS((struct timespec ts));
+static boolean insert_lname P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, boolean ignore_case));
+static boolean launch P_((struct predicate *pred_ptr));
+static char *format_date P_((time_t when, int kind));
#ifdef DEBUG
struct pred_assoc
{
- PRED_FUNC pred_func;
+ PFB pred_func;
char *pred_name;
};
@@ -176,16 +103,13 @@ struct pred_assoc pred_table[] =
{pred_and, "and "},
{pred_anewer, "anewer "},
{pred_atime, "atime "},
- {pred_closeparen, ") "},
- {pred_cmin, "cmin "},
+ {pred_close, ") "},
+ {pred_amin, "cmin "},
{pred_cnewer, "cnewer "},
{pred_comma, ", "},
{pred_ctime, "ctime "},
- {pred_delete, "delete "},
{pred_empty, "empty "},
{pred_exec, "exec "},
- {pred_execdir, "execdir "},
- {pred_executable, "executable "},
{pred_false, "false "},
{pred_fprint, "fprint "},
{pred_fprint0, "fprint0 "},
@@ -200,64 +124,66 @@ struct pred_assoc pred_table[] =
{pred_links, "links "},
{pred_lname, "lname "},
{pred_ls, "ls "},
- {pred_mmin, "mmin "},
+ {pred_amin, "mmin "},
{pred_mtime, "mtime "},
{pred_name, "name "},
{pred_negate, "not "},
{pred_newer, "newer "},
- {pred_newerXY, "newerXY "},
{pred_nogroup, "nogroup "},
{pred_nouser, "nouser "},
{pred_ok, "ok "},
- {pred_okdir, "okdir "},
- {pred_openparen, "( "},
+ {pred_open, "( "},
{pred_or, "or "},
{pred_path, "path "},
{pred_perm, "perm "},
{pred_print, "print "},
{pred_print0, "print0 "},
{pred_prune, "prune "},
- {pred_quit, "quit "},
- {pred_readable, "readable "},
{pred_regex, "regex "},
- {pred_samefile,"samefile "},
{pred_size, "size "},
{pred_true, "true "},
{pred_type, "type "},
{pred_uid, "uid "},
{pred_used, "used "},
{pred_user, "user "},
- {pred_writable, "writable "},
{pred_xtype, "xtype "},
{0, "none "}
};
-#endif
-
-/* Returns ts1 - ts2 */
-static double ts_difference(struct timespec ts1,
- struct timespec ts2)
+
+struct op_assoc
{
- double d = difftime(ts1.tv_sec, ts2.tv_sec)
- + (1.0e-9 * (ts1.tv_nsec - ts2.tv_nsec));
- return d;
-}
+ short type;
+ char *type_name;
+};
-
-static int
-compare_ts(struct timespec ts1,
- struct timespec ts2)
+struct op_assoc type_table[] =
{
- if ((ts1.tv_sec == ts2.tv_sec) &&
- (ts1.tv_nsec == ts2.tv_nsec))
- {
- return 0;
- }
- else
- {
- double diff = ts_difference(ts1, ts2);
- return diff < 0.0 ? -1 : +1;
- }
-}
+ {NO_TYPE, "no "},
+ {PRIMARY_TYPE, "primary "},
+ {UNI_OP, "uni_op "},
+ {BI_OP, "bi_op "},
+ {OPEN_PAREN, "open_paren "},
+ {CLOSE_PAREN, "close_paren "},
+ {-1, "unknown "}
+};
+
+struct prec_assoc
+{
+ short prec;
+ char *prec_name;
+};
+
+struct prec_assoc prec_table[] =
+{
+ {NO_PREC, "no "},
+ {COMMA_PREC, "comma "},
+ {OR_PREC, "or "},
+ {AND_PREC, "and "},
+ {NEGATE_PREC, "negate "},
+ {MAX_PREC, "max "},
+ {-1, "unknown "}
+};
+#endif /* DEBUG */
/* Predicate processing routines.
@@ -267,212 +193,210 @@ compare_ts(struct timespec ts1,
Return true if the file passes this predicate, false if not. */
-
-/* pred_timewindow
- *
- * Returns true if THE_TIME is
- * COMP_GT: after the specified time
- * COMP_LT: before the specified time
- * COMP_EQ: after the specified time but by not more than WINDOW seconds.
- */
-static boolean
-pred_timewindow(struct timespec ts, struct predicate const *pred_ptr, int window)
+boolean
+pred_amin (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- switch (pred_ptr->args.reftime.kind)
+ switch (pred_ptr->args.info.kind)
{
case COMP_GT:
- return compare_ts(ts, pred_ptr->args.reftime.ts) > 0;
-
+ if (stat_buf->st_atime > (time_t) pred_ptr->args.info.l_val)
+ return (true);
+ break;
case COMP_LT:
- return compare_ts(ts, pred_ptr->args.reftime.ts) < 0;
-
+ if (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val)
+ return (true);
+ break;
case COMP_EQ:
- {
- /* consider "find . -mtime 0".
- *
- * Here, the origin is exactly 86400 seconds before the start
- * of the program (since -daystart was not specified). This
- * function will be called with window=86400 and
- * pred_ptr->args.reftime.ts as the origin. Hence a file
- * created the instant the program starts will show a time
- * difference (value of delta) of 86400. Similarly, a file
- * created exactly 24h ago would be the newest file which was
- * _not_ created today. So, if delta is 0.0, the file
- * was not created today. If the delta is 86400, the file
- * was created this instant.
- */
- double delta = ts_difference(ts, pred_ptr->args.reftime.ts);
- return (delta > 0.0 && delta <= window);
- }
+ if ((stat_buf->st_atime >= (time_t) pred_ptr->args.info.l_val)
+ && (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val + 60))
+ return (true);
+ break;
}
- assert (0);
- abort ();
-}
-
-
-boolean
-pred_amin (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
-{
- (void) &pathname;
- return pred_timewindow(get_stat_atime(stat_buf), pred_ptr, 60);
+ return (false);
}
boolean
-pred_and (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_and (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
if (pred_ptr->pred_left == NULL
- || apply_predicate(pathname, stat_buf, pred_ptr->pred_left))
+ || (*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
+ pred_ptr->pred_left))
{
- return apply_predicate(pathname, stat_buf, pred_ptr->pred_right);
+ /* Check whether we need a stat here. */
+ if (pred_ptr->need_stat)
+ {
+ if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
+ {
+ error (0, errno, "%s", pathname);
+ exit_status = 1;
+ return (false);
+ }
+ have_stat = true;
+ }
+ return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
+ pred_ptr->pred_right));
}
else
- return false;
+ return (false);
}
boolean
-pred_anewer (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_anewer (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) &pathname;
- assert (COMP_GT == pred_ptr->args.reftime.kind);
- return compare_ts(get_stat_atime(stat_buf), pred_ptr->args.reftime.ts) > 0;
+ if (stat_buf->st_atime > pred_ptr->args.time)
+ return (true);
+ return (false);
}
boolean
-pred_atime (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_atime (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) &pathname;
- return pred_timewindow(get_stat_atime(stat_buf), pred_ptr, DAYSECS);
+ switch (pred_ptr->args.info.kind)
+ {
+ case COMP_GT:
+ if (stat_buf->st_atime > (time_t) pred_ptr->args.info.l_val)
+ return (true);
+ break;
+ case COMP_LT:
+ if (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val)
+ return (true);
+ break;
+ case COMP_EQ:
+ if ((stat_buf->st_atime >= (time_t) pred_ptr->args.info.l_val)
+ && (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val
+ + DAYSECS))
+ return (true);
+ break;
+ }
+ return (false);
}
boolean
-pred_closeparen (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_close (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) &pathname;
- (void) &stat_buf;
- (void) &pred_ptr;
-
- return true;
+ return (true);
}
boolean
-pred_cmin (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_cmin (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) pathname;
- return pred_timewindow(get_stat_ctime(stat_buf), pred_ptr, 60);
+ switch (pred_ptr->args.info.kind)
+ {
+ case COMP_GT:
+ if (stat_buf->st_ctime > (time_t) pred_ptr->args.info.l_val)
+ return (true);
+ break;
+ case COMP_LT:
+ if (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val)
+ return (true);
+ break;
+ case COMP_EQ:
+ if ((stat_buf->st_ctime >= (time_t) pred_ptr->args.info.l_val)
+ && (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val + 60))
+ return (true);
+ break;
+ }
+ return (false);
}
boolean
-pred_cnewer (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_cnewer (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) pathname;
-
- assert (COMP_GT == pred_ptr->args.reftime.kind);
- return compare_ts(get_stat_ctime(stat_buf), pred_ptr->args.reftime.ts) > 0;
+ if (stat_buf->st_ctime > pred_ptr->args.time)
+ return (true);
+ return (false);
}
boolean
-pred_comma (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_comma (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
if (pred_ptr->pred_left != NULL)
+ (*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
+ pred_ptr->pred_left);
+ /* Check whether we need a stat here. */
+ if (pred_ptr->need_stat)
{
- apply_predicate(pathname, stat_buf,pred_ptr->pred_left);
+ if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
+ {
+ error (0, errno, "%s", pathname);
+ exit_status = 1;
+ return (false);
+ }
+ have_stat = true;
}
- return apply_predicate(pathname, stat_buf, pred_ptr->pred_right);
+ return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
+ pred_ptr->pred_right));
}
boolean
-pred_ctime (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_ctime (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) &pathname;
- return pred_timewindow(get_stat_ctime(stat_buf), pred_ptr, DAYSECS);
-}
-
-static boolean
-perform_delete(int flags)
-{
- return 0 == unlinkat(state.cwd_dir_fd, state.rel_pathname, flags);
-}
-
-
-boolean
-pred_delete (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
-{
- (void) pred_ptr;
- (void) stat_buf;
- if (strcmp (state.rel_pathname, "."))
+ switch (pred_ptr->args.info.kind)
{
- int flags=0;
- if (state.have_stat && S_ISDIR(stat_buf->st_mode))
- flags |= AT_REMOVEDIR;
- if (perform_delete(flags))
- {
- return true;
- }
- else
- {
- if (EISDIR == errno)
- {
- if ((flags & AT_REMOVEDIR) == 0)
- {
- /* unlink() operation failed because we should have done rmdir(). */
- flags |= AT_REMOVEDIR;
- if (perform_delete(flags))
- return true;
- }
- }
- }
- error (0, errno, _("cannot delete %s"),
- safely_quote_err_filename(0, pathname));
- /* Previously I had believed that having the -delete action
- * return false provided the user with control over whether an
- * error message is issued. While this is true, the policy of
- * not affecting the exit status is contrary to the POSIX
- * requirement that diagnostic messages are accompanied by a
- * nonzero exit status. While -delete is not a POSIX option and
- * we can therefore opt not to follow POSIX in this case, that
- * seems somewhat arbitrary and confusing. So, as of
- * findutils-4.3.11, we also set the exit status in this case.
- */
- state.exit_status = 1;
- return false;
- }
- else
- {
- /* nothing to do. */
- return true;
+ case COMP_GT:
+ if (stat_buf->st_ctime > (time_t) pred_ptr->args.info.l_val)
+ return (true);
+ break;
+ case COMP_LT:
+ if (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val)
+ return (true);
+ break;
+ case COMP_EQ:
+ if ((stat_buf->st_ctime >= (time_t) pred_ptr->args.info.l_val)
+ && (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val
+ + DAYSECS))
+ return (true);
+ break;
}
+ return (false);
}
boolean
-pred_empty (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_empty (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) pathname;
- (void) pred_ptr;
-
if (S_ISDIR (stat_buf->st_mode))
{
- int fd;
DIR *d;
struct dirent *dp;
boolean empty = true;
errno = 0;
- if ((fd = openat(state.cwd_dir_fd, state.rel_pathname, O_RDONLY
-#if defined O_LARGEFILE
- |O_LARGEFILE
-#endif
- )) < 0)
- {
- error (0, errno, "%s", safely_quote_err_filename(0, pathname));
- state.exit_status = 1;
- return false;
- }
- d = fdopendir (fd);
+ d = opendir (rel_pathname);
if (d == NULL)
{
- error (0, errno, "%s", safely_quote_err_filename(0, pathname));
- state.exit_status = 1;
- return false;
+ error (0, errno, "%s", pathname);
+ exit_status = 1;
+ return (false);
}
for (dp = readdir (d); dp; dp = readdir (d))
{
@@ -486,9 +410,9 @@ pred_empty (const char *pathname, struct stat *stat_buf, struct predicate *pred_
}
if (CLOSEDIR (d))
{
- error (0, errno, "%s", safely_quote_err_filename(0, pathname));
- state.exit_status = 1;
- return false;
+ error (0, errno, "%s", pathname);
+ exit_status = 1;
+ return (false);
}
return (empty);
}
@@ -498,288 +422,162 @@ pred_empty (const char *pathname, struct stat *stat_buf, struct predicate *pred_
return (false);
}
-static boolean
-new_impl_pred_exec (int dirfd, const char *pathname,
- struct stat *stat_buf,
- struct predicate *pred_ptr,
- const char *prefix, size_t pfxlen)
+boolean
+pred_exec (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- struct exec_val *execp = &pred_ptr->args.exec_vec;
- size_t len = strlen(pathname);
-
- (void) stat_buf;
- execp->dirfd = dirfd;
- if (execp->multiple)
- {
- /* Push the argument onto the current list.
- * The command may or may not be run at this point,
- * depending on the command line length limits.
- */
- bc_push_arg(&execp->ctl,
- &execp->state,
- pathname, len+1,
- prefix, pfxlen,
- 0);
-
- /* remember that there are pending execdirs. */
- state.execdirs_outstanding = true;
-
- /* POSIX: If the primary expression is punctuated by a plus
- * sign, the primary shall always evaluate as true
- */
- return true;
- }
- else
- {
- int i;
+ int i;
+ int path_pos;
+ struct exec_val *execp; /* Pointer for efficiency. */
- for (i=0; i<execp->num_args; ++i)
- {
- bc_do_insert(&execp->ctl,
- &execp->state,
- execp->replace_vec[i],
- strlen(execp->replace_vec[i]),
- prefix, pfxlen,
- pathname, len,
- 0);
- }
+ execp = &pred_ptr->args.exec_vec;
- /* Actually invoke the command. */
- return execp->ctl.exec_callback(&execp->ctl,
- &execp->state);
+ /* Replace "{}" with the real path in each affected arg. */
+ for (path_pos = 0; execp->paths[path_pos].offset >= 0; path_pos++)
+ {
+ register char *from, *to;
+
+ i = execp->paths[path_pos].offset;
+ execp->vec[i] =
+ xmalloc (strlen (execp->paths[path_pos].origarg) + 1
+ + (strlen (pathname) - 2) * execp->paths[path_pos].count);
+ for (from = execp->paths[path_pos].origarg, to = execp->vec[i]; *from; )
+ if (from[0] == '{' && from[1] == '}')
+ {
+ to = stpcpy (to, pathname);
+ from += 2;
+ }
+ else
+ *to++ = *from++;
+ *to = *from; /* Copy null. */
}
-}
+ i = launch (pred_ptr);
-boolean
-pred_exec (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
-{
- return new_impl_pred_exec(get_start_dirfd(),
- pathname, stat_buf, pred_ptr, NULL, 0);
-}
+ /* Free the temporary args. */
+ for (path_pos = 0; execp->paths[path_pos].offset >= 0; path_pos++)
+ free (execp->vec[execp->paths[path_pos].offset]);
-boolean
-pred_execdir (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
-{
- const char *prefix = (state.rel_pathname[0] == '/') ? NULL : "./";
- (void) &pathname;
- return new_impl_pred_exec (get_current_dirfd(),
- state.rel_pathname, stat_buf, pred_ptr,
- prefix, (prefix ? 2 : 0));
+ return (i);
}
boolean
-pred_false (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_false (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) &pathname;
- (void) &stat_buf;
- (void) &pred_ptr;
-
-
return (false);
}
boolean
-pred_fls (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
-{
- FILE * stream = pred_ptr->args.printf_vec.stream;
- list_file (pathname, state.cwd_dir_fd, state.rel_pathname, stat_buf,
- options.start_time.tv_sec,
- options.output_block_size,
- pred_ptr->literal_control_chars, stream);
- return true;
-}
-
-boolean
-pred_fprint (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_fls (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) &pathname;
- (void) &stat_buf;
-
- print_quoted(pred_ptr->args.printf_vec.stream,
- pred_ptr->args.printf_vec.quote_opts,
- pred_ptr->args.printf_vec.dest_is_tty,
- "%s\n",
- pathname);
- return true;
+ list_file (pathname, rel_pathname, stat_buf, pred_ptr->args.stream);
+ return (true);
}
boolean
-pred_fprint0 (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_fprint (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- FILE * fp = pred_ptr->args.printf_vec.stream;
-
- (void) &stat_buf;
-
- fputs (pathname, fp);
- putc (0, fp);
- return true;
-}
-
-
-
-static char*
-mode_to_filetype(mode_t m)
-{
-#define HANDLE_TYPE(t,letter) if (m==t) { return letter; }
-#ifdef S_IFREG
- HANDLE_TYPE(S_IFREG, "f"); /* regular file */
-#endif
-#ifdef S_IFDIR
- HANDLE_TYPE(S_IFDIR, "d"); /* directory */
-#endif
-#ifdef S_IFLNK
- HANDLE_TYPE(S_IFLNK, "l"); /* symbolic link */
-#endif
-#ifdef S_IFSOCK
- HANDLE_TYPE(S_IFSOCK, "s"); /* Unix domain socket */
-#endif
-#ifdef S_IFBLK
- HANDLE_TYPE(S_IFBLK, "b"); /* block device */
-#endif
-#ifdef S_IFCHR
- HANDLE_TYPE(S_IFCHR, "c"); /* character device */
-#endif
-#ifdef S_IFIFO
- HANDLE_TYPE(S_IFIFO, "p"); /* FIFO */
-#endif
-#ifdef S_IFDOOR
- HANDLE_TYPE(S_IFDOOR, "D"); /* Door (e.g. on Solaris) */
-#endif
- return "U"; /* Unknown */
-}
-
-static double
-file_sparseness(const struct stat *p)
-{
-#if defined HAVE_STRUCT_STAT_ST_BLOCKS
- if (0 == p->st_size)
- {
- if (0 == p->st_blocks)
- return 1.0;
- else
- return p->st_blocks < 0 ? -HUGE_VAL : HUGE_VAL;
- }
- else
- {
- double blklen = file_blocksize(p) * (double)p->st_blocks;
- return blklen / p->st_size;
- }
-#else
- return 1.0;
-#endif
+ fputs (pathname, pred_ptr->args.stream);
+ putc ('\n', pred_ptr->args.stream);
+ return (true);
}
-
-
-static void
-checked_fprintf(struct format_val *dest, const char *fmt, ...)
-{
- int rv;
- va_list ap;
-
- va_start(ap, fmt);
- rv = vfprintf(dest->stream, fmt, ap);
- if (rv < 0)
- nonfatal_file_error(dest->filename);
-}
-
-
-static void
-checked_print_quoted (struct format_val *dest,
- const char *format, const char *s)
+boolean
+pred_fprint0 (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- int rv = print_quoted(dest->stream, dest->quote_opts, dest->dest_is_tty,
- format, s);
- if (rv < 0)
- nonfatal_file_error(dest->filename);
+ fputs (pathname, pred_ptr->args.stream);
+ putc (0, pred_ptr->args.stream);
+ return (true);
}
-
-static void
-checked_fwrite(void *p, size_t siz, size_t nmemb, struct format_val *dest)
+boolean
+pred_fprintf (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- int items_written = fwrite(p, siz, nmemb, dest->stream);
- if (items_written < nmemb)
- nonfatal_file_error(dest->filename);
-}
+ FILE *fp = pred_ptr->args.printf_vec.stream;
+ struct segment *segment;
+ char *cp;
-static void
-checked_fflush(struct format_val *dest)
-{
- if (0 != fflush(dest->stream))
+ for (segment = pred_ptr->args.printf_vec.segment; segment;
+ segment = segment->next)
{
- nonfatal_file_error(dest->filename);
- }
-}
+ if (segment->kind & 0xff00) /* Component of date. */
+ {
+ time_t t;
-static void
-do_fprintf(struct format_val *dest,
- struct segment *segment,
- const char *pathname,
- const struct stat *stat_buf)
-{
- char hbuf[LONGEST_HUMAN_READABLE + 1];
- const char *cp;
+ switch (segment->kind & 0xff)
+ {
+ case 'A':
+ t = stat_buf->st_atime;
+ break;
+ case 'C':
+ t = stat_buf->st_ctime;
+ break;
+ case 'T':
+ t = stat_buf->st_mtime;
+ break;
+ default:
+ abort ();
+ }
+ fprintf (fp, segment->text,
+ format_date (t, (segment->kind >> 8) & 0xff));
+ continue;
+ }
- switch (segment->segkind)
- {
- case KIND_PLAIN: /* Plain text string (no % conversion). */
- /* trusted */
- checked_fwrite(segment->text, 1, segment->text_len, dest);
- break;
-
- case KIND_STOP: /* Terminate argument and flush output. */
- /* trusted */
- checked_fwrite(segment->text, 1, segment->text_len, dest);
- checked_fflush(dest);
- break;
-
- case KIND_FORMAT:
- switch (segment->format_char[0])
+ switch (segment->kind)
{
+ case KIND_PLAIN: /* Plain text string (no % conversion). */
+ fwrite (segment->text, 1, segment->text_len, fp);
+ break;
+ case KIND_STOP: /* Terminate argument and flush output. */
+ fwrite (segment->text, 1, segment->text_len, fp);
+ fflush (fp);
+ return (true);
case 'a': /* atime in `ctime' format. */
- /* UNTRUSTED, probably unexploitable */
- checked_fprintf (dest, segment->text, ctime_format (get_stat_atime(stat_buf)));
+ cp = ctime (&stat_buf->st_atime);
+ cp[24] = '\0';
+ fprintf (fp, segment->text, cp);
break;
case 'b': /* size in 512-byte blocks */
- /* UNTRUSTED, probably unexploitable */
- checked_fprintf (dest, segment->text,
- human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf),
- hbuf, human_ceiling,
- ST_NBLOCKSIZE, 512));
+ fprintf (fp, segment->text, ST_NBLOCKS (stat_buf));
break;
case 'c': /* ctime in `ctime' format */
- /* UNTRUSTED, probably unexploitable */
- checked_fprintf (dest, segment->text, ctime_format (get_stat_ctime(stat_buf)));
+ cp = ctime (&stat_buf->st_ctime);
+ cp[24] = '\0';
+ fprintf (fp, segment->text, cp);
break;
case 'd': /* depth in search tree */
- /* UNTRUSTED, probably unexploitable */
- checked_fprintf (dest, segment->text, state.curdepth);
- break;
- case 'D': /* Device on which file exists (stat.st_dev) */
- /* trusted */
- checked_fprintf (dest, segment->text,
- human_readable ((uintmax_t) stat_buf->st_dev, hbuf,
- human_ceiling, 1, 1));
+ fprintf (fp, segment->text, curdepth);
break;
- case 'f': /* base name of path */
- /* sanitised */
- {
- char *base = base_name (pathname);
- checked_print_quoted (dest, segment->text, base);
- free (base);
- }
+ case 'f': /* basename of path */
+ cp = strrchr (pathname, '/');
+ if (cp)
+ cp++;
+ else
+ cp = pathname;
+ fprintf (fp, segment->text, cp);
break;
- case 'F': /* file system type */
- /* trusted */
- checked_print_quoted (dest, segment->text, filesystem_type (stat_buf, pathname));
+ case 'F': /* filesystem type */
+ fprintf (fp, segment->text,
+ filesystem_type (pathname, rel_pathname, stat_buf));
break;
case 'g': /* group name */
- /* trusted */
- /* (well, the actual group is selected by the user but
- * its name was selected by the system administrator)
- */
{
struct group *g;
@@ -787,158 +585,77 @@ do_fprintf(struct format_val *dest,
if (g)
{
segment->text[segment->text_len] = 's';
- checked_fprintf (dest, segment->text, g->gr_name);
+ fprintf (fp, segment->text, g->gr_name);
break;
}
- else
- {
- /* Do nothing. */
- /*FALLTHROUGH*/
- }
+ /* else fallthru */
}
- /*FALLTHROUGH*/ /*...sometimes, so 'G' case.*/
-
case 'G': /* GID number */
- /* UNTRUSTED, probably unexploitable */
- checked_fprintf (dest, segment->text,
- human_readable ((uintmax_t) stat_buf->st_gid, hbuf,
- human_ceiling, 1, 1));
+ segment->text[segment->text_len] = 'u';
+ fprintf (fp, segment->text, stat_buf->st_gid);
break;
case 'h': /* leading directories part of path */
- /* sanitised */
{
+ char cc;
+
cp = strrchr (pathname, '/');
if (cp == NULL) /* No leading directories. */
- {
- /* If there is no slash in the pathname, we still
- * print the string because it contains characters
- * other than just '%s'. The %h expands to ".".
- */
- checked_print_quoted (dest, segment->text, ".");
- }
- else
- {
- char *s = strdup(pathname);
- s[cp - pathname] = 0;
- checked_print_quoted (dest, segment->text, s);
- free(s);
- }
+ break;
+ cc = *cp;
+ *cp = '\0';
+ fprintf (fp, segment->text, pathname);
+ *cp = cc;
+ break;
}
- break;
-
case 'H': /* ARGV element file was found under */
- /* trusted */
{
- char *s = xmalloc(state.starting_path_length+1);
- memcpy(s, pathname, state.starting_path_length);
- s[state.starting_path_length] = 0;
- checked_fprintf (dest, segment->text, s);
- free(s);
- }
- break;
+ char cc = pathname[path_length];
+ pathname[path_length] = '\0';
+ fprintf (fp, segment->text, pathname);
+ pathname[path_length] = cc;
+ break;
+ }
case 'i': /* inode number */
- /* UNTRUSTED, but not exploitable I think */
- checked_fprintf (dest, segment->text,
- human_readable ((uintmax_t) stat_buf->st_ino, hbuf,
- human_ceiling,
- 1, 1));
+ fprintf (fp, segment->text, stat_buf->st_ino);
break;
case 'k': /* size in 1K blocks */
- /* UNTRUSTED, but not exploitable I think */
- checked_fprintf (dest, segment->text,
- human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf),
- hbuf, human_ceiling,
- ST_NBLOCKSIZE, 1024));
+ fprintf (fp, segment->text, (ST_NBLOCKS (stat_buf) + 1) / 2);
break;
case 'l': /* object of symlink */
- /* sanitised */
#ifdef S_ISLNK
{
char *linkname = 0;
if (S_ISLNK (stat_buf->st_mode))
{
- linkname = get_link_name_at (pathname, state.cwd_dir_fd, state.rel_pathname);
+ linkname = get_link_name (pathname, rel_pathname);
if (linkname == 0)
- state.exit_status = 1;
+ exit_status = 1;
}
if (linkname)
{
- checked_print_quoted (dest, segment->text, linkname);
+ fprintf (fp, segment->text, linkname);
free (linkname);
}
else
- {
- /* We still need to honour the field width etc., so this is
- * not a no-op.
- */
- checked_print_quoted (dest, segment->text, "");
- }
+ fprintf (fp, segment->text, "");
}
#endif /* S_ISLNK */
break;
-
- case 'M': /* mode as 10 chars (eg., "-rwxr-x--x" */
- /* UNTRUSTED, probably unexploitable */
- {
- char modestring[16] ;
- filemodestring (stat_buf, modestring);
- modestring[10] = '\0';
- checked_fprintf (dest, segment->text, modestring);
- }
- break;
-
case 'm': /* mode as octal number (perms only) */
- /* UNTRUSTED, probably unexploitable */
- {
- /* Output the mode portably using the traditional numbers,
- even if the host unwisely uses some other numbering
- scheme. But help the compiler in the common case where
- the host uses the traditional numbering scheme. */
- mode_t m = stat_buf->st_mode;
- boolean traditional_numbering_scheme =
- (S_ISUID == 04000 && S_ISGID == 02000 && S_ISVTX == 01000
- && S_IRUSR == 00400 && S_IWUSR == 00200 && S_IXUSR == 00100
- && S_IRGRP == 00040 && S_IWGRP == 00020 && S_IXGRP == 00010
- && S_IROTH == 00004 && S_IWOTH == 00002 && S_IXOTH == 00001);
- checked_fprintf (dest, segment->text,
- (traditional_numbering_scheme
- ? m & MODE_ALL
- : ((m & S_ISUID ? 04000 : 0)
- | (m & S_ISGID ? 02000 : 0)
- | (m & S_ISVTX ? 01000 : 0)
- | (m & S_IRUSR ? 00400 : 0)
- | (m & S_IWUSR ? 00200 : 0)
- | (m & S_IXUSR ? 00100 : 0)
- | (m & S_IRGRP ? 00040 : 0)
- | (m & S_IWGRP ? 00020 : 0)
- | (m & S_IXGRP ? 00010 : 0)
- | (m & S_IROTH ? 00004 : 0)
- | (m & S_IWOTH ? 00002 : 0)
- | (m & S_IXOTH ? 00001 : 0))));
- }
+ fprintf (fp, segment->text, stat_buf->st_mode & 07777);
break;
-
case 'n': /* number of links */
- /* UNTRUSTED, probably unexploitable */
- checked_fprintf (dest, segment->text,
- human_readable ((uintmax_t) stat_buf->st_nlink,
- hbuf,
- human_ceiling,
- 1, 1));
+ fprintf (fp, segment->text, stat_buf->st_nlink);
break;
-
case 'p': /* pathname */
- /* sanitised */
- checked_print_quoted (dest, segment->text, pathname);
+ fprintf (fp, segment->text, pathname);
break;
-
case 'P': /* pathname with ARGV element stripped */
- /* sanitised */
- if (state.curdepth > 0)
+ if (curdepth)
{
- cp = pathname + state.starting_path_length;
+ cp = pathname + path_length;
if (*cp == '/')
/* Move past the slash between the ARGV element
and the rest of the pathname. But if the ARGV element
@@ -947,36 +664,18 @@ do_fprintf(struct format_val *dest,
cp++;
}
else
- {
- cp = "";
- }
- checked_print_quoted (dest, segment->text, cp);
+ cp = "";
+ fprintf (fp, segment->text, cp);
break;
-
case 's': /* size in bytes */
- /* UNTRUSTED, probably unexploitable */
- checked_fprintf (dest, segment->text,
- human_readable ((uintmax_t) stat_buf->st_size,
- hbuf, human_ceiling, 1, 1));
+ fprintf (fp, segment->text, stat_buf->st_size);
break;
-
- case 'S': /* sparseness */
- /* UNTRUSTED, probably unexploitable */
- checked_fprintf (dest, segment->text, file_sparseness(stat_buf));;
- break;
-
case 't': /* mtime in `ctime' format */
- /* UNTRUSTED, probably unexploitable */
- checked_fprintf (dest, segment->text,
- ctime_format (get_stat_mtime(stat_buf)));
+ cp = ctime (&stat_buf->st_mtime);
+ cp[24] = '\0';
+ fprintf (fp, segment->text, cp);
break;
-
case 'u': /* user name */
- /* trusted */
- /* (well, the actual user is selected by the user on systems
- * where chown is not restricted, but the user name was
- * selected by the system administrator)
- */
{
struct passwd *p;
@@ -984,177 +683,50 @@ do_fprintf(struct format_val *dest,
if (p)
{
segment->text[segment->text_len] = 's';
- checked_fprintf (dest, segment->text, p->pw_name);
+ fprintf (fp, segment->text, p->pw_name);
break;
}
/* else fallthru */
}
- /* FALLTHROUGH*/ /* .. to case U */
-
case 'U': /* UID number */
- /* UNTRUSTED, probably unexploitable */
- checked_fprintf (dest, segment->text,
- human_readable ((uintmax_t) stat_buf->st_uid, hbuf,
- human_ceiling, 1, 1));
- break;
-
- /* %Y: type of file system entry like `ls -l`:
- * (d,-,l,s,p,b,c,n) n=nonexistent(symlink)
- */
- case 'Y': /* in case of symlink */
- /* trusted */
- {
-#ifdef S_ISLNK
- if (S_ISLNK (stat_buf->st_mode))
- {
- struct stat sbuf;
- /* If we would normally follow links, do not do so.
- * If we would normally not follow links, do so.
- */
- if ((following_links() ? lstat : stat)
- (state.rel_pathname, &sbuf) != 0)
- {
- if ( errno == ENOENT )
- {
- checked_fprintf (dest, segment->text, "N");
- break;
- }
- else if ( errno == ELOOP )
- {
- checked_fprintf (dest, segment->text, "L");
- break;
- }
- else
- {
- checked_fprintf (dest, segment->text, "?");
- error (0, errno, "%s",
- safely_quote_err_filename(0, pathname));
- /* exit_status = 1;
- return ; */
- break;
- }
- }
- checked_fprintf (dest, segment->text,
- mode_to_filetype(sbuf.st_mode & S_IFMT));
- }
-#endif /* S_ISLNK */
- else
- {
- checked_fprintf (dest, segment->text,
- mode_to_filetype(stat_buf->st_mode & S_IFMT));
- }
- }
- break;
-
- case 'y':
- /* trusted */
- {
- checked_fprintf (dest, segment->text,
- mode_to_filetype(stat_buf->st_mode & S_IFMT));
- }
+ segment->text[segment->text_len] = 'u';
+ fprintf (fp, segment->text, stat_buf->st_uid);
break;
}
- /* end of KIND_FORMAT case */
- break;
- }
-}
-
-boolean
-pred_fprintf (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
-{
- struct format_val *dest = &pred_ptr->args.printf_vec;
- struct segment *segment;
-
- for (segment = dest->segment; segment; segment = segment->next)
- {
- if ( (KIND_FORMAT == segment->segkind) && segment->format_char[1]) /* Component of date. */
- {
- struct timespec ts;
- int valid = 0;
-
- switch (segment->format_char[0])
- {
- case 'A':
- ts = get_stat_atime(stat_buf);
- valid = 1;
- break;
- case 'B':
- ts = get_stat_birthtime(stat_buf);
- if ('@' == segment->format_char[1])
- valid = 1;
- else
- valid = (ts.tv_nsec >= 0);
- break;
- case 'C':
- ts = get_stat_ctime(stat_buf);
- valid = 1;
- break;
- case 'T':
- ts = get_stat_mtime(stat_buf);
- valid = 1;
- break;
- default:
- assert (0);
- abort ();
- }
- /* We trust the output of format_date not to contain
- * nasty characters, though the value of the date
- * is itself untrusted data.
- */
- if (valid)
- {
- /* trusted */
- checked_fprintf (dest, segment->text,
- format_date (ts, segment->format_char[1]));
- }
- else
- {
- /* The specified timestamp is not available, output
- * nothing for the timestamp, but use the rest (so that
- * for example find foo -printf '[%Bs] %p\n' can print
- * "[] foo").
- */
- /* trusted */
- checked_fprintf (dest, segment->text, "");
- }
- }
- else
- {
- /* Print a segment which is not a date. */
- do_fprintf(dest, segment, pathname, stat_buf);
- }
}
- return true;
+ return (true);
}
boolean
-pred_fstype (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_fstype (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) pathname;
-
- if (strcmp (filesystem_type (stat_buf, pathname), pred_ptr->args.str) == 0)
- return true;
- else
- return false;
+ if (strcmp (filesystem_type (pathname, rel_pathname, stat_buf),
+ pred_ptr->args.str) == 0)
+ return (true);
+ return (false);
}
boolean
-pred_gid (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_gid (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) pathname;
-
- switch (pred_ptr->args.numinfo.kind)
+ switch (pred_ptr->args.info.kind)
{
case COMP_GT:
- if (stat_buf->st_gid > pred_ptr->args.numinfo.l_val)
+ if (stat_buf->st_gid > pred_ptr->args.info.l_val)
return (true);
break;
case COMP_LT:
- if (stat_buf->st_gid < pred_ptr->args.numinfo.l_val)
+ if (stat_buf->st_gid < pred_ptr->args.info.l_val)
return (true);
break;
case COMP_EQ:
- if (stat_buf->st_gid == pred_ptr->args.numinfo.l_val)
+ if (stat_buf->st_gid == pred_ptr->args.info.l_val)
return (true);
break;
}
@@ -1162,10 +734,11 @@ pred_gid (const char *pathname, struct stat *stat_buf, struct predicate *pred_pt
}
boolean
-pred_group (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_group (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) pathname;
-
if (pred_ptr->args.gid == stat_buf->st_gid)
return (true);
else
@@ -1173,60 +746,46 @@ pred_group (const char *pathname, struct stat *stat_buf, struct predicate *pred_
}
boolean
-pred_ilname (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_ilname (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- return match_lname (pathname, stat_buf, pred_ptr, true);
-}
-
-/* Common code between -name, -iname. PATHNAME is being visited, STR
- is name to compare basename against, and FLAGS are passed to
- fnmatch. Recall that 'find / -name /' is one of the few times where a '/'
- in the -name must actually find something. */
-static boolean
-pred_name_common (const char *pathname, const char *str, int flags)
-{
- boolean b;
- /* We used to use last_component() here, but that would not allow us to modify the
- * input string, which is const. We could optimise by duplicating the string only
- * if we need to modify it, and I'll do that if there is a measurable
- * performance difference on a machine built after 1990...
- */
- char *base = base_name (pathname);
- /* remove trailing slashes, but leave "/" or "//foo" unchanged. */
- strip_trailing_slashes(base);
-
- /* FNM_PERIOD is not used here because POSIX requires that it not be.
- * See http://standards.ieee.org/reading/ieee/interp/1003-2-92_int/pasc-1003.2-126.html
- */
- b = fnmatch (str, base, flags) == 0;
- free (base);
- return b;
+ return insert_lname (pathname, stat_buf, pred_ptr, true);
}
boolean
-pred_iname (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_iname (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) stat_buf;
- return pred_name_common (pathname, pred_ptr->args.str, FNM_CASEFOLD);
+ char *base;
+
+ base = basename (pathname);
+ if (fnmatch (pred_ptr->args.str, base, FNM_PERIOD | FNM_CASEFOLD) == 0)
+ return (true);
+ return (false);
}
boolean
-pred_inum (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_inum (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) pathname;
-
- switch (pred_ptr->args.numinfo.kind)
+ switch (pred_ptr->args.info.kind)
{
case COMP_GT:
- if (stat_buf->st_ino > pred_ptr->args.numinfo.l_val)
+ if (stat_buf->st_ino > pred_ptr->args.info.l_val)
return (true);
break;
case COMP_LT:
- if (stat_buf->st_ino < pred_ptr->args.numinfo.l_val)
+ if (stat_buf->st_ino < pred_ptr->args.info.l_val)
return (true);
break;
case COMP_EQ:
- if (stat_buf->st_ino == pred_ptr->args.numinfo.l_val)
+ if (stat_buf->st_ino == pred_ptr->args.info.l_val)
return (true);
break;
}
@@ -1234,32 +793,34 @@ pred_inum (const char *pathname, struct stat *stat_buf, struct predicate *pred_p
}
boolean
-pred_ipath (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_ipath (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) stat_buf;
-
if (fnmatch (pred_ptr->args.str, pathname, FNM_CASEFOLD) == 0)
return (true);
return (false);
}
boolean
-pred_links (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_links (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) pathname;
-
- switch (pred_ptr->args.numinfo.kind)
+ switch (pred_ptr->args.info.kind)
{
case COMP_GT:
- if (stat_buf->st_nlink > pred_ptr->args.numinfo.l_val)
+ if (stat_buf->st_nlink > pred_ptr->args.info.l_val)
return (true);
break;
case COMP_LT:
- if (stat_buf->st_nlink < pred_ptr->args.numinfo.l_val)
+ if (stat_buf->st_nlink < pred_ptr->args.info.l_val)
return (true);
break;
case COMP_EQ:
- if (stat_buf->st_nlink == pred_ptr->args.numinfo.l_val)
+ if (stat_buf->st_nlink == pred_ptr->args.info.l_val)
return (true);
break;
}
@@ -1267,19 +828,26 @@ pred_links (const char *pathname, struct stat *stat_buf, struct predicate *pred_
}
boolean
-pred_lname (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_lname (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- return match_lname (pathname, stat_buf, pred_ptr, false);
+ return insert_lname (pathname, stat_buf, pred_ptr, false);
}
static boolean
-match_lname (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, boolean ignore_case)
+insert_lname (pathname, stat_buf, pred_ptr, ignore_case)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
+ boolean ignore_case;
{
boolean ret = false;
#ifdef S_ISLNK
if (S_ISLNK (stat_buf->st_mode))
{
- char *linkname = get_link_name_at (pathname, state.cwd_dir_fd, state.rel_pathname);
+ char *linkname = get_link_name (pathname, rel_pathname);
if (linkname)
{
if (fnmatch (pred_ptr->args.str, linkname,
@@ -1289,103 +857,122 @@ match_lname (const char *pathname, struct stat *stat_buf, struct predicate *pred
}
}
#endif /* S_ISLNK */
- return ret;
-}
-
-boolean
-pred_ls (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
-{
- return pred_fls(pathname, stat_buf, pred_ptr);
+ return (ret);
}
boolean
-pred_mmin (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_ls (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) &pathname;
- return pred_timewindow(get_stat_mtime(stat_buf), pred_ptr, 60);
+ list_file (pathname, rel_pathname, stat_buf, stdout);
+ return (true);
}
boolean
-pred_mtime (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_mmin (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) pathname;
- return pred_timewindow(get_stat_mtime(stat_buf), pred_ptr, DAYSECS);
+ switch (pred_ptr->args.info.kind)
+ {
+ case COMP_GT:
+ if (stat_buf->st_mtime > (time_t) pred_ptr->args.info.l_val)
+ return (true);
+ break;
+ case COMP_LT:
+ if (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val)
+ return (true);
+ break;
+ case COMP_EQ:
+ if ((stat_buf->st_mtime >= (time_t) pred_ptr->args.info.l_val)
+ && (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val + 60))
+ return (true);
+ break;
+ }
+ return (false);
}
boolean
-pred_name (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_mtime (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) stat_buf;
- return pred_name_common (pathname, pred_ptr->args.str, 0);
+ switch (pred_ptr->args.info.kind)
+ {
+ case COMP_GT:
+ if (stat_buf->st_mtime > (time_t) pred_ptr->args.info.l_val)
+ return (true);
+ break;
+ case COMP_LT:
+ if (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val)
+ return (true);
+ break;
+ case COMP_EQ:
+ if ((stat_buf->st_mtime >= (time_t) pred_ptr->args.info.l_val)
+ && (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val
+ + DAYSECS))
+ return (true);
+ break;
+ }
+ return (false);
}
boolean
-pred_negate (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_name (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- return !apply_predicate(pathname, stat_buf, pred_ptr->pred_right);
-}
+ char *base;
-boolean
-pred_newer (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
-{
- (void) pathname;
-
- assert (COMP_GT == pred_ptr->args.reftime.kind);
- return compare_ts(get_stat_mtime(stat_buf), pred_ptr->args.reftime.ts) > 0;
+ base = basename (pathname);
+ if (fnmatch (pred_ptr->args.str, base, FNM_PERIOD) == 0)
+ return (true);
+ return (false);
}
boolean
-pred_newerXY (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_negate (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- struct timespec ts;
- boolean collected = false;
-
- assert (COMP_GT == pred_ptr->args.reftime.kind);
-
- switch (pred_ptr->args.reftime.xval)
+ /* Check whether we need a stat here. */
+ if (pred_ptr->need_stat)
{
- case XVAL_TIME:
- assert (pred_ptr->args.reftime.xval != XVAL_TIME);
- return false;
-
- case XVAL_ATIME:
- ts = get_stat_atime(stat_buf);
- collected = true;
- break;
-
- case XVAL_BIRTHTIME:
- ts = get_stat_birthtime(stat_buf);
- collected = true;
- if (ts.tv_nsec < 0);
+ if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
{
- /* XXX: Cannot determine birth time. Warn once. */
- error(0, 0, _("Warning: cannot determine birth time of file %s"),
- safely_quote_err_filename(0, pathname));
- return false;
+ error (0, errno, "%s", pathname);
+ exit_status = 1;
+ return (false);
}
- break;
-
- case XVAL_CTIME:
- ts = get_stat_ctime(stat_buf);
- collected = true;
- break;
-
- case XVAL_MTIME:
- ts = get_stat_mtime(stat_buf);
- collected = true;
- break;
+ have_stat = true;
}
-
- assert (collected);
- return compare_ts(ts, pred_ptr->args.reftime.ts) > 0;
+ return (!(*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
+ pred_ptr->pred_right));
}
boolean
-pred_nogroup (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_newer (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
+{
+ if (stat_buf->st_mtime > pred_ptr->args.time)
+ return (true);
+ return (false);
+}
+
+boolean
+pred_nogroup (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) pathname;
- (void) pred_ptr;
-
#ifdef CACHE_IDS
extern char *gid_unused;
@@ -1396,249 +983,157 @@ pred_nogroup (const char *pathname, struct stat *stat_buf, struct predicate *pre
}
boolean
-pred_nouser (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_nouser (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
#ifdef CACHE_IDS
extern char *uid_unused;
-#endif
-
- (void) pathname;
- (void) pred_ptr;
-
-#ifdef CACHE_IDS
+
return uid_unused[(unsigned) stat_buf->st_uid];
#else
return getpwuid (stat_buf->st_uid) == NULL;
#endif
}
-
-static boolean
-is_ok(const char *program, const char *arg)
+boolean
+pred_ok (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
+ int i, yes;
+
fflush (stdout);
- /* The draft open standard requires that, in the POSIX locale,
- the last non-blank character of this prompt be '?'.
- The exact format is not specified.
- This standard does not have requirements for locales other than POSIX
- */
- /* XXX: printing UNTRUSTED data here. */
- fprintf (stderr, _("< %s ... %s > ? "), program, arg);
+ fprintf (stderr, "< %s ... %s > ? ",
+ pred_ptr->args.exec_vec.vec[0], pathname);
fflush (stderr);
- return yesno();
-}
-
-boolean
-pred_ok (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
-{
- if (is_ok(pred_ptr->args.exec_vec.replace_vec[0], pathname))
- return new_impl_pred_exec (get_start_dirfd(),
- pathname, stat_buf, pred_ptr, NULL, 0);
- else
- return false;
-}
-
-boolean
-pred_okdir (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
-{
- const char *prefix = (state.rel_pathname[0] == '/') ? NULL : "./";
- if (is_ok(pred_ptr->args.exec_vec.replace_vec[0], pathname))
- return new_impl_pred_exec (get_current_dirfd(),
- state.rel_pathname, stat_buf, pred_ptr,
- prefix, (prefix ? 2 : 0));
- else
- return false;
+ i = getchar ();
+ yes = (i == 'y' || i == 'Y');
+ while (i != EOF && i != '\n')
+ i = getchar ();
+ if (!yes)
+ return (false);
+ return pred_exec (pathname, stat_buf, pred_ptr);
}
boolean
-pred_openparen (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_open (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) pathname;
- (void) stat_buf;
- (void) pred_ptr;
- return true;
+ return (true);
}
boolean
-pred_or (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_or (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
if (pred_ptr->pred_left == NULL
- || !apply_predicate(pathname, stat_buf, pred_ptr->pred_left))
+ || !(*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
+ pred_ptr->pred_left))
{
- return apply_predicate(pathname, stat_buf, pred_ptr->pred_right);
+ /* Check whether we need a stat here. */
+ if (pred_ptr->need_stat)
+ {
+ if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
+ {
+ error (0, errno, "%s", pathname);
+ exit_status = 1;
+ return (false);
+ }
+ have_stat = true;
+ }
+ return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
+ pred_ptr->pred_right));
}
else
- return true;
+ return (true);
}
boolean
-pred_path (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_path (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) stat_buf;
if (fnmatch (pred_ptr->args.str, pathname, 0) == 0)
return (true);
return (false);
}
boolean
-pred_perm (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_perm (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- mode_t mode = stat_buf->st_mode;
- mode_t perm_val = pred_ptr->args.perm.val[S_ISDIR (mode) != 0];
- (void) pathname;
- switch (pred_ptr->args.perm.kind)
+ if (pred_ptr->args.perm & 010000)
{
- case PERM_AT_LEAST:
- return (mode & perm_val) == perm_val;
- break;
-
- case PERM_ANY:
- /* True if any of the bits set in the mask are also set in the file's mode.
- *
- *
- * Otherwise, if onum is prefixed by a hyphen, the primary shall
- * evaluate as true if at least all of the bits specified in
- * onum that are also set in the octal mask 07777 are set.
- *
- * Eric Blake's interpretation is that the mode argument is zero,
-
- */
- if (0 == perm_val)
- return true; /* Savannah bug 14748; we used to return false */
- else
- return (mode & perm_val) != 0;
- break;
-
- case PERM_EXACT:
- return (mode & MODE_ALL) == perm_val;
- break;
-
- default:
- abort ();
- break;
+ /* Magic flag set in parse_perm:
+ true if at least the given bits are set. */
+ if ((stat_buf->st_mode & 07777 & pred_ptr->args.perm)
+ == (pred_ptr->args.perm & 07777))
+ return (true);
}
-}
-
-
-struct access_check_args
-{
- const char *filename;
- int access_type;
- int cb_errno;
-};
-
-
-static int
-access_callback(void *context)
-{
- int rv;
- struct access_check_args *args = context;
- if ((rv = access(args->filename, args->access_type)) < 0)
- args->cb_errno = errno;
- return rv;
-}
-
-static int
-can_access(int access_type)
-{
- struct access_check_args args;
- args.filename = state.rel_pathname;
- args.access_type = access_type;
- args.cb_errno = 0;
- return 0 == run_in_dir(state.cwd_dir_fd, access_callback, &args);
-}
-
-
-boolean
-pred_executable (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
-{
- (void) pathname;
- (void) stat_buf;
- (void) pred_ptr;
-
- return can_access(X_OK);
-}
-
-boolean
-pred_readable (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
-{
- (void) pathname;
- (void) stat_buf;
- (void) pred_ptr;
-
- return can_access(R_OK);
-}
-
-boolean
-pred_writable (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
-{
- (void) pathname;
- (void) stat_buf;
- (void) pred_ptr;
-
- return can_access(W_OK);
-}
-
-boolean
-pred_print (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
-{
- (void) stat_buf;
- (void) pred_ptr;
-
- print_quoted(pred_ptr->args.printf_vec.stream,
- pred_ptr->args.printf_vec.quote_opts,
- pred_ptr->args.printf_vec.dest_is_tty,
- "%s\n", pathname);
- return true;
+ else if (pred_ptr->args.perm & 020000)
+ {
+ /* Magic flag set in parse_perm:
+ true if any of the given bits are set. */
+ if ((stat_buf->st_mode & 07777) & pred_ptr->args.perm)
+ return (true);
+ }
+ else
+ {
+ /* True if exactly the given bits are set. */
+ if ((stat_buf->st_mode & 07777) == pred_ptr->args.perm)
+ return (true);
+ }
+ return (false);
}
boolean
-pred_print0 (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_print (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- return pred_fprint0(pathname, stat_buf, pred_ptr);
+ puts (pathname);
+ return (true);
}
boolean
-pred_prune (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_print0 (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) pathname;
- (void) pred_ptr;
-
- if (options.do_dir_first == true && /* no effect with -depth */
- stat_buf != NULL &&
- S_ISDIR(stat_buf->st_mode))
- state.stop_at_current_level = true;
-
- /* findutils used to return options.do_dir_first here, so that -prune
- * returns true only if -depth is not in effect. But POSIX requires
- * that -prune always evaluate as true.
- */
- return true;
+ fputs (pathname, stdout);
+ putc (0, stdout);
+ return (true);
}
boolean
-pred_quit (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_prune (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) pathname;
- (void) stat_buf;
- (void) pred_ptr;
-
- /* Run any cleanups. This includes executing any command lines
- * we have partly built but not executed.
- */
- cleanup();
-
- /* Since -exec and friends don't leave child processes running in the
- * background, there is no need to wait for them here.
- */
- exit(state.exit_status); /* 0 for success, etc. */
+ stop_at_current_level = true;
+ return (do_dir_first); /* This is what SunOS find seems to do. */
}
boolean
-pred_regex (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_regex (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
int len = strlen (pathname);
-(void) stat_buf;
if (re_match (pred_ptr->args.regex, pathname, len, 0,
(struct re_registers *) NULL) == len)
return (true);
@@ -1646,13 +1141,15 @@ pred_regex (const char *pathname, struct stat *stat_buf, struct predicate *pred_
}
boolean
-pred_size (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_size (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- uintmax_t f_val;
+ unsigned long f_val;
- (void) pathname;
- f_val = ((stat_buf->st_size / pred_ptr->args.size.blocksize)
- + (stat_buf->st_size % pred_ptr->args.size.blocksize != 0));
+ f_val = (stat_buf->st_size + pred_ptr->args.size.blocksize - 1)
+ / pred_ptr->args.size.blocksize;
switch (pred_ptr->args.size.kind)
{
case COMP_GT:
@@ -1672,57 +1169,22 @@ pred_size (const char *pathname, struct stat *stat_buf, struct predicate *pred_p
}
boolean
-pred_samefile (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
-{
- /* Potential optimisation: because of the loop protection, we always
- * know the device of the current directory, hence the device number
- * of the file we're currently considering. If -L is not in effect,
- * and the device number of the file we're looking for is not the
- * same as the device number of the current directory, this
- * predicate cannot return true. Hence there would be no need to
- * stat the file we're looking at.
- */
- (void) pathname;
-
- /* We will often still have an fd open on the file under consideration,
- * but that's just to ensure inode number stability by maintaining
- * a reference to it; we don't need the file for anything else.
- */
- return stat_buf->st_ino == pred_ptr->args.samefileid.ino
- && stat_buf->st_dev == pred_ptr->args.samefileid.dev;
-}
-
-boolean
-pred_true (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_true (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) pathname;
- (void) stat_buf;
- (void) pred_ptr;
- return true;
+ return (true);
}
boolean
-pred_type (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_type (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- mode_t mode;
- mode_t type = pred_ptr->args.type;
-
- assert (state.have_type);
-
- if (0 == state.type)
- {
- /* This can sometimes happen with broken NFS servers.
- * See Savannah bug #16378.
- */
- return false;
- }
-
- (void) pathname;
-
- if (state.have_stat)
- mode = stat_buf->st_mode;
- else
- mode = state.type;
+ unsigned long mode = stat_buf->st_mode;
+ unsigned long type = pred_ptr->args.type;
#ifndef S_IFMT
/* POSIX system; check `mode' the slow way. */
@@ -1739,9 +1201,6 @@ pred_type (const char *pathname, struct stat *stat_buf, struct predicate *pred_p
#ifdef S_IFSOCK
|| (S_ISSOCK (mode) && type == S_IFSOCK)
#endif
-#ifdef S_IFDOOR
- || (S_ISDOOR (mode) && type == S_IFDOOR)
-#endif
)
#else /* S_IFMT */
/* Unix system; check `mode' the fast way. */
@@ -1753,21 +1212,23 @@ pred_type (const char *pathname, struct stat *stat_buf, struct predicate *pred_p
}
boolean
-pred_uid (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_uid (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) pathname;
- switch (pred_ptr->args.numinfo.kind)
+ switch (pred_ptr->args.info.kind)
{
case COMP_GT:
- if (stat_buf->st_uid > pred_ptr->args.numinfo.l_val)
+ if (stat_buf->st_uid > pred_ptr->args.info.l_val)
return (true);
break;
case COMP_LT:
- if (stat_buf->st_uid < pred_ptr->args.numinfo.l_val)
+ if (stat_buf->st_uid < pred_ptr->args.info.l_val)
return (true);
break;
case COMP_EQ:
- if (stat_buf->st_uid == pred_ptr->args.numinfo.l_val)
+ if (stat_buf->st_uid == pred_ptr->args.info.l_val)
return (true);
break;
}
@@ -1775,29 +1236,39 @@ pred_uid (const char *pathname, struct stat *stat_buf, struct predicate *pred_pt
}
boolean
-pred_used (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_used (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- struct timespec delta, at, ct;
+ time_t delta;
- (void) pathname;
-
- /* TODO: this needs to be retested carefully (manually, if necessary) */
- at = get_stat_atime(stat_buf);
- ct = get_stat_ctime(stat_buf);
- delta.tv_sec = at.tv_sec - ct.tv_sec;
- delta.tv_nsec = at.tv_nsec - ct.tv_nsec;
- if (delta.tv_nsec < 0)
+ delta = stat_buf->st_atime - stat_buf->st_ctime; /* Use difftime? */
+ switch (pred_ptr->args.info.kind)
{
- delta.tv_nsec += 1000000000;
- delta.tv_sec -= 1;
+ case COMP_GT:
+ if (delta > (time_t) pred_ptr->args.info.l_val)
+ return (true);
+ break;
+ case COMP_LT:
+ if (delta < (time_t) pred_ptr->args.info.l_val)
+ return (true);
+ break;
+ case COMP_EQ:
+ if ((delta >= (time_t) pred_ptr->args.info.l_val)
+ && (delta < (time_t) pred_ptr->args.info.l_val + DAYSECS))
+ return (true);
+ break;
}
- return pred_timewindow(delta, pred_ptr, DAYSECS);
+ return (false);
}
boolean
-pred_user (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_user (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- (void) pathname;
if (pred_ptr->args.uid == stat_buf->st_uid)
return (true);
else
@@ -1805,40 +1276,24 @@ pred_user (const char *pathname, struct stat *stat_buf, struct predicate *pred_p
}
boolean
-pred_xtype (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+pred_xtype (pathname, stat_buf, pred_ptr)
+ char *pathname;
+ struct stat *stat_buf;
+ struct predicate *pred_ptr;
{
- struct stat sbuf; /* local copy, not stat_buf because we're using a different stat method */
- int (*ystat) (const char*, struct stat *p);
+ struct stat sbuf;
+ int (*ystat) ();
- /* If we would normally stat the link itself, stat the target instead.
- * If we would normally follow the link, stat the link itself instead.
- */
- if (following_links())
- ystat = optionp_stat;
- else
- ystat = optionl_stat;
-
- set_stat_placeholders(&sbuf);
- if ((*ystat) (state.rel_pathname, &sbuf) != 0)
+ ystat = xstat == lstat ? stat : lstat;
+ if ((*ystat) (rel_pathname, &sbuf) != 0)
{
- if (following_links() && errno == ENOENT)
- {
- /* If we failed to follow the symlink,
- * fall back on looking at the symlink itself.
- */
- /* Mimic behavior of ls -lL. */
- return (pred_type (pathname, stat_buf, pred_ptr));
- }
- else
- {
- error (0, errno, "%s", safely_quote_err_filename(0, pathname));
- state.exit_status = 1;
- }
- return false;
+ if (ystat == stat && errno == ENOENT)
+ /* Mimic behavior of ls -lL. */
+ return (pred_type (pathname, stat_buf, pred_ptr));
+ error (0, errno, "%s", pathname);
+ exit_status = 1;
+ return (false);
}
- /* Now that we have our stat() information, query it in the same
- * way that -type does.
- */
return (pred_type (pathname, &sbuf, pred_ptr));
}
@@ -1860,84 +1315,21 @@ pred_xtype (const char *pathname, struct stat *stat_buf, struct predicate *pred_
zero, and the exit arg (status high) is 0.
Otherwise return false, possibly printing an error message. */
-
static boolean
-prep_child_for_exec (boolean close_stdin, int dirfd)
-{
- boolean ok = true;
- if (close_stdin)
- {
- const char inputfile[] = "/dev/null";
-
- if (close(0) < 0)
- {
- error(0, errno, _("Cannot close standard input"));
- ok = false;
- }
- else
- {
- if (open(inputfile, O_RDONLY
-#if defined O_LARGEFILE
- |O_LARGEFILE
-#endif
- ) < 0)
- {
- /* This is not entirely fatal, since
- * executing the child with a closed
- * stdin is almost as good as executing it
- * with its stdin attached to /dev/null.
- */
- error (0, errno, "%s", safely_quote_err_filename(0, inputfile));
- /* do not set ok=false, it is OK to continue anyway. */
- }
- }
- }
-
- /* Even if DebugSearch is set, don't announce our change of
- * directory, since we're not going to emit a subsequent
- * announcement of a call to stat() anyway, as we're about to exec
- * something.
- */
- if (dirfd != AT_FDCWD)
- {
- assert (dirfd >= 0);
- if (0 != fchdir(dirfd))
- {
- /* If we cannot execute our command in the correct directory,
- * we should not execute it at all.
- */
- error(0, errno, _("Failed to change directory"));
- ok = false;
- }
- }
- return ok;
-}
-
-
-
-int
-launch (const struct buildcmd_control *ctl,
- struct buildcmd_state *buildstate)
+launch (pred_ptr)
+ struct predicate *pred_ptr;
{
- int wait_status;
- pid_t child_pid;
+ int status;
+ pid_t wait_ret, child_pid;
+ struct exec_val *execp; /* Pointer for efficiency. */
static int first_time = 1;
- const struct exec_val *execp = buildstate->usercontext;
- if (!execp->use_current_dir)
- {
- assert (starting_desc >= 0);
- assert (execp->dirfd == starting_desc);
- }
-
-
- /* Null terminate the arg list. */
- bc_push_arg (ctl, buildstate, (char *) NULL, 0, NULL, 0, false);
-
+ execp = &pred_ptr->args.exec_vec;
+
/* Make sure output of command doesn't get mixed with find output. */
fflush (stdout);
fflush (stderr);
-
+
/* Make sure to listen for the kids. */
if (first_time)
{
@@ -1947,275 +1339,150 @@ launch (const struct buildcmd_control *ctl,
child_pid = fork ();
if (child_pid == -1)
- error (1, errno, _("cannot fork"));
+ error (1, errno, "cannot fork");
if (child_pid == 0)
{
- /* We are the child. */
- assert (starting_desc >= 0);
- if (!prep_child_for_exec(execp->close_stdin, execp->dirfd))
+ /* We be the child. */
+#ifndef HAVE_FCHDIR
+ if (chdir (starting_dir) < 0)
{
- _exit(1);
+ error (0, errno, "%s", starting_dir);
+ _exit (1);
}
-
- execvp (buildstate->cmd_argv[0], buildstate->cmd_argv);
- error (0, errno, "%s",
- safely_quote_err_filename(0, buildstate->cmd_argv[0]));
+#else
+ if (fchdir (starting_desc) < 0)
+ {
+ error (0, errno, "cannot return to starting directory");
+ _exit (1);
+ }
+#endif
+ execvp (execp->vec[0], execp->vec);
+ error (0, errno, "%s", execp->vec[0]);
_exit (1);
}
-
- /* In parent; set up for next time. */
- bc_clear_args(ctl, buildstate);
-
-
- while (waitpid (child_pid, &wait_status, 0) == (pid_t) -1)
+ wait_ret = wait (&status);
+ if (wait_ret == -1)
{
- if (errno != EINTR)
- {
- error (0, errno, _("error waiting for %s"),
- safely_quote_err_filename(0, buildstate->cmd_argv[0]));
- state.exit_status = 1;
- return 0; /* FAIL */
- }
+ error (0, errno, "error waiting for %s", execp->vec[0]);
+ exit_status = 1;
+ return (false);
}
-
- if (WIFSIGNALED (wait_status))
+ if (wait_ret != child_pid)
{
- error (0, 0, _("%s terminated by signal %d"),
- quotearg_n_style(0, options.err_quoting_style,
- buildstate->cmd_argv[0]),
- WTERMSIG (wait_status));
-
- if (execp->multiple)
- {
- /* -exec \; just returns false if the invoked command fails.
- * -exec {} + returns true if the invoked command fails, but
- * sets the program exit status.
- */
- state.exit_status = 1;
- }
-
- return 1; /* OK */
+ error (0, 0, "wait got pid %d, expected pid %d", wait_ret, child_pid);
+ exit_status = 1;
+ return (false);
}
-
- if (0 == WEXITSTATUS (wait_status))
+ if (WIFSTOPPED (status))
{
- return 1; /* OK */
+ error (0, 0, "%s stopped by signal %d",
+ execp->vec[0], WSTOPSIG (status));
+ exit_status = 1;
+ return (false);
}
- else
+ if (WIFSIGNALED (status))
{
- if (execp->multiple)
- {
- /* -exec \; just returns false if the invoked command fails.
- * -exec {} + returns true if the invoked command fails, but
- * sets the program exit status.
- */
- state.exit_status = 1;
- }
- return 0; /* FAIL */
+ error (0, 0, "%s terminated by signal %d",
+ execp->vec[0], WTERMSIG (status));
+ exit_status = 1;
+ return (false);
}
-
+ return (!WEXITSTATUS (status));
}
-
/* Return a static string formatting the time WHEN according to the
- * strftime format character KIND.
- *
- * This function contains a number of assertions. These look like
- * runtime checks of the results of computations, which would be a
- * problem since external events should not be tested for with
- * "assert" (instead you should use "if"). However, they are not
- * really runtime checks. The assertions actually exist to verify
- * that the various buffers are correctly sized.
- */
+ strftime format character KIND. */
+
static char *
-format_date (struct timespec ts, int kind)
-{
- /* In theory, we use an extra 10 characters for 9 digits of
- * nanoseconds and 1 for the decimal point. However, the real
- * world is more complex than that.
- *
- * For example, some systems return junk in the tv_nsec part of
- * st_birthtime. An example of this is the NetBSD-4.0-RELENG kernel
- * (at Sat Mar 24 18:46:46 2007) running a NetBSD-3.1-RELEASE
- * runtime and examining files on an msdos filesytem. So for that
- * reason we set NS_BUF_LEN to 32, which is simply "long enough" as
- * opposed to "exactly the right size". Note that the behaviour of
- * NetBSD appears to be a result of the use of uninitialised data,
- * as it's not 100% reproducible (more like 25%).
- */
- enum {
- NS_BUF_LEN = 32,
- DATE_LEN_PERCENT_APLUS=21 /* length of result of %A+ (it's longer than %c)*/
- };
- static char buf[128u+10u + MAX(DATE_LEN_PERCENT_APLUS,
- MAX (LONGEST_HUMAN_READABLE + 2, NS_BUF_LEN+64+200))];
- char ns_buf[NS_BUF_LEN]; /* -.9999999990 (- sign can happen!)*/
- int charsprinted, need_ns_suffix;
- struct tm *tm;
- char fmt[6];
-
- /* human_readable() assumes we pass a buffer which is at least as
- * long as LONGEST_HUMAN_READABLE. We use an assertion here to
- * ensure that no nasty unsigned overflow happend in our calculation
- * of the size of buf. Do the assertion here rather than in the
- * code for %@ so that we find the problem quickly if it exists. If
- * you want to submit a patch to move this into the if statement, go
- * ahead, I'll apply it. But include performance timings
- * demonstrating that the performance difference is actually
- * measurable.
- */
- verify (sizeof(buf) >= LONGEST_HUMAN_READABLE);
-
- charsprinted = 0;
- need_ns_suffix = 0;
-
- /* Format the main part of the time. */
- if (kind == '+')
+format_date (when, kind)
+ time_t when;
+ int kind;
+{
+ static char fmt[3];
+ static char buf[64]; /* More than enough space. */
+
+ if (kind == '@')
{
- strcpy (fmt, "%F+%T");
- need_ns_suffix = 1;
+ sprintf (buf, "%ld", when);
+ return (buf);
}
else
{
fmt[0] = '%';
fmt[1] = kind;
fmt[2] = '\0';
-
- /* %a, %c, and %t are handled in ctime_format() */
- switch (kind)
- {
- case 'S':
- case 'T':
- case 'X':
- case '@':
- need_ns_suffix = 1;
- break;
- default:
- need_ns_suffix = 0;
- break;
- }
+ if (strftime (buf, sizeof (buf), fmt, localtime (&when)))
+ return (buf);
}
+ return "";
+}
+
+#ifdef DEBUG
+/* Return a pointer to the string representation of
+ the predicate function PRED_FUNC. */
- if (need_ns_suffix)
- {
- /* Format the nanoseconds part. Leave a trailing zero to
- * discourage people from writing scripts which extract the
- * fractional part of the timestamp by using column offsets.
- * The reason for discouraging this is that in the future, the
- * granularity may not be nanoseconds.
- */
- ns_buf[0] = 0;
- charsprinted = snprintf(ns_buf, NS_BUF_LEN, ".%09ld0", (long int)ts.tv_nsec);
- assert (charsprinted < NS_BUF_LEN);
- }
+char *
+find_pred_name (pred_func)
+ PFB pred_func;
+{
+ int i;
- if (kind != '@'
- && (tm = localtime (&ts.tv_sec))
- && strftime (buf, sizeof buf, fmt, tm))
- {
- /* For %AS, %CS, %TS, add the fractional part of the seconds
- * information.
- */
- if (need_ns_suffix)
- {
- assert ((sizeof buf - strlen(buf)) > strlen(ns_buf));
- strcat(buf, ns_buf);
- }
- return buf;
- }
- else
- {
- uintmax_t w = ts.tv_sec;
- size_t used, len, remaining;
-
- /* XXX: note that we are negating an unsigned type which is the
- * widest possible unsigned type.
- */
- char *p = human_readable (ts.tv_sec < 0 ? -w : w, buf + 1,
- human_ceiling, 1, 1);
- assert (p > buf);
- assert (p < (buf + (sizeof buf)));
- if (ts.tv_sec < 0)
- *--p = '-'; /* XXX: Ugh, relying on internal details of human_readable(). */
-
- /* Add the nanoseconds part. Because we cannot enforce a
- * particlar implementation of human_readable, we cannot assume
- * any particular value for (p-buf). So we need to be careful
- * that there is enough space remaining in the buffer.
- */
- if (need_ns_suffix)
- {
- len = strlen(p);
- used = (p-buf) + len; /* Offset into buf of current end */
- assert (sizeof buf > used); /* Ensure we can perform subtraction safely. */
- remaining = sizeof buf - used - 1u; /* allow space for NUL */
-
- if (strlen(ns_buf) >= remaining)
- {
- error(0, 0,
- "charsprinted=%ld but remaining=%lu: ns_buf=%s",
- (long)charsprinted, (unsigned long)remaining, ns_buf);
- }
- assert (strlen(ns_buf) < remaining);
- strcat(p, ns_buf);
- }
- return p;
- }
+ for (i = 0; pred_table[i].pred_func != 0; i++)
+ if (pred_table[i].pred_func == pred_func)
+ break;
+ return (pred_table[i].pred_name);
}
-static const char *weekdays[] =
- {
- "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
- };
-static char * months[] =
- {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- };
+static char *
+type_name (type)
+ short type;
+{
+ int i;
+ for (i = 0; type_table[i].type != (short) -1; i++)
+ if (type_table[i].type == type)
+ break;
+ return (type_table[i].type_name);
+}
static char *
-ctime_format (struct timespec ts)
+prec_name (prec)
+ short prec;
{
- const struct tm * ptm;
-#define TIME_BUF_LEN 1024u
- static char resultbuf[TIME_BUF_LEN];
- int nout;
-
- ptm = localtime(&ts.tv_sec);
- if (ptm)
- {
- assert (ptm->tm_wday >= 0);
- assert (ptm->tm_wday < 7);
- assert (ptm->tm_mon >= 0);
- assert (ptm->tm_mon < 12);
- assert (ptm->tm_hour >= 0);
- assert (ptm->tm_hour < 24);
- assert (ptm->tm_min < 60);
- assert (ptm->tm_sec <= 61); /* allows 2 leap seconds. */
-
- /* wkday mon mday hh:mm:ss.nnnnnnnnn yyyy */
- nout = snprintf(resultbuf, TIME_BUF_LEN,
- "%3s %3s %2d %02d:%02d:%02d.%010ld %04d",
- weekdays[ptm->tm_wday],
- months[ptm->tm_mon],
- ptm->tm_mday,
- ptm->tm_hour,
- ptm->tm_min,
- ptm->tm_sec,
- (long int)ts.tv_nsec,
- 1900 + ptm->tm_year);
-
- assert (nout < TIME_BUF_LEN);
- return resultbuf;
- }
- else
- {
- /* The time cannot be represented as a struct tm.
- Output it as an integer. */
- return format_date (ts, '@');
- }
+ int i;
+
+ for (i = 0; prec_table[i].prec != (short) -1; i++)
+ if (prec_table[i].prec == prec)
+ break;
+ return (prec_table[i].prec_name);
+}
+
+/* Walk the expression tree NODE to stdout.
+ INDENT is the number of levels to indent the left margin. */
+
+void
+print_tree (node, indent)
+ struct predicate *node;
+ int indent;
+{
+ int i;
+
+ if (node == NULL)
+ return;
+ for (i = 0; i < indent; i++)
+ printf (" ");
+ printf ("pred = %s type = %s prec = %s addr = %x\n",
+ find_pred_name (node->pred_func),
+ type_name (node->p_type), prec_name (node->p_prec), node);
+ for (i = 0; i < indent; i++)
+ printf (" ");
+ printf ("left:\n");
+ print_tree (node->pred_left, indent + 1);
+ for (i = 0; i < indent; i++)
+ printf (" ");
+ printf ("right:\n");
+ print_tree (node->pred_right, indent + 1);
}
/* Copy STR into BUF and trim blanks from the end of BUF.
@@ -2239,8 +1506,10 @@ blank_rtrim (str, buf)
}
/* Print out the predicate list starting at NODE. */
+
void
-print_list (FILE *fp, struct predicate *node)
+print_list (node)
+ struct predicate *node;
{
struct predicate *cur;
char name[256];
@@ -2248,161 +1517,9 @@ print_list (FILE *fp, struct predicate *node)
cur = node;
while (cur != NULL)
{
- fprintf (fp, "[%s] ", blank_rtrim (cur->p_name, name));
+ printf ("%s ", blank_rtrim (find_pred_name (cur->pred_func), name));
cur = cur->pred_next;
}
- fprintf (fp, "\n");
-}
-
-/* Print out the predicate list starting at NODE. */
-static void
-print_parenthesised(FILE *fp, struct predicate *node)
-{
- int parens = 0;
-
- if (node)
- {
- if ((pred_is(node, pred_or) || pred_is(node, pred_and))
- && node->pred_left == NULL)
- {
- /* We print "<nothing> or X" as just "X"
- * We print "<nothing> and X" as just "X"
- */
- print_parenthesised(fp, node->pred_right);
- }
- else
- {
- if (node->pred_left || node->pred_right)
- parens = 1;
-
- if (parens)
- fprintf(fp, "%s", " ( ");
- print_optlist(fp, node);
- if (parens)
- fprintf(fp, "%s", " ) ");
- }
- }
-}
-
-void
-print_optlist (FILE *fp, const struct predicate *p)
-{
- if (p)
- {
- print_parenthesised(fp, p->pred_left);
- fprintf (fp,
- "%s%s",
- p->need_stat ? "[call stat] " : "",
- p->need_type ? "[need type] " : "");
- print_predicate(fp, p);
- fprintf(fp, " [%g] ", p->est_success_rate);
- if (options.debug_options & DebugSuccessRates)
- {
- fprintf(fp, "[%ld/%ld", p->perf.successes, p->perf.visits);
- if (p->perf.visits)
- {
- double real_rate = (double)p->perf.successes / (double)p->perf.visits;
- fprintf(fp, "=%g] ", real_rate);
- }
- else
- {
- fprintf(fp, "=_] ");
- }
- }
- print_parenthesised(fp, p->pred_right);
- }
-}
-
-void show_success_rates(const struct predicate *p)
-{
- if (options.debug_options & DebugSuccessRates)
- {
- fprintf(stderr, "Predicate success rates after completion:\n");
- print_optlist(stderr, p);
- fprintf(stderr, "\n");
- }
-}
-
-
-
-
-#ifdef _NDEBUG
-/* If _NDEBUG is defined, the assertions will do nothing. Hence
- * there is no point in having a function body for pred_sanity_check()
- * if that preprocessor macro is defined.
- */
-void
-pred_sanity_check(const struct predicate *predicates)
-{
- /* Do nothing, since assert is a no-op with _NDEBUG set */
- return;
-}
-#else
-void
-pred_sanity_check(const struct predicate *predicates)
-{
- const struct predicate *p;
-
- for (p=predicates; p != NULL; p=p->pred_next)
- {
- /* All predicates must do something. */
- assert (p->pred_func != NULL);
-
- /* All predicates must have a parser table entry. */
- assert (p->parser_entry != NULL);
-
- /* If the parser table tells us that just one predicate function is
- * possible, verify that that is still the one that is in effect.
- * If the parser has NULL for the predicate function, that means that
- * the parse_xxx function fills it in, so we can't check it.
- */
- if (p->parser_entry->pred_func)
- {
- assert (p->parser_entry->pred_func == p->pred_func);
- }
-
- switch (p->parser_entry->type)
- {
- /* Options all take effect during parsing, so there should
- * be no predicate entries corresponding to them. Hence we
- * should not see any ARG_OPTION or ARG_POSITIONAL_OPTION
- * items.
- *
- * This is a silly way of coding this test, but it prevents
- * a compiler warning (i.e. otherwise it would think that
- * there would be case statements missing).
- */
- case ARG_OPTION:
- case ARG_POSITIONAL_OPTION:
- assert (p->parser_entry->type != ARG_OPTION);
- assert (p->parser_entry->type != ARG_POSITIONAL_OPTION);
- break;
-
- case ARG_ACTION:
- assert(p->side_effects); /* actions have side effects. */
- if (!pred_is(p, pred_prune) && !pred_is(p, pred_quit))
- {
- /* actions other than -prune and -quit should
- * inhibit the default -print
- */
- assert (p->no_default_print);
- }
- break;
-
- /* We happen to know that the only user of ARG_SPECIAL_PARSE
- * is a test, so handle it like ARG_TEST.
- */
- case ARG_SPECIAL_PARSE:
- case ARG_TEST:
- case ARG_PUNCTUATION:
- case ARG_NOOP:
- /* Punctuation and tests should have no side
- * effects and not inhibit default print.
- */
- assert (!p->no_default_print);
- assert (!p->side_effects);
- break;
- }
- }
+ printf ("\n");
}
-#endif
+#endif /* DEBUG */
diff --git a/find/tree.c b/find/tree.c
index 7420c604..22092427 100644
--- a/find/tree.c
+++ b/find/tree.c
@@ -1,62 +1,29 @@
/* tree.c -- helper functions to build and evaluate the expression tree.
- Copyright (C) 1990, 91, 92, 93, 94, 2000, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
+ 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 3 of the License, or
- (at your option) any later version.
-
+ 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, see <http://www.gnu.org/licenses/>.
-*/
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <config.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
#include "defs.h"
-#include <assert.h>
-#include <stdlib.h>
-
-#include "xalloc.h"
-#include "error.h"
-
-
-#if ENABLE_NLS
-# include <libintl.h>
-# define _(Text) gettext (Text)
-#else
-# define _(Text) Text
-#endif
-#ifdef gettext_noop
-# define N_(String) gettext_noop (String)
-#else
-/* See locate.c for explanation as to why not use (String) */
-# define N_(String) String
-#endif
-
-
-
-/* All predicates for each path to process. */
-static struct predicate *predicates = NULL;
-
-/* The root of the evaluation tree. */
-static struct predicate *eval_tree = NULL;
-
-/* The last predicate allocated. */
-static struct predicate *last_pred = NULL;
-
-
-static struct predicate *scan_rest PARAMS((struct predicate **input,
- struct predicate *head,
- short int prev_prec));
-static void merge_pred PARAMS((struct predicate *beg_list, struct predicate *end_list, struct predicate **last_p));
-static struct predicate *set_new_parent PARAMS((struct predicate *curr, enum predicate_precedence high_prec, struct predicate **prevp));
-static const char *cost_name PARAMS((enum EvaluationCost cost));
-
+static struct predicate *scan_rest P_((struct predicate **input, struct predicate *head, int prev_prec));
+static void merge_pred P_((struct predicate *beg_list, struct predicate *end_list, struct predicate **last_p));
+static struct predicate *set_new_parent P_((struct predicate *curr, enum predicate_precedence high_prec, struct predicate **prevp));
/* Return a pointer to a tree that represents the
expression prior to non-unary operator *INPUT.
@@ -78,48 +45,20 @@ static const char *cost_name PARAMS((enum EvaluationCost cost));
our caller, so get_expr recurses. */
struct predicate *
-get_expr (struct predicate **input,
- short int prev_prec,
- const struct predicate* prev_pred)
+get_expr (input, prev_prec)
+ struct predicate **input;
+ short prev_prec;
{
- struct predicate *next = NULL;
- struct predicate *this_pred = (*input);
+ struct predicate *next;
if (*input == NULL)
- error (1, 0, _("invalid expression"));
-
+ error (1, 0, "invalid expression");
switch ((*input)->p_type)
{
case NO_TYPE:
- error (1, 0, _("invalid expression"));
- break;
-
case BI_OP:
- /* e.g. "find . -a" */
- error (1, 0, _("invalid expression; you have used a binary operator '%s' with nothing before it."), this_pred->p_name);
- break;
-
case CLOSE_PAREN:
- if ((UNI_OP == prev_pred->p_type
- || BI_OP == prev_pred->p_type)
- && !this_pred->artificial)
- {
- /* e.g. "find \( -not \)" or "find \( -true -a \" */
- error(1, 0, _("expected an expression between '%s' and ')'"),
- prev_pred->p_name);
- }
- else if ( (*input)->artificial )
- {
- /* We have reached the end of the user-supplied predicates
- * unexpectedly.
- */
- /* e.g. "find . -true -a" */
- error (1, 0, _("expected an expression after '%s'"), prev_pred->p_name);
- }
- else
- {
- error (1, 0, _("invalid expression; you have too many ')'"));
- }
+ error (1, 0, "invalid expression");
break;
case PRIMARY_TYPE:
@@ -130,33 +69,20 @@ get_expr (struct predicate **input,
case UNI_OP:
next = *input;
*input = (*input)->pred_next;
- next->pred_right = get_expr (input, NEGATE_PREC, next);
+ next->pred_right = get_expr (input, NEGATE_PREC);
break;
case OPEN_PAREN:
- if ( (NULL == (*input)->pred_next) || (*input)->pred_next->artificial )
- {
- /* user typed something like "find . (", and so the ) we are
- * looking at is from the artificial "( ) -print" that we
- * add.
- */
- error (1, 0, _("invalid expression; expected to find a ')' but didn't see one. Perhaps you need an extra predicate after '%s'"), this_pred->p_name);
- }
- prev_pred = (*input);
*input = (*input)->pred_next;
- if ( (*input)->p_type == CLOSE_PAREN )
- {
- error (1, 0, _("invalid expression; empty parentheses are not allowed."));
- }
- next = get_expr (input, NO_PREC, prev_pred);
+ next = get_expr (input, NO_PREC);
if ((*input == NULL)
|| ((*input)->p_type != CLOSE_PAREN))
- error (1, 0, _("invalid expression; I was expecting to find a ')' somewhere but did not see one."));
+ error (1, 0, "invalid expression");
*input = (*input)->pred_next; /* move over close */
break;
-
+
default:
- error (1, 0, _("oops -- invalid expression type!"));
+ error (1, 0, "oops -- invalid expression type!");
break;
}
@@ -171,7 +97,7 @@ get_expr (struct predicate **input,
{
next = scan_rest (input, next, prev_prec);
if (next == NULL)
- error (1, 0, _("invalid expression"));
+ error (1, 0, "invalid expression");
}
return (next);
}
@@ -190,9 +116,10 @@ get_expr (struct predicate **input,
PREV_PREC is the precedence of the previous predicate element. */
static struct predicate *
-scan_rest (struct predicate **input,
- struct predicate *head,
- short int prev_prec)
+scan_rest (input, head, prev_prec)
+ struct predicate **input;
+ struct predicate *head;
+ short prev_prec;
{
struct predicate *tree; /* The new tree we are building. */
@@ -207,410 +134,26 @@ scan_rest (struct predicate **input,
case PRIMARY_TYPE:
case UNI_OP:
case OPEN_PAREN:
- /* I'm not sure how we get here, so it is not obvious what
- * sort of mistakes might give rise to this condition.
- */
- error (1, 0, _("invalid expression"));
+ error (1, 0, "invalid expression");
break;
case BI_OP:
- {
- struct predicate *prev = (*input);
- (*input)->pred_left = tree;
- tree = *input;
- *input = (*input)->pred_next;
- tree->pred_right = get_expr (input, tree->p_prec, prev);
- break;
- }
+ (*input)->pred_left = tree;
+ tree = *input;
+ *input = (*input)->pred_next;
+ tree->pred_right = get_expr (input, tree->p_prec);
+ break;
case CLOSE_PAREN:
- return tree;
+ return (tree);
default:
- error (1, 0,
- _("oops -- invalid expression type (%d)!"),
- (int)(*input)->p_type);
+ error (1, 0, "oops -- invalid expression type!");
break;
}
}
- return tree;
-}
-
-/* Returns true if the specified predicate is reorderable. */
-static boolean
-predicate_is_cost_free(const struct predicate *p)
-{
- if (pred_is(p, pred_name) ||
- pred_is(p, pred_path) ||
- pred_is(p, pred_iname) ||
- pred_is(p, pred_ipath))
- {
- /* Traditionally (at least 4.1.7 through 4.2.x) GNU find always
- * optimised these cases.
- */
- return true;
- }
- else if (options.optimisation_level > 0)
- {
- if (pred_is(p, pred_and) ||
- pred_is(p, pred_negate) ||
- pred_is(p, pred_comma) ||
- pred_is(p, pred_or))
- return false;
- else
- return NeedsNothing == p->p_cost;
- }
- else
- {
- return false;
- }
-}
-
-/* Prints a predicate */
-void print_predicate(FILE *fp, const struct predicate *p)
-{
- fprintf (fp, "%s%s%s",
- p->p_name,
- p->arg_text ? " " : "",
- p->arg_text ? p->arg_text : "");
-}
-
-
-struct predlist
-{
- struct predicate *head;
- struct predicate *tail;
-};
-
-static void
-predlist_init(struct predlist *p)
-{
- p->head = p->tail = NULL;
-}
-
-static void
-predlist_insert(struct predlist *list,
- struct predicate *curr,
- struct predicate **pprev)
-{
- struct predicate **insertpos = &(list->head);
-
- *pprev = curr->pred_left;
- if (options.optimisation_level > 2)
- {
- /* Insert the new node in the list after any other entries which
- * are more selective.
- */
- if (0)
- while ( (*insertpos) && ((*insertpos)->est_success_rate < curr->est_success_rate) )
- {
- insertpos = &((*insertpos)->pred_left);
- }
- }
- curr->pred_left = (*insertpos);
- (*insertpos) = curr;
- if (NULL == list->tail)
- list->tail = list->head;
-}
-
-static int
-pred_cost_compare(const struct predicate *p1, const struct predicate *p2, boolean wantfailure)
-{
- if (p1->p_cost == p2->p_cost)
- {
- if (p1->est_success_rate == p2->est_success_rate)
- return 0;
- else if (wantfailure)
- return p1->est_success_rate < p2->est_success_rate ? -1 : 1;
- else
- return p1->est_success_rate < p2->est_success_rate ? 1 : -1;
- }
- else
- {
- return p1->p_cost < p2->p_cost ? -1 : 1;
- }
-}
-
-
-static void
-predlist_merge_sort(struct predlist *list,
- struct predicate **last)
-{
- struct predlist new_list;
- struct predicate *p, *q;
-
- if (NULL == list->head)
- return; /* nothing to do */
-
- if (options.debug_options & DebugTreeOpt)
- {
- fprintf(stderr, "%s:\n", "predlist before merge sort");
- print_tree(stderr, list->head, 2);
- }
-
- calculate_derived_rates(list->head);
- predlist_init(&new_list);
- while (list->head)
- {
- /* remove head of source list */
- q = list->head;
- list->head = list->head->pred_left;
- q->pred_left = NULL;
-
- /* insert it into the new list */
- for (p=new_list.head; p; p=p->pred_left)
- {
- /* If these operations are OR operations, we want to get a
- * successful test as soon as possible, to take advantage of
- * the short-circuit evaluation. If they're AND, we want to
- * get an unsuccessful result early for the same reason.
- * Therefore we invert the sense of the comparison for the
- * OR case. We only want to invert the sense of the success
- * rate comparison, not the operation cost comparison. Hence we
- * pass a flag into pred_cost_compare().
- */
- boolean wantfailure = (OR_PREC != p->p_prec);
- if (pred_cost_compare(p->pred_right, q->pred_right, wantfailure) >= 0)
- break;
- }
- if (p)
- {
- /* insert into existing list */
- q->pred_left = p->pred_left;
- if (NULL == q->pred_left)
- new_list.tail = q;
- p->pred_left = q;
- }
- else
- {
- q->pred_left = new_list.head; /* prepend */
- new_list.head = q;
- if (NULL == new_list.tail)
- new_list.tail = q; /* first item in new list */
- }
- }
- if (options.debug_options & DebugTreeOpt)
- {
- fprintf(stderr, "%s:\n", "predlist after merge sort");
- print_tree(stderr, new_list.head, 2);
- }
-
- calculate_derived_rates(new_list.head);
- merge_pred(new_list.head, new_list.tail, last);
- predlist_init(list);
-}
-
-static void
-merge_lists(struct predlist lists[], int nlists,
- struct predlist *name_list,
- struct predlist *regex_list,
- struct predicate **last)
-{
- int i;
- static void (*mergefn)(struct predlist *, struct predicate**);
-
- mergefn = predlist_merge_sort;
-
- mergefn(name_list, last);
- mergefn(regex_list, last);
-
- for (i=0; i<nlists; i++)
- mergefn(&lists[i], last);
-}
-
-
-
-static boolean
-subtree_has_side_effects(const struct predicate *p)
-{
- if (p)
- {
- return p->side_effects
- || subtree_has_side_effects(p->pred_left)
- || subtree_has_side_effects(p->pred_right);
- }
- else
- {
-
- return false;
- }
-}
-
-static int
-worst_cost (const struct predicate *p)
-{
- if (p)
- {
- unsigned int cost_r, cost_l, worst;
- cost_l = worst_cost(p->pred_left);
- cost_r = worst_cost(p->pred_right);
- worst = (cost_l > cost_r) ? cost_l : cost_r;
- if (worst < p->p_cost)
- worst = p->p_cost;
- return worst;
- }
- else
- {
- return 0;
- }
-}
-
-
-
-static void
-perform_arm_swap(struct predicate *p)
-{
- struct predicate *tmp = p->pred_left->pred_right;
- p->pred_left->pred_right = p->pred_right;
- p->pred_right = tmp;
-}
-
-/* Consider swapping p->pred_left->pred_right with p->pred_right,
- * if that yields a faster evaluation. Normally the left predicate is
- * evaluated first.
- *
- * If the operation is an OR, we want the left predicate to be the one that
- * succeeds most often. If it is an AND, we want it to be the predicate that
- * fails most often.
- *
- * We don't consider swapping arms of an operator where their cost is
- * different or where they have side effects.
- *
- * A viable test case for this is
- * ./find -D opt -O3 . \! -type f -o -type d
- * Here, the ! -type f should be evaluated first,
- * as we assume that 95% of inodes are vanilla files.
- */
-static boolean
-consider_arm_swap(struct predicate *p)
-{
- int left_cost, right_cost;
- const char *reason = NULL;
- struct predicate **pl, **pr;
-
- if (BI_OP != p->p_type)
- reason = "Not a binary operation";
-
- if (!reason)
- {
- if (NULL == p->pred_left || NULL == p->pred_right)
- reason = "Doesn't have two arms";
- }
-
-
- if (!reason)
- {
- if (NULL == p->pred_left->pred_right)
- reason = "Left arm has no child on RHS";
- }
- pr = &p->pred_right;
- pl = &p->pred_left->pred_right;
-
- if (!reason)
- {
- if (subtree_has_side_effects(*pl))
- reason = "Left subtree has side-effects";
- }
- if (!reason)
- {
- if (subtree_has_side_effects(*pr))
- reason = "Right subtree has side-effects";
- }
-
- if (!reason)
- {
- left_cost = worst_cost(*pl);
- right_cost = worst_cost(*pr);
-
- if (left_cost < right_cost)
- {
- reason = "efficient as-is";
- }
- }
- if (!reason)
- {
- boolean want_swap;
-
- if (left_cost == right_cost)
- {
- /* it's a candidate */
- float succ_rate_l = (*pl)->est_success_rate;
- float succ_rate_r = (*pr)->est_success_rate;
-
- if (options.debug_options & DebugTreeOpt)
- {
- fprintf(stderr, "Success rates: l=%f, r=%f\n", succ_rate_l, succ_rate_r);
- }
-
- if (pred_is(p, pred_or))
- {
- want_swap = succ_rate_r < succ_rate_l;
- if (!want_swap)
- reason = "Operation is OR and right success rate >= left";
- }
- else if (pred_is(p, pred_and))
- {
- want_swap = succ_rate_r > succ_rate_l;
- if (!want_swap)
- reason = "Operation is AND and right success rate <= left";
- }
- else
- {
- want_swap = false;
- reason = "Not AND or OR";
- }
- }
- else
- {
- want_swap = true;
- }
-
- if (want_swap)
- {
- if (options.debug_options & DebugTreeOpt)
- {
- fprintf(stderr, "Performing arm swap on:\n");
- print_tree (stderr, p, 0);
- }
- perform_arm_swap(p);
- return true;
- }
- }
-
-
- if (options.debug_options & DebugTreeOpt)
- {
- fprintf(stderr, "Not an arm swap candidate (%s):\n", reason);
- print_tree (stderr, p, 0);
- }
- return false;
-}
-
-static boolean
-do_arm_swaps(struct predicate *p)
-{
- if (p)
- {
- boolean swapped;
- do
- {
- swapped = false;
- if (consider_arm_swap(p)
- || do_arm_swaps(p->pred_left)
- || do_arm_swaps(p->pred_right))
- {
- swapped = true;
- }
- } while (swapped);
- return swapped;
- }
- else
- {
- return false;
- }
+ return (tree);
}
-
-
/* Optimize the ordering of the predicates in the tree. Rearrange
them to minimize work. Strategies:
@@ -619,21 +162,10 @@ do_arm_swaps(struct predicate *p)
predicates (if any) which have "side effects", such as printing.
The grouping implements the partial ordering on predicates which
those with side effects impose.
+ * Place -name, -path, and -regex at the front of a group, with
+ -name and -path ahead of -regex. Predicates that are moved to the
+ front of a group by definition do not have side effects.
- * Place -name, -iname, -path, -ipath, -regex and -iregex at the front
- of a group, with -name, -iname, -path and -ipath ahead of
- -regex and -iregex. Predicates which are moved to the front
- of a group by definition do not have side effects. Both
- -regex and -iregex both use pred_regex.
-
- If higher optimisation levels have been selected, reordering also
- occurs according to the p_cost member of each predicate (which
- reflects the performance cost of the test). The ordering also
- bears in mind whether these operations are more likely to succeed
- or fail. When evauating a chain of OR conditions, we prefer
- tests likely to succeed at the front of the list. For AND, we
- prefer tests likely to fail at the front of the list.
-
This routine "normalizes" the predicate tree by ensuring that
all expression predicates have AND (or OR or COMMA) parent nodes
which are linked along the left edge of the expression tree.
@@ -643,27 +175,29 @@ do_arm_swaps(struct predicate *p)
to be rearranged. opt_expr may return a new root pointer there.
Return true if the tree contains side effects, false if not. */
-static boolean
-opt_expr (struct predicate **eval_treep)
+boolean
+opt_expr (eval_treep)
+ struct predicate **eval_treep;
{
- struct predlist regex_list={NULL,NULL}, name_list={NULL,NULL};
- struct predlist cbo_list[NumEvaluationCosts];
- int i;
+ /* List of -name and -path predicates to move. */
+ struct predicate *name_list = NULL;
+ struct predicate *end_name_list = NULL;
+ /* List of -regex predicates to move. */
+ struct predicate *regex_list = NULL;
+ struct predicate *end_regex_list = NULL;
struct predicate *curr;
struct predicate **prevp; /* Address of `curr' node. */
struct predicate **last_sidep; /* Last predicate with side effects. */
- PRED_FUNC pred_func;
+ PFB pred_func;
enum predicate_type p_type;
boolean has_side_effects = false; /* Return value. */
enum predicate_precedence prev_prec, /* precedence of last BI_OP in branch */
biop_prec; /* topmost BI_OP precedence in branch */
+
if (eval_treep == NULL || *eval_treep == NULL)
return (false);
- for (i=0; i<NumEvaluationCosts; i++)
- predlist_init(&cbo_list[i]);
-
/* Set up to normalize tree as a left-linked list of ANDs or ORs.
Set `curr' to the leftmost node, `prevp' to its address, and
`pred_func' to the predicate type of its parent. */
@@ -681,16 +215,14 @@ opt_expr (struct predicate **eval_treep)
if (curr->p_type != BI_OP)
set_new_parent (curr, prev_prec, prevp);
- if (options.debug_options & (DebugExpressionTree|DebugTreeOpt))
- {
- /* Normalized tree. */
- fprintf (stderr, "Normalized Eval Tree:\n");
- print_tree (stderr, *eval_treep, 0);
- }
-
+#ifdef DEBUG
+ /* Normalized tree. */
+ printf ("Normalized Eval Tree:\n");
+ print_tree (*eval_treep, 0);
+#endif
+
/* Rearrange the predicates. */
prevp = eval_treep;
- biop_prec = NO_PREC; /* not COMMA_PREC */
if ((*prevp) && (*prevp)->p_type == BI_OP)
biop_prec = (*prevp)->p_prec;
while ((curr = *prevp) != NULL)
@@ -705,68 +237,44 @@ opt_expr (struct predicate **eval_treep)
{
if (curr->p_prec != biop_prec)
curr = set_new_parent(curr, biop_prec, prevp);
+ else
+ biop_prec = curr->p_prec;
}
/* See which predicate type we have. */
p_type = curr->pred_right->p_type;
pred_func = curr->pred_right->pred_func;
-
switch (p_type)
{
case NO_TYPE:
case PRIMARY_TYPE:
- /* Don't rearrange the arguments of the comma operator, it is
- not commutative. */
- if (biop_prec == COMMA_PREC)
- break;
+ /* If it's one of our special primaries, move it to the
+ front of the list for that primary. */
+ if (pred_func == pred_name || pred_func == pred_path)
+ {
+ *prevp = curr->pred_left;
+ curr->pred_left = name_list;
+ name_list = curr;
- /* If this predicate has no side effects, consider reordering it. */
- if (!curr->pred_right->side_effects)
+ if (end_name_list == NULL)
+ end_name_list = curr;
+
+ continue;
+ }
+
+ if (pred_func == pred_regex)
{
- boolean reorder;
-
- /* If it's one of our special primaries, move it to the
- front of the list for that primary. */
- if (predicate_is_cost_free(curr->pred_right))
- {
- if (options.debug_options & DebugTreeOpt)
- {
- fprintf(stderr, "-O%d: promoting cheap predicate ",
- (int)options.optimisation_level);
- print_predicate(stderr, curr->pred_right);
- fprintf(stderr, " into name_list\n");
- }
- predlist_insert(&name_list, curr, prevp);
- continue;
- }
-
- if (pred_func == pred_regex)
- {
- predlist_insert(&regex_list, curr, prevp);
- continue;
- }
+ *prevp = curr->pred_left;
+ curr->pred_left = regex_list;
+ regex_list = curr;
+
+ if (end_regex_list == NULL)
+ end_regex_list = curr;
- reorder = ((options.optimisation_level > 1)
- && (NeedsType == curr->pred_right->p_cost)
- && !curr->pred_right->need_stat) ||
- (options.optimisation_level > 2);
-
- if (reorder)
- {
- if (options.debug_options & DebugTreeOpt)
- {
- fprintf(stderr, "-O%d: categorising predicate ",
- (int)options.optimisation_level);
- print_predicate(stderr, curr->pred_right);
- fprintf(stderr, " by cost (%s)\n",
- cost_name(curr->pred_right->p_cost));
- }
- predlist_insert(&cbo_list[curr->pred_right->p_cost], curr, prevp);
- continue;
- }
+ continue;
}
-
+
break;
case UNI_OP:
@@ -785,7 +293,7 @@ opt_expr (struct predicate **eval_treep)
all of the user's parentheses. */
default:
- error (1, 0, _("oops -- invalid expression type!"));
+ error (1, 0, "oops -- invalid expression type!");
break;
}
@@ -794,7 +302,18 @@ opt_expr (struct predicate **eval_treep)
last_sidep = prevp;
/* Incorporate lists and reset list pointers for this group. */
- merge_lists(cbo_list, NumEvaluationCosts, &name_list, &regex_list, last_sidep);
+ if (name_list != NULL)
+ {
+ merge_pred (name_list, end_name_list, last_sidep);
+ name_list = end_name_list = NULL;
+ }
+
+ if (regex_list != NULL)
+ {
+ merge_pred (regex_list, end_regex_list, last_sidep);
+ regex_list = end_regex_list = NULL;
+ }
+
has_side_effects = true;
}
@@ -803,59 +322,46 @@ opt_expr (struct predicate **eval_treep)
/* Do final list merges. */
last_sidep = prevp;
- merge_lists(cbo_list, NumEvaluationCosts, &name_list, &regex_list, last_sidep);
- return has_side_effects;
-}
-
-static float
-constrain_rate(float rate)
-{
- if (rate > 1.0f)
- return 1.0;
- else if (rate < 0.0)
- return 0.0;
- else
- return rate;
+ if (name_list != NULL)
+ merge_pred (name_list, end_name_list, last_sidep);
+ if (regex_list != NULL)
+ merge_pred (regex_list, end_regex_list, last_sidep);
+
+ return (has_side_effects);
}
-
+
/* Link in a new parent BI_OP node for CURR, at *PREVP, with precedence
HIGH_PREC. */
static struct predicate *
-set_new_parent (struct predicate *curr, enum predicate_precedence high_prec, struct predicate **prevp)
+set_new_parent (curr, high_prec, prevp)
+ struct predicate *curr;
+ enum predicate_precedence high_prec;
+ struct predicate **prevp;
{
struct predicate *new_parent;
- new_parent = xmalloc (sizeof (struct predicate));
+ new_parent = (struct predicate *) xmalloc (sizeof (struct predicate));
new_parent->p_type = BI_OP;
new_parent->p_prec = high_prec;
new_parent->need_stat = false;
- new_parent->need_type = false;
- new_parent->p_cost = NeedsNothing;
-
+
switch (high_prec)
{
case COMMA_PREC:
new_parent->pred_func = pred_comma;
- new_parent->p_name = ",";
- new_parent->est_success_rate = 1.0;
break;
case OR_PREC:
new_parent->pred_func = pred_or;
- new_parent->p_name = "-o";
- new_parent->est_success_rate = constrain_rate(curr->est_success_rate);
break;
case AND_PREC:
new_parent->pred_func = pred_and;
- new_parent->p_name = "-a";
- new_parent->est_success_rate = constrain_rate(curr->est_success_rate);
break;
default:
; /* empty */
}
new_parent->side_effects = false;
- new_parent->no_default_print = false;
new_parent->args.str = NULL;
new_parent->pred_next = NULL;
@@ -865,14 +371,19 @@ set_new_parent (struct predicate *curr, enum predicate_precedence high_prec, str
new_parent->pred_right = curr;
*prevp = new_parent;
- return new_parent;
+#ifdef DEBUG
+ new_parent->p_name = (char *) find_pred_name (new_parent->pred_func);
+#endif /* DEBUG */
+
+ return (new_parent);
}
/* Merge the predicate list that starts at BEG_LIST and ends at END_LIST
into the tree at LAST_P. */
static void
-merge_pred (struct predicate *beg_list, struct predicate *end_list, struct predicate **last_p)
+merge_pred (beg_list, end_list, last_p)
+ struct predicate *beg_list, *end_list, **last_p;
{
end_list->pred_left = *last_p;
*last_p = beg_list;
@@ -888,768 +399,35 @@ merge_pred (struct predicate *beg_list, struct predicate *end_list, struct predi
that a stat is made as late as possible. Return true if the top node
in TREE requires a stat, false if not. */
-
-struct pred_cost_lookup
-{
- PRED_FUNC fn;
- enum EvaluationCost cost;
-};
-static struct pred_cost_lookup costlookup[] =
- {
- { pred_amin , NeedsStatInfo },
- { pred_and , NeedsNothing, },
- { pred_anewer , NeedsStatInfo, },
- { pred_atime , NeedsStatInfo, },
- { pred_closeparen, NeedsNothing },
- { pred_cmin , NeedsStatInfo, },
- { pred_cnewer , NeedsStatInfo, },
- { pred_comma , NeedsNothing, },
- { pred_ctime , NeedsStatInfo, },
- { pred_delete , NeedsSyncDiskHit },
- { pred_empty , NeedsStatInfo },
- { pred_exec , NeedsEventualExec },
- { pred_execdir , NeedsEventualExec },
- { pred_executable, NeedsAccessInfo },
- { pred_false , NeedsNothing },
- { pred_fprint , NeedsNothing },
- { pred_fprint0 , NeedsNothing },
- { pred_fprintf , NeedsNothing },
- { pred_fstype , NeedsStatInfo }, /* true for amortised cost */
- { pred_gid , NeedsStatInfo },
- { pred_group , NeedsStatInfo },
- { pred_ilname , NeedsLinkName },
- { pred_iname , NeedsNothing },
- { pred_inum , NeedsStatInfo },
- { pred_ipath , NeedsNothing },
- { pred_links , NeedsStatInfo },
- { pred_lname , NeedsLinkName },
- { pred_ls , NeedsStatInfo },
- { pred_fls , NeedsStatInfo },
- { pred_mmin , NeedsStatInfo },
- { pred_mtime , NeedsStatInfo },
- { pred_name , NeedsNothing },
- { pred_negate , NeedsNothing, },
- { pred_newer , NeedsStatInfo, },
- { pred_newerXY , NeedsStatInfo, },
- { pred_nogroup , NeedsStatInfo }, /* true for amortised cost if caching is on */
- { pred_nouser , NeedsStatInfo }, /* true for amortised cost if caching is on */
- { pred_ok , NeedsUserInteraction },
- { pred_okdir , NeedsUserInteraction },
- { pred_openparen , NeedsNothing },
- { pred_or , NeedsNothing, },
- { pred_path , NeedsNothing },
- { pred_perm , NeedsStatInfo },
- { pred_print , NeedsNothing },
- { pred_print0 , NeedsNothing },
- { pred_prune , NeedsNothing },
- { pred_quit , NeedsNothing },
- { pred_readable , NeedsAccessInfo },
- { pred_regex , NeedsNothing },
- { pred_samefile , NeedsStatInfo },
- { pred_size , NeedsStatInfo },
- { pred_true , NeedsNothing },
- { pred_type , NeedsType },
- { pred_uid , NeedsStatInfo },
- { pred_used , NeedsStatInfo },
- { pred_user , NeedsStatInfo },
- { pred_writable , NeedsAccessInfo },
- { pred_xtype , NeedsType } /* roughly correct unless most files are symlinks */
- };
-static int pred_table_sorted = 0;
-
-static boolean
-check_sorted(void *base, size_t members, size_t membersize,
- int (*cmpfn)(const void*, const void*))
-{
- const char *p = base;
- size_t i;
- for (i=1u; i<members; ++i)
- {
- int result = cmpfn(p+i*membersize, p+(i-1)*membersize);
- if (result < 0)
- return false;
- result = cmpfn(p+(i-1)*membersize, p+i*membersize);
- assert (result <= 0);
- }
- return true;
-}
-
-
-static int
-cost_table_comparison(const void *p1, const void *p2)
-{
- /* We have to compare the function pointers with memcmp(),
- * because ISO C does not allow magnitude comparison of
- * function pointers (just equality testing).
- */
- const struct pred_cost_lookup *pc1 = p1;
- const struct pred_cost_lookup *pc2 = p2;
- union {
- PRED_FUNC pfn;
- char mem[sizeof (PRED_FUNC)];
- } u1, u2;
-
- u1.pfn = pc1->fn;
- u2.pfn = pc2->fn;
- return memcmp(u1.mem, u2.mem, sizeof(u1.pfn));
-}
-
-static enum EvaluationCost
-get_pred_cost(const struct predicate *p)
-{
- enum EvaluationCost data_requirement_cost = NeedsNothing;
- enum EvaluationCost inherent_cost = NeedsUnknown;
-
- if (p->need_stat)
- {
- data_requirement_cost = NeedsStatInfo;
- }
- else if (p->need_type)
- {
- data_requirement_cost = NeedsType;
- }
- else
- {
- data_requirement_cost = NeedsNothing;
- }
-
- if (pred_is(p, pred_exec) || pred_is(p, pred_execdir))
- {
- if (p->args.exec_vec.multiple)
- inherent_cost = NeedsEventualExec;
- else
- inherent_cost = NeedsImmediateExec;
- }
- else if (pred_is(p, pred_fprintf))
- {
- /* the parser calculated the cost for us. */
- inherent_cost = p->p_cost;
- }
- else
- {
- struct pred_cost_lookup key;
- void *entry;
-
- if (!pred_table_sorted)
- {
- qsort(costlookup,
- sizeof(costlookup)/sizeof(costlookup[0]),
- sizeof(costlookup[0]),
- cost_table_comparison);
-
- if (!check_sorted(costlookup,
- sizeof(costlookup)/sizeof(costlookup[0]),
- sizeof(costlookup[0]),
- cost_table_comparison))
- {
- error(1, 0, "Failed to sort the costlookup array (indirect).");
- }
- pred_table_sorted = 1;
- }
- key.fn = p->pred_func;
- entry = bsearch(&key, costlookup,
- sizeof(costlookup)/sizeof(costlookup[0]),
- sizeof(costlookup[0]),
- cost_table_comparison);
- if (entry)
- {
- inherent_cost = ((const struct pred_cost_lookup*)entry)->cost;
- }
- else
- {
- error(0, 0, "warning: no cost entry for predicate %s", p->p_name);
- inherent_cost = NeedsUnknown;
- }
- }
-
- if (inherent_cost > data_requirement_cost)
- return inherent_cost;
- else
- return data_requirement_cost;
-}
-
-static void
-estimate_costs (struct predicate *tree)
+boolean
+mark_stat (tree)
+ struct predicate *tree;
{
- if (tree)
- {
- estimate_costs(tree->pred_right);
- estimate_costs(tree->pred_left);
-
- tree->p_cost = get_pred_cost(tree);
- }
-}
-
-struct predicate*
-get_eval_tree(void)
-{
- return eval_tree;
-}
-
-static float
-getrate(const struct predicate *p)
-{
- if (p)
- return p->est_success_rate;
- else
- return 1.0f;
-}
-
-
-float
-calculate_derived_rates(struct predicate *p)
-{
- assert (NULL != p);
-
- if (p->pred_right)
- calculate_derived_rates(p->pred_right);
- if (p->pred_left)
- calculate_derived_rates(p->pred_left);
-
- assert (p->p_type != CLOSE_PAREN);
- assert (p->p_type != OPEN_PAREN);
-
- switch (p->p_type)
+ /* The tree is executed in-order, so walk this way (apologies to Aerosmith)
+ to find the first predicate for which the stat is needed. */
+ switch (tree->p_type)
{
case NO_TYPE:
- assert (NULL == p->pred_right);
- assert (NULL == p->pred_left);
- return p->est_success_rate;
-
case PRIMARY_TYPE:
- assert (NULL == p->pred_right);
- assert (NULL == p->pred_left);
- return p->est_success_rate;
+ return tree->need_stat;
case UNI_OP:
- /* Unary operators must have exactly one operand */
- assert (pred_is(p, pred_negate));
- assert (NULL == p->pred_left);
- p->est_success_rate = (1.0 - p->pred_right->est_success_rate);
- return p->est_success_rate;
+ if (mark_stat (tree->pred_right))
+ tree->need_stat = true;
+ return (false);
case BI_OP:
- {
- float rate;
- /* Binary operators must have two operands */
- if (pred_is(p, pred_and))
- {
- rate = getrate(p->pred_right) * getrate(p->pred_left);
- }
- else if (pred_is(p, pred_comma))
- {
- rate = 1.0f;
- }
- else if (pred_is(p, pred_or))
- {
- rate = getrate(p->pred_right) + getrate(p->pred_left);
- }
- else
- {
- /* only and, or and comma are BI_OP. */
- assert (0);
- abort ();
- }
- p->est_success_rate = constrain_rate(rate);
- }
- return p->est_success_rate;
-
- case OPEN_PAREN:
- case CLOSE_PAREN:
- p->est_success_rate = 1.0;
- return p->est_success_rate;
- }
- assert (0);
- abort ();
-}
-
-/* opt_expr() rearranges predicates such that each left subtree is
- * rooted at a logical predicate (e.g. and or or). check_normalization()
- * asserts that this property still holds.
- *
- */
-static void check_normalization(struct predicate *p, boolean at_root)
-{
- if (at_root)
- {
- assert (BI_OP == p->p_type);
- }
-
- if (p->pred_left)
- {
- assert (BI_OP == p->pred_left->p_type);
- check_normalization(p->pred_left, false);
- }
- if (p->pred_right)
- {
- check_normalization(p->pred_right, false);
- }
-}
-
-struct predicate*
-build_expression_tree(int argc, char *argv[], int end_of_leading_options)
-{
- const struct parser_table *parse_entry; /* Pointer to the parsing table entry for this expression. */
- char *predicate_name; /* Name of predicate being parsed. */
- struct predicate *cur_pred;
- const struct parser_table *entry_close, *entry_print, *entry_open;
- int i, oldi;
-
- predicates = NULL;
-
- /* Find where in ARGV the predicates begin by skipping the list of
- * start points.
- */
- for (i = end_of_leading_options; i < argc && !looks_like_expression(argv[i], true); i++)
- {
- /* Do nothing. */ ;
- }
-
- /* Enclose the expression in `( ... )' so a default -print will
- apply to the whole expression. */
- entry_open = find_parser("(");
- entry_close = find_parser(")");
- entry_print = find_parser("print");
- assert (entry_open != NULL);
- assert (entry_close != NULL);
- assert (entry_print != NULL);
-
- parse_openparen (entry_open, argv, &argc);
- last_pred->p_name = "(";
- predicates->artificial = true;
- parse_begin_user_args(argv, argc, last_pred, predicates);
- pred_sanity_check(last_pred);
-
- /* Build the input order list. */
- while (i < argc )
- {
- if (!looks_like_expression(argv[i], false))
- {
- error (0, 0, _("paths must precede expression: %s"), argv[i]);
- usage(stderr, 1, NULL);
- }
-
- predicate_name = argv[i];
- parse_entry = find_parser (predicate_name);
- if (parse_entry == NULL)
- {
- /* Command line option not recognized */
- error (1, 0, _("unknown predicate `%s'"), predicate_name);
- }
-
- /* We have recognised a test of the form -foo. Eat that,
- * unless it is a predicate like -newerXY.
- */
- if (parse_entry->type != ARG_SPECIAL_PARSE)
- {
- i++;
- }
- oldi = i;
- if (!(*(parse_entry->parser_func)) (parse_entry, argv, &i))
- {
- if (argv[i])
- {
- if ( (ARG_SPECIAL_PARSE == parse_entry->type) && (i == oldi) )
- {
- /* The special parse function spat out the
- * predicate. It must be invalid, or not tasty.
- */
- error (1, 0, _("invalid predicate `%s'"),
- predicate_name);
- }
- else
- {
- error (1, 0, _("invalid argument `%s' to `%s'"),
- argv[i], predicate_name);
- }
- }
- else
- {
- /* Command line option requires an argument */
- error (1, 0, _("missing argument to `%s'"), predicate_name);
- }
- }
- else
- {
- last_pred->p_name = predicate_name;
-
- /* If the parser consumed an argument, save it. */
- if (i != oldi)
- last_pred->arg_text = argv[oldi];
- else
- last_pred->arg_text = NULL;
- }
- pred_sanity_check(last_pred);
- pred_sanity_check(predicates); /* XXX: expensive */
- }
- parse_end_user_args(argv, argc, last_pred, predicates);
- if (predicates->pred_next == NULL)
- {
- /* No predicates that do something other than set a global variable
- were given; remove the unneeded initial `(' and add `-print'. */
- cur_pred = predicates;
- predicates = last_pred = predicates->pred_next;
- free (cur_pred);
- parse_print (entry_print, argv, &argc);
- last_pred->p_name = "-print";
- pred_sanity_check(last_pred);
- pred_sanity_check(predicates); /* XXX: expensive */
- }
- else if (!default_prints (predicates->pred_next))
- {
- /* One or more predicates that produce output were given;
- remove the unneeded initial `('. */
- cur_pred = predicates;
- predicates = predicates->pred_next;
- pred_sanity_check(predicates); /* XXX: expensive */
- free (cur_pred);
- }
- else
- {
- /* `( user-supplied-expression ) -print'. */
- parse_closeparen (entry_close, argv, &argc);
- last_pred->p_name = ")";
- last_pred->artificial = true;
- pred_sanity_check(last_pred);
- parse_print (entry_print, argv, &argc);
- last_pred->p_name = "-print";
- last_pred->artificial = true;
- pred_sanity_check(last_pred);
- pred_sanity_check(predicates); /* XXX: expensive */
- }
-
- if (options.debug_options & (DebugExpressionTree|DebugTreeOpt))
- {
- fprintf (stderr, "Predicate List:\n");
- print_list (stderr, predicates);
- }
-
- /* do a sanity check */
- check_option_combinations(predicates);
- pred_sanity_check(predicates);
-
- /* Done parsing the predicates. Build the evaluation tree. */
- cur_pred = predicates;
- eval_tree = get_expr (&cur_pred, NO_PREC, NULL);
- calculate_derived_rates(eval_tree);
-
- /* Check if we have any left-over predicates (this fixes
- * Debian bug #185202).
- */
- if (cur_pred != NULL)
- {
- /* cur_pred->p_name is often NULL here */
- if (pred_is(cur_pred, pred_closeparen))
- {
- /* e.g. "find \( -true \) \)" */
- error (1, 0, _("you have too many ')'"));
- }
- else
- {
- if (cur_pred->p_name)
- error (1, 0, _("unexpected extra predicate '%s'"), cur_pred->p_name);
- else
- error (1, 0, _("unexpected extra predicate"));
- }
- }
-
- if (options.debug_options & (DebugExpressionTree|DebugTreeOpt))
- {
- fprintf (stderr, "Eval Tree:\n");
- print_tree (stderr, eval_tree, 0);
- }
-
- estimate_costs(eval_tree);
-
- /* Rearrange the eval tree in optimal-predicate order. */
- opt_expr (&eval_tree);
-
- /* Check that the tree is in normalised order (opt_expr does this) */
- check_normalization(eval_tree, true);
-
- do_arm_swaps(eval_tree);
-
- /* Check that the tree is still in normalised order */
- check_normalization(eval_tree, true);
-
- if (options.debug_options & (DebugExpressionTree|DebugTreeOpt))
- {
- fprintf (stderr, "Optimized Eval Tree:\n");
- print_tree (stderr, eval_tree, 0);
- fprintf (stderr, "Optimized command line:\n");
- print_optlist(stderr, eval_tree);
- fprintf(stderr, "\n");
- }
-
- return eval_tree;
-}
-
-/* Initialise the performance data for a predicate.
- */
-static void
-init_pred_perf(struct predicate *pred)
-{
- struct predicate_performance_info *p = &pred->perf;
- p->visits = p->successes = 0;
-}
-
-
-/* Return a pointer to a new predicate structure, which has been
- linked in as the last one in the predicates list.
-
- Set `predicates' to point to the start of the predicates list.
- Set `last_pred' to point to the new last predicate in the list.
-
- Set all cells in the new structure to the default values. */
-
-struct predicate *
-get_new_pred (const struct parser_table *entry)
-{
- register struct predicate *new_pred;
- (void) entry;
-
- /* Options should not be turned into predicates. */
- assert (entry->type != ARG_OPTION);
- assert (entry->type != ARG_POSITIONAL_OPTION);
-
- if (predicates == NULL)
- {
- predicates = (struct predicate *)
- xmalloc (sizeof (struct predicate));
- last_pred = predicates;
- }
- else
- {
- new_pred = xmalloc (sizeof (struct predicate));
- last_pred->pred_next = new_pred;
- last_pred = new_pred;
- }
- last_pred->parser_entry = entry;
- last_pred->pred_func = NULL;
- last_pred->p_name = NULL;
- last_pred->p_type = NO_TYPE;
- last_pred->p_prec = NO_PREC;
- last_pred->side_effects = false;
- last_pred->no_default_print = false;
- last_pred->need_stat = true;
- last_pred->need_type = true;
- last_pred->args.str = NULL;
- last_pred->pred_next = NULL;
- last_pred->pred_left = NULL;
- last_pred->pred_right = NULL;
- last_pred->literal_control_chars = options.literal_control_chars;
- last_pred->artificial = false;
- last_pred->est_success_rate = 1.0;
- init_pred_perf(last_pred);
- return last_pred;
-}
-
-/* Return a pointer to a new predicate, with operator check.
- Like get_new_pred, but it checks to make sure that the previous
- predicate is an operator. If it isn't, the AND operator is inserted. */
+ /* ANDs and ORs are linked along ->left ending in NULL. */
+ if (tree->pred_left != NULL)
+ mark_stat (tree->pred_left);
-struct predicate *
-get_new_pred_chk_op (const struct parser_table *entry)
-{
- struct predicate *new_pred;
- static const struct parser_table *entry_and = NULL;
-
- /* Locate the entry in the parser table for the "and" operator */
- if (NULL == entry_and)
- entry_and = find_parser("and");
-
- /* Check that it's actually there. If not, that is a bug.*/
- assert (entry_and != NULL);
+ if (mark_stat (tree->pred_right))
+ tree->need_stat = true;
- if (last_pred)
- switch (last_pred->p_type)
- {
- case NO_TYPE:
- error (1, 0, _("oops -- invalid default insertion of and!"));
- break;
+ return (false);
- case PRIMARY_TYPE:
- case CLOSE_PAREN:
- /* We need to interpose the and operator. */
- new_pred = get_new_pred (entry_and);
- new_pred->pred_func = pred_and;
- new_pred->p_name = "-a";
- new_pred->p_type = BI_OP;
- new_pred->p_prec = AND_PREC;
- new_pred->need_stat = false;
- new_pred->need_type = false;
- new_pred->args.str = NULL;
- new_pred->side_effects = false;
- new_pred->no_default_print = false;
- break;
-
- default:
- break;
- }
-
- new_pred = get_new_pred (entry);
- new_pred->parser_entry = entry;
- return new_pred;
-}
-
-struct cost_assoc
-{
- enum EvaluationCost cost;
- char *name;
-};
-struct cost_assoc cost_table[] =
- {
- { NeedsNothing, "Nothing" },
- { NeedsType, "Type" },
- { NeedsStatInfo, "StatInfo" },
- { NeedsLinkName, "LinkName" },
- { NeedsAccessInfo, "AccessInfo" },
- { NeedsSyncDiskHit, "SyncDiskHit" },
- { NeedsEventualExec, "EventualExec" },
- { NeedsImmediateExec, "ImmediateExec" },
- { NeedsUserInteraction, "UserInteraction" },
- { NeedsUnknown, "Unknown" }
- };
-
-struct prec_assoc
-{
- short prec;
- char *prec_name;
-};
-
-static struct prec_assoc prec_table[] =
-{
- {NO_PREC, "no"},
- {COMMA_PREC, "comma"},
- {OR_PREC, "or"},
- {AND_PREC, "and"},
- {NEGATE_PREC, "negate"},
- {MAX_PREC, "max"},
- {-1, "unknown "}
-};
-
-struct op_assoc
-{
- short type;
- char *type_name;
-};
-
-static struct op_assoc type_table[] =
-{
- {NO_TYPE, "no"},
- {PRIMARY_TYPE, "primary"},
- {UNI_OP, "uni_op"},
- {BI_OP, "bi_op"},
- {OPEN_PAREN, "open_paren "},
- {CLOSE_PAREN, "close_paren "},
- {-1, "unknown"}
-};
-
-static const char *
-cost_name (enum EvaluationCost cost)
-{
- unsigned int i;
- unsigned int n = sizeof(cost_table)/sizeof(cost_table[0]);
-
- for (i = 0; i<n; ++i)
- if (cost_table[i].cost == cost)
- return cost_table[i].name;
- return "unknown";
-}
-
-
-static char *
-type_name (type)
- short type;
-{
- int i;
-
- for (i = 0; type_table[i].type != (short) -1; i++)
- if (type_table[i].type == type)
- break;
- return (type_table[i].type_name);
-}
-
-static char *
-prec_name (prec)
- short prec;
-{
- int i;
-
- for (i = 0; prec_table[i].prec != (short) -1; i++)
- if (prec_table[i].prec == prec)
- break;
- return (prec_table[i].prec_name);
-}
-
-
-/* Walk the expression tree NODE to stdout.
- INDENT is the number of levels to indent the left margin. */
-
-void
-print_tree (FILE *fp, struct predicate *node, int indent)
-{
- int i;
-
- if (node == NULL)
- return;
- for (i = 0; i < indent; i++)
- fprintf (fp, " ");
- fprintf (fp, "pred=[");
- print_predicate(fp, node);
- fprintf (fp, "] type=%s prec=%s",
- type_name (node->p_type), prec_name (node->p_prec));
- fprintf (fp, " cost=%s rate=%#03.2g %sside effects ",
- cost_name(node->p_cost),
- node->est_success_rate,
- (node->side_effects ? "" : "no "));
-
- if (node->need_stat || node->need_type)
- {
- int comma = 0;
-
- fprintf (fp, "Needs ");
- if (node->need_stat)
- {
- fprintf (fp, "stat");
- comma = 1;
- }
- if (node->need_type)
- {
- fprintf (fp, "%stype", comma ? "," : "");
- }
- }
- fprintf (fp, "\n");
-
-
- for (i = 0; i < indent; i++)
- fprintf (fp, " ");
- if (NULL == node->pred_left && NULL == node->pred_right)
- {
- fprintf (fp, "no children.\n");
- }
- else
- {
- if (node->pred_left)
- {
- fprintf (fp, "left:\n");
- print_tree (fp, node->pred_left, indent + 1);
- }
- else
- {
- fprintf (fp, "no left.\n");
- }
-
- for (i = 0; i < indent; i++)
- fprintf (fp, " ");
- if (node->pred_right)
- {
- fprintf (fp, "right:\n");
- print_tree (fp, node->pred_right, indent + 1);
- }
- else
- {
- fprintf (fp, "no right.\n");
- }
+ default:
+ error (1, 0, "oops -- invalid expression type!");
+ return (false);
}
}
diff --git a/find/util.c b/find/util.c
index 40f36d5a..95ce57e0 100644
--- a/find/util.c
+++ b/find/util.c
@@ -1,77 +1,119 @@
/* util.c -- functions for initializing new tree elements, and other things.
- Copyright (C) 1990, 91, 92, 93, 94, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
+ 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 3 of the License, or
- (at your option) any later version.
-
+ 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, see <http://www.gnu.org/licenses/>.
-*/
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <config.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
#include "defs.h"
+
+/* Return the last component of pathname FNAME, with leading slashes
+ compressed into one slash. */
-#include <fcntl.h>
-#ifdef HAVE_SYS_UTSNAME_H
-#include <sys/utsname.h>
-#endif
-#include <sys/time.h>
-#include <ctype.h>
-#include <string.h>
-#include <limits.h>
-#include <errno.h>
-#include <assert.h>
+char *
+basename (fname)
+ char *fname;
+{
+ char *p;
-#include "xalloc.h"
-#include "quotearg.h"
-#include "timespec.h"
-#include "error.h"
-#include "verify.h"
-#include "openat.h"
+ /* For "/", "//", etc., return "/". */
+ for (p = fname; *p == '/'; ++p)
+ /* Do nothing. */ ;
+ if (*p == '\0')
+ return p - 1;
+ p = strrchr (fname, '/');
+ return (p == NULL ? fname : p + 1);
+}
+
+/* Return a pointer to a new predicate structure, which has been
+ linked in as the last one in the predicates list.
-#if ENABLE_NLS
-# include <libintl.h>
-# define _(Text) gettext (Text)
-#else
-# define _(Text) Text
-#endif
-#ifdef gettext_noop
-# define N_(String) gettext_noop (String)
-#else
-/* See locate.c for explanation as to why not use (String) */
-# define N_(String) String
-#endif
+ Set `predicates' to point to the start of the predicates list.
+ Set `last_pred' to point to the new last predicate in the list.
+
+ Set all cells in the new structure to the default values. */
-
-struct debug_option_assoc
+struct predicate *
+get_new_pred ()
{
- char *name;
- int val;
- char *docstring;
-};
-static struct debug_option_assoc debugassoc[] =
- {
- { "help", DebugHelp, "Explain the various -D options" },
- { "tree", DebugExpressionTree, "Display the expression tree" },
- { "search",DebugSearch, "Navigate the directory tree verbosely" },
- { "stat", DebugStat, "Trace calls to stat(2) and lstat(2)" },
- { "rates", DebugSuccessRates, "Indicate how often each predicate succeeded" },
- { "opt", DebugExpressionTree|DebugTreeOpt, "Show diagnostic information relating to optimisation" },
- { "exec", DebugExec, "Show diagnostic information relating to -exec, -execdir, -ok and -okdir" }
- };
-#define N_DEBUGASSOC (sizeof(debugassoc)/sizeof(debugassoc[0]))
+ register struct predicate *new_pred;
+ if (predicates == NULL)
+ {
+ predicates = (struct predicate *)
+ xmalloc (sizeof (struct predicate));
+ last_pred = predicates;
+ }
+ else
+ {
+ new_pred = (struct predicate *) xmalloc (sizeof (struct predicate));
+ last_pred->pred_next = new_pred;
+ last_pred = new_pred;
+ }
+ last_pred->pred_func = NULL;
+#ifdef DEBUG
+ last_pred->p_name = NULL;
+#endif /* DEBUG */
+ last_pred->p_type = NO_TYPE;
+ last_pred->p_prec = NO_PREC;
+ last_pred->side_effects = false;
+ last_pred->need_stat = true;
+ last_pred->args.str = NULL;
+ last_pred->pred_next = NULL;
+ last_pred->pred_left = NULL;
+ last_pred->pred_right = NULL;
+ return (last_pred);
+}
+
+/* Return a pointer to a new predicate, with operator check.
+ Like get_new_pred, but it checks to make sure that the previous
+ predicate is an operator. If it isn't, the AND operator is inserted. */
+struct predicate *
+get_new_pred_chk_op ()
+{
+ struct predicate *new_pred;
-
-/* Add a primary of predicate type PRED_FUNC (described by ENTRY) to the predicate input list.
+ if (last_pred)
+ switch (last_pred->p_type)
+ {
+ case NO_TYPE:
+ error (1, 0, "oops -- invalid default insertion of and!");
+ break;
+
+ case PRIMARY_TYPE:
+ case CLOSE_PAREN:
+ new_pred = get_new_pred ();
+ new_pred->pred_func = pred_and;
+#ifdef DEBUG
+ new_pred->p_name = find_pred_name (pred_and);
+#endif /* DEBUG */
+ new_pred->p_type = BI_OP;
+ new_pred->p_prec = AND_PREC;
+ new_pred->need_stat = false;
+ new_pred->args.str = NULL;
+
+ default:
+ break;
+ }
+ return (get_new_pred ());
+}
+
+/* Add a primary of predicate type PRED_FUNC to the predicate input list.
Return a pointer to the predicate node just inserted.
@@ -88,952 +130,29 @@ static struct debug_option_assoc debugassoc[] =
operator. */
struct predicate *
-insert_primary_withpred (const struct parser_table *entry, PRED_FUNC pred_func)
+insert_primary (pred_func)
+ boolean (*pred_func) ();
{
struct predicate *new_pred;
- new_pred = get_new_pred_chk_op (entry);
+ new_pred = get_new_pred_chk_op ();
new_pred->pred_func = pred_func;
- new_pred->p_name = entry->parser_name;
+#ifdef DEBUG
+ new_pred->p_name = find_pred_name (pred_func);
+#endif /* DEBUG */
new_pred->args.str = NULL;
new_pred->p_type = PRIMARY_TYPE;
new_pred->p_prec = NO_PREC;
- return new_pred;
-}
-
-/* Add a primary described by ENTRY to the predicate input list.
-
- Return a pointer to the predicate node just inserted.
-
- Fills in the following cells of the new predicate node:
-
- pred_func PRED_FUNC
- args(.str) NULL
- p_type PRIMARY_TYPE
- p_prec NO_PREC
-
- Other cells that need to be filled in are defaulted by
- get_new_pred_chk_op, which is used to insure that the prior node is
- either not there at all (we are the very first node) or is an
- operator. */
-struct predicate *
-insert_primary (const struct parser_table *entry)
-{
- assert (entry->pred_func != NULL);
- return insert_primary_withpred(entry, entry->pred_func);
-}
-
-
-
-static void
-show_valid_debug_options(FILE *fp, int full)
-{
- int i;
- if (full)
- {
- fprintf(fp, "Valid arguments for -D:\n");
- for (i=0; i<N_DEBUGASSOC; ++i)
- {
- fprintf(fp, "%-10s %s\n",
- debugassoc[i].name,
- debugassoc[i].docstring);
- }
- }
- else
- {
- for (i=0; i<N_DEBUGASSOC; ++i)
- {
- fprintf(fp, "%s%s", (i>0 ? "|" : ""), debugassoc[i].name);
- }
- }
+ return (new_pred);
}
void
-usage (FILE *fp, int status, char *msg)
+usage (msg)
+ char *msg;
{
if (msg)
- fprintf (fp, "%s: %s\n", program_name, msg);
-
- fprintf (fp, _("Usage: %s [-H] [-L] [-P] [-Olevel] [-D "), program_name);
- show_valid_debug_options(fp, 0);
- fprintf (fp, _("] [path...] [expression]\n"));
- if (0 != status)
- exit (status);
-}
-
-void
-set_stat_placeholders(struct stat *p)
-{
-#if HAVE_STRUCT_STAT_ST_BIRTHTIME
- p->st_birthtime = 0;
-#endif
-#if HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC
- p->st_birthtimensec = 0;
-#endif
-#if HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC
- p->st_birthtimespec.tv_nsec = -1;
-#endif
-#if HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_SEC
- p->st_birthtimespec.tv_sec = 0;
-#endif
-}
-
-
-/* Get the stat information for a file, if it is
- * not already known.
- */
-int
-get_statinfo (const char *pathname, const char *name, struct stat *p)
-{
- /* Set markers in fields so we have a good idea if the implementation
- * didn't bother to set them (e.g., NetBSD st_birthtimespec for MS-DOS
- * files)
- */
- if (!state.have_stat)
- {
- set_stat_placeholders(p);
- if (0 == (*options.xstat) (name, p))
- {
- if (00000 == p->st_mode)
- {
- /* Savannah bug #16378. */
- error(0, 0, _("Warning: file %s appears to have mode 0000"),
- quotearg_n_style(0, options.err_quoting_style, name));
- }
- }
- else
- {
- if (!options.ignore_readdir_race || (errno != ENOENT) )
- {
- error (0, errno, "%s",
- safely_quote_err_filename(0, pathname));
- state.exit_status = 1;
- }
- return -1;
- }
- }
- state.have_stat = true;
- state.have_type = true;
- state.type = p->st_mode;
-
- return 0;
-}
-
-
-/* Get the stat/type information for a file, if it is
- * not already known.
- */
-int
-get_info (const char *pathname,
- struct stat *p,
- struct predicate *pred_ptr)
-{
- boolean todo = false;
-
- /* If we need the full stat info, or we need the type info but don't
- * already have it, stat the file now.
- */
- if (pred_ptr->need_stat)
- todo = true;
- else if ((pred_ptr->need_type && (0 == state.have_type)))
- todo = true;
-
- if (todo)
- return get_statinfo(pathname, state.rel_pathname, p);
- else
- return 0;
-}
-
-/* Determine if we can use O_NOFOLLOW.
- */
-#if defined O_NOFOLLOW
-boolean
-check_nofollow(void)
-{
- struct utsname uts;
- float release;
-
- if (0 == O_NOFOLLOW)
- {
- return false;
- }
-
- if (0 == uname(&uts))
- {
- /* POSIX requires that atof() ignore "unrecognised suffixes". */
- release = atof(uts.release);
-
- if (0 == strcmp("Linux", uts.sysname))
- {
- /* Linux kernels 2.1.126 and earlier ignore the O_NOFOLLOW flag. */
- return release >= 2.2; /* close enough */
- }
- else if (0 == strcmp("FreeBSD", uts.sysname))
- {
- /* FreeBSD 3.0-CURRENT and later support it */
- return release >= 3.1;
- }
- }
-
- /* Well, O_NOFOLLOW was defined, so we'll try to use it. */
- return true;
-}
-#endif
-
-
-
-/* Examine the predicate list for instances of -execdir or -okdir
- * which have been terminated with '+' (build argument list) rather
- * than ';' (singles only). If there are any, run them (this will
- * have no effect if there are no arguments waiting).
- */
-static void
-do_complete_pending_execdirs(struct predicate *p, int dirfd)
-{
- if (NULL == p)
- return;
-
- assert (state.execdirs_outstanding);
-
- do_complete_pending_execdirs(p->pred_left, dirfd);
-
- if (pred_is(p, pred_execdir) || pred_is(p, pred_okdir))
- {
- /* It's an exec-family predicate. p->args.exec_val is valid. */
- if (p->args.exec_vec.multiple)
- {
- struct exec_val *execp = &p->args.exec_vec;
-
- /* This one was terminated by '+' and so might have some
- * left... Run it if necessary.
- */
- if (execp->state.todo)
- {
- /* There are not-yet-executed arguments. */
- launch (&execp->ctl, &execp->state);
- }
- }
- }
-
- do_complete_pending_execdirs(p->pred_right, dirfd);
-}
-
-void
-complete_pending_execdirs(int dirfd)
-{
- if (state.execdirs_outstanding)
- {
- do_complete_pending_execdirs(get_eval_tree(), dirfd);
- state.execdirs_outstanding = false;
- }
-}
-
-
-
-/* Examine the predicate list for instances of -exec which have been
- * terminated with '+' (build argument list) rather than ';' (singles
- * only). If there are any, run them (this will have no effect if
- * there are no arguments waiting).
- */
-void
-complete_pending_execs(struct predicate *p)
-{
- if (NULL == p)
- return;
-
- complete_pending_execs(p->pred_left);
-
- /* It's an exec-family predicate then p->args.exec_val is valid
- * and we can check it.
- */
- /* XXX: what about pred_ok() ? */
- if (pred_is(p, pred_exec) && p->args.exec_vec.multiple)
- {
- struct exec_val *execp = &p->args.exec_vec;
-
- /* This one was terminated by '+' and so might have some
- * left... Run it if necessary. Set state.exit_status if
- * there are any problems.
- */
- if (execp->state.todo)
- {
- /* There are not-yet-executed arguments. */
- launch (&execp->ctl, &execp->state);
- }
- }
-
- complete_pending_execs(p->pred_right);
-}
-
-static void
-traverse_tree(struct predicate *tree,
- void (*callback)(struct predicate*))
-{
- if (tree->pred_left)
- traverse_tree(tree->pred_left, callback);
-
- callback(tree);
-
- if (tree->pred_right)
- traverse_tree(tree->pred_right, callback);
-}
-
-static void
-flush_and_close_output_files(struct predicate *p)
-{
- if (pred_is(p, pred_fprint)
- || pred_is(p, pred_fprintf)
- || pred_is(p, pred_fls)
- || pred_is(p, pred_fprint0))
- {
- FILE *f = p->args.printf_vec.stream;
- bool failed;
-
- if (f == stdout || f == stderr)
- failed = fflush(p->args.printf_vec.stream) == EOF;
- else
- failed = fclose(p->args.printf_vec.stream) == EOF;
-
- if (failed)
- nonfatal_file_error(p->args.printf_vec.filename);
- }
- else if (pred_is(p, pred_print))
- {
- if (fflush(p->args.printf_vec.stream) == EOF)
- {
- nonfatal_file_error(p->args.printf_vec.filename);
- }
- }
- else if (pred_is(p, pred_ls) || pred_is(p, pred_print0))
- {
- if (fflush(stdout) == EOF)
- {
- /* XXX: migrate to printf_vec. */
- nonfatal_file_error("standard output");
- }
- }
+ fprintf (stderr, "%s: %s\n", program_name, msg);
+ fprintf (stderr, "\
+Usage: %s [path...] [expression]\n", program_name);
+ exit (1);
}
-
-/* Complete any outstanding commands.
- */
-void
-cleanup(void)
-{
- struct predicate *eval_tree = get_eval_tree();
- if (eval_tree)
- {
- traverse_tree(eval_tree, complete_pending_execs);
- complete_pending_execdirs(get_current_dirfd());
- traverse_tree(eval_tree, flush_and_close_output_files);
- }
-}
-
-/* Savannah bug #16378 manifests as an assertion failure in pred_type()
- * when an NFS server returns st_mode with value 0 (of course the stat(2)
- * system call is itself returning 0 in this case).
- */
-#undef DEBUG_SV_BUG_16378
-#if defined DEBUG_SV_BUG_16378
-static int hook_fstatat(int fd, const char *name, struct stat *p, int flags)
-{
- static int warned = 0;
-
- if (!warned)
- {
- /* No use of _() here; no point asking translators to translate a debug msg */
- error(0, 0,
- "Warning: some debug code is enabled for Savannah bug #16378; "
- "this should not occur in released versions of findutils!");
- warned = 1;
- }
-
- if (0 == strcmp(name, "./mode0file")
- || 0 == strcmp(name, "mode0file"))
- {
- time_t now = time(NULL);
- long day = 86400;
-
- p->st_rdev = 0;
- p->st_dev = 0x300;
- p->st_ino = 0;
- p->st_mode = 0; /* SV bug #16378 */
- p->st_nlink = 1;
- p->st_uid = geteuid();
- p->st_gid = 0;
- p->st_size = 42;
- p->st_blksize = 32768;
- p->st_atime = now-1*day;
- p->st_mtime = now-2*day;
- p->st_ctime = now-3*day;
-
- return 0;
- }
- return fstatat(fd, name, p, flags);
-}
-
-# undef fstatat
-# define fstatat(fd,name,p,flags) hook_fstatat((fd),(name),(p),(flags))
-#endif
-
-
-static int
-fallback_stat(const char *name, struct stat *p, int prev_rv)
-{
- /* Our original stat() call failed. Perhaps we can't follow a
- * symbolic link. If that might be the problem, lstat() the link.
- * Otherwise, admit defeat.
- */
- switch (errno)
- {
- case ENOENT:
- case ENOTDIR:
- if (options.debug_options & DebugStat)
- fprintf(stderr, "fallback_stat(): stat(%s) failed; falling back on lstat()\n", name);
- return fstatat(state.cwd_dir_fd, name, p, AT_SYMLINK_NOFOLLOW);
-
- case EACCES:
- case EIO:
- case ELOOP:
- case ENAMETOOLONG:
-#ifdef EOVERFLOW
- case EOVERFLOW: /* EOVERFLOW is not #defined on UNICOS. */
-#endif
- default:
- return prev_rv;
- }
-}
-
-
-/* optionh_stat() implements the stat operation when the -H option is
- * in effect.
- *
- * If the item to be examined is a command-line argument, we follow
- * symbolic links. If the stat() call fails on the command-line item,
- * we fall back on the properties of the symbolic link.
- *
- * If the item to be examined is not a command-line argument, we
- * examine the link itself.
- */
-int
-optionh_stat(const char *name, struct stat *p)
-{
- if (AT_FDCWD != state.cwd_dir_fd)
- assert (state.cwd_dir_fd >= 0);
- set_stat_placeholders(p);
- if (0 == state.curdepth)
- {
- /* This file is from the command line; deference the link (if it
- * is a link).
- */
- int rv;
- rv = fstatat(state.cwd_dir_fd, name, p, 0);
- if (0 == rv)
- return 0; /* success */
- else
- return fallback_stat(name, p, rv);
- }
- else
- {
- /* Not a file on the command line; do not dereference the link.
- */
- return fstatat(state.cwd_dir_fd, name, p, AT_SYMLINK_NOFOLLOW);
- }
-}
-
-/* optionl_stat() implements the stat operation when the -L option is
- * in effect. That option makes us examine the thing the symbolic
- * link points to, not the symbolic link itself.
- */
-int
-optionl_stat(const char *name, struct stat *p)
-{
- int rv;
- if (AT_FDCWD != state.cwd_dir_fd)
- assert (state.cwd_dir_fd >= 0);
-
- set_stat_placeholders(p);
- rv = fstatat(state.cwd_dir_fd, name, p, 0);
- if (0 == rv)
- return 0; /* normal case. */
- else
- return fallback_stat(name, p, rv);
-}
-
-/* optionp_stat() implements the stat operation when the -P option is
- * in effect (this is also the default). That option makes us examine
- * the symbolic link itself, not the thing it points to.
- */
-int
-optionp_stat(const char *name, struct stat *p)
-{
- assert ((state.cwd_dir_fd >= 0) || (state.cwd_dir_fd==AT_FDCWD));
- set_stat_placeholders(p);
- return fstatat(state.cwd_dir_fd, name, p, AT_SYMLINK_NOFOLLOW);
-}
-
-
-static uintmax_t stat_count = 0u;
-
-int
-debug_stat (const char *file, struct stat *bufp)
-{
- ++stat_count;
- fprintf (stderr, "debug_stat (%s)\n", file);
-
- switch (options.symlink_handling)
- {
- case SYMLINK_ALWAYS_DEREF:
- return optionl_stat(file, bufp);
- case SYMLINK_DEREF_ARGSONLY:
- return optionh_stat(file, bufp);
- case SYMLINK_NEVER_DEREF:
- return optionp_stat(file, bufp);
- }
- /*NOTREACHED*/
- assert (0);
- return -1;
-}
-
-
-int
-following_links(void)
-{
- switch (options.symlink_handling)
- {
- case SYMLINK_ALWAYS_DEREF:
- return 1;
- case SYMLINK_DEREF_ARGSONLY:
- return (state.curdepth == 0);
- case SYMLINK_NEVER_DEREF:
- default:
- return 0;
- }
-}
-
-
-/* Take a "mode" indicator and fill in the files of 'state'.
- */
-int
-digest_mode(mode_t mode,
- const char *pathname,
- const char *name,
- struct stat *pstat,
- boolean leaf)
-{
- /* If we know the type of the directory entry, and it is not a
- * symbolic link, we may be able to avoid a stat() or lstat() call.
- */
- if (mode)
- {
- if (S_ISLNK(mode) && following_links())
- {
- /* mode is wrong because we should have followed the symlink. */
- if (get_statinfo(pathname, name, pstat) != 0)
- return 0;
- mode = state.type = pstat->st_mode;
- state.have_type = true;
- }
- else
- {
- state.have_type = true;
- pstat->st_mode = state.type = mode;
- }
- }
- else
- {
- /* Mode is not yet known; may have to stat the file unless we
- * can deduce that it is not a directory (which is all we need to
- * know at this stage)
- */
- if (leaf)
- {
- state.have_stat = false;
- state.have_type = false;;
- state.type = 0;
- }
- else
- {
- if (get_statinfo(pathname, name, pstat) != 0)
- return 0;
-
- /* If -L is in effect and we are dealing with a symlink,
- * st_mode is the mode of the pointed-to file, while mode is
- * the mode of the directory entry (S_IFLNK). Hence now
- * that we have the stat information, override "mode".
- */
- state.type = pstat->st_mode;
- state.have_type = true;
- }
- }
-
- /* success. */
- return 1;
-}
-
-
-/* Return true if there are no predicates with no_default_print in
- predicate list PRED, false if there are any.
- Returns true if default print should be performed */
-
-boolean
-default_prints (struct predicate *pred)
-{
- while (pred != NULL)
- {
- if (pred->no_default_print)
- return (false);
- pred = pred->pred_next;
- }
- return (true);
-}
-
-boolean
-looks_like_expression(const char *arg, boolean leading)
-{
- switch (arg[0])
- {
- case '-':
- if (arg[1]) /* "-foo" is an expression. */
- return true;
- else
- return false; /* Just "-" is a filename. */
- break;
-
- case ')':
- case ',':
- if (arg[1])
- return false; /* )x and ,z are not expressions */
- else
- return !leading; /* A leading ) or , is not either */
-
- /* ( and ! are part of an expression, but (2 and !foo are
- * filenames.
- */
- case '!':
- case '(':
- if (arg[1])
- return false;
- else
- return true;
-
- default:
- return false;
- }
-}
-
-static void
-process_debug_options(char *arg)
-{
- const char *p;
- char *token_context = NULL;
- const char delimiters[] = ",";
- boolean empty = true;
- size_t i;
-
- p = strtok_r(arg, delimiters, &token_context);
- while (p)
- {
- empty = false;
-
- for (i=0; i<N_DEBUGASSOC; ++i)
- {
- if (0 == strcmp(debugassoc[i].name, p))
- {
- options.debug_options |= debugassoc[i].val;
- break;
- }
- }
- if (i >= N_DEBUGASSOC)
- {
- error(0, 0, _("Ignoring unrecognised debug flag %s"),
- quotearg_n_style(0, options.err_quoting_style, arg));
- }
- p = strtok_r(NULL, delimiters, &token_context);
- }
- if (empty)
- {
- error(1, 0, _("Empty argument to the -D option."));
- }
- else if (options.debug_options & DebugHelp)
- {
- show_valid_debug_options(stdout, 1);
- exit(0);
- }
-}
-
-static void
-process_optimisation_option(const char *arg)
-{
- if (0 == arg[0])
- {
- error(1, 0, _("The -O option must be immediately followed by a decimal integer"));
- }
- else
- {
- unsigned long opt_level;
- char *end;
-
- if (!isdigit( (unsigned char) arg[0] ))
- {
- error(1, 0, _("Please specify a decimal number immediately after -O"));
- }
- else
- {
- int prev_errno = errno;
- errno = 0;
-
- opt_level = strtoul(arg, &end, 10);
- if ( (0==opt_level) && (end==arg) )
- {
- error(1, 0, _("Please specify a decimal number immediately after -O"));
- }
- else if (*end)
- {
- /* unwanted trailing characters. */
- error(1, 0, _("Invalid optimisation level %s"), arg);
- }
- else if ( (ULONG_MAX==opt_level) && errno)
- {
- error(1, errno, _("Invalid optimisation level %s"), arg);
- }
- else if (opt_level > USHRT_MAX)
- {
- /* tricky to test, as on some platforms USHORT_MAX and ULONG_MAX
- * can have the same value, though this is unusual.
- */
- error(1, 0, _("Optimisation level %lu is too high. "
- "If you want to find files very quickly, "
- "consider using GNU locate."),
- opt_level);
- }
- else
- {
- options.optimisation_level = opt_level;
- errno = prev_errno;
- }
- }
- }
-}
-
-int
-process_leading_options(int argc, char *argv[])
-{
- int i, end_of_leading_options;
-
- for (i=1; (end_of_leading_options = i) < argc; ++i)
- {
- if (0 == strcmp("-H", argv[i]))
- {
- /* Meaning: dereference symbolic links on command line, but nowhere else. */
- set_follow_state(SYMLINK_DEREF_ARGSONLY);
- }
- else if (0 == strcmp("-L", argv[i]))
- {
- /* Meaning: dereference all symbolic links. */
- set_follow_state(SYMLINK_ALWAYS_DEREF);
- }
- else if (0 == strcmp("-P", argv[i]))
- {
- /* Meaning: never dereference symbolic links (default). */
- set_follow_state(SYMLINK_NEVER_DEREF);
- }
- else if (0 == strcmp("--", argv[i]))
- {
- /* -- signifies the end of options. */
- end_of_leading_options = i+1; /* Next time start with the next option */
- break;
- }
- else if (0 == strcmp("-D", argv[i]))
- {
- process_debug_options(argv[i+1]);
- ++i; /* skip the argument too. */
- }
- else if (0 == strncmp("-O", argv[i], 2))
- {
- process_optimisation_option(argv[i]+2);
- }
- else
- {
- /* Hmm, must be one of
- * (a) A path name
- * (b) A predicate
- */
- end_of_leading_options = i; /* Next time start with this option */
- break;
- }
- }
- return end_of_leading_options;
-}
-
-static struct timespec
-now(void)
-{
- struct timespec retval;
- struct timeval tv;
- time_t t;
-
- if (0 == gettimeofday(&tv, NULL))
- {
- retval.tv_sec = tv.tv_sec;
- retval.tv_nsec = tv.tv_usec * 1000; /* convert unit from microseconds to nanoseconds */
- return retval;
- }
- t = time(NULL);
- assert (t != (time_t)-1);
- retval.tv_sec = t;
- retval.tv_nsec = 0;
- return retval;
-}
-
-void
-set_option_defaults(struct options *p)
-{
- if (getenv("POSIXLY_CORRECT"))
- p->posixly_correct = true;
- else
- p->posixly_correct = false;
-
- /* We call check_nofollow() before setlocale() because the numbers
- * for which we check (in the results of uname) definitiely have "."
- * as the decimal point indicator even under locales for which that
- * is not normally true. Hence atof() would do the wrong thing
- * if we call it after setlocale().
- */
-#ifdef O_NOFOLLOW
- p->open_nofollow_available = check_nofollow();
-#else
- p->open_nofollow_available = false;
-#endif
-
- p->regex_options = RE_SYNTAX_EMACS;
-
- if (isatty(0))
- {
- p->warnings = true;
- p->literal_control_chars = false;
- }
- else
- {
- p->warnings = false;
- p->literal_control_chars = false; /* may change */
- }
- if (p->posixly_correct)
- {
- p->warnings = false;
- }
-
- p->do_dir_first = true;
- p->explicit_depth = false;
- p->maxdepth = p->mindepth = -1;
-
- p->start_time = now();
- p->cur_day_start.tv_sec = p->start_time.tv_sec - DAYSECS;
- p->cur_day_start.tv_nsec = p->start_time.tv_nsec;
-
- p->full_days = false;
- p->stay_on_filesystem = false;
- p->ignore_readdir_race = false;
-
- if (p->posixly_correct)
- p->output_block_size = 512;
- else
- p->output_block_size = 1024;
-
- p->debug_options = 0uL;
- p->optimisation_level = 0;
-
- if (getenv("FIND_BLOCK_SIZE"))
- {
- error (1, 0, _("The environment variable FIND_BLOCK_SIZE is not supported, the only thing that affects the block size is the POSIXLY_CORRECT environment variable"));
- }
-
-#if LEAF_OPTIMISATION
- /* The leaf optimisation is enabled. */
- p->no_leaf_check = false;
-#else
- /* The leaf optimisation is disabled. */
- p->no_leaf_check = true;
-#endif
-
- set_follow_state(SYMLINK_NEVER_DEREF); /* The default is equivalent to -P. */
-
- p->err_quoting_style = locale_quoting_style;
-}
-
-
-/* get_start_dirfd
- *
- * Returns the fd for the directory we started in.
- */
-int get_start_dirfd(void)
-{
- return starting_desc;
-}
-
-/* apply_predicate
- *
- */
-boolean
-apply_predicate(const char *pathname, struct stat *stat_buf, struct predicate *p)
-{
- ++p->perf.visits;
-
- if (p->need_stat || p->need_type)
- {
- /* We may need a stat here. */
- if (get_info(pathname, stat_buf, p) != 0)
- return false;
- }
- if ((p->pred_func)(pathname, stat_buf, p))
- {
- ++(p->perf.successes);
- return true;
- }
- else
- {
- return false;
- }
-}
-
-
-/* safely_quote_err_filename
- *
- */
-const char *
-safely_quote_err_filename (int n, char const *arg)
-{
- return quotearg_n_style (n, options.err_quoting_style, arg);
-}
-
-/* report_file_err
- */
-static void
-report_file_err(int exitval, int errno_value, const char *name)
-{
- /* It is important that the errno value is passed in as a function
- * argument before we call safely_quote_err_filename(), because otherwise
- * we might find that safely_quote_err_filename() changes errno.
- */
- if (state.exit_status < 1)
- state.exit_status = 1;
-
- error (exitval, errno_value, "%s", safely_quote_err_filename(0, name));
-}
-
-/* fatal_file_error
- *
- */
-void
-fatal_file_error(const char *name)
-{
- report_file_err(1, errno, name);
- /*NOTREACHED*/
- abort();
-}
-
-void
-nonfatal_file_error(const char *name)
-{
- report_file_err(0, errno, name);
-}
-
diff --git a/find/version.c b/find/version.c
new file mode 100644
index 00000000..460883ff
--- /dev/null
+++ b/find/version.c
@@ -0,0 +1 @@
+char *version_string = "4.1";
diff --git a/install-sh b/install-sh
new file mode 100755
index 00000000..ab74c882
--- /dev/null
+++ b/install-sh
@@ -0,0 +1,238 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+tranformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 8f8319a5..568061f3 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -1,44 +1,19 @@
-## Process this file with automake to produce Makefile.in.
+LIBRARIES = find
+find_SOURCES = regex.c dirname.c error.c filemode.c getopt.c getopt1.c \
+idcache.c listfile.c modechange.c nextelem.c savedir.c xmalloc.c getline.c \
+xstrdup.c xgetcwd.c fnmatch.c $(find_OPT_SOURCES)
-AUTOMAKE_OPTIONS = 1.5 gnits
-# no-dependencies
+find_OPT_SOURCES = fileblocks.c memcmp.c memset.c mktime.c stpcpy.c strdup.c \
+strftime.c strspn.c strstr.c strtol.c alloca.c
-noinst_LIBRARIES = libfind.a
+DIST_OTHER = fnmatch.h getopt.h modechange.h modetype.h pathmax.h \
+regex.h wait.h
-if CROSS_COMPILING
-# The regexprops program needs to be a native executable, so we
-# can't build it with a cross-compiler.
-else
-noinst_PROGRAMS = regexprops
-regexprops_SOURCES = regexprops.c regextype.c
-endif
-
-libfind_a_SOURCES = gnulib-version.c findutils-version.c
-EXTRA_DIST = modetype.h wait.h extendbuf.h savedirinfo.h buildcmd.h \
- gnulib-version.h gnulib-version.c findutils-version.h
-BUILT_SOURCES = gnulib-version.c
-SUFFIXES =
-MOSTLYCLEANFILES =
-CLEANFILES =
-DISTCLEANFILES =
-MAINTAINERCLEANFILES =
-
-
-INCLUDES = -I../gnulib/lib -I$(top_srcdir)/gnulib/lib
-LDADD = ../gnulib/lib/libgnulib.a @LIBINTL@
-
-libfind_a_SOURCES += modetype.h nextelem.h printquoted.h listfile.h \
- regextype.h dircallback.h
-libfind_a_SOURCES += listfile.c nextelem.c extendbuf.c buildcmd.c savedirinfo.c \
- forcefindlib.c qmark.c printquoted.c regextype.c dircallback.c
-
-EXTRA_DIST += waitpid.c forcefindlib.c
-
-
-libfind_a_LIBADD = @FINDLIBOBJS@
-libfind_a_DEPENDENCIES = @FINDLIBOBJS@
-# libfind_la_LIBADD = @LTFINDLIBOBJS@
-
-# libfind_a_OBJECTS += @FINDLIBOBJS@
-# libfind_la_OBJECTS += @LTFINDLIBOBJS@
+CONFIG_HEADER = ../config.h
+INCLUDES = -I.. -I$(srcdir)
+fnmatch.o: fnmatch.h
+getopt1.o: getopt.h
+listfile.o xgetcwd.o: pathmax.h
+modechange.o: modechange.h
+regex.o: regex.h
diff --git a/lib/Makefile.in b/lib/Makefile.in
new file mode 100644
index 00000000..534b294a
--- /dev/null
+++ b/lib/Makefile.in
@@ -0,0 +1,136 @@
+# Makefile.in generated automatically by automake from Makefile.am.
+# Copyright (C) 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = $(exec_prefix)/bin
+sbindir = $(exec_prefix)/sbin
+libexecdir = $(exec_prefix)/libexec
+datadir = $(prefix)/share
+sysconfdir = $(prefix)/etc
+sharedstatedir = $(prefix)/com
+localstatedir = $(prefix)/var
+libdir = $(exec_prefix)/lib
+infodir = $(prefix)/info
+mandir = $(prefix)/man
+includedir = $(prefix)/include
+oldincludedir = /usr/include
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+transform = @program_transform_name@
+
+ALL = ${PROGRAMS} ${LIBPROGRAMS} ${SCRIPTS} ${LIBSCRIPTS} ${LIBFILES}
+CC = @CC@
+LEX = @LEX@
+YACC = @YACC@
+ANSI2KNR = ./ansi2knr
+
+DEFS = @DEFS@
+CPPFLAGS = @CPPFLAGS@
+CFLAGS = @CFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+
+find_OBJECTS = regex.o dirname.o error.o filemode.o getopt.o getopt1.o idcache.o listfile.o modechange.o nextelem.o savedir.o xmalloc.o getline.o xstrdup.o xgetcwd.o fnmatch.o
+LIBFILES = libfind.a
+AR = ar
+RANLIB = @RANLIB@
+ALLOCA = @ALLOCA@
+LIBOBJS = @LIBOBJS@
+
+SOURCES = ${find_SOURCES}
+DIST_CONF = Makefile.am Makefile.in
+DIST_FILES = $(DIST_CONF) $(SOURCES) $(TEXINFOS) $(INFOS) $(MANS) $(DIST_OTHER)
+
+LIBRARIES = find
+find_SOURCES = regex.c dirname.c error.c filemode.c getopt.c getopt1.c \
+idcache.c listfile.c modechange.c nextelem.c savedir.c xmalloc.c getline.c \
+xstrdup.c xgetcwd.c fnmatch.c $(find_OPT_SOURCES)
+
+find_OPT_SOURCES = fileblocks.c memcmp.c memset.c mktime.c stpcpy.c strdup.c \
+strftime.c strspn.c strstr.c strtol.c alloca.c
+
+DIST_OTHER = fnmatch.h getopt.h modechange.h modetype.h pathmax.h \
+regex.h wait.h
+
+CONFIG_HEADER = ../config.h
+INCLUDES = -I.. -I$(srcdir)
+
+all:: ${ALL}
+
+.c.o:
+ $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $<
+
+$(find_OBJECTS): ../config.h
+install:: install-libraries
+
+install-libraries: $(LIBFILES)
+
+uninstall:: uninstall-libraries
+
+uninstall-libraries:
+
+libfind.a: $(find_OBJECTS) @LIBOBJS@ @ALLOCA@
+ rm -f libfind.a
+ $(AR) cru libfind.a $(find_OBJECTS) @LIBOBJS@ @ALLOCA@
+ $(RANLIB) libfind.a
+
+mostlyclean:
+ rm -f *.o core
+
+clean: mostlyclean
+ rm -f $(PROGRAMS) $(LIBPROGRAMS) $(LIBFILES) $(TEXFILES) $(CLEANFILES)
+
+distclean: clean
+ rm -f Makefile *.tab.c $(DISTCLEANFILES)
+ rm -f config.cache config.log config.status ${CONFIG_HEADER} stamp-h
+
+realclean: distclean
+ rm -f TAGS $(INFOS)
+
+dist: $(DIST_FILES) $(DIST_DIRS)
+ -mkdir ../`cat ../distname`/$(subdir)
+ @for file in $(DIST_FILES); do \
+ echo linking $$file; \
+ ln $(srcdir)/$$file ../`cat ../distname`/$(subdir)/$$file || \
+ { echo copying $$file instead; cp -p $(srcdir)/$$file ../`cat ../distname`/$(subdir)/$$file;}; \
+ done
+
+check dvi info install uninstall::
+
+tags:: TAGS
+
+TAGS::
+ cd $(srcdir); etags $(SOURCES)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
+
+fnmatch.o: fnmatch.h
+getopt1.o: getopt.h
+listfile.o xgetcwd.o: pathmax.h
+modechange.o: modechange.h
+regex.o: regex.h
diff --git a/lib/alloca.c b/lib/alloca.c
new file mode 100644
index 00000000..7020f32c
--- /dev/null
+++ b/lib/alloca.c
@@ -0,0 +1,492 @@
+/* alloca.c -- allocate automatically reclaimed memory
+ (Mostly) portable public-domain implementation -- D A Gwyn
+
+ This implementation of the PWB library alloca function,
+ which is used to allocate space off the run-time stack so
+ that it is automatically reclaimed upon procedure exit,
+ was inspired by discussions with J. Q. Johnson of Cornell.
+ J.Otto Tennant <jot@cray.com> contributed the Cray support.
+
+ There are some preprocessor constants that can
+ be defined when compiling for your specific system, for
+ improved efficiency; however, the defaults should be okay.
+
+ The general concept of this implementation is to keep
+ track of all alloca-allocated blocks, and reclaim any
+ that are found to be deeper in the stack than the current
+ invocation. This heuristic does not reclaim storage as
+ soon as it becomes invalid, but it will do so eventually.
+
+ As a special case, alloca(0) reclaims storage without
+ allocating any. It is a good idea to use alloca(0) in
+ your main control loop, etc. to force garbage collection. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef emacs
+#include "blockinput.h"
+#endif
+
+/* If compiling with GCC 2, this file's not needed. */
+#if !defined (__GNUC__) || __GNUC__ < 2
+
+/* If someone has defined alloca as a macro,
+ there must be some other way alloca is supposed to work. */
+#ifndef alloca
+
+#ifdef emacs
+#ifdef static
+/* actually, only want this if static is defined as ""
+ -- this is for usg, in which emacs must undefine static
+ in order to make unexec workable
+ */
+#ifndef STACK_DIRECTION
+you
+lose
+-- must know STACK_DIRECTION at compile-time
+#endif /* STACK_DIRECTION undefined */
+#endif /* static */
+#endif /* emacs */
+
+/* If your stack is a linked list of frames, you have to
+ provide an "address metric" ADDRESS_FUNCTION macro. */
+
+#if defined (CRAY) && defined (CRAY_STACKSEG_END)
+long i00afunc ();
+#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
+#else
+#define ADDRESS_FUNCTION(arg) &(arg)
+#endif
+
+#if __STDC__
+typedef void *pointer;
+#else
+typedef char *pointer;
+#endif
+
+#define NULL 0
+
+/* Different portions of Emacs need to call different versions of
+ malloc. The Emacs executable needs alloca to call xmalloc, because
+ ordinary malloc isn't protected from input signals. On the other
+ hand, the utilities in lib-src need alloca to call malloc; some of
+ them are very simple, and don't have an xmalloc routine.
+
+ Non-Emacs programs expect this to call use xmalloc.
+
+ Callers below should use malloc. */
+
+#ifndef emacs
+#define malloc xmalloc
+#endif
+extern pointer malloc ();
+
+/* Define STACK_DIRECTION if you know the direction of stack
+ growth for your system; otherwise it will be automatically
+ deduced at run-time.
+
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+
+#ifndef STACK_DIRECTION
+#define STACK_DIRECTION 0 /* Direction unknown. */
+#endif
+
+#if STACK_DIRECTION != 0
+
+#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
+
+#else /* STACK_DIRECTION == 0; need run-time code. */
+
+static int stack_dir; /* 1 or -1 once known. */
+#define STACK_DIR stack_dir
+
+static void
+find_stack_direction ()
+{
+ static char *addr = NULL; /* Address of first `dummy', once known. */
+ auto char dummy; /* To get stack address. */
+
+ if (addr == NULL)
+ { /* Initial entry. */
+ addr = ADDRESS_FUNCTION (dummy);
+
+ find_stack_direction (); /* Recurse once. */
+ }
+ else
+ {
+ /* Second entry. */
+ if (ADDRESS_FUNCTION (dummy) > addr)
+ stack_dir = 1; /* Stack grew upward. */
+ else
+ stack_dir = -1; /* Stack grew downward. */
+ }
+}
+
+#endif /* STACK_DIRECTION == 0 */
+
+/* An "alloca header" is used to:
+ (a) chain together all alloca'ed blocks;
+ (b) keep track of stack depth.
+
+ It is very important that sizeof(header) agree with malloc
+ alignment chunk size. The following default should work okay. */
+
+#ifndef ALIGN_SIZE
+#define ALIGN_SIZE sizeof(double)
+#endif
+
+typedef union hdr
+{
+ char align[ALIGN_SIZE]; /* To force sizeof(header). */
+ struct
+ {
+ union hdr *next; /* For chaining headers. */
+ char *deep; /* For stack depth measure. */
+ } h;
+} header;
+
+static header *last_alloca_header = NULL; /* -> last alloca header. */
+
+/* Return a pointer to at least SIZE bytes of storage,
+ which will be automatically reclaimed upon exit from
+ the procedure that called alloca. Originally, this space
+ was supposed to be taken from the current stack frame of the
+ caller, but that method cannot be made to work for some
+ implementations of C, for example under Gould's UTX/32. */
+
+pointer
+alloca (size)
+ unsigned size;
+{
+ auto char probe; /* Probes stack depth: */
+ register char *depth = ADDRESS_FUNCTION (probe);
+
+#if STACK_DIRECTION == 0
+ if (STACK_DIR == 0) /* Unknown growth direction. */
+ find_stack_direction ();
+#endif
+
+ /* Reclaim garbage, defined as all alloca'd storage that
+ was allocated from deeper in the stack than currently. */
+
+ {
+ register header *hp; /* Traverses linked list. */
+
+#ifdef emacs
+ BLOCK_INPUT;
+#endif
+
+ for (hp = last_alloca_header; hp != NULL;)
+ if ((STACK_DIR > 0 && hp->h.deep > depth)
+ || (STACK_DIR < 0 && hp->h.deep < depth))
+ {
+ register header *np = hp->h.next;
+
+ free ((pointer) hp); /* Collect garbage. */
+
+ hp = np; /* -> next header. */
+ }
+ else
+ break; /* Rest are not deeper. */
+
+ last_alloca_header = hp; /* -> last valid storage. */
+
+#ifdef emacs
+ UNBLOCK_INPUT;
+#endif
+ }
+
+ if (size == 0)
+ return NULL; /* No allocation required. */
+
+ /* Allocate combined header + user data storage. */
+
+ {
+ register pointer new = malloc (sizeof (header) + size);
+ /* Address of header. */
+
+ ((header *) new)->h.next = last_alloca_header;
+ ((header *) new)->h.deep = depth;
+
+ last_alloca_header = (header *) new;
+
+ /* User storage begins just after header. */
+
+ return (pointer) ((char *) new + sizeof (header));
+ }
+}
+
+#if defined (CRAY) && defined (CRAY_STACKSEG_END)
+
+#ifdef DEBUG_I00AFUNC
+#include <stdio.h>
+#endif
+
+#ifndef CRAY_STACK
+#define CRAY_STACK
+#ifndef CRAY2
+/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
+struct stack_control_header
+ {
+ long shgrow:32; /* Number of times stack has grown. */
+ long shaseg:32; /* Size of increments to stack. */
+ long shhwm:32; /* High water mark of stack. */
+ long shsize:32; /* Current size of stack (all segments). */
+ };
+
+/* The stack segment linkage control information occurs at
+ the high-address end of a stack segment. (The stack
+ grows from low addresses to high addresses.) The initial
+ part of the stack segment linkage control information is
+ 0200 (octal) words. This provides for register storage
+ for the routine which overflows the stack. */
+
+struct stack_segment_linkage
+ {
+ long ss[0200]; /* 0200 overflow words. */
+ long sssize:32; /* Number of words in this segment. */
+ long ssbase:32; /* Offset to stack base. */
+ long:32;
+ long sspseg:32; /* Offset to linkage control of previous
+ segment of stack. */
+ long:32;
+ long sstcpt:32; /* Pointer to task common address block. */
+ long sscsnm; /* Private control structure number for
+ microtasking. */
+ long ssusr1; /* Reserved for user. */
+ long ssusr2; /* Reserved for user. */
+ long sstpid; /* Process ID for pid based multi-tasking. */
+ long ssgvup; /* Pointer to multitasking thread giveup. */
+ long sscray[7]; /* Reserved for Cray Research. */
+ long ssa0;
+ long ssa1;
+ long ssa2;
+ long ssa3;
+ long ssa4;
+ long ssa5;
+ long ssa6;
+ long ssa7;
+ long sss0;
+ long sss1;
+ long sss2;
+ long sss3;
+ long sss4;
+ long sss5;
+ long sss6;
+ long sss7;
+ };
+
+#else /* CRAY2 */
+/* The following structure defines the vector of words
+ returned by the STKSTAT library routine. */
+struct stk_stat
+ {
+ long now; /* Current total stack size. */
+ long maxc; /* Amount of contiguous space which would
+ be required to satisfy the maximum
+ stack demand to date. */
+ long high_water; /* Stack high-water mark. */
+ long overflows; /* Number of stack overflow ($STKOFEN) calls. */
+ long hits; /* Number of internal buffer hits. */
+ long extends; /* Number of block extensions. */
+ long stko_mallocs; /* Block allocations by $STKOFEN. */
+ long underflows; /* Number of stack underflow calls ($STKRETN). */
+ long stko_free; /* Number of deallocations by $STKRETN. */
+ long stkm_free; /* Number of deallocations by $STKMRET. */
+ long segments; /* Current number of stack segments. */
+ long maxs; /* Maximum number of stack segments so far. */
+ long pad_size; /* Stack pad size. */
+ long current_address; /* Current stack segment address. */
+ long current_size; /* Current stack segment size. This
+ number is actually corrupted by STKSTAT to
+ include the fifteen word trailer area. */
+ long initial_address; /* Address of initial segment. */
+ long initial_size; /* Size of initial segment. */
+ };
+
+/* The following structure describes the data structure which trails
+ any stack segment. I think that the description in 'asdef' is
+ out of date. I only describe the parts that I am sure about. */
+
+struct stk_trailer
+ {
+ long this_address; /* Address of this block. */
+ long this_size; /* Size of this block (does not include
+ this trailer). */
+ long unknown2;
+ long unknown3;
+ long link; /* Address of trailer block of previous
+ segment. */
+ long unknown5;
+ long unknown6;
+ long unknown7;
+ long unknown8;
+ long unknown9;
+ long unknown10;
+ long unknown11;
+ long unknown12;
+ long unknown13;
+ long unknown14;
+ };
+
+#endif /* CRAY2 */
+#endif /* not CRAY_STACK */
+
+#ifdef CRAY2
+/* Determine a "stack measure" for an arbitrary ADDRESS.
+ I doubt that "lint" will like this much. */
+
+static long
+i00afunc (long *address)
+{
+ struct stk_stat status;
+ struct stk_trailer *trailer;
+ long *block, size;
+ long result = 0;
+
+ /* We want to iterate through all of the segments. The first
+ step is to get the stack status structure. We could do this
+ more quickly and more directly, perhaps, by referencing the
+ $LM00 common block, but I know that this works. */
+
+ STKSTAT (&status);
+
+ /* Set up the iteration. */
+
+ trailer = (struct stk_trailer *) (status.current_address
+ + status.current_size
+ - 15);
+
+ /* There must be at least one stack segment. Therefore it is
+ a fatal error if "trailer" is null. */
+
+ if (trailer == 0)
+ abort ();
+
+ /* Discard segments that do not contain our argument address. */
+
+ while (trailer != 0)
+ {
+ block = (long *) trailer->this_address;
+ size = trailer->this_size;
+ if (block == 0 || size == 0)
+ abort ();
+ trailer = (struct stk_trailer *) trailer->link;
+ if ((block <= address) && (address < (block + size)))
+ break;
+ }
+
+ /* Set the result to the offset in this segment and add the sizes
+ of all predecessor segments. */
+
+ result = address - block;
+
+ if (trailer == 0)
+ {
+ return result;
+ }
+
+ do
+ {
+ if (trailer->this_size <= 0)
+ abort ();
+ result += trailer->this_size;
+ trailer = (struct stk_trailer *) trailer->link;
+ }
+ while (trailer != 0);
+
+ /* We are done. Note that if you present a bogus address (one
+ not in any segment), you will get a different number back, formed
+ from subtracting the address of the first block. This is probably
+ not what you want. */
+
+ return (result);
+}
+
+#else /* not CRAY2 */
+/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
+ Determine the number of the cell within the stack,
+ given the address of the cell. The purpose of this
+ routine is to linearize, in some sense, stack addresses
+ for alloca. */
+
+static long
+i00afunc (long address)
+{
+ long stkl = 0;
+
+ long size, pseg, this_segment, stack;
+ long result = 0;
+
+ struct stack_segment_linkage *ssptr;
+
+ /* Register B67 contains the address of the end of the
+ current stack segment. If you (as a subprogram) store
+ your registers on the stack and find that you are past
+ the contents of B67, you have overflowed the segment.
+
+ B67 also points to the stack segment linkage control
+ area, which is what we are really interested in. */
+
+ stkl = CRAY_STACKSEG_END ();
+ ssptr = (struct stack_segment_linkage *) stkl;
+
+ /* If one subtracts 'size' from the end of the segment,
+ one has the address of the first word of the segment.
+
+ If this is not the first segment, 'pseg' will be
+ nonzero. */
+
+ pseg = ssptr->sspseg;
+ size = ssptr->sssize;
+
+ this_segment = stkl - size;
+
+ /* It is possible that calling this routine itself caused
+ a stack overflow. Discard stack segments which do not
+ contain the target address. */
+
+ while (!(this_segment <= address && address <= stkl))
+ {
+#ifdef DEBUG_I00AFUNC
+ fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
+#endif
+ if (pseg == 0)
+ break;
+ stkl = stkl - pseg;
+ ssptr = (struct stack_segment_linkage *) stkl;
+ size = ssptr->sssize;
+ pseg = ssptr->sspseg;
+ this_segment = stkl - size;
+ }
+
+ result = address - this_segment;
+
+ /* If you subtract pseg from the current end of the stack,
+ you get the address of the previous stack segment's end.
+ This seems a little convoluted to me, but I'll bet you save
+ a cycle somewhere. */
+
+ while (pseg != 0)
+ {
+#ifdef DEBUG_I00AFUNC
+ fprintf (stderr, "%011o %011o\n", pseg, size);
+#endif
+ stkl = stkl - pseg;
+ ssptr = (struct stack_segment_linkage *) stkl;
+ size = ssptr->sssize;
+ pseg = ssptr->sspseg;
+ result += size;
+ }
+ return (result);
+}
+
+#endif /* not CRAY2 */
+#endif /* CRAY */
+
+#endif /* no alloca */
+#endif /* not GCC version 2 */
diff --git a/lib/dirname.c b/lib/dirname.c
new file mode 100644
index 00000000..15d25967
--- /dev/null
+++ b/lib/dirname.c
@@ -0,0 +1,70 @@
+/* dirname.c -- return all but the last element in a path
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+char *malloc ();
+#endif
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#else
+#include <strings.h>
+#ifndef strrchr
+#define strrchr rindex
+#endif
+#endif
+
+/* Return the leading directories part of PATH,
+ allocated with malloc. If out of memory, return 0.
+ Assumes that trailing slashes have already been
+ removed. */
+
+char *
+dirname (path)
+ char *path;
+{
+ char *newpath;
+ char *slash;
+ int length; /* Length of result, not including NUL. */
+
+ slash = strrchr (path, '/');
+ if (slash == 0)
+ {
+ /* File is in the current directory. */
+ path = ".";
+ length = 1;
+ }
+ else
+ {
+ /* Remove any trailing slashes from the result. */
+ while (slash > path && *slash == '/')
+ --slash;
+
+ length = slash - path + 1;
+ }
+ newpath = (char *) malloc (length + 1);
+ if (newpath == 0)
+ return 0;
+ strncpy (newpath, path, length);
+ newpath[length] = 0;
+ return newpath;
+}
diff --git a/lib/error.c b/lib/error.c
new file mode 100644
index 00000000..19c2ba88
--- /dev/null
+++ b/lib/error.c
@@ -0,0 +1,119 @@
+/* error.c -- error handler for noninteractive utilities
+ Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+
+#if HAVE_VPRINTF || HAVE_DOPRNT
+# if __STDC__
+# include <stdarg.h>
+# define VA_START(args, lastarg) va_start(args, lastarg)
+# else
+# include <varargs.h>
+# define VA_START(args, lastarg) va_start(args)
+# endif
+#else
+# define va_alist a1, a2, a3, a4, a5, a6, a7, a8
+# define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
+#endif
+
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#else
+void exit ();
+#endif
+
+/* If NULL, error will flush stdout, then print on stderr the program
+ name, a colon and a space. Otherwise, error will call this
+ function without parameters instead. */
+void (*error_print_progname) () = NULL;
+
+/* The calling program should define program_name and set it to the
+ name of the executing program. */
+extern char *program_name;
+
+#if HAVE_STRERROR
+char *strerror ();
+#else
+static char *
+private_strerror (errnum)
+ int errnum;
+{
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+
+ if (errnum > 0 && errnum <= sys_nerr)
+ return sys_errlist[errnum];
+ return "Unknown system error";
+}
+#define strerror private_strerror
+#endif
+
+/* Print the program name and error message MESSAGE, which is a printf-style
+ format string with optional args.
+ If ERRNUM is nonzero, print its corresponding system error message.
+ Exit with status STATUS if it is nonzero. */
+/* VARARGS */
+
+void
+#if defined(VA_START) && __STDC__
+error (int status, int errnum, const char *message, ...)
+#else
+error (status, errnum, message, va_alist)
+ int status;
+ int errnum;
+ char *message;
+ va_dcl
+#endif
+{
+#ifdef VA_START
+ va_list args;
+#endif
+
+ if (error_print_progname)
+ (*error_print_progname) ();
+ else
+ {
+ fflush (stdout);
+ fprintf (stderr, "%s: ", program_name);
+ }
+
+#ifdef VA_START
+ VA_START (args, message);
+# if HAVE_VPRINTF
+ vfprintf (stderr, message, args);
+# else
+ _doprnt (message, args, stderr);
+# endif
+ va_end (args);
+#else
+ fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
+#endif
+
+ if (errnum)
+ fprintf (stderr, ": %s", strerror (errnum));
+ putc ('\n', stderr);
+ fflush (stderr);
+ if (status)
+ exit (status);
+}
diff --git a/lib/fileblocks.c b/lib/fileblocks.c
new file mode 100644
index 00000000..83ac04fd
--- /dev/null
+++ b/lib/fileblocks.c
@@ -0,0 +1,66 @@
+/* Convert file size to number of blocks on System V-like machines.
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Brian L. Matthews, blm@6sceng.UUCP. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if !defined (HAVE_ST_BLOCKS) && !defined(_POSIX_SOURCE)
+#include <sys/types.h>
+#include <sys/param.h>
+
+#ifndef NINDIR
+/* Some SysV's, like Irix, seem to lack these. Hope they're correct. */
+/* Size of a indirect block, in bytes. */
+#ifndef BSIZE
+#define BSIZE 1024
+#endif
+
+/* Number of inode pointers per indirect block. */
+#define NINDIR (BSIZE/sizeof(daddr_t))
+#endif /* !NINDIR */
+
+/* Number of direct block addresses in an inode. */
+#define NDIR 10
+
+/* Return the number of 512-byte blocks in a file of SIZE bytes. */
+
+long
+st_blocks (size)
+ long size;
+{
+ long datablks = (size + 512 - 1) / 512;
+ long indrblks = 0;
+
+ if (datablks > NDIR)
+ {
+ indrblks = (datablks - NDIR - 1) / NINDIR + 1;
+
+ if (datablks > NDIR + NINDIR)
+ {
+ indrblks += (datablks - NDIR - NINDIR - 1) / (NINDIR * NINDIR) + 1;
+
+ if (datablks > NDIR + NINDIR + NINDIR * NINDIR)
+ indrblks++;
+ }
+ }
+
+ return datablks + indrblks;
+}
+#endif
diff --git a/lib/filemode.c b/lib/filemode.c
new file mode 100644
index 00000000..c86ee2ff
--- /dev/null
+++ b/lib/filemode.c
@@ -0,0 +1,237 @@
+/* filemode.c -- make a string describing file modes
+ Copyright (C) 1985, 1990, 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifndef S_IREAD
+#define S_IREAD S_IRUSR
+#define S_IWRITE S_IWUSR
+#define S_IEXEC S_IXUSR
+#endif
+
+#ifdef STAT_MACROS_BROKEN
+#undef S_ISBLK
+#undef S_ISCHR
+#undef S_ISDIR
+#undef S_ISFIFO
+#undef S_ISLNK
+#undef S_ISMPB
+#undef S_ISMPC
+#undef S_ISNWK
+#undef S_ISREG
+#undef S_ISSOCK
+#endif /* STAT_MACROS_BROKEN. */
+
+#if !defined(S_ISBLK) && defined(S_IFBLK)
+#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+#endif
+#if !defined(S_ISCHR) && defined(S_IFCHR)
+#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG) && defined(S_IFREG)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISFIFO) && defined(S_IFIFO)
+#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+#endif
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+#if !defined(S_ISSOCK) && defined(S_IFSOCK)
+#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+#endif
+#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
+#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
+#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
+#endif
+#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
+#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
+#endif
+
+void mode_string ();
+static char ftypelet ();
+static void rwx ();
+static void setst ();
+
+/* filemodestring - fill in string STR with an ls-style ASCII
+ representation of the st_mode field of file stats block STATP.
+ 10 characters are stored in STR; no terminating null is added.
+ The characters stored in STR are:
+
+ 0 File type. 'd' for directory, 'c' for character
+ special, 'b' for block special, 'm' for multiplex,
+ 'l' for symbolic link, 's' for socket, 'p' for fifo,
+ '-' for regular, '?' for any other file type
+
+ 1 'r' if the owner may read, '-' otherwise.
+
+ 2 'w' if the owner may write, '-' otherwise.
+
+ 3 'x' if the owner may execute, 's' if the file is
+ set-user-id, '-' otherwise.
+ 'S' if the file is set-user-id, but the execute
+ bit isn't set.
+
+ 4 'r' if group members may read, '-' otherwise.
+
+ 5 'w' if group members may write, '-' otherwise.
+
+ 6 'x' if group members may execute, 's' if the file is
+ set-group-id, '-' otherwise.
+ 'S' if it is set-group-id but not executable.
+
+ 7 'r' if any user may read, '-' otherwise.
+
+ 8 'w' if any user may write, '-' otherwise.
+
+ 9 'x' if any user may execute, 't' if the file is "sticky"
+ (will be retained in swap space after execution), '-'
+ otherwise.
+ 'T' if the file is sticky but not executable. */
+
+void
+filemodestring (statp, str)
+ struct stat *statp;
+ char *str;
+{
+ mode_string (statp->st_mode, str);
+}
+
+/* Like filemodestring, but only the relevant part of the `struct stat'
+ is given as an argument. */
+
+void
+mode_string (mode, str)
+ unsigned short mode;
+ char *str;
+{
+ str[0] = ftypelet ((long) mode);
+ rwx ((mode & 0700) << 0, &str[1]);
+ rwx ((mode & 0070) << 3, &str[4]);
+ rwx ((mode & 0007) << 6, &str[7]);
+ setst (mode, str);
+}
+
+/* Return a character indicating the type of file described by
+ file mode BITS:
+ 'd' for directories
+ 'b' for block special files
+ 'c' for character special files
+ 'm' for multiplexor files
+ 'l' for symbolic links
+ 's' for sockets
+ 'p' for fifos
+ '-' for regular files
+ '?' for any other file type. */
+
+static char
+ftypelet (bits)
+ long bits;
+{
+#ifdef S_ISBLK
+ if (S_ISBLK (bits))
+ return 'b';
+#endif
+ if (S_ISCHR (bits))
+ return 'c';
+ if (S_ISDIR (bits))
+ return 'd';
+ if (S_ISREG (bits))
+ return '-';
+#ifdef S_ISFIFO
+ if (S_ISFIFO (bits))
+ return 'p';
+#endif
+#ifdef S_ISLNK
+ if (S_ISLNK (bits))
+ return 'l';
+#endif
+#ifdef S_ISSOCK
+ if (S_ISSOCK (bits))
+ return 's';
+#endif
+#ifdef S_ISMPC
+ if (S_ISMPC (bits))
+ return 'm';
+#endif
+#ifdef S_ISNWK
+ if (S_ISNWK (bits))
+ return 'n';
+#endif
+ return '?';
+}
+
+/* Look at read, write, and execute bits in BITS and set
+ flags in CHARS accordingly. */
+
+static void
+rwx (bits, chars)
+ unsigned short bits;
+ char *chars;
+{
+ chars[0] = (bits & S_IREAD) ? 'r' : '-';
+ chars[1] = (bits & S_IWRITE) ? 'w' : '-';
+ chars[2] = (bits & S_IEXEC) ? 'x' : '-';
+}
+
+/* Set the 's' and 't' flags in file attributes string CHARS,
+ according to the file mode BITS. */
+
+static void
+setst (bits, chars)
+ unsigned short bits;
+ char *chars;
+{
+#ifdef S_ISUID
+ if (bits & S_ISUID)
+ {
+ if (chars[3] != 'x')
+ /* Set-uid, but not executable by owner. */
+ chars[3] = 'S';
+ else
+ chars[3] = 's';
+ }
+#endif
+#ifdef S_ISGID
+ if (bits & S_ISGID)
+ {
+ if (chars[6] != 'x')
+ /* Set-gid, but not executable by group. */
+ chars[6] = 'S';
+ else
+ chars[6] = 's';
+ }
+#endif
+#ifdef S_ISVTX
+ if (bits & S_ISVTX)
+ {
+ if (chars[9] != 'x')
+ /* Sticky, but not executable by others. */
+ chars[9] = 'T';
+ else
+ chars[9] = 't';
+ }
+#endif
+}
diff --git a/lib/fnmatch.c b/lib/fnmatch.c
new file mode 100644
index 00000000..2fb65b52
--- /dev/null
+++ b/lib/fnmatch.c
@@ -0,0 +1,200 @@
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <fnmatch.h>
+#include <ctype.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__)
+
+
+#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
+extern int errno;
+#endif
+
+/* Match STRING against the filename pattern PATTERN, returning zero if
+ it matches, nonzero if not. */
+int
+fnmatch (pattern, string, flags)
+ const char *pattern;
+ const char *string;
+ int flags;
+{
+ register const char *p = pattern, *n = string;
+ register char c;
+
+/* Note that this evalutes C many times. */
+#define FOLD(c) ((flags & FNM_CASEFOLD) && isupper (c) ? tolower (c) : (c))
+
+ while ((c = *p++) != '\0')
+ {
+ c = FOLD (c);
+
+ switch (c)
+ {
+ case '?':
+ if (*n == '\0')
+ return FNM_NOMATCH;
+ else if ((flags & FNM_FILE_NAME) && *n == '/')
+ return FNM_NOMATCH;
+ else if ((flags & FNM_PERIOD) && *n == '.' &&
+ (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+ return FNM_NOMATCH;
+ break;
+
+ case '\\':
+ if (!(flags & FNM_NOESCAPE))
+ {
+ c = *p++;
+ c = FOLD (c);
+ }
+ if (FOLD (*n) != c)
+ return FNM_NOMATCH;
+ break;
+
+ case '*':
+ if ((flags & FNM_PERIOD) && *n == '.' &&
+ (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+ return FNM_NOMATCH;
+
+ for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
+ if (((flags & FNM_FILE_NAME) && *n == '/') ||
+ (c == '?' && *n == '\0'))
+ return FNM_NOMATCH;
+
+ if (c == '\0')
+ return 0;
+
+ {
+ char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
+ c1 = FOLD (c1);
+ for (--p; *n != '\0'; ++n)
+ if ((c == '[' || FOLD (*n) == c1) &&
+ fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
+ return 0;
+ return FNM_NOMATCH;
+ }
+
+ case '[':
+ {
+ /* Nonzero if the sense of the character class is inverted. */
+ register int not;
+
+ if (*n == '\0')
+ return FNM_NOMATCH;
+
+ if ((flags & FNM_PERIOD) && *n == '.' &&
+ (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+ return FNM_NOMATCH;
+
+ not = (*p == '!' || *p == '^');
+ if (not)
+ ++p;
+
+ c = *p++;
+ for (;;)
+ {
+ register char cstart = c, cend = c;
+
+ if (!(flags & FNM_NOESCAPE) && c == '\\')
+ cstart = cend = *p++;
+
+ cstart = cend = FOLD (cstart);
+
+ if (c == '\0')
+ /* [ (unterminated) loses. */
+ return FNM_NOMATCH;
+
+ c = *p++;
+ c = FOLD (c);
+
+ if ((flags & FNM_FILE_NAME) && c == '/')
+ /* [/] can never match. */
+ return FNM_NOMATCH;
+
+ if (c == '-' && *p != ']')
+ {
+ cend = *p++;
+ if (!(flags & FNM_NOESCAPE) && cend == '\\')
+ cend = *p++;
+ if (cend == '\0')
+ return FNM_NOMATCH;
+ cend = FOLD (cend);
+
+ c = *p++;
+ }
+
+ if (FOLD (*n) >= cstart && FOLD (*n) <= cend)
+ goto matched;
+
+ if (c == ']')
+ break;
+ }
+ if (!not)
+ return FNM_NOMATCH;
+ break;
+
+ matched:;
+ /* Skip the rest of the [...] that already matched. */
+ while (c != ']')
+ {
+ if (c == '\0')
+ /* [... (unterminated) loses. */
+ return FNM_NOMATCH;
+
+ c = *p++;
+ if (!(flags & FNM_NOESCAPE) && c == '\\')
+ /* XXX 1003.2d11 is unclear if this is right. */
+ ++p;
+ }
+ if (not)
+ return FNM_NOMATCH;
+ }
+ break;
+
+ default:
+ if (c != FOLD (*n))
+ return FNM_NOMATCH;
+ }
+
+ ++n;
+ }
+
+ if (*n == '\0')
+ return 0;
+
+ if ((flags & FNM_LEADING_DIR) && *n == '/')
+ /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
+ return 0;
+
+ return FNM_NOMATCH;
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
diff --git a/lib/fnmatch.h b/lib/fnmatch.h
new file mode 100644
index 00000000..69eab0c0
--- /dev/null
+++ b/lib/fnmatch.h
@@ -0,0 +1,67 @@
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#ifndef _FNMATCH_H
+
+#define _FNMATCH_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined (__cplusplus) || (defined (__STDC__) && __STDC__)
+#undef __P
+#define __P(args) args
+#else /* Not C++ or ANSI C. */
+#undef __P
+#define __P(args) ()
+/* We can get away without defining `const' here only because in this file
+ it is used only inside the prototype for `fnmatch', which is elided in
+ non-ANSI C where `const' is problematical. */
+#endif /* C++ or ANSI C. */
+
+
+/* We #undef these before defining them because some losing systems
+ (HP-UX A.08.07 for example) define these in <unistd.h>. */
+#undef FNM_PATHNAME
+#undef FNM_NOESCAPE
+#undef FNM_PERIOD
+
+/* Bits set in the FLAGS argument to `fnmatch'. */
+#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
+#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */
+#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */
+
+#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_GNU_SOURCE)
+#define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */
+#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */
+#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */
+#endif
+
+/* Value returned by `fnmatch' if STRING does not match PATTERN. */
+#define FNM_NOMATCH 1
+
+/* Match STRING against the filename pattern PATTERN,
+ returning zero if it matches, FNM_NOMATCH if not. */
+extern int fnmatch __P ((const char *__pattern, const char *__string,
+ int __flags));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* fnmatch.h */
diff --git a/lib/getline.c b/lib/getline.c
new file mode 100644
index 00000000..519ff932
--- /dev/null
+++ b/lib/getline.c
@@ -0,0 +1,126 @@
+/* getline.c -- Replacement for GNU C library function getline
+
+Copyright (C) 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 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. */
+
+/* Written by Jan Brittenson, bson@gnu.ai.mit.edu. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+#define NDEBUG
+#include <assert.h>
+
+#if STDC_HEADERS
+#include <stdlib.h>
+#else
+char *malloc (), *realloc ();
+#endif
+
+/* Always add at least this many bytes when extending the buffer. */
+#define MIN_CHUNK 64
+
+/* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR
+ + OFFSET (and null-terminate it). *LINEPTR is a pointer returned from
+ malloc (or NULL), pointing to *N characters of space. It is realloc'd
+ as necessary. Return the number of characters read (not including the
+ null terminator), or -1 on error or EOF. */
+
+int
+getstr (lineptr, n, stream, terminator, offset)
+ char **lineptr;
+ size_t *n;
+ FILE *stream;
+ char terminator;
+ int offset;
+{
+ int nchars_avail; /* Allocated but unused chars in *LINEPTR. */
+ char *read_pos; /* Where we're reading into *LINEPTR. */
+ int ret;
+
+ if (!lineptr || !n || !stream)
+ return -1;
+
+ if (!*lineptr)
+ {
+ *n = MIN_CHUNK;
+ *lineptr = malloc (*n);
+ if (!*lineptr)
+ return -1;
+ }
+
+ nchars_avail = *n - offset;
+ read_pos = *lineptr + offset;
+
+ for (;;)
+ {
+ register int c = getc (stream);
+
+ /* We always want at least one char left in the buffer, since we
+ always (unless we get an error while reading the first char)
+ NUL-terminate the line buffer. */
+
+ assert(*n - nchars_avail == read_pos - *lineptr);
+ if (nchars_avail < 1)
+ {
+ if (*n > MIN_CHUNK)
+ *n *= 2;
+ else
+ *n += MIN_CHUNK;
+
+ nchars_avail = *n + *lineptr - read_pos;
+ *lineptr = realloc (*lineptr, *n);
+ if (!*lineptr)
+ return -1;
+ read_pos = *n - nchars_avail + *lineptr;
+ assert(*n - nchars_avail == read_pos - *lineptr);
+ }
+
+ if (c == EOF || ferror (stream))
+ {
+ /* Return partial line, if any. */
+ if (read_pos == *lineptr)
+ return -1;
+ else
+ break;
+ }
+
+ *read_pos++ = c;
+ nchars_avail--;
+
+ if (c == terminator)
+ /* Return the line. */
+ break;
+ }
+
+ /* Done - NUL terminate and return the number of chars read. */
+ *read_pos = '\0';
+
+ ret = read_pos - (*lineptr + offset);
+ return ret;
+}
+
+int
+getline (lineptr, n, stream)
+ char **lineptr;
+ size_t *n;
+ FILE *stream;
+{
+ return getstr (lineptr, n, stream, '\n', 0);
+}
diff --git a/lib/getopt.c b/lib/getopt.c
new file mode 100644
index 00000000..43c0a6a9
--- /dev/null
+++ b/lib/getopt.c
@@ -0,0 +1,748 @@
+/* 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, 94
+ 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. */
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+ Ditto for AIX 3.2 and <stdlib.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if !defined (__STDC__) || !__STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+#include <stdlib.h>
+#endif /* GNU C library. */
+
+/* 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 = NULL;
+
+/* 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;
+
+/* Value of POSIXLY_CORRECT environment variable. */
+static char *posixly_correct;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+#include <string.h>
+#define my_index strchr
+#else
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+ const char *str;
+ int chr;
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+ If not using GCC, it is ok not to declare it. */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+ That was relevant to code that was here before. */
+#if !defined (__STDC__) || !__STDC__
+/* gcc with -traditional declares the built-in strlen to return int,
+ and has done so at least since version 2.4.5. -- rms. */
+extern int strlen (const char *);
+#endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+static void
+exchange (argv)
+ char **argv;
+{
+ int 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;
+}
+
+/* Initialize the internal data when the first call is made. */
+
+static const char *
+_getopt_initialize (optstring)
+ const char *optstring;
+{
+ /* 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. */
+
+ first_nonopt = last_nonopt = optind = 1;
+
+ nextchar = NULL;
+
+ posixly_correct = getenv ("POSIXLY_CORRECT");
+
+ /* 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 (posixly_correct != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+
+ return optstring;
+}
+
+/* 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;
+{
+ optarg = NULL;
+
+ if (optind == 0)
+ optstring = _getopt_initialize (optstring);
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ /* Advance to the next ARGV-element. */
+
+ 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;
+
+ /* Skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc
+ && (argv[optind][0] != '-' || argv[optind][1] == '\0'))
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* The 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'))
+ {
+ if (ordering == REQUIRE_ORDER)
+ return EOF;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Skip the initial punctuation. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ /* Decode the current option-ARGV-element. */
+
+ /* Check whether the ARGV-element is a long option.
+
+ If long_only and the ARGV-element has the form "-f", where f is
+ a valid short option, don't consider it an abbreviated form of
+ a long option that starts with f. Otherwise there would be no
+ way to give the -f short option.
+
+ On the other hand, if there's a long option "fubar" and
+ the ARGV-element is "-fu", do consider that an abbreviation of
+ the long option, just like "--fu", and not "-f" with arg "u".
+
+ This distinction seems to be the most useful approach. */
+
+ if (longopts != NULL
+ && (argv[optind][1] == '-'
+ || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound;
+ int option_index;
+
+ for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, nextchar, nameend - nextchar))
+ {
+ if (nameend - 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 or later 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 (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = nameend + 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] == '-'
+ || 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 short 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 (posixly_correct)
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+ else
+ fprintf (stderr, "%s: invalid option -- %c\n", argv[0], c);
+ }
+ 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 = NULL;
+ 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)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: option requires an argument -- %c\n",
+ argv[0], c);
+ }
+ 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 */
diff --git a/lib/getopt.h b/lib/getopt.h
new file mode 100644
index 00000000..4ac33b71
--- /dev/null
+++ b/lib/getopt.h
@@ -0,0 +1,129 @@
+/* Declarations for getopt.
+ Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+#if defined (__STDC__) && __STDC__
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#if defined (__STDC__) && __STDC__
+#ifdef __GNU_LIBRARY__
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/lib/getopt1.c b/lib/getopt1.c
new file mode 100644
index 00000000..4580211c
--- /dev/null
+++ b/lib/getopt1.c
@@ -0,0 +1,180 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993, 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
+#include <config.h>
+#endif
+
+#include "getopt.h"
+
+#if !defined (__STDC__) || !__STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#else
+char *getenv ();
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+ If an option that starts with '-' (not '--') doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] =
+ {
+ {"add", 1, 0, 0},
+ {"append", 0, 0, 0},
+ {"delete", 1, 0, 0},
+ {"verbose", 0, 0, 0},
+ {"create", 0, 0, 0},
+ {"file", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long (argc, argv, "abc:d:0123456789",
+ long_options, &option_index);
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case 0:
+ printf ("option %s", long_options[option_index].name);
+ if (optarg)
+ printf (" with arg %s", optarg);
+ printf ("\n");
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case 'd':
+ printf ("option d with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/lib/idcache.c b/lib/idcache.c
new file mode 100644
index 00000000..34dcc07c
--- /dev/null
+++ b/lib/idcache.c
@@ -0,0 +1,210 @@
+/* idcache.c -- map user and group IDs, cached for speed
+ Copyright (C) 1985, 1988, 1989, 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifndef _POSIX_VERSION
+struct passwd *getpwuid ();
+struct passwd *getpwnam ();
+struct group *getgrgid ();
+struct group *getgrnam ();
+#endif
+
+char *xmalloc ();
+char *xstrdup ();
+
+struct userid
+{
+ union
+ {
+ uid_t u;
+ gid_t g;
+ } id;
+ char *name;
+ struct userid *next;
+};
+
+static struct userid *user_alist;
+
+/* The members of this list have names not in the local passwd file. */
+static struct userid *nouser_alist;
+
+/* Translate UID to a login name or a stringified number,
+ with cache. */
+
+char *
+getuser (uid)
+ uid_t uid;
+{
+ register struct userid *tail;
+ struct passwd *pwent;
+ char usernum_string[20];
+
+ for (tail = user_alist; tail; tail = tail->next)
+ if (tail->id.u == uid)
+ return tail->name;
+
+ pwent = getpwuid (uid);
+ tail = (struct userid *) xmalloc (sizeof (struct userid));
+ tail->id.u = uid;
+ if (pwent == 0)
+ {
+ sprintf (usernum_string, "%u", (unsigned) uid);
+ tail->name = xstrdup (usernum_string);
+ }
+ else
+ tail->name = xstrdup (pwent->pw_name);
+
+ /* Add to the head of the list, so most recently used is first. */
+ tail->next = user_alist;
+ user_alist = tail;
+ return tail->name;
+}
+
+/* Translate USER to a UID, with cache.
+ Return NULL if there is no such user.
+ (We also cache which user names have no passwd entry,
+ so we don't keep looking them up.) */
+
+uid_t *
+getuidbyname (user)
+ char *user;
+{
+ register struct userid *tail;
+ struct passwd *pwent;
+
+ for (tail = user_alist; tail; tail = tail->next)
+ /* Avoid a function call for the most common case. */
+ if (*tail->name == *user && !strcmp (tail->name, user))
+ return &tail->id.u;
+
+ for (tail = nouser_alist; tail; tail = tail->next)
+ /* Avoid a function call for the most common case. */
+ if (*tail->name == *user && !strcmp (tail->name, user))
+ return 0;
+
+ pwent = getpwnam (user);
+
+ tail = (struct userid *) xmalloc (sizeof (struct userid));
+ tail->name = xstrdup (user);
+
+ /* Add to the head of the list, so most recently used is first. */
+ if (pwent)
+ {
+ tail->id.u = pwent->pw_uid;
+ tail->next = user_alist;
+ user_alist = tail;
+ return &tail->id.u;
+ }
+
+ tail->next = nouser_alist;
+ nouser_alist = tail;
+ return 0;
+}
+
+/* Use the same struct as for userids. */
+static struct userid *group_alist;
+static struct userid *nogroup_alist;
+
+/* Translate GID to a group name or a stringified number,
+ with cache. */
+
+char *
+getgroup (gid)
+ gid_t gid;
+{
+ register struct userid *tail;
+ struct group *grent;
+ char groupnum_string[20];
+
+ for (tail = group_alist; tail; tail = tail->next)
+ if (tail->id.g == gid)
+ return tail->name;
+
+ grent = getgrgid (gid);
+ tail = (struct userid *) xmalloc (sizeof (struct userid));
+ tail->id.g = gid;
+ if (grent == 0)
+ {
+ sprintf (groupnum_string, "%u", (unsigned int) gid);
+ tail->name = xstrdup (groupnum_string);
+ }
+ else
+ tail->name = xstrdup (grent->gr_name);
+
+ /* Add to the head of the list, so most recently used is first. */
+ tail->next = group_alist;
+ group_alist = tail;
+ return tail->name;
+}
+
+/* Translate GROUP to a UID, with cache.
+ Return NULL if there is no such group.
+ (We also cache which group names have no group entry,
+ so we don't keep looking them up.) */
+
+gid_t *
+getgidbyname (group)
+ char *group;
+{
+ register struct userid *tail;
+ struct group *grent;
+
+ for (tail = group_alist; tail; tail = tail->next)
+ /* Avoid a function call for the most common case. */
+ if (*tail->name == *group && !strcmp (tail->name, group))
+ return &tail->id.g;
+
+ for (tail = nogroup_alist; tail; tail = tail->next)
+ /* Avoid a function call for the most common case. */
+ if (*tail->name == *group && !strcmp (tail->name, group))
+ return 0;
+
+ grent = getgrnam (group);
+
+ tail = (struct userid *) xmalloc (sizeof (struct userid));
+ tail->name = xstrdup (group);
+
+ /* Add to the head of the list, so most recently used is first. */
+ if (grent)
+ {
+ tail->id.g = grent->gr_gid;
+ tail->next = group_alist;
+ group_alist = tail;
+ return &tail->id.g;
+ }
+
+ tail->next = nogroup_alist;
+ nogroup_alist = tail;
+ return 0;
+}
diff --git a/lib/listfile.c b/lib/listfile.c
index 9b4ed20d..7e32079f 100644
--- a/lib/listfile.c
+++ b/lib/listfile.c
@@ -1,46 +1,44 @@
/* listfile.c -- display a long listing of a file
- Copyright (C) 1991, 1993, 2000, 2004, 2005, 2007 Free Software Foundation, Inc.
+ Copyright (C) 1991, 1993 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
+ 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 3 of the License, or
- (at your option) any later version.
-
+ 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, see <http://www.gnu.org/licenses/>.
-*/
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#ifdef HAVE_CONFIG_H
#include <config.h>
-
-#include <alloca.h>
+#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
-#include <stdlib.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <unistd.h> /* for readlink() */
-#include <openat.h>
-
-#include "human.h"
-#include "xalloc.h"
#include "pathmax.h"
-#include "error.h"
-#include "filemode.h"
-#include "dircallback.h"
-#include "idcache.h"
-#include "listfile.h"
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+char *getenv ();
+extern int errno;
+#endif
/* Since major is a function on SVR4, we can't use `ifndef major'. */
#ifdef MAJOR_IN_MKDEV
@@ -52,31 +50,6 @@
#define HAVE_MAJOR
#endif
-
-
-
-
-#ifdef HAVE_LOCALE_H
-#include <locale.h>
-#endif
-
-#if ENABLE_NLS
-# include <libintl.h>
-# define _(Text) gettext (Text)
-#else
-# define _(Text) Text
-#define textdomain(Domain)
-#define bindtextdomain(Package, Directory)
-#endif
-#ifdef gettext_noop
-# define N_(String) gettext_noop (String)
-#else
-/* See locate.c for explanation as to why not use (String) */
-# define N_(String) String
-#endif
-
-
-
#ifdef STAT_MACROS_BROKEN
#undef S_ISCHR
#undef S_ISBLK
@@ -89,69 +62,40 @@
#ifndef S_ISBLK
#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
#endif
-#if defined S_IFLNK && !defined S_ISLNK
+#if defined(S_IFLNK) && !defined(S_ISLNK)
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
#endif
-/* Get or fake the disk device blocksize.
- Usually defined by sys/param.h (if at all). */
-#ifndef DEV_BSIZE
-# ifdef BSIZE
-# define DEV_BSIZE BSIZE
-# else /* !BSIZE */
-# define DEV_BSIZE 4096
-# endif /* !BSIZE */
-#endif /* !DEV_BSIZE */
+#if defined(S_ISLNK)
+int readlink ();
+#endif
/* Extract or fake data from a `struct stat'.
- ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes.
- ST_NBLOCKS: Number of blocks in the file, including indirect blocks.
- ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */
-#ifndef HAVE_STRUCT_STAT_ST_BLOCKS
-# define ST_BLKSIZE(statbuf) DEV_BSIZE
-# if defined _POSIX_SOURCE || !defined BSIZE /* fileblocks.c uses BSIZE. */
-# define ST_NBLOCKS(statbuf) \
- (S_ISREG ((statbuf).st_mode) \
- || S_ISDIR ((statbuf).st_mode) \
- ? (statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0) : 0)
-# else /* !_POSIX_SOURCE && BSIZE */
-# define ST_NBLOCKS(statbuf) \
- (S_ISREG ((statbuf).st_mode) \
- || S_ISDIR ((statbuf).st_mode) \
- ? st_blocks ((statbuf).st_size) : 0)
-# endif /* !_POSIX_SOURCE && BSIZE */
-#else /* HAVE_STRUCT_STAT_ST_BLOCKS */
-/* Some systems, like Sequents, return st_blksize of 0 on pipes. */
-# define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \
- ? (statbuf).st_blksize : DEV_BSIZE)
-# if defined hpux || defined __hpux__ || defined __hpux
-/* HP-UX counts st_blocks in 1024-byte units.
- This loses when mixing HP-UX and BSD filesystems with NFS. */
-# define ST_NBLOCKSIZE 1024
-# else /* !hpux */
-# if defined _AIX && defined _I386
-/* AIX PS/2 counts st_blocks in 4K units. */
-# define ST_NBLOCKSIZE (4 * 1024)
-# else /* not AIX PS/2 */
-# if defined _CRAY
-# define ST_NBLOCKS(statbuf) \
- (S_ISREG ((statbuf).st_mode) \
- || S_ISDIR ((statbuf).st_mode) \
- ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0)
-# endif /* _CRAY */
-# endif /* not AIX PS/2 */
-# endif /* !hpux */
-#endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
-
-#ifndef ST_NBLOCKS
-# define ST_NBLOCKS(statbuf) \
- (S_ISREG ((statbuf).st_mode) \
- || S_ISDIR ((statbuf).st_mode) \
- ? (statbuf).st_blocks : 0)
+ ST_NBLOCKS: Number of 512-byte blocks in the file
+ (including indirect blocks).
+ HP-UX, perhaps uniquely, counts st_blocks in 1024-byte units.
+ This workaround loses when mixing HP-UX and 4BSD filesystems, though. */
+#ifdef _POSIX_SOURCE
+# define ST_NBLOCKS(statp) (((statp)->st_size + 512 - 1) / 512)
+#else
+# ifndef HAVE_ST_BLOCKS
+# define ST_NBLOCKS(statp) (st_blocks ((statp)->st_size))
+# else
+# if defined(hpux) || defined(__hpux__)
+# define ST_NBLOCKS(statp) ((statp)->st_blocks * 2)
+# else
+# define ST_NBLOCKS(statp) ((statp)->st_blocks)
+# endif
+# endif
#endif
-#ifndef ST_NBLOCKSIZE
-# define ST_NBLOCKSIZE 512
+/* Convert B 512-byte blocks to kilobytes if K is nonzero,
+ otherwise return it unchanged. */
+#define convert_blocks(b, k) ((k) ? ((b) + 1) / 2 : (b))
+
+#ifndef _POSIX_VERSION
+struct passwd *getpwuid ();
+struct group *getgrgid ();
#endif
#ifdef major /* Might be defined in sys/types.h. */
@@ -163,148 +107,86 @@
#endif
#undef HAVE_MAJOR
+char *xmalloc ();
+void error ();
+void mode_string ();
-static void print_name (register const char *p, FILE *stream, int literal_control_chars);
-
-
-size_t
-file_blocksize(const struct stat *p)
-{
- return ST_NBLOCKSIZE;
-}
-
-
+char *get_link_name ();
+char *getgroup ();
+char *getuser ();
+void print_name_with_quoting ();
/* NAME is the name to print.
RELNAME is the path to access it from the current directory.
STATP is the results of stat or lstat on it.
- Use CURRENT_TIME to decide whether to print yyyy or hh:mm.
- Use OUTPUT_BLOCK_SIZE to determine how to print file block counts
- and sizes.
STREAM is the stdio stream to print on. */
void
-list_file (const char *name,
- int dirfd,
- char *relname,
- const struct stat *statp,
- time_t current_time,
- int output_block_size,
- int literal_control_chars,
- FILE *stream)
+list_file (name, relname, statp, stream)
+ char *name;
+ char *relname;
+ struct stat *statp;
+ FILE *stream;
{
- char modebuf[12];
- struct tm const *when_local;
- char const *user_name;
- char const *group_name;
- char hbuf[LONGEST_HUMAN_READABLE + 1];
-
-#if HAVE_ST_DM_MODE
- /* Cray DMF: look at the file's migrated, not real, status */
- strmode (statp->st_dm_mode, modebuf);
-#else
- strmode (statp->st_mode, modebuf);
-#endif
+ static int kilobytes = -1; /* -1 = uninitialized, 0 = 512, 1 = 1024. */
+ char modebuf[20];
+ char timebuf[40];
+ time_t current_time = time ((time_t *) 0);
- fprintf (stream, "%6s ",
- human_readable ((uintmax_t) statp->st_ino, hbuf,
- human_ceiling,
- 1, 1));
+ if (kilobytes == -1)
+ kilobytes = getenv ("POSIXLY_CORRECT") == 0;
+
+ mode_string (statp->st_mode, modebuf);
+ modebuf[10] = '\0';
+
+ strcpy (timebuf, ctime (&statp->st_mtime));
+ if (current_time > statp->st_mtime + 6L * 30L * 24L * 60L * 60L /* Old. */
+ || current_time < statp->st_mtime - 60L * 60L) /* In the future. */
+ {
+ /* The file is fairly old or in the future.
+ POSIX says the cutoff is 6 months old;
+ approximate this by 6*30 days.
+ Allow a 1 hour slop factor for what is considered "the future",
+ to allow for NFS server/client clock disagreement.
+ Show the year instead of the time of day. */
+ strcpy (timebuf + 11, timebuf + 19);
+ }
+ timebuf[16] = 0;
- fprintf (stream, "%4s ",
- human_readable ((uintmax_t) ST_NBLOCKS (*statp), hbuf,
- human_ceiling,
- ST_NBLOCKSIZE, output_block_size));
+ fprintf (stream, "%6lu ", statp->st_ino);
+ fprintf (stream, "%4u ", convert_blocks (ST_NBLOCKS (statp), kilobytes));
- /* modebuf includes the space between the mode and the number of links,
- as the POSIX "optional alternate access method flag". */
- fprintf (stream, "%s%3lu ", modebuf, (unsigned long) statp->st_nlink);
+ /* The space between the mode and the number of links is the POSIX
+ "optional alternate access method flag". */
+ fprintf (stream, "%s %3u ", modebuf, statp->st_nlink);
- user_name = getuser (statp->st_uid);
- if (user_name)
- fprintf (stream, "%-8s ", user_name);
- else
- fprintf (stream, "%-8lu ", (unsigned long) statp->st_uid);
+ fprintf (stream, "%-8.8s ", getuser (statp->st_uid));
- group_name = getgroup (statp->st_gid);
- if (group_name)
- fprintf (stream, "%-8s ", group_name);
- else
- fprintf (stream, "%-8lu ", (unsigned long) statp->st_gid);
+ fprintf (stream, "%-8.8s ", getgroup (statp->st_gid));
if (S_ISCHR (statp->st_mode) || S_ISBLK (statp->st_mode))
#ifdef HAVE_ST_RDEV
- fprintf (stream, "%3lu, %3lu ",
- (unsigned long) major (statp->st_rdev),
- (unsigned long) minor (statp->st_rdev));
+ fprintf (stream, "%3u, %3u ", major (statp->st_rdev), minor (statp->st_rdev));
#else
fprintf (stream, " ");
#endif
else
- fprintf (stream, "%8s ",
- human_readable ((uintmax_t) statp->st_size, hbuf,
- human_ceiling,
- 1,
- output_block_size < 0 ? output_block_size : 1));
+ fprintf (stream, "%8lu ", statp->st_size);
- if ((when_local = localtime (&statp->st_mtime)))
- {
- char init_bigbuf[256];
- char *buf = init_bigbuf;
- size_t bufsize = sizeof init_bigbuf;
+ fprintf (stream, "%s ", timebuf + 4);
- /* Use strftime rather than ctime, because the former can produce
- locale-dependent names for the month (%b).
-
- Output the year if the file is fairly old or in the future.
- POSIX says the cutoff is 6 months old;
- approximate this by 6*30 days.
- Allow a 1 hour slop factor for what is considered "the future",
- to allow for NFS server/client clock disagreement. */
- char const *fmt =
- ((current_time - 6 * 30 * 24 * 60 * 60 <= statp->st_mtime
- && statp->st_mtime <= current_time + 60 * 60)
- ? "%b %e %H:%M"
- : "%b %e %Y");
-
- while (!strftime (buf, bufsize, fmt, when_local))
- buf = alloca (bufsize *= 2);
-
- fprintf (stream, "%s ", buf);
- }
- else
- {
- /* The time cannot be represented as a local time;
- print it as a huge integer number of seconds. */
- int width = 12;
-
- if (statp->st_mtime < 0)
- {
- char const *num = human_readable (- (uintmax_t) statp->st_mtime,
- hbuf, human_ceiling, 1, 1);
- int sign_width = width - strlen (num);
- fprintf (stream, "%*s%s ",
- sign_width < 0 ? 0 : sign_width, "-", num);
- }
- else
- fprintf (stream, "%*s ", width,
- human_readable ((uintmax_t) statp->st_mtime, hbuf,
- human_ceiling,
- 1, 1));
- }
-
- print_name (name, stream, literal_control_chars);
+ print_name_with_quoting (name, stream);
#ifdef S_ISLNK
if (S_ISLNK (statp->st_mode))
{
- char *linkname = get_link_name_at (name, dirfd, relname);
+ char *linkname = get_link_name (name, relname);
if (linkname)
{
fputs (" -> ", stream);
- print_name (linkname, stream, literal_control_chars);
+ print_name_with_quoting (linkname, stream);
free (linkname);
}
}
@@ -312,16 +194,10 @@ list_file (const char *name,
putc ('\n', stream);
}
-
-static void
-print_name_without_quoting (const char *p, FILE *stream)
-{
- fprintf(stream, "%s", p);
-}
-
-
-static void
-print_name_with_quoting (register const char *p, FILE *stream)
+void
+print_name_with_quoting (p, stream)
+ register char *p;
+ FILE *stream;
{
register unsigned char c;
@@ -370,17 +246,11 @@ print_name_with_quoting (register const char *p, FILE *stream)
}
}
-static void print_name (register const char *p, FILE *stream, int literal_control_chars)
-{
- if (literal_control_chars)
- print_name_without_quoting(p, stream);
- else
- print_name_with_quoting(p, stream);
-}
-
#ifdef S_ISLNK
-static char *
-get_link_name (const char *name, char *relname)
+char *
+get_link_name (name, relname)
+ char *name;
+ char *relname;
{
register char *linkname;
register int linklen;
@@ -389,7 +259,7 @@ get_link_name (const char *name, char *relname)
mount points with some automounters.
So allocate a pessimistic PATH_MAX + 1 bytes. */
#define LINK_BUF PATH_MAX
- linkname = xmalloc (LINK_BUF + 1);
+ linkname = (char *) xmalloc (LINK_BUF + 1);
linklen = readlink (relname, linkname, LINK_BUF);
if (linklen < 0)
{
@@ -400,34 +270,4 @@ get_link_name (const char *name, char *relname)
linkname[linklen] = '\0';
return linkname;
}
-
-struct link_name_args
-{
- const char *name;
- char *relname;
- char *result;
-};
-
-static int
-get_link_name_cb(void *context)
-{
- struct link_name_args *args = context;
- args->result = get_link_name(args->name, args->relname);
- return 0;
-}
-
-char *
-get_link_name_at (const char *name, int dirfd, char *relname)
-{
- struct link_name_args args;
- args.result = NULL;
- args.name = name;
- args.relname = relname;
- if (0 == run_in_dir(dirfd, get_link_name_cb, &args))
- return args.result;
- else
- return NULL;
-}
-
-
#endif
diff --git a/lib/memcmp.c b/lib/memcmp.c
new file mode 100644
index 00000000..339b5818
--- /dev/null
+++ b/lib/memcmp.c
@@ -0,0 +1,32 @@
+/* memcmp.c -- compare memory.
+ Return:
+ <0 if S1 < S2,
+ 0 if strings are identical,
+ >0 if S1 > S2.
+ Stops looking after N characters. Doesn't stop at nulls.
+ In the public domain.
+ By David MacKenzie <djm@gnu.ai.mit.edu>. */
+
+#include <sys/types.h>
+
+int
+#if __STDC__
+memcmp (void const *v1, void const *v2, size_t n)
+{
+ register char *s1 = (char *) v1, *s2 = (char *) v2;
+#else
+memcmp (s1, s2, n)
+ register char *s1, *s2;
+ register unsigned n;
+{
+#endif
+ register int diff;
+
+ while (n--)
+ {
+ diff = *s1++ - *s2++;
+ if (diff)
+ return diff;
+ }
+ return 0;
+}
diff --git a/lib/memset.c b/lib/memset.c
new file mode 100644
index 00000000..0e819f20
--- /dev/null
+++ b/lib/memset.c
@@ -0,0 +1,29 @@
+/* memset.c -- set an area of memory to a given value
+ Copyright (C) 1991 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. */
+
+char *
+memset (str, c, len)
+ char *str;
+ int c;
+ unsigned len;
+{
+ register char *st = str;
+
+ while (len-- > 0)
+ *st++ = c;
+ return str;
+}
diff --git a/lib/mktime.c b/lib/mktime.c
new file mode 100644
index 00000000..d441d8d8
--- /dev/null
+++ b/lib/mktime.c
@@ -0,0 +1,502 @@
+/* Copyright (C) 1993, 1994 Free Software Foundation, Inc.
+ Contributed by Noel Cragg (noel@cs.oberlin.edu), with fixes by
+ Michael E. Calwas (calwas@ttd.teradyne.com) and
+ Wade Hampton (tasi029@tmn.com).
+
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+/* Define this to have a standalone program to test this implementation of
+ mktime. */
+/* #define DEBUG */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h> /* Some systems define `time_t' here. */
+#include <time.h>
+
+
+#ifndef __isleap
+/* Nonzero if YEAR is a leap year (every 4 years,
+ except every 100th isn't, and every 400th is). */
+#define __isleap(year) \
+ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+#endif
+
+#ifndef __P
+#if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
+#define __P(args) args
+#else
+#define __P(args) ()
+#endif /* GCC. */
+#endif /* Not __P. */
+
+/* How many days are in each month. */
+const unsigned short int __mon_lengths[2][12] =
+ {
+ /* Normal years. */
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ /* Leap years. */
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+ };
+
+
+static int times_through_search; /* This library routine should never
+ hang -- make sure we always return
+ when we're searching for a value */
+
+
+#ifdef DEBUG
+
+#include <stdio.h>
+#include <ctype.h>
+
+int debugging_enabled = 0;
+
+/* Print the values in a `struct tm'. */
+static void
+printtm (it)
+ struct tm *it;
+{
+ printf ("%02d/%02d/%04d %02d:%02d:%02d (%s) yday:%03d dst:%d gmtoffset:%ld",
+ it->tm_mon + 1,
+ it->tm_mday,
+ it->tm_year + 1900,
+ it->tm_hour,
+ it->tm_min,
+ it->tm_sec,
+ it->tm_zone,
+ it->tm_yday,
+ it->tm_isdst,
+ it->tm_gmtoff);
+}
+#endif
+
+
+static time_t
+dist_tm (t1, t2)
+ struct tm *t1;
+ struct tm *t2;
+{
+ time_t distance = 0;
+ unsigned long int v1, v2;
+ int diff_flag = 0;
+
+ v1 = v2 = 0;
+
+#define doit(x, secs) \
+ v1 += t1->x * secs; \
+ v2 += t2->x * secs; \
+ if (!diff_flag) \
+ { \
+ if (t1->x < t2->x) \
+ diff_flag = -1; \
+ else if (t1->x > t2->x) \
+ diff_flag = 1; \
+ }
+
+ doit (tm_year, 31536000); /* Okay, not all years have 365 days. */
+ doit (tm_mon, 2592000); /* Okay, not all months have 30 days. */
+ doit (tm_mday, 86400);
+ doit (tm_hour, 3600);
+ doit (tm_min, 60);
+ doit (tm_sec, 1);
+
+#undef doit
+
+ /* We should also make sure that the sign of DISTANCE is correct -- if
+ DIFF_FLAG is positive, the distance should be positive and vice versa. */
+
+ distance = (v1 > v2) ? (v1 - v2) : (v2 - v1);
+ if (diff_flag < 0)
+ distance = -distance;
+
+ if (times_through_search > 20) /* Arbitrary # of calls, but makes sure we
+ never hang if there's a problem with
+ this algorithm. */
+ {
+ distance = diff_flag;
+ }
+
+ /* We need this DIFF_FLAG business because it is forseeable that the
+ distance may be zero when, in actuality, the two structures are
+ different. This is usually the case when the dates are 366 days apart
+ and one of the years is a leap year. */
+
+ if (distance == 0 && diff_flag)
+ distance = 86400 * diff_flag;
+
+ return distance;
+}
+
+
+/* MKTIME converts the values in a struct tm to a time_t. The values
+ in tm_wday and tm_yday are ignored; other values can be put outside
+ of legal ranges since they will be normalized. This routine takes
+ care of that normalization. */
+
+void
+do_normalization (tmptr)
+ struct tm *tmptr;
+{
+
+#define normalize(foo,x,y,bar); \
+ while (tmptr->foo < x) \
+ { \
+ tmptr->bar--; \
+ tmptr->foo = (y - (x - tmptr->foo) + 1); \
+ } \
+ while (tmptr->foo > y) \
+ { \
+ tmptr->foo = (x + (tmptr->foo - y) - 1); \
+ tmptr->bar++; \
+ }
+
+ normalize (tm_sec, 0, 59, tm_min);
+ normalize (tm_min, 0, 59, tm_hour);
+ normalize (tm_hour, 0, 23, tm_mday);
+
+ /* Do the month first, so day range can be found. */
+ normalize (tm_mon, 0, 11, tm_year);
+
+ /* Since the day range modifies the month, we should be careful how
+ we reference the array of month lengths -- it is possible that
+ the month will go negative, hence the modulo...
+
+ Also, tm_year is the year - 1900, so we have to 1900 to have it
+ work correctly. */
+
+ normalize (tm_mday, 1,
+ __mon_lengths[__isleap (tmptr->tm_year + 1900)]
+ [((tmptr->tm_mon < 0)
+ ? (12 + (tmptr->tm_mon % 12))
+ : (tmptr->tm_mon % 12)) ],
+ tm_mon);
+
+ /* Do the month again, because the day may have pushed it out of range. */
+ normalize (tm_mon, 0, 11, tm_year);
+
+ /* Do the day again, because the month may have changed the range. */
+ normalize (tm_mday, 1,
+ __mon_lengths[__isleap (tmptr->tm_year + 1900)]
+ [((tmptr->tm_mon < 0)
+ ? (12 + (tmptr->tm_mon % 12))
+ : (tmptr->tm_mon % 12)) ],
+ tm_mon);
+
+#ifdef DEBUG
+ if (debugging_enabled)
+ {
+ printf (" After normalizing:\n ");
+ printtm (tmptr);
+ putchar ('\n');
+ }
+#endif
+
+}
+
+
+/* Here's where the work gets done. */
+
+#define BAD_STRUCT_TM ((time_t) -1)
+
+time_t
+_mktime_internal (timeptr, producer)
+ struct tm *timeptr;
+ struct tm *(*producer) __P ((const time_t *));
+{
+ struct tm our_tm; /* our working space */
+ struct tm *me = &our_tm; /* a pointer to the above */
+ time_t result; /* the value we return */
+
+ *me = *timeptr; /* copy the struct tm that was passed
+ in by the caller */
+
+
+ /***************************/
+ /* Normalize the structure */
+ /***************************/
+
+ /* This routine assumes that the value of TM_ISDST is -1, 0, or 1.
+ If the user didn't pass it in that way, fix it. */
+
+ if (me->tm_isdst > 0)
+ me->tm_isdst = 1;
+ else if (me->tm_isdst < 0)
+ me->tm_isdst = -1;
+
+ do_normalization (me);
+
+ /* Get out of here if it's not possible to represent this struct.
+ If any of the values in the normalized struct tm are negative,
+ our algorithms won't work. Luckily, we only need to check the
+ year at this point; normalization guarantees that all values will
+ be in correct ranges EXCEPT the year. */
+
+ if (me->tm_year < 0)
+ return BAD_STRUCT_TM;
+
+ /*************************************************/
+ /* Find the appropriate time_t for the structure */
+ /*************************************************/
+
+ /* Modified b-search -- make intelligent guesses as to where the
+ time might lie along the timeline, assuming that our target time
+ lies a linear distance (w/o considering time jumps of a
+ particular region).
+
+ Assume that time does not fluctuate at all along the timeline --
+ e.g., assume that a day will always take 86400 seconds, etc. --
+ and come up with a hypothetical value for the time_t
+ representation of the struct tm TARGET, in relation to the guess
+ variable -- it should be pretty close!
+
+ After testing this, the maximum number of iterations that I had
+ on any number that I tried was 3! Not bad.
+
+ The reason this is not a subroutine is that we will modify some
+ fields in the struct tm (yday and mday). I've never felt good
+ about side-effects when writing structured code... */
+
+ {
+ struct tm *guess_tm;
+ time_t guess = 0;
+ time_t distance = 0;
+ time_t last_distance = 0;
+
+ times_through_search = 0;
+
+ do
+ {
+ guess += distance;
+
+ times_through_search++;
+
+ guess_tm = (*producer) (&guess);
+
+#ifdef DEBUG
+ if (debugging_enabled)
+ {
+ printf (" Guessing time_t == %d\n ", (int) guess);
+ printtm (guess_tm);
+ putchar ('\n');
+ }
+#endif
+
+ /* How far is our guess from the desired struct tm? */
+ distance = dist_tm (me, guess_tm);
+
+ /* Handle periods of time where a period of time is skipped.
+ For example, 2:15 3 April 1994 does not exist, because DST
+ is in effect. The distance function will alternately
+ return values of 3600 and -3600, because it doesn't know
+ that the requested time doesn't exist. In these situations
+ (even if the skip is not exactly an hour) the distances
+ returned will be the same, but alternating in sign. We
+ want the later time, so check to see that the distance is
+ oscillating and we've chosen the correct of the two
+ possibilities.
+
+ Useful: 3 Apr 94 765356300, 30 Oct 94 783496000 */
+
+ if ((distance == -last_distance) && (distance < last_distance))
+ {
+ /* If the caller specified that the DST flag was off, it's
+ not possible to represent this time. */
+ if (me->tm_isdst == 0)
+ {
+#ifdef DEBUG
+ printf (" Distance is oscillating -- dst flag nixes struct!\n");
+#endif
+ return BAD_STRUCT_TM;
+ }
+
+#ifdef DEBUG
+ printf (" Distance is oscillating -- chose the later time.\n");
+#endif
+ distance = 0;
+ }
+
+ if ((distance == 0) && (me->tm_isdst != -1)
+ && (me->tm_isdst != guess_tm->tm_isdst))
+ {
+ /* If we're in this code, we've got the right time but the
+ wrong daylight savings flag. We need to move away from
+ the time that we have and approach the other time from
+ the other direction. That is, if I've requested the
+ non-DST version of a time and I get the DST version
+ instead, I want to put us forward in time and search
+ backwards to get the other time. I checked all of the
+ configuration files for the tz package -- no entry
+ saves more than two hours, so I think we'll be safe by
+ moving 24 hours in one direction. IF THE AMOUNT OF
+ TIME SAVED IN THE CONFIGURATION FILES CHANGES, THIS
+ VALUE MAY NEED TO BE ADJUSTED. Luckily, we can never
+ have more than one level of overlaps, or this would
+ never work. */
+
+#define SKIP_VALUE 86400
+
+ if (guess_tm->tm_isdst == 0)
+ /* we got the later one, but want the earlier one */
+ distance = -SKIP_VALUE;
+ else
+ distance = SKIP_VALUE;
+
+#ifdef DEBUG
+ printf (" Got the right time, wrong DST value -- adjusting\n");
+#endif
+ }
+
+ last_distance = distance;
+
+ } while (distance != 0);
+
+ /* Check to see that the dst flag matches */
+
+ if (me->tm_isdst != -1)
+ {
+ if (me->tm_isdst != guess_tm->tm_isdst)
+ {
+#ifdef DEBUG
+ printf (" DST flag doesn't match! FIXME?\n");
+#endif
+ return BAD_STRUCT_TM;
+ }
+ }
+
+ result = guess; /* Success! */
+
+ /* On successful completion, the values of tm_wday and tm_yday
+ have to be set appropriately. */
+
+ /* me->tm_yday = guess_tm->tm_yday;
+ me->tm_mday = guess_tm->tm_mday; */
+
+ *me = *guess_tm;
+ }
+
+ /* Update the caller's version of the structure */
+
+ *timeptr = *me;
+
+ return result;
+}
+
+time_t
+#ifdef DEBUG /* make it work even if the system's
+ libc has it's own mktime routine */
+my_mktime (timeptr)
+#else
+mktime (timeptr)
+#endif
+ struct tm *timeptr;
+{
+ return _mktime_internal (timeptr, localtime);
+}
+
+#ifdef DEBUG
+void
+main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ int time;
+ int result_time;
+ struct tm *tmptr;
+
+ if (argc == 1)
+ {
+ long q;
+
+ printf ("starting long test...\n");
+
+ for (q = 10000000; q < 1000000000; q += 599)
+ {
+ struct tm *tm = localtime ((time_t *) &q);
+ if ((q % 10000) == 0) { printf ("%ld\n", q); fflush (stdout); }
+ if (q != my_mktime (tm))
+ { printf ("failed for %ld\n", q); fflush (stdout); }
+ }
+
+ printf ("test finished\n");
+
+ exit (0);
+ }
+
+ if (argc != 2)
+ {
+ printf ("wrong # of args\n");
+ exit (0);
+ }
+
+ debugging_enabled = 1; /* We want to see the info */
+
+ ++argv;
+ time = atoi (*argv);
+
+ tmptr = localtime ((time_t *) &time);
+ printf ("Localtime tells us that a time_t of %d represents\n ", time);
+ printtm (tmptr);
+ putchar ('\n');
+
+ printf (" Given localtime's return val, mktime returns %d which is\n ",
+ (int) my_mktime (tmptr));
+ printtm (tmptr);
+ putchar ('\n');
+
+#if 0
+ tmptr->tm_sec -= 20;
+ tmptr->tm_min -= 20;
+ tmptr->tm_hour -= 20;
+ tmptr->tm_mday -= 20;
+ tmptr->tm_mon -= 20;
+ tmptr->tm_year -= 20;
+ tmptr->tm_gmtoff -= 20000; /* This has no effect! */
+ tmptr->tm_zone = NULL; /* Nor does this! */
+ tmptr->tm_isdst = -1;
+#endif
+
+ tmptr->tm_hour += 1;
+ tmptr->tm_isdst = -1;
+
+ printf ("\n\nchanged ranges: ");
+ printtm (tmptr);
+ putchar ('\n');
+
+ result_time = my_mktime (tmptr);
+ printf ("\nmktime: %d\n", result_time);
+
+ tmptr->tm_isdst = 0;
+
+ printf ("\n\nchanged ranges: ");
+ printtm (tmptr);
+ putchar ('\n');
+
+ result_time = my_mktime (tmptr);
+ printf ("\nmktime: %d\n", result_time);
+}
+#endif /* DEBUG */
+
+
+/*
+Local Variables:
+compile-command: "gcc -g mktime.c -o mktime -DDEBUG"
+End:
+*/
diff --git a/lib/modechange.c b/lib/modechange.c
new file mode 100644
index 00000000..3862599e
--- /dev/null
+++ b/lib/modechange.c
@@ -0,0 +1,341 @@
+/* modechange.c -- file mode manipulation
+ Copyright (C) 1989, 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by David MacKenzie <djm@ai.mit.edu> */
+
+/* The ASCII mode string is compiled into a linked list of `struct
+ modechange', which can then be applied to each file to be changed.
+ We do this instead of re-parsing the ASCII string for each file
+ because the compiled form requires less computation to use; when
+ changing the mode of many files, this probably results in a
+ performance gain. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "modechange.h"
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+char *malloc ();
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifdef STAT_MACROS_BROKEN
+#undef S_ISDIR
+#endif /* STAT_MACROS_BROKEN. */
+
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+/* Return newly allocated memory to hold one element of type TYPE. */
+#define talloc(type) ((type *) malloc (sizeof (type)))
+
+#define isodigit(c) ((c) >= '0' && (c) <= '7')
+
+static int oatoi ();
+
+/* Return a linked list of file mode change operations created from
+ MODE_STRING, an ASCII string that contains either an octal number
+ specifying an absolute mode, or symbolic mode change operations with
+ the form:
+ [ugoa...][[+-=][rwxXstugo...]...][,...]
+ MASKED_OPS is a bitmask indicating which symbolic mode operators (=+-)
+ should not affect bits set in the umask when no users are given.
+ Operators not selected in MASKED_OPS ignore the umask.
+
+ Return MODE_INVALID if `mode_string' does not contain a valid
+ representation of file mode change operations;
+ return MODE_MEMORY_EXHAUSTED if there is insufficient memory. */
+
+struct mode_change *
+mode_compile (mode_string, masked_ops)
+ register char *mode_string;
+ unsigned masked_ops;
+{
+ struct mode_change *head; /* First element of the linked list. */
+ struct mode_change *change; /* An element of the linked list. */
+ int i; /* General purpose temporary. */
+ unsigned short umask_value; /* The umask value (surprise). */
+ unsigned short affected_bits; /* Which bits in the mode are operated on. */
+ unsigned short affected_masked; /* `affected_bits' modified by umask. */
+ unsigned ops_to_mask; /* Operators to actually use umask on. */
+
+ i = oatoi (mode_string);
+ if (i >= 0)
+ {
+ if (i > 07777)
+ return MODE_INVALID;
+ head = talloc (struct mode_change);
+ if (head == NULL)
+ return MODE_MEMORY_EXHAUSTED;
+ head->next = NULL;
+ head->op = '=';
+ head->flags = 0;
+ head->value = i;
+ head->affected = 07777; /* Affect all permissions. */
+ return head;
+ }
+
+ umask_value = umask (0);
+ umask (umask_value); /* Restore the old value. */
+
+ head = NULL;
+#ifdef lint
+ change = NULL;
+#endif
+ --mode_string;
+
+ /* One loop iteration for each "ugoa...=+-rwxXstugo...[=+-rwxXstugo...]". */
+ do
+ {
+ affected_bits = 0;
+ ops_to_mask = 0;
+ /* Turn on all the bits in `affected_bits' for each group given. */
+ for (++mode_string;; ++mode_string)
+ switch (*mode_string)
+ {
+ case 'u':
+ affected_bits |= 04700;
+ break;
+ case 'g':
+ affected_bits |= 02070;
+ break;
+ case 'o':
+ affected_bits |= 01007;
+ break;
+ case 'a':
+ affected_bits |= 07777;
+ break;
+ default:
+ goto no_more_affected;
+ }
+
+ no_more_affected:
+ /* If none specified, affect all bits, except perhaps those
+ set in the umask. */
+ if (affected_bits == 0)
+ {
+ affected_bits = 07777;
+ ops_to_mask = masked_ops;
+ }
+
+ while (*mode_string == '=' || *mode_string == '+' || *mode_string == '-')
+ {
+ /* Add the element to the tail of the list, so the operations
+ are performed in the correct order. */
+ if (head == NULL)
+ {
+ head = talloc (struct mode_change);
+ if (head == NULL)
+ return MODE_MEMORY_EXHAUSTED;
+ change = head;
+ }
+ else
+ {
+ change->next = talloc (struct mode_change);
+ if (change->next == NULL)
+ {
+ mode_free (change);
+ return MODE_MEMORY_EXHAUSTED;
+ }
+ change = change->next;
+ }
+
+ change->next = NULL;
+ change->op = *mode_string; /* One of "=+-". */
+ affected_masked = affected_bits;
+ if (ops_to_mask & (*mode_string == '=' ? MODE_MASK_EQUALS
+ : *mode_string == '+' ? MODE_MASK_PLUS
+ : MODE_MASK_MINUS))
+ affected_masked &= ~umask_value;
+ change->affected = affected_masked;
+ change->value = 0;
+ change->flags = 0;
+
+ /* Set `value' according to the bits set in `affected_masked'. */
+ for (++mode_string;; ++mode_string)
+ switch (*mode_string)
+ {
+ case 'r':
+ change->value |= 00444 & affected_masked;
+ break;
+ case 'w':
+ change->value |= 00222 & affected_masked;
+ break;
+ case 'X':
+ change->flags |= MODE_X_IF_ANY_X;
+ /* Fall through. */
+ case 'x':
+ change->value |= 00111 & affected_masked;
+ break;
+ case 's':
+ /* Set the setuid/gid bits if `u' or `g' is selected. */
+ change->value |= 06000 & affected_masked;
+ break;
+ case 't':
+ /* Set the "save text image" bit if `o' is selected. */
+ change->value |= 01000 & affected_masked;
+ break;
+ case 'u':
+ /* Set the affected bits to the value of the `u' bits
+ on the same file. */
+ if (change->value)
+ goto invalid;
+ change->value = 00700;
+ change->flags |= MODE_COPY_EXISTING;
+ break;
+ case 'g':
+ /* Set the affected bits to the value of the `g' bits
+ on the same file. */
+ if (change->value)
+ goto invalid;
+ change->value = 00070;
+ change->flags |= MODE_COPY_EXISTING;
+ break;
+ case 'o':
+ /* Set the affected bits to the value of the `o' bits
+ on the same file. */
+ if (change->value)
+ goto invalid;
+ change->value = 00007;
+ change->flags |= MODE_COPY_EXISTING;
+ break;
+ default:
+ goto no_more_values;
+ }
+ no_more_values:;
+ }
+ } while (*mode_string == ',');
+ if (*mode_string == 0)
+ return head;
+invalid:
+ mode_free (head);
+ return MODE_INVALID;
+}
+
+/* Return file mode OLDMODE, adjusted as indicated by the list of change
+ operations CHANGES. If OLDMODE is a directory, the type `X'
+ change affects it even if no execute bits were set in OLDMODE.
+ The returned value has the S_IFMT bits cleared. */
+
+unsigned short
+mode_adjust (oldmode, changes)
+ unsigned oldmode;
+ register struct mode_change *changes;
+{
+ unsigned short newmode; /* The adjusted mode and one operand. */
+ unsigned short value; /* The other operand. */
+
+ newmode = oldmode & 07777;
+
+ for (; changes; changes = changes->next)
+ {
+ if (changes->flags & MODE_COPY_EXISTING)
+ {
+ /* Isolate in `value' the bits in `newmode' to copy, given in
+ the mask `changes->value'. */
+ value = newmode & changes->value;
+
+ if (changes->value & 00700)
+ /* Copy `u' permissions onto `g' and `o'. */
+ value |= (value >> 3) | (value >> 6);
+ else if (changes->value & 00070)
+ /* Copy `g' permissions onto `u' and `o'. */
+ value |= (value << 3) | (value >> 3);
+ else
+ /* Copy `o' permissions onto `u' and `g'. */
+ value |= (value << 3) | (value << 6);
+
+ /* In order to change only `u', `g', or `o' permissions,
+ or some combination thereof, clear unselected bits.
+ This can not be done in mode_compile because the value
+ to which the `changes->affected' mask is applied depends
+ on the old mode of each file. */
+ value &= changes->affected;
+ }
+ else
+ {
+ value = changes->value;
+ /* If `X', do not affect the execute bits if the file is not a
+ directory and no execute bits are already set. */
+ if ((changes->flags & MODE_X_IF_ANY_X)
+ && !S_ISDIR (oldmode)
+ && (newmode & 00111) == 0)
+ value &= ~00111; /* Clear the execute bits. */
+ }
+
+ switch (changes->op)
+ {
+ case '=':
+ /* Preserve the previous values in `newmode' of bits that are
+ not affected by this change operation. */
+ newmode = (newmode & ~changes->affected) | value;
+ break;
+ case '+':
+ newmode |= value;
+ break;
+ case '-':
+ newmode &= ~value;
+ break;
+ }
+ }
+ return newmode;
+}
+
+/* Free the memory used by the list of file mode change operations
+ CHANGES. */
+
+void
+mode_free (changes)
+ register struct mode_change *changes;
+{
+ register struct mode_change *next;
+
+ while (changes)
+ {
+ next = changes->next;
+ free (changes);
+ changes = next;
+ }
+}
+
+/* Return a positive integer containing the value of the ASCII
+ octal number S. If S is not an octal number, return -1. */
+
+static int
+oatoi (s)
+ char *s;
+{
+ register int i;
+
+ if (*s == 0)
+ return -1;
+ for (i = 0; isodigit (*s); ++s)
+ i = i * 8 + *s - '0';
+ if (*s)
+ return -1;
+ return i;
+}
diff --git a/lib/modechange.h b/lib/modechange.h
new file mode 100644
index 00000000..4a298830
--- /dev/null
+++ b/lib/modechange.h
@@ -0,0 +1,55 @@
+/* modechange.h -- definitions for file mode manipulation
+ Copyright (C) 1989, 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Masks for the `flags' field in a `struct mode_change'. */
+
+/* Affect the execute bits only if at least one execute bit is set already,
+ or if the file is a directory. */
+#define MODE_X_IF_ANY_X 01
+
+/* If set, copy some existing permissions for u, g, or o onto the other two.
+ Which of u, g, or o is copied is determined by which bits are set in the
+ `value' field. */
+#define MODE_COPY_EXISTING 02
+
+struct mode_change
+{
+ char op; /* One of "=+-". */
+ char flags; /* Special operations. */
+ unsigned short affected; /* Set for u/g/o/s/s/t, if to be affected. */
+ unsigned short value; /* Bits to add/remove. */
+ struct mode_change *next; /* Link to next change in list. */
+};
+
+/* Masks for mode_compile argument. */
+#define MODE_MASK_EQUALS 1
+#define MODE_MASK_PLUS 2
+#define MODE_MASK_MINUS 4
+
+/* Error return values for mode_compile. */
+#define MODE_INVALID (struct mode_change *) 0
+#define MODE_MEMORY_EXHAUSTED (struct mode_change *) 1
+
+#ifdef __STDC__
+struct mode_change *mode_compile (char *, unsigned);
+unsigned short mode_adjust (unsigned, struct mode_change *);
+void mode_free (struct mode_change *);
+#else
+struct mode_change *mode_compile ();
+unsigned short mode_adjust ();
+void mode_free ();
+#endif
diff --git a/lib/modetype.h b/lib/modetype.h
index 2c99ecaf..fd4092bf 100644
--- a/lib/modetype.h
+++ b/lib/modetype.h
@@ -1,28 +1,25 @@
/* modetype.h -- file type bits definitions for POSIX systems
Requires sys/types.h sys/stat.h.
- Copyright (C) 1990, 2007 Free Software Foundation, Inc.
+ Copyright (C) 1990 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
+ 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 3 of the License, or
- (at your option) any later version.
-
+ 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, see <http://www.gnu.org/licenses/>.
-*/
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* POSIX.1 doesn't mention the S_IFMT bits; instead, it uses S_IStype
test macros. To make storing file types more convenient, define
them; the values don't need to correspond to what the kernel uses,
because of the way we use them. */
-#ifndef INC_MODETYPE_H
-#define INC_MODETYPE_H 1
-
#ifndef S_IFMT /* Doesn't have traditional Unix macros. */
#define S_IFBLK 1
#define S_IFCHR 2
@@ -37,9 +34,6 @@
#ifdef S_ISSOCK
#define S_IFSOCK 64
#endif
-#ifdef S_ISDOOR
-#define S_IFDOOR 128
-#endif
#endif /* !S_IFMT */
#ifdef STAT_MACROS_BROKEN
@@ -50,7 +44,6 @@
#undef S_ISFIFO
#undef S_ISLNK
#undef S_ISSOCK
-#undef S_ISDOOR
#undef S_ISMPB
#undef S_ISMPC
#undef S_ISNWK
@@ -79,64 +72,10 @@
#if !defined(S_ISSOCK) && defined(S_IFSOCK)
#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
#endif
-#if !defined(S_ISDOOR) && defined(S_IFDOOR)
-#define S_ISDOOR(m) (((m) & S_IFMT) == S_IFDOOR)
-#endif
#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
-/* Also available on Coherent, according to
- * Albert D. Cahalan (acahalan@cs.uml.edu)
- */
-#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB) /* multiplexed block device */
-#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC) /* multiplexed char device */
-/* GNU BFD library source uses type letter 'm' for these */
+#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
+#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
#endif
-
#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
-/* Apparently HPUX ls gives 'n' as the type letter for these. */
#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
#endif
-
-#endif
-
-/* The above macros don't handle
- * /bin/ls letters Mode What is it?
- * S_IFNAM (Xenix "name files")
- * H S_ISCDF (HPUX Context Dependent Files)
- * S_IFCMP
- * S_IFSHAD
- */
-
-/*
-In message <199907051927.PAA01106@jupiter.cs.uml.edu>
-Albert Cahalan wrote:-
-
-BTW, I believe many of these can't actually exist on disk.
-Some of these (like S_IFSHAD AFAIK) are not seen by userspace.
-
-hex name ls octal description
-0000 000000 SCO out-of-service inode, BSD unknown type
-1000 S_IFIFO p| 010000 fifo (named pipe)
-2000 S_IFCHR c 020000 character special
-3000 S_IFMPC 030000 multiplexed character device (Coherent)
-4000 S_IFDIR d/ 040000 directory
-5000 S_IFNAM 050000 XENIX special named file
-6000 S_IFBLK b 060000 block special
-7000 S_IFMPB 070000 multiplexed block device (Coherent)
-8000 S_IFREG - 100000 regular
-9000 S_IFCMP 110000 VxFS compressed (file?)
-9000 S_IFNWK 110000 HP-UX network special
-a000 S_IFLNK l@ 120000 symbolic link
-b000 S_IFSHAD 130000 Solaris shadow inode for ACL
-c000 S_IFSOCK s= 140000 socket (also "S_IFSOC" on VxFS)
-d000 S_IFDOOR D 150000 Solaris door
-e000 S_IFWHT w% 160000 BSD whiteout (not used for inode)
-f000 S_IFMT 170000 mask (not used for inode)
-hex name ls octal description
-0200 S_ISVTX 001000 save swapped text even after use
-0400 S_ISGID 002000 set group ID on execution
-0400 S_ENFMT 002000 SysV forced file locking (shared w/ S_ISGID)
-0800 S_CDF 004000 HP-UX hidden directory
-0800 S_ISUID 004000 set user ID on execution
-
-
-*/
diff --git a/lib/nextelem.c b/lib/nextelem.c
index a4bd8dd6..4b9ddc1f 100644
--- a/lib/nextelem.c
+++ b/lib/nextelem.c
@@ -1,28 +1,29 @@
/* Return the next element of a path.
- Copyright (C) 1992,2005 Free Software Foundation, Inc.
+ Copyright (C) 1992 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
+ 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 3 of the License, or
- (at your option) any later version.
-
+ 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, see <http://www.gnu.org/licenses/>.
-*/
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-/* Written by David MacKenzie <djm@gnu.org>,
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>,
inspired by John P. Rouillard <rouilj@cs.umb.edu>. */
+#ifdef HAVE_CONFIG_H
#include <config.h>
-
+#endif
#include <stdio.h>
-#if defined HAVE_STRING_H || defined STDC_HEADERS
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
#include <string.h>
#else
#include <strings.h>
@@ -30,12 +31,9 @@
#define strchr index
#endif
#endif
-#if defined STDC_HEADERS
-#include <stdlib.h>
-#endif
-
-#include "nextelem.h"
+char *strdup ();
+void free ();
/* Return the next element of a colon-separated path.
A null entry in the path is equivalent to "." (the current directory).
@@ -45,7 +43,8 @@
return NULL if there are no more elements. */
char *
-next_element (const char *new_path, int curdir_ok)
+next_element (new_path)
+ char *new_path;
{
static char *path = NULL; /* Freshly allocated copy of NEW_PATH. */
static char *end; /* Start of next element to return. */
@@ -66,7 +65,7 @@ next_element (const char *new_path, int curdir_ok)
if (final_colon)
{
final_colon = 0;
- return curdir_ok ? "." : "";
+ return ".";
}
return NULL;
}
@@ -79,7 +78,7 @@ next_element (const char *new_path, int curdir_ok)
{
/* An empty path element. */
*end++ = '\0';
- return curdir_ok ? "." : "";
+ return ".";
}
else if (end == NULL)
{
diff --git a/lib/pathmax.h b/lib/pathmax.h
new file mode 100644
index 00000000..00fb0b51
--- /dev/null
+++ b/lib/pathmax.h
@@ -0,0 +1,53 @@
+/* Define PATH_MAX somehow. Requires sys/types.h.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _PATHMAX_H
+#define _PATHMAX_H
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
+ PATH_MAX but might cause redefinition warnings when sys/param.h is
+ later included (as on MORE/BSD 4.3). */
+#if defined(_POSIX_VERSION) || (defined(HAVE_LIMITS_H) && !defined(__GNUC__))
+#include <limits.h>
+#endif
+
+#ifndef _POSIX_PATH_MAX
+#define _POSIX_PATH_MAX 255
+#endif
+
+#if !defined(PATH_MAX) && defined(_PC_PATH_MAX)
+#define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
+#endif
+
+/* Don't include sys/param.h if it already has been. */
+#if defined(HAVE_SYS_PARAM_H) && !defined(PATH_MAX) && !defined(MAXPATHLEN)
+#include <sys/param.h>
+#endif
+
+#if !defined(PATH_MAX) && defined(MAXPATHLEN)
+#define PATH_MAX MAXPATHLEN
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX _POSIX_PATH_MAX
+#endif
+
+#endif /* _PATHMAX_H */
diff --git a/lib/regex.c b/lib/regex.c
new file mode 100644
index 00000000..33c7ea24
--- /dev/null
+++ b/lib/regex.c
@@ -0,0 +1,5244 @@
+/* Extended regular expression matching and search library,
+ version 0.12.
+ (Implements POSIX draft P10003.2/D11.2, except for
+ internationalization features.)
+
+ Copyright (C) 1993, 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* AIX requires this to be the first thing in the file. */
+#if defined (_AIX) && !defined (REGEX_MALLOC)
+ #pragma alloca
+#endif
+
+#define _GNU_SOURCE
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* We need this for `regex.h', and perhaps for the Emacs include files. */
+#include <sys/types.h>
+
+/* The `emacs' switch turns on certain matching commands
+ that make sense only in Emacs. */
+#ifdef emacs
+
+#include "lisp.h"
+#include "buffer.h"
+#include "syntax.h"
+
+/* Emacs uses `NULL' as a predicate. */
+#undef NULL
+
+#else /* not emacs */
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+char *malloc ();
+char *realloc ();
+#endif
+
+
+/* We used to test for `BSTRING' here, but only GCC and Emacs define
+ `BSTRING', as far as I know, and neither of them use this code. */
+#ifndef INHIBIT_STRING_HEADER
+#if HAVE_STRING_H || STDC_HEADERS
+#include <string.h>
+#ifndef bcmp
+#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n))
+#endif
+#ifndef bcopy
+#define bcopy(s, d, n) memcpy ((d), (s), (n))
+#endif
+#ifndef bzero
+#define bzero(s, n) memset ((s), 0, (n))
+#endif
+#else
+#include <strings.h>
+#endif
+#endif
+
+/* Define the syntax stuff for \<, \>, etc. */
+
+/* This must be nonzero for the wordchar and notwordchar pattern
+ commands in re_match_2. */
+#ifndef Sword
+#define Sword 1
+#endif
+
+#ifdef SYNTAX_TABLE
+
+extern char *re_syntax_table;
+
+#else /* not SYNTAX_TABLE */
+
+/* How many characters in the character set. */
+#define CHAR_SET_SIZE 256
+
+static char re_syntax_table[CHAR_SET_SIZE];
+
+static void
+init_syntax_once ()
+{
+ register int c;
+ static int done = 0;
+
+ if (done)
+ return;
+
+ bzero (re_syntax_table, sizeof re_syntax_table);
+
+ for (c = 'a'; c <= 'z'; c++)
+ re_syntax_table[c] = Sword;
+
+ for (c = 'A'; c <= 'Z'; c++)
+ re_syntax_table[c] = Sword;
+
+ for (c = '0'; c <= '9'; c++)
+ re_syntax_table[c] = Sword;
+
+ re_syntax_table['_'] = Sword;
+
+ done = 1;
+}
+
+#endif /* not SYNTAX_TABLE */
+
+#define SYNTAX(c) re_syntax_table[c]
+
+#endif /* not emacs */
+
+/* Get the interface, including the syntax bits. */
+#include "regex.h"
+
+/* isalpha etc. are used for the character classes. */
+#include <ctype.h>
+
+/* Jim Meyering writes:
+
+ "... Some ctype macros are valid only for character codes that
+ isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when
+ using /bin/cc or gcc but without giving an ansi option). So, all
+ ctype uses should be through macros like ISPRINT... If
+ STDC_HEADERS is defined, then autoconf has verified that the ctype
+ macros don't need to be guarded with references to isascii. ...
+ Defining isascii to 1 should let any compiler worth its salt
+ eliminate the && through constant folding." */
+
+#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
+#define ISASCII(c) 1
+#else
+#define ISASCII(c) isascii(c)
+#endif
+
+#ifdef isblank
+#define ISBLANK(c) (ISASCII (c) && isblank (c))
+#else
+#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
+#endif
+#ifdef isgraph
+#define ISGRAPH(c) (ISASCII (c) && isgraph (c))
+#else
+#define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
+#endif
+
+#define ISPRINT(c) (ISASCII (c) && isprint (c))
+#define ISDIGIT(c) (ISASCII (c) && isdigit (c))
+#define ISALNUM(c) (ISASCII (c) && isalnum (c))
+#define ISALPHA(c) (ISASCII (c) && isalpha (c))
+#define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
+#define ISLOWER(c) (ISASCII (c) && islower (c))
+#define ISPUNCT(c) (ISASCII (c) && ispunct (c))
+#define ISSPACE(c) (ISASCII (c) && isspace (c))
+#define ISUPPER(c) (ISASCII (c) && isupper (c))
+#define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* We remove any previous definition of `SIGN_EXTEND_CHAR',
+ since ours (we hope) works properly with all combinations of
+ machines, compilers, `char' and `unsigned char' argument types.
+ (Per Bothner suggested the basic approach.) */
+#undef SIGN_EXTEND_CHAR
+#if __STDC__
+#define SIGN_EXTEND_CHAR(c) ((signed char) (c))
+#else /* not __STDC__ */
+/* As in Harbison and Steele. */
+#define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128)
+#endif
+
+/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we
+ use `alloca' instead of `malloc'. This is because using malloc in
+ re_search* or re_match* could cause memory leaks when C-g is used in
+ Emacs; also, malloc is slower and causes storage fragmentation. On
+ the other hand, malloc is more portable, and easier to debug.
+
+ Because we sometimes use alloca, some routines have to be macros,
+ not functions -- `alloca'-allocated space disappears at the end of the
+ function it is called in. */
+
+#ifdef REGEX_MALLOC
+
+#define REGEX_ALLOCATE malloc
+#define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize)
+
+#else /* not REGEX_MALLOC */
+
+/* Emacs already defines alloca, sometimes. */
+#ifndef alloca
+
+/* Make alloca work the best possible way. */
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#if HAVE_ALLOCA_H
+#include <alloca.h>
+#else /* not __GNUC__ or HAVE_ALLOCA_H */
+#ifndef _AIX /* Already did AIX, up at the top. */
+char *alloca ();
+#endif /* not _AIX */
+#endif /* not HAVE_ALLOCA_H */
+#endif /* not __GNUC__ */
+
+#endif /* not alloca */
+
+#define REGEX_ALLOCATE alloca
+
+/* Assumes a `char *destination' variable. */
+#define REGEX_REALLOCATE(source, osize, nsize) \
+ (destination = (char *) alloca (nsize), \
+ bcopy (source, destination, osize), \
+ destination)
+
+#endif /* not REGEX_MALLOC */
+
+
+/* True if `size1' is non-NULL and PTR is pointing anywhere inside
+ `string1' or just past its end. This works if PTR is NULL, which is
+ a good thing. */
+#define FIRST_STRING_P(ptr) \
+ (size1 && string1 <= (ptr) && (ptr) <= string1 + size1)
+
+/* (Re)Allocate N items of type T using malloc, or fail. */
+#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t)))
+#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t)))
+#define RETALLOC_IF(addr, n, t) \
+ if (addr) RETALLOC((addr), (n), t); else (addr) = TALLOC ((n), t)
+#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t)))
+
+#define BYTEWIDTH 8 /* In bits. */
+
+#define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
+
+#undef MAX
+#undef MIN
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+typedef char boolean;
+#define false 0
+#define true 1
+
+static int re_match_2_internal ();
+
+/* These are the command codes that appear in compiled regular
+ expressions. Some opcodes are followed by argument bytes. A
+ command code can specify any interpretation whatsoever for its
+ arguments. Zero bytes may appear in the compiled regular expression. */
+
+typedef enum
+{
+ no_op = 0,
+
+ /* Followed by one byte giving n, then by n literal bytes. */
+ exactn,
+
+ /* Matches any (more or less) character. */
+ anychar,
+
+ /* Matches any one char belonging to specified set. First
+ following byte is number of bitmap bytes. Then come bytes
+ for a bitmap saying which chars are in. Bits in each byte
+ are ordered low-bit-first. A character is in the set if its
+ bit is 1. A character too large to have a bit in the map is
+ automatically not in the set. */
+ charset,
+
+ /* Same parameters as charset, but match any character that is
+ not one of those specified. */
+ charset_not,
+
+ /* Start remembering the text that is matched, for storing in a
+ register. Followed by one byte with the register number, in
+ the range 0 to one less than the pattern buffer's re_nsub
+ field. Then followed by one byte with the number of groups
+ inner to this one. (This last has to be part of the
+ start_memory only because we need it in the on_failure_jump
+ of re_match_2.) */
+ start_memory,
+
+ /* Stop remembering the text that is matched and store it in a
+ memory register. Followed by one byte with the register
+ number, in the range 0 to one less than `re_nsub' in the
+ pattern buffer, and one byte with the number of inner groups,
+ just like `start_memory'. (We need the number of inner
+ groups here because we don't have any easy way of finding the
+ corresponding start_memory when we're at a stop_memory.) */
+ stop_memory,
+
+ /* Match a duplicate of something remembered. Followed by one
+ byte containing the register number. */
+ duplicate,
+
+ /* Fail unless at beginning of line. */
+ begline,
+
+ /* Fail unless at end of line. */
+ endline,
+
+ /* Succeeds if at beginning of buffer (if emacs) or at beginning
+ of string to be matched (if not). */
+ begbuf,
+
+ /* Analogously, for end of buffer/string. */
+ endbuf,
+
+ /* Followed by two byte relative address to which to jump. */
+ jump,
+
+ /* Same as jump, but marks the end of an alternative. */
+ jump_past_alt,
+
+ /* Followed by two-byte relative address of place to resume at
+ in case of failure. */
+ on_failure_jump,
+
+ /* Like on_failure_jump, but pushes a placeholder instead of the
+ current string position when executed. */
+ on_failure_keep_string_jump,
+
+ /* Throw away latest failure point and then jump to following
+ two-byte relative address. */
+ pop_failure_jump,
+
+ /* Change to pop_failure_jump if know won't have to backtrack to
+ match; otherwise change to jump. This is used to jump
+ back to the beginning of a repeat. If what follows this jump
+ clearly won't match what the repeat does, such that we can be
+ sure that there is no use backtracking out of repetitions
+ already matched, then we change it to a pop_failure_jump.
+ Followed by two-byte address. */
+ maybe_pop_jump,
+
+ /* Jump to following two-byte address, and push a dummy failure
+ point. This failure point will be thrown away if an attempt
+ is made to use it for a failure. A `+' construct makes this
+ before the first repeat. Also used as an intermediary kind
+ of jump when compiling an alternative. */
+ dummy_failure_jump,
+
+ /* Push a dummy failure point and continue. Used at the end of
+ alternatives. */
+ push_dummy_failure,
+
+ /* Followed by two-byte relative address and two-byte number n.
+ After matching N times, jump to the address upon failure. */
+ succeed_n,
+
+ /* Followed by two-byte relative address, and two-byte number n.
+ Jump to the address N times, then fail. */
+ jump_n,
+
+ /* Set the following two-byte relative address to the
+ subsequent two-byte number. The address *includes* the two
+ bytes of number. */
+ set_number_at,
+
+ wordchar, /* Matches any word-constituent character. */
+ notwordchar, /* Matches any char that is not a word-constituent. */
+
+ wordbeg, /* Succeeds if at word beginning. */
+ wordend, /* Succeeds if at word end. */
+
+ wordbound, /* Succeeds if at a word boundary. */
+ notwordbound /* Succeeds if not at a word boundary. */
+
+#ifdef emacs
+ ,before_dot, /* Succeeds if before point. */
+ at_dot, /* Succeeds if at point. */
+ after_dot, /* Succeeds if after point. */
+
+ /* Matches any character whose syntax is specified. Followed by
+ a byte which contains a syntax code, e.g., Sword. */
+ syntaxspec,
+
+ /* Matches any character whose syntax is not that specified. */
+ notsyntaxspec
+#endif /* emacs */
+} re_opcode_t;
+
+/* Common operations on the compiled pattern. */
+
+/* Store NUMBER in two contiguous bytes starting at DESTINATION. */
+
+#define STORE_NUMBER(destination, number) \
+ do { \
+ (destination)[0] = (number) & 0377; \
+ (destination)[1] = (number) >> 8; \
+ } while (0)
+
+/* Same as STORE_NUMBER, except increment DESTINATION to
+ the byte after where the number is stored. Therefore, DESTINATION
+ must be an lvalue. */
+
+#define STORE_NUMBER_AND_INCR(destination, number) \
+ do { \
+ STORE_NUMBER (destination, number); \
+ (destination) += 2; \
+ } while (0)
+
+/* Put into DESTINATION a number stored in two contiguous bytes starting
+ at SOURCE. */
+
+#define EXTRACT_NUMBER(destination, source) \
+ do { \
+ (destination) = *(source) & 0377; \
+ (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \
+ } while (0)
+
+#ifdef DEBUG
+static void
+extract_number (dest, source)
+ int *dest;
+ unsigned char *source;
+{
+ int temp = SIGN_EXTEND_CHAR (*(source + 1));
+ *dest = *source & 0377;
+ *dest += temp << 8;
+}
+
+#ifndef EXTRACT_MACROS /* To debug the macros. */
+#undef EXTRACT_NUMBER
+#define EXTRACT_NUMBER(dest, src) extract_number (&dest, src)
+#endif /* not EXTRACT_MACROS */
+
+#endif /* DEBUG */
+
+/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number.
+ SOURCE must be an lvalue. */
+
+#define EXTRACT_NUMBER_AND_INCR(destination, source) \
+ do { \
+ EXTRACT_NUMBER (destination, source); \
+ (source) += 2; \
+ } while (0)
+
+#ifdef DEBUG
+static void
+extract_number_and_incr (destination, source)
+ int *destination;
+ unsigned char **source;
+{
+ extract_number (destination, *source);
+ *source += 2;
+}
+
+#ifndef EXTRACT_MACROS
+#undef EXTRACT_NUMBER_AND_INCR
+#define EXTRACT_NUMBER_AND_INCR(dest, src) \
+ extract_number_and_incr (&dest, &src)
+#endif /* not EXTRACT_MACROS */
+
+#endif /* DEBUG */
+
+/* If DEBUG is defined, Regex prints many voluminous messages about what
+ it is doing (if the variable `debug' is nonzero). If linked with the
+ main program in `iregex.c', you can enter patterns and strings
+ interactively. And if linked with the main program in `main.c' and
+ the other test files, you can run the already-written tests. */
+
+#ifdef DEBUG
+
+/* We use standard I/O for debugging. */
+#include <stdio.h>
+
+/* It is useful to test things that ``must'' be true when debugging. */
+#include <assert.h>
+
+static int debug = 0;
+
+#define DEBUG_STATEMENT(e) e
+#define DEBUG_PRINT1(x) if (debug) printf (x)
+#define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2)
+#define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3)
+#define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4)
+#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \
+ if (debug) print_partial_compiled_pattern (s, e)
+#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \
+ if (debug) print_double_string (w, s1, sz1, s2, sz2)
+
+
+extern void printchar ();
+
+/* Print the fastmap in human-readable form. */
+
+void
+print_fastmap (fastmap)
+ char *fastmap;
+{
+ unsigned was_a_range = 0;
+ unsigned i = 0;
+
+ while (i < (1 << BYTEWIDTH))
+ {
+ if (fastmap[i++])
+ {
+ was_a_range = 0;
+ printchar (i - 1);
+ while (i < (1 << BYTEWIDTH) && fastmap[i])
+ {
+ was_a_range = 1;
+ i++;
+ }
+ if (was_a_range)
+ {
+ printf ("-");
+ printchar (i - 1);
+ }
+ }
+ }
+ putchar ('\n');
+}
+
+
+/* Print a compiled pattern string in human-readable form, starting at
+ the START pointer into it and ending just before the pointer END. */
+
+void
+print_partial_compiled_pattern (start, end)
+ unsigned char *start;
+ unsigned char *end;
+{
+ int mcnt, mcnt2;
+ unsigned char *p = start;
+ unsigned char *pend = end;
+
+ if (start == NULL)
+ {
+ printf ("(null)\n");
+ return;
+ }
+
+ /* Loop over pattern commands. */
+ while (p < pend)
+ {
+ printf ("%d:\t", p - start);
+
+ switch ((re_opcode_t) *p++)
+ {
+ case no_op:
+ printf ("/no_op");
+ break;
+
+ case exactn:
+ mcnt = *p++;
+ printf ("/exactn/%d", mcnt);
+ do
+ {
+ putchar ('/');
+ printchar (*p++);
+ }
+ while (--mcnt);
+ break;
+
+ case start_memory:
+ mcnt = *p++;
+ printf ("/start_memory/%d/%d", mcnt, *p++);
+ break;
+
+ case stop_memory:
+ mcnt = *p++;
+ printf ("/stop_memory/%d/%d", mcnt, *p++);
+ break;
+
+ case duplicate:
+ printf ("/duplicate/%d", *p++);
+ break;
+
+ case anychar:
+ printf ("/anychar");
+ break;
+
+ case charset:
+ case charset_not:
+ {
+ register int c, last = -100;
+ register int in_range = 0;
+
+ printf ("/charset [%s",
+ (re_opcode_t) *(p - 1) == charset_not ? "^" : "");
+
+ assert (p + *p < pend);
+
+ for (c = 0; c < 256; c++)
+ if (c / 8 < *p
+ && (p[1 + (c/8)] & (1 << (c % 8))))
+ {
+ /* Are we starting a range? */
+ if (last + 1 == c && ! in_range)
+ {
+ putchar ('-');
+ in_range = 1;
+ }
+ /* Have we broken a range? */
+ else if (last + 1 != c && in_range)
+ {
+ printchar (last);
+ in_range = 0;
+ }
+
+ if (! in_range)
+ printchar (c);
+
+ last = c;
+ }
+
+ if (in_range)
+ printchar (last);
+
+ putchar (']');
+
+ p += 1 + *p;
+ }
+ break;
+
+ case begline:
+ printf ("/begline");
+ break;
+
+ case endline:
+ printf ("/endline");
+ break;
+
+ case on_failure_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/on_failure_jump to %d", p + mcnt - start);
+ break;
+
+ case on_failure_keep_string_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/on_failure_keep_string_jump to %d", p + mcnt - start);
+ break;
+
+ case dummy_failure_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/dummy_failure_jump to %d", p + mcnt - start);
+ break;
+
+ case push_dummy_failure:
+ printf ("/push_dummy_failure");
+ break;
+
+ case maybe_pop_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/maybe_pop_jump to %d", p + mcnt - start);
+ break;
+
+ case pop_failure_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/pop_failure_jump to %d", p + mcnt - start);
+ break;
+
+ case jump_past_alt:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/jump_past_alt to %d", p + mcnt - start);
+ break;
+
+ case jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/jump to %d", p + mcnt - start);
+ break;
+
+ case succeed_n:
+ extract_number_and_incr (&mcnt, &p);
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/succeed_n to %d, %d times", p + mcnt - start, mcnt2);
+ break;
+
+ case jump_n:
+ extract_number_and_incr (&mcnt, &p);
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/jump_n to %d, %d times", p + mcnt - start, mcnt2);
+ break;
+
+ case set_number_at:
+ extract_number_and_incr (&mcnt, &p);
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/set_number_at location %d to %d", p + mcnt - start, mcnt2);
+ break;
+
+ case wordbound:
+ printf ("/wordbound");
+ break;
+
+ case notwordbound:
+ printf ("/notwordbound");
+ break;
+
+ case wordbeg:
+ printf ("/wordbeg");
+ break;
+
+ case wordend:
+ printf ("/wordend");
+
+#ifdef emacs
+ case before_dot:
+ printf ("/before_dot");
+ break;
+
+ case at_dot:
+ printf ("/at_dot");
+ break;
+
+ case after_dot:
+ printf ("/after_dot");
+ break;
+
+ case syntaxspec:
+ printf ("/syntaxspec");
+ mcnt = *p++;
+ printf ("/%d", mcnt);
+ break;
+
+ case notsyntaxspec:
+ printf ("/notsyntaxspec");
+ mcnt = *p++;
+ printf ("/%d", mcnt);
+ break;
+#endif /* emacs */
+
+ case wordchar:
+ printf ("/wordchar");
+ break;
+
+ case notwordchar:
+ printf ("/notwordchar");
+ break;
+
+ case begbuf:
+ printf ("/begbuf");
+ break;
+
+ case endbuf:
+ printf ("/endbuf");
+ break;
+
+ default:
+ printf ("?%d", *(p-1));
+ }
+
+ putchar ('\n');
+ }
+
+ printf ("%d:\tend of pattern.\n", p - start);
+}
+
+
+void
+print_compiled_pattern (bufp)
+ struct re_pattern_buffer *bufp;
+{
+ unsigned char *buffer = bufp->buffer;
+
+ print_partial_compiled_pattern (buffer, buffer + bufp->used);
+ printf ("%d bytes used/%d bytes allocated.\n", bufp->used, bufp->allocated);
+
+ if (bufp->fastmap_accurate && bufp->fastmap)
+ {
+ printf ("fastmap: ");
+ print_fastmap (bufp->fastmap);
+ }
+
+ printf ("re_nsub: %d\t", bufp->re_nsub);
+ printf ("regs_alloc: %d\t", bufp->regs_allocated);
+ printf ("can_be_null: %d\t", bufp->can_be_null);
+ printf ("newline_anchor: %d\n", bufp->newline_anchor);
+ printf ("no_sub: %d\t", bufp->no_sub);
+ printf ("not_bol: %d\t", bufp->not_bol);
+ printf ("not_eol: %d\t", bufp->not_eol);
+ printf ("syntax: %d\n", bufp->syntax);
+ /* Perhaps we should print the translate table? */
+}
+
+
+void
+print_double_string (where, string1, size1, string2, size2)
+ const char *where;
+ const char *string1;
+ const char *string2;
+ int size1;
+ int size2;
+{
+ unsigned this_char;
+
+ if (where == NULL)
+ printf ("(null)");
+ else
+ {
+ if (FIRST_STRING_P (where))
+ {
+ for (this_char = where - string1; this_char < size1; this_char++)
+ printchar (string1[this_char]);
+
+ where = string2;
+ }
+
+ for (this_char = where - string2; this_char < size2; this_char++)
+ printchar (string2[this_char]);
+ }
+}
+
+#else /* not DEBUG */
+
+#undef assert
+#define assert(e)
+
+#define DEBUG_STATEMENT(e)
+#define DEBUG_PRINT1(x)
+#define DEBUG_PRINT2(x1, x2)
+#define DEBUG_PRINT3(x1, x2, x3)
+#define DEBUG_PRINT4(x1, x2, x3, x4)
+#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)
+#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)
+
+#endif /* not DEBUG */
+
+/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can
+ also be assigned to arbitrarily: each pattern buffer stores its own
+ syntax, so it can be changed between regex compilations. */
+reg_syntax_t re_syntax_options = RE_SYNTAX_EMACS;
+
+
+/* Specify the precise syntax of regexps for compilation. This provides
+ for compatibility for various utilities which historically have
+ different, incompatible syntaxes.
+
+ The argument SYNTAX is a bit mask comprised of the various bits
+ defined in regex.h. We return the old syntax. */
+
+reg_syntax_t
+re_set_syntax (syntax)
+ reg_syntax_t syntax;
+{
+ reg_syntax_t ret = re_syntax_options;
+
+ re_syntax_options = syntax;
+ return ret;
+}
+
+/* This table gives an error message for each of the error codes listed
+ in regex.h. Obviously the order here has to be same as there. */
+
+static const char *re_error_msg[] =
+ { NULL, /* REG_NOERROR */
+ "No match", /* REG_NOMATCH */
+ "Invalid regular expression", /* REG_BADPAT */
+ "Invalid collation character", /* REG_ECOLLATE */
+ "Invalid character class name", /* REG_ECTYPE */
+ "Trailing backslash", /* REG_EESCAPE */
+ "Invalid back reference", /* REG_ESUBREG */
+ "Unmatched [ or [^", /* REG_EBRACK */
+ "Unmatched ( or \\(", /* REG_EPAREN */
+ "Unmatched \\{", /* REG_EBRACE */
+ "Invalid content of \\{\\}", /* REG_BADBR */
+ "Invalid range end", /* REG_ERANGE */
+ "Memory exhausted", /* REG_ESPACE */
+ "Invalid preceding regular expression", /* REG_BADRPT */
+ "Premature end of regular expression", /* REG_EEND */
+ "Regular expression too big", /* REG_ESIZE */
+ "Unmatched ) or \\)", /* REG_ERPAREN */
+ };
+
+/* Avoiding alloca during matching, to placate r_alloc. */
+
+/* Define MATCH_MAY_ALLOCATE unless we need to make sure that the
+ searching and matching functions should not call alloca. On some
+ systems, alloca is implemented in terms of malloc, and if we're
+ using the relocating allocator routines, then malloc could cause a
+ relocation, which might (if the strings being searched are in the
+ ralloc heap) shift the data out from underneath the regexp
+ routines.
+
+ Here's another reason to avoid allocation: Emacs
+ processes input from X in a signal handler; processing X input may
+ call malloc; if input arrives while a matching routine is calling
+ malloc, then we're scrod. But Emacs can't just block input while
+ calling matching routines; then we don't notice interrupts when
+ they come in. So, Emacs blocks input around all regexp calls
+ except the matching calls, which it leaves unprotected, in the
+ faith that they will not malloc. */
+
+/* Normally, this is fine. */
+#define MATCH_MAY_ALLOCATE
+
+/* The match routines may not allocate if (1) they would do it with malloc
+ and (2) it's not safe for them to use malloc. */
+#if (defined (C_ALLOCA) || defined (REGEX_MALLOC)) && (defined (emacs) || defined (REL_ALLOC))
+#undef MATCH_MAY_ALLOCATE
+#endif
+
+
+/* Failure stack declarations and macros; both re_compile_fastmap and
+ re_match_2 use a failure stack. These have to be macros because of
+ REGEX_ALLOCATE. */
+
+
+/* Number of failure points for which to initially allocate space
+ when matching. If this number is exceeded, we allocate more
+ space, so it is not a hard limit. */
+#ifndef INIT_FAILURE_ALLOC
+#define INIT_FAILURE_ALLOC 5
+#endif
+
+/* Roughly the maximum number of failure points on the stack. Would be
+ exactly that if always used MAX_FAILURE_SPACE each time we failed.
+ This is a variable only so users of regex can assign to it; we never
+ change it ourselves. */
+int re_max_failures = 2000;
+
+typedef unsigned char *fail_stack_elt_t;
+
+typedef struct
+{
+ fail_stack_elt_t *stack;
+ unsigned size;
+ unsigned avail; /* Offset of next open position. */
+} fail_stack_type;
+
+#define FAIL_STACK_EMPTY() (fail_stack.avail == 0)
+#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0)
+#define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size)
+#define FAIL_STACK_TOP() (fail_stack.stack[fail_stack.avail])
+
+
+/* Initialize `fail_stack'. Do `return -2' if the alloc fails. */
+
+#ifdef MATCH_MAY_ALLOCATE
+#define INIT_FAIL_STACK() \
+ do { \
+ fail_stack.stack = (fail_stack_elt_t *) \
+ REGEX_ALLOCATE (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t)); \
+ \
+ if (fail_stack.stack == NULL) \
+ return -2; \
+ \
+ fail_stack.size = INIT_FAILURE_ALLOC; \
+ fail_stack.avail = 0; \
+ } while (0)
+#else
+#define INIT_FAIL_STACK() \
+ do { \
+ fail_stack.avail = 0; \
+ } while (0)
+#endif
+
+
+/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items.
+
+ Return 1 if succeeds, and 0 if either ran out of memory
+ allocating space for it or it was already too large.
+
+ REGEX_REALLOCATE requires `destination' be declared. */
+
+#define DOUBLE_FAIL_STACK(fail_stack) \
+ ((fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS \
+ ? 0 \
+ : ((fail_stack).stack = (fail_stack_elt_t *) \
+ REGEX_REALLOCATE ((fail_stack).stack, \
+ (fail_stack).size * sizeof (fail_stack_elt_t), \
+ ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)), \
+ \
+ (fail_stack).stack == NULL \
+ ? 0 \
+ : ((fail_stack).size <<= 1, \
+ 1)))
+
+
+/* Push PATTERN_OP on FAIL_STACK.
+
+ Return 1 if was able to do so and 0 if ran out of memory allocating
+ space to do so. */
+#define PUSH_PATTERN_OP(pattern_op, fail_stack) \
+ ((FAIL_STACK_FULL () \
+ && !DOUBLE_FAIL_STACK (fail_stack)) \
+ ? 0 \
+ : ((fail_stack).stack[(fail_stack).avail++] = pattern_op, \
+ 1))
+
+/* This pushes an item onto the failure stack. Must be a four-byte
+ value. Assumes the variable `fail_stack'. Probably should only
+ be called from within `PUSH_FAILURE_POINT'. */
+#define PUSH_FAILURE_ITEM(item) \
+ fail_stack.stack[fail_stack.avail++] = (fail_stack_elt_t) item
+
+/* The complement operation. Assumes `fail_stack' is nonempty. */
+#define POP_FAILURE_ITEM() fail_stack.stack[--fail_stack.avail]
+
+/* Used to omit pushing failure point id's when we're not debugging. */
+#ifdef DEBUG
+#define DEBUG_PUSH PUSH_FAILURE_ITEM
+#define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_ITEM ()
+#else
+#define DEBUG_PUSH(item)
+#define DEBUG_POP(item_addr)
+#endif
+
+
+/* Push the information about the state we will need
+ if we ever fail back to it.
+
+ Requires variables fail_stack, regstart, regend, reg_info, and
+ num_regs be declared. DOUBLE_FAIL_STACK requires `destination' be
+ declared.
+
+ Does `return FAILURE_CODE' if runs out of memory. */
+
+#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \
+ do { \
+ char *destination; \
+ /* Must be int, so when we don't save any registers, the arithmetic \
+ of 0 + -1 isn't done as unsigned. */ \
+ int this_reg; \
+ \
+ DEBUG_STATEMENT (failure_id++); \
+ DEBUG_STATEMENT (nfailure_points_pushed++); \
+ DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \
+ DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail);\
+ DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\
+ \
+ DEBUG_PRINT2 (" slots needed: %d\n", NUM_FAILURE_ITEMS); \
+ DEBUG_PRINT2 (" available: %d\n", REMAINING_AVAIL_SLOTS); \
+ \
+ /* Ensure we have enough space allocated for what we will push. */ \
+ while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS) \
+ { \
+ if (!DOUBLE_FAIL_STACK (fail_stack)) \
+ return failure_code; \
+ \
+ DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \
+ (fail_stack).size); \
+ DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\
+ } \
+ \
+ /* Push the info, starting with the registers. */ \
+ DEBUG_PRINT1 ("\n"); \
+ \
+ for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \
+ this_reg++) \
+ { \
+ DEBUG_PRINT2 (" Pushing reg: %d\n", this_reg); \
+ DEBUG_STATEMENT (num_regs_pushed++); \
+ \
+ DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \
+ PUSH_FAILURE_ITEM (regstart[this_reg]); \
+ \
+ DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \
+ PUSH_FAILURE_ITEM (regend[this_reg]); \
+ \
+ DEBUG_PRINT2 (" info: 0x%x\n ", reg_info[this_reg]); \
+ DEBUG_PRINT2 (" match_null=%d", \
+ REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \
+ DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \
+ DEBUG_PRINT2 (" matched_something=%d", \
+ MATCHED_SOMETHING (reg_info[this_reg])); \
+ DEBUG_PRINT2 (" ever_matched=%d", \
+ EVER_MATCHED_SOMETHING (reg_info[this_reg])); \
+ DEBUG_PRINT1 ("\n"); \
+ PUSH_FAILURE_ITEM (reg_info[this_reg].word); \
+ } \
+ \
+ DEBUG_PRINT2 (" Pushing low active reg: %d\n", lowest_active_reg);\
+ PUSH_FAILURE_ITEM (lowest_active_reg); \
+ \
+ DEBUG_PRINT2 (" Pushing high active reg: %d\n", highest_active_reg);\
+ PUSH_FAILURE_ITEM (highest_active_reg); \
+ \
+ DEBUG_PRINT2 (" Pushing pattern 0x%x: ", pattern_place); \
+ DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend); \
+ PUSH_FAILURE_ITEM (pattern_place); \
+ \
+ DEBUG_PRINT2 (" Pushing string 0x%x: `", string_place); \
+ DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, \
+ size2); \
+ DEBUG_PRINT1 ("'\n"); \
+ PUSH_FAILURE_ITEM (string_place); \
+ \
+ DEBUG_PRINT2 (" Pushing failure id: %u\n", failure_id); \
+ DEBUG_PUSH (failure_id); \
+ } while (0)
+
+/* This is the number of items that are pushed and popped on the stack
+ for each register. */
+#define NUM_REG_ITEMS 3
+
+/* Individual items aside from the registers. */
+#ifdef DEBUG
+#define NUM_NONREG_ITEMS 5 /* Includes failure point id. */
+#else
+#define NUM_NONREG_ITEMS 4
+#endif
+
+/* We push at most this many items on the stack. */
+#define MAX_FAILURE_ITEMS ((num_regs - 1) * NUM_REG_ITEMS + NUM_NONREG_ITEMS)
+
+/* We actually push this many items. */
+#define NUM_FAILURE_ITEMS \
+ ((highest_active_reg - lowest_active_reg + 1) * NUM_REG_ITEMS \
+ + NUM_NONREG_ITEMS)
+
+/* How many items can still be added to the stack without overflowing it. */
+#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail)
+
+
+/* Pops what PUSH_FAIL_STACK pushes.
+
+ We restore into the parameters, all of which should be lvalues:
+ STR -- the saved data position.
+ PAT -- the saved pattern position.
+ LOW_REG, HIGH_REG -- the highest and lowest active registers.
+ REGSTART, REGEND -- arrays of string positions.
+ REG_INFO -- array of information about each subexpression.
+
+ Also assumes the variables `fail_stack' and (if debugging), `bufp',
+ `pend', `string1', `size1', `string2', and `size2'. */
+
+#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\
+{ \
+ DEBUG_STATEMENT (fail_stack_elt_t failure_id;) \
+ int this_reg; \
+ const unsigned char *string_temp; \
+ \
+ assert (!FAIL_STACK_EMPTY ()); \
+ \
+ /* Remove failure points and point to how many regs pushed. */ \
+ DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \
+ DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \
+ DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \
+ \
+ assert (fail_stack.avail >= NUM_NONREG_ITEMS); \
+ \
+ DEBUG_POP (&failure_id); \
+ DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); \
+ \
+ /* If the saved string location is NULL, it came from an \
+ on_failure_keep_string_jump opcode, and we want to throw away the \
+ saved NULL, thus retaining our current position in the string. */ \
+ string_temp = POP_FAILURE_ITEM (); \
+ if (string_temp != NULL) \
+ str = (const char *) string_temp; \
+ \
+ DEBUG_PRINT2 (" Popping string 0x%x: `", str); \
+ DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \
+ DEBUG_PRINT1 ("'\n"); \
+ \
+ pat = (unsigned char *) POP_FAILURE_ITEM (); \
+ DEBUG_PRINT2 (" Popping pattern 0x%x: ", pat); \
+ DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \
+ \
+ /* Restore register info. */ \
+ high_reg = (unsigned) POP_FAILURE_ITEM (); \
+ DEBUG_PRINT2 (" Popping high active reg: %d\n", high_reg); \
+ \
+ low_reg = (unsigned) POP_FAILURE_ITEM (); \
+ DEBUG_PRINT2 (" Popping low active reg: %d\n", low_reg); \
+ \
+ for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \
+ { \
+ DEBUG_PRINT2 (" Popping reg: %d\n", this_reg); \
+ \
+ reg_info[this_reg].word = POP_FAILURE_ITEM (); \
+ DEBUG_PRINT2 (" info: 0x%x\n", reg_info[this_reg]); \
+ \
+ regend[this_reg] = (const char *) POP_FAILURE_ITEM (); \
+ DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \
+ \
+ regstart[this_reg] = (const char *) POP_FAILURE_ITEM (); \
+ DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \
+ } \
+ \
+ DEBUG_STATEMENT (nfailure_points_popped++); \
+} /* POP_FAILURE_POINT */
+
+
+
+/* Structure for per-register (a.k.a. per-group) information.
+ This must not be longer than one word, because we push this value
+ onto the failure stack. Other register information, such as the
+ starting and ending positions (which are addresses), and the list of
+ inner groups (which is a bits list) are maintained in separate
+ variables.
+
+ We are making a (strictly speaking) nonportable assumption here: that
+ the compiler will pack our bit fields into something that fits into
+ the type of `word', i.e., is something that fits into one item on the
+ failure stack. */
+typedef union
+{
+ fail_stack_elt_t word;
+ struct
+ {
+ /* This field is one if this group can match the empty string,
+ zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */
+#define MATCH_NULL_UNSET_VALUE 3
+ unsigned match_null_string_p : 2;
+ unsigned is_active : 1;
+ unsigned matched_something : 1;
+ unsigned ever_matched_something : 1;
+ } bits;
+} register_info_type;
+
+#define REG_MATCH_NULL_STRING_P(R) ((R).bits.match_null_string_p)
+#define IS_ACTIVE(R) ((R).bits.is_active)
+#define MATCHED_SOMETHING(R) ((R).bits.matched_something)
+#define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something)
+
+
+/* Call this when have matched a real character; it sets `matched' flags
+ for the subexpressions which we are currently inside. Also records
+ that those subexprs have matched. */
+#define SET_REGS_MATCHED() \
+ do \
+ { \
+ unsigned r; \
+ for (r = lowest_active_reg; r <= highest_active_reg; r++) \
+ { \
+ MATCHED_SOMETHING (reg_info[r]) \
+ = EVER_MATCHED_SOMETHING (reg_info[r]) \
+ = 1; \
+ } \
+ } \
+ while (0)
+
+
+/* Registers are set to a sentinel when they haven't yet matched. */
+#define REG_UNSET_VALUE ((char *) -1)
+#define REG_UNSET(e) ((e) == REG_UNSET_VALUE)
+
+
+
+/* How do we implement a missing MATCH_MAY_ALLOCATE?
+ We make the fail stack a global thing, and then grow it to
+ re_max_failures when we compile. */
+#ifndef MATCH_MAY_ALLOCATE
+static fail_stack_type fail_stack;
+
+static const char ** regstart, ** regend;
+static const char ** old_regstart, ** old_regend;
+static const char **best_regstart, **best_regend;
+static register_info_type *reg_info;
+static const char **reg_dummy;
+static register_info_type *reg_info_dummy;
+#endif
+
+
+/* Subroutine declarations and macros for regex_compile. */
+
+static void store_op1 (), store_op2 ();
+static void insert_op1 (), insert_op2 ();
+static boolean at_begline_loc_p (), at_endline_loc_p ();
+static boolean group_in_compile_stack ();
+static reg_errcode_t compile_range ();
+
+/* Fetch the next character in the uncompiled pattern---translating it
+ if necessary. Also cast from a signed character in the constant
+ string passed to us by the user to an unsigned char that we can use
+ as an array index (in, e.g., `translate'). */
+#define PATFETCH(c) \
+ do {if (p == pend) return REG_EEND; \
+ c = (unsigned char) *p++; \
+ if (translate) c = translate[c]; \
+ } while (0)
+
+/* Fetch the next character in the uncompiled pattern, with no
+ translation. */
+#define PATFETCH_RAW(c) \
+ do {if (p == pend) return REG_EEND; \
+ c = (unsigned char) *p++; \
+ } while (0)
+
+/* Go backwards one character in the pattern. */
+#define PATUNFETCH p--
+
+
+/* If `translate' is non-null, return translate[D], else just D. We
+ cast the subscript to translate because some data is declared as
+ `char *', to avoid warnings when a string constant is passed. But
+ when we use a character as a subscript we must make it unsigned. */
+#define TRANSLATE(d) (translate ? translate[(unsigned char) (d)] : (d))
+
+
+/* Macros for outputting the compiled pattern into `buffer'. */
+
+/* If the buffer isn't allocated when it comes in, use this. */
+#define INIT_BUF_SIZE 32
+
+/* Make sure we have at least N more bytes of space in buffer. */
+#define GET_BUFFER_SPACE(n) \
+ while (b - bufp->buffer + (n) > bufp->allocated) \
+ EXTEND_BUFFER ()
+
+/* Make sure we have one more byte of buffer space and then add C to it. */
+#define BUF_PUSH(c) \
+ do { \
+ GET_BUFFER_SPACE (1); \
+ *b++ = (unsigned char) (c); \
+ } while (0)
+
+
+/* Ensure we have two more bytes of buffer space and then append C1 and C2. */
+#define BUF_PUSH_2(c1, c2) \
+ do { \
+ GET_BUFFER_SPACE (2); \
+ *b++ = (unsigned char) (c1); \
+ *b++ = (unsigned char) (c2); \
+ } while (0)
+
+
+/* As with BUF_PUSH_2, except for three bytes. */
+#define BUF_PUSH_3(c1, c2, c3) \
+ do { \
+ GET_BUFFER_SPACE (3); \
+ *b++ = (unsigned char) (c1); \
+ *b++ = (unsigned char) (c2); \
+ *b++ = (unsigned char) (c3); \
+ } while (0)
+
+
+/* Store a jump with opcode OP at LOC to location TO. We store a
+ relative address offset by the three bytes the jump itself occupies. */
+#define STORE_JUMP(op, loc, to) \
+ store_op1 (op, loc, (to) - (loc) - 3)
+
+/* Likewise, for a two-argument jump. */
+#define STORE_JUMP2(op, loc, to, arg) \
+ store_op2 (op, loc, (to) - (loc) - 3, arg)
+
+/* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */
+#define INSERT_JUMP(op, loc, to) \
+ insert_op1 (op, loc, (to) - (loc) - 3, b)
+
+/* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */
+#define INSERT_JUMP2(op, loc, to, arg) \
+ insert_op2 (op, loc, (to) - (loc) - 3, arg, b)
+
+
+/* This is not an arbitrary limit: the arguments which represent offsets
+ into the pattern are two bytes long. So if 2^16 bytes turns out to
+ be too small, many things would have to change. */
+#define MAX_BUF_SIZE (1L << 16)
+
+
+/* Extend the buffer by twice its current size via realloc and
+ reset the pointers that pointed into the old block to point to the
+ correct places in the new one. If extending the buffer results in it
+ being larger than MAX_BUF_SIZE, then flag memory exhausted. */
+#define EXTEND_BUFFER() \
+ do { \
+ unsigned char *old_buffer = bufp->buffer; \
+ if (bufp->allocated == MAX_BUF_SIZE) \
+ return REG_ESIZE; \
+ bufp->allocated <<= 1; \
+ if (bufp->allocated > MAX_BUF_SIZE) \
+ bufp->allocated = MAX_BUF_SIZE; \
+ bufp->buffer = (unsigned char *) realloc (bufp->buffer, bufp->allocated);\
+ if (bufp->buffer == NULL) \
+ return REG_ESPACE; \
+ /* If the buffer moved, move all the pointers into it. */ \
+ if (old_buffer != bufp->buffer) \
+ { \
+ b = (b - old_buffer) + bufp->buffer; \
+ begalt = (begalt - old_buffer) + bufp->buffer; \
+ if (fixup_alt_jump) \
+ fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\
+ if (laststart) \
+ laststart = (laststart - old_buffer) + bufp->buffer; \
+ if (pending_exact) \
+ pending_exact = (pending_exact - old_buffer) + bufp->buffer; \
+ } \
+ } while (0)
+
+
+/* Since we have one byte reserved for the register number argument to
+ {start,stop}_memory, the maximum number of groups we can report
+ things about is what fits in that byte. */
+#define MAX_REGNUM 255
+
+/* But patterns can have more than `MAX_REGNUM' registers. We just
+ ignore the excess. */
+typedef unsigned regnum_t;
+
+
+/* Macros for the compile stack. */
+
+/* Since offsets can go either forwards or backwards, this type needs to
+ be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */
+typedef int pattern_offset_t;
+
+typedef struct
+{
+ pattern_offset_t begalt_offset;
+ pattern_offset_t fixup_alt_jump;
+ pattern_offset_t inner_group_offset;
+ pattern_offset_t laststart_offset;
+ regnum_t regnum;
+} compile_stack_elt_t;
+
+
+typedef struct
+{
+ compile_stack_elt_t *stack;
+ unsigned size;
+ unsigned avail; /* Offset of next open position. */
+} compile_stack_type;
+
+
+#define INIT_COMPILE_STACK_SIZE 32
+
+#define COMPILE_STACK_EMPTY (compile_stack.avail == 0)
+#define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size)
+
+/* The next available element. */
+#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail])
+
+
+/* Set the bit for character C in a list. */
+#define SET_LIST_BIT(c) \
+ (b[((unsigned char) (c)) / BYTEWIDTH] \
+ |= 1 << (((unsigned char) c) % BYTEWIDTH))
+
+
+/* Get the next unsigned number in the uncompiled pattern. */
+#define GET_UNSIGNED_NUMBER(num) \
+ { if (p != pend) \
+ { \
+ PATFETCH (c); \
+ while (ISDIGIT (c)) \
+ { \
+ if (num < 0) \
+ num = 0; \
+ num = num * 10 + c - '0'; \
+ if (p == pend) \
+ break; \
+ PATFETCH (c); \
+ } \
+ } \
+ }
+
+#define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */
+
+#define IS_CHAR_CLASS(string) \
+ (STREQ (string, "alpha") || STREQ (string, "upper") \
+ || STREQ (string, "lower") || STREQ (string, "digit") \
+ || STREQ (string, "alnum") || STREQ (string, "xdigit") \
+ || STREQ (string, "space") || STREQ (string, "print") \
+ || STREQ (string, "punct") || STREQ (string, "graph") \
+ || STREQ (string, "cntrl") || STREQ (string, "blank"))
+
+/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX.
+ Returns one of error codes defined in `regex.h', or zero for success.
+
+ Assumes the `allocated' (and perhaps `buffer') and `translate'
+ fields are set in BUFP on entry.
+
+ If it succeeds, results are put in BUFP (if it returns an error, the
+ contents of BUFP are undefined):
+ `buffer' is the compiled pattern;
+ `syntax' is set to SYNTAX;
+ `used' is set to the length of the compiled pattern;
+ `fastmap_accurate' is zero;
+ `re_nsub' is the number of subexpressions in PATTERN;
+ `not_bol' and `not_eol' are zero;
+
+ The `fastmap' and `newline_anchor' fields are neither
+ examined nor set. */
+
+/* Return, freeing storage we allocated. */
+#define FREE_STACK_RETURN(value) \
+ return (free (compile_stack.stack), value)
+
+static reg_errcode_t
+regex_compile (pattern, size, syntax, bufp)
+ const char *pattern;
+ int size;
+ reg_syntax_t syntax;
+ struct re_pattern_buffer *bufp;
+{
+ /* We fetch characters from PATTERN here. Even though PATTERN is
+ `char *' (i.e., signed), we declare these variables as unsigned, so
+ they can be reliably used as array indices. */
+ register unsigned char c, c1;
+
+ /* A random temporary spot in PATTERN. */
+ const char *p1;
+
+ /* Points to the end of the buffer, where we should append. */
+ register unsigned char *b;
+
+ /* Keeps track of unclosed groups. */
+ compile_stack_type compile_stack;
+
+ /* Points to the current (ending) position in the pattern. */
+ const char *p = pattern;
+ const char *pend = pattern + size;
+
+ /* How to translate the characters in the pattern. */
+ char *translate = bufp->translate;
+
+ /* Address of the count-byte of the most recently inserted `exactn'
+ command. This makes it possible to tell if a new exact-match
+ character can be added to that command or if the character requires
+ a new `exactn' command. */
+ unsigned char *pending_exact = 0;
+
+ /* Address of start of the most recently finished expression.
+ This tells, e.g., postfix * where to find the start of its
+ operand. Reset at the beginning of groups and alternatives. */
+ unsigned char *laststart = 0;
+
+ /* Address of beginning of regexp, or inside of last group. */
+ unsigned char *begalt;
+
+ /* Place in the uncompiled pattern (i.e., the {) to
+ which to go back if the interval is invalid. */
+ const char *beg_interval;
+
+ /* Address of the place where a forward jump should go to the end of
+ the containing expression. Each alternative of an `or' -- except the
+ last -- ends with a forward jump of this sort. */
+ unsigned char *fixup_alt_jump = 0;
+
+ /* Counts open-groups as they are encountered. Remembered for the
+ matching close-group on the compile stack, so the same register
+ number is put in the stop_memory as the start_memory. */
+ regnum_t regnum = 0;
+
+#ifdef DEBUG
+ DEBUG_PRINT1 ("\nCompiling pattern: ");
+ if (debug)
+ {
+ unsigned debug_count;
+
+ for (debug_count = 0; debug_count < size; debug_count++)
+ printchar (pattern[debug_count]);
+ putchar ('\n');
+ }
+#endif /* DEBUG */
+
+ /* Initialize the compile stack. */
+ compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t);
+ if (compile_stack.stack == NULL)
+ return REG_ESPACE;
+
+ compile_stack.size = INIT_COMPILE_STACK_SIZE;
+ compile_stack.avail = 0;
+
+ /* Initialize the pattern buffer. */
+ bufp->syntax = syntax;
+ bufp->fastmap_accurate = 0;
+ bufp->not_bol = bufp->not_eol = 0;
+
+ /* Set `used' to zero, so that if we return an error, the pattern
+ printer (for debugging) will think there's no pattern. We reset it
+ at the end. */
+ bufp->used = 0;
+
+ /* Always count groups, whether or not bufp->no_sub is set. */
+ bufp->re_nsub = 0;
+
+#if !defined (emacs) && !defined (SYNTAX_TABLE)
+ /* Initialize the syntax table. */
+ init_syntax_once ();
+#endif
+
+ if (bufp->allocated == 0)
+ {
+ if (bufp->buffer)
+ { /* If zero allocated, but buffer is non-null, try to realloc
+ enough space. This loses if buffer's address is bogus, but
+ that is the user's responsibility. */
+ RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char);
+ }
+ else
+ { /* Caller did not allocate a buffer. Do it for them. */
+ bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char);
+ }
+ if (!bufp->buffer) FREE_STACK_RETURN (REG_ESPACE);
+
+ bufp->allocated = INIT_BUF_SIZE;
+ }
+
+ begalt = b = bufp->buffer;
+
+ /* Loop through the uncompiled pattern until we're at the end. */
+ while (p != pend)
+ {
+ PATFETCH (c);
+
+ switch (c)
+ {
+ case '^':
+ {
+ if ( /* If at start of pattern, it's an operator. */
+ p == pattern + 1
+ /* If context independent, it's an operator. */
+ || syntax & RE_CONTEXT_INDEP_ANCHORS
+ /* Otherwise, depends on what's come before. */
+ || at_begline_loc_p (pattern, p, syntax))
+ BUF_PUSH (begline);
+ else
+ goto normal_char;
+ }
+ break;
+
+
+ case '$':
+ {
+ if ( /* If at end of pattern, it's an operator. */
+ p == pend
+ /* If context independent, it's an operator. */
+ || syntax & RE_CONTEXT_INDEP_ANCHORS
+ /* Otherwise, depends on what's next. */
+ || at_endline_loc_p (p, pend, syntax))
+ BUF_PUSH (endline);
+ else
+ goto normal_char;
+ }
+ break;
+
+
+ case '+':
+ case '?':
+ if ((syntax & RE_BK_PLUS_QM)
+ || (syntax & RE_LIMITED_OPS))
+ goto normal_char;
+ handle_plus:
+ case '*':
+ /* If there is no previous pattern... */
+ if (!laststart)
+ {
+ if (syntax & RE_CONTEXT_INVALID_OPS)
+ FREE_STACK_RETURN (REG_BADRPT);
+ else if (!(syntax & RE_CONTEXT_INDEP_OPS))
+ goto normal_char;
+ }
+
+ {
+ /* Are we optimizing this jump? */
+ boolean keep_string_p = false;
+
+ /* 1 means zero (many) matches is allowed. */
+ char zero_times_ok = 0, many_times_ok = 0;
+
+ /* If there is a sequence of repetition chars, collapse it
+ down to just one (the right one). We can't combine
+ interval operators with these because of, e.g., `a{2}*',
+ which should only match an even number of `a's. */
+
+ for (;;)
+ {
+ zero_times_ok |= c != '+';
+ many_times_ok |= c != '?';
+
+ if (p == pend)
+ break;
+
+ PATFETCH (c);
+
+ if (c == '*'
+ || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?')))
+ ;
+
+ else if (syntax & RE_BK_PLUS_QM && c == '\\')
+ {
+ if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+ PATFETCH (c1);
+ if (!(c1 == '+' || c1 == '?'))
+ {
+ PATUNFETCH;
+ PATUNFETCH;
+ break;
+ }
+
+ c = c1;
+ }
+ else
+ {
+ PATUNFETCH;
+ break;
+ }
+
+ /* If we get here, we found another repeat character. */
+ }
+
+ /* Star, etc. applied to an empty pattern is equivalent
+ to an empty pattern. */
+ if (!laststart)
+ break;
+
+ /* Now we know whether or not zero matches is allowed
+ and also whether or not two or more matches is allowed. */
+ if (many_times_ok)
+ { /* More than one repetition is allowed, so put in at the
+ end a backward relative jump from `b' to before the next
+ jump we're going to put in below (which jumps from
+ laststart to after this jump).
+
+ But if we are at the `*' in the exact sequence `.*\n',
+ insert an unconditional jump backwards to the .,
+ instead of the beginning of the loop. This way we only
+ push a failure point once, instead of every time
+ through the loop. */
+ assert (p - 1 > pattern);
+
+ /* Allocate the space for the jump. */
+ GET_BUFFER_SPACE (3);
+
+ /* We know we are not at the first character of the pattern,
+ because laststart was nonzero. And we've already
+ incremented `p', by the way, to be the character after
+ the `*'. Do we have to do something analogous here
+ for null bytes, because of RE_DOT_NOT_NULL? */
+ if (TRANSLATE (*(p - 2)) == TRANSLATE ('.')
+ && zero_times_ok
+ && p < pend && TRANSLATE (*p) == TRANSLATE ('\n')
+ && !(syntax & RE_DOT_NEWLINE))
+ { /* We have .*\n. */
+ STORE_JUMP (jump, b, laststart);
+ keep_string_p = true;
+ }
+ else
+ /* Anything else. */
+ STORE_JUMP (maybe_pop_jump, b, laststart - 3);
+
+ /* We've added more stuff to the buffer. */
+ b += 3;
+ }
+
+ /* On failure, jump from laststart to b + 3, which will be the
+ end of the buffer after this jump is inserted. */
+ GET_BUFFER_SPACE (3);
+ INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump
+ : on_failure_jump,
+ laststart, b + 3);
+ pending_exact = 0;
+ b += 3;
+
+ if (!zero_times_ok)
+ {
+ /* At least one repetition is required, so insert a
+ `dummy_failure_jump' before the initial
+ `on_failure_jump' instruction of the loop. This
+ effects a skip over that instruction the first time
+ we hit that loop. */
+ GET_BUFFER_SPACE (3);
+ INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6);
+ b += 3;
+ }
+ }
+ break;
+
+
+ case '.':
+ laststart = b;
+ BUF_PUSH (anychar);
+ break;
+
+
+ case '[':
+ {
+ boolean had_char_class = false;
+
+ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+ /* Ensure that we have enough space to push a charset: the
+ opcode, the length count, and the bitset; 34 bytes in all. */
+ GET_BUFFER_SPACE (34);
+
+ laststart = b;
+
+ /* We test `*p == '^' twice, instead of using an if
+ statement, so we only need one BUF_PUSH. */
+ BUF_PUSH (*p == '^' ? charset_not : charset);
+ if (*p == '^')
+ p++;
+
+ /* Remember the first position in the bracket expression. */
+ p1 = p;
+
+ /* Push the number of bytes in the bitmap. */
+ BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
+
+ /* Clear the whole map. */
+ bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
+
+ /* charset_not matches newline according to a syntax bit. */
+ if ((re_opcode_t) b[-2] == charset_not
+ && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
+ SET_LIST_BIT ('\n');
+
+ /* Read in characters and ranges, setting map bits. */
+ for (;;)
+ {
+ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+ PATFETCH (c);
+
+ /* \ might escape characters inside [...] and [^...]. */
+ if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
+ {
+ if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+ PATFETCH (c1);
+ SET_LIST_BIT (c1);
+ continue;
+ }
+
+ /* Could be the end of the bracket expression. If it's
+ not (i.e., when the bracket expression is `[]' so
+ far), the ']' character bit gets set way below. */
+ if (c == ']' && p != p1 + 1)
+ break;
+
+ /* Look ahead to see if it's a range when the last thing
+ was a character class. */
+ if (had_char_class && c == '-' && *p != ']')
+ FREE_STACK_RETURN (REG_ERANGE);
+
+ /* Look ahead to see if it's a range when the last thing
+ was a character: if this is a hyphen not at the
+ beginning or the end of a list, then it's the range
+ operator. */
+ if (c == '-'
+ && !(p - 2 >= pattern && p[-2] == '[')
+ && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
+ && *p != ']')
+ {
+ reg_errcode_t ret
+ = compile_range (&p, pend, translate, syntax, b);
+ if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
+ }
+
+ else if (p[0] == '-' && p[1] != ']')
+ { /* This handles ranges made up of characters only. */
+ reg_errcode_t ret;
+
+ /* Move past the `-'. */
+ PATFETCH (c1);
+
+ ret = compile_range (&p, pend, translate, syntax, b);
+ if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
+ }
+
+ /* See if we're at the beginning of a possible character
+ class. */
+
+ else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
+ { /* Leave room for the null. */
+ char str[CHAR_CLASS_MAX_LENGTH + 1];
+
+ PATFETCH (c);
+ c1 = 0;
+
+ /* If pattern is `[[:'. */
+ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+ for (;;)
+ {
+ PATFETCH (c);
+ if (c == ':' || c == ']' || p == pend
+ || c1 == CHAR_CLASS_MAX_LENGTH)
+ break;
+ str[c1++] = c;
+ }
+ str[c1] = '\0';
+
+ /* If isn't a word bracketed by `[:' and:`]':
+ undo the ending character, the letters, and leave
+ the leading `:' and `[' (but set bits for them). */
+ if (c == ':' && *p == ']')
+ {
+ int ch;
+ boolean is_alnum = STREQ (str, "alnum");
+ boolean is_alpha = STREQ (str, "alpha");
+ boolean is_blank = STREQ (str, "blank");
+ boolean is_cntrl = STREQ (str, "cntrl");
+ boolean is_digit = STREQ (str, "digit");
+ boolean is_graph = STREQ (str, "graph");
+ boolean is_lower = STREQ (str, "lower");
+ boolean is_print = STREQ (str, "print");
+ boolean is_punct = STREQ (str, "punct");
+ boolean is_space = STREQ (str, "space");
+ boolean is_upper = STREQ (str, "upper");
+ boolean is_xdigit = STREQ (str, "xdigit");
+
+ if (!IS_CHAR_CLASS (str))
+ FREE_STACK_RETURN (REG_ECTYPE);
+
+ /* Throw away the ] at the end of the character
+ class. */
+ PATFETCH (c);
+
+ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+ for (ch = 0; ch < 1 << BYTEWIDTH; ch++)
+ {
+ /* This was split into 3 if's to
+ avoid an arbitrary limit in some compiler. */
+ if ( (is_alnum && ISALNUM (ch))
+ || (is_alpha && ISALPHA (ch))
+ || (is_blank && ISBLANK (ch))
+ || (is_cntrl && ISCNTRL (ch)))
+ SET_LIST_BIT (ch);
+ if ( (is_digit && ISDIGIT (ch))
+ || (is_graph && ISGRAPH (ch))
+ || (is_lower && ISLOWER (ch))
+ || (is_print && ISPRINT (ch)))
+ SET_LIST_BIT (ch);
+ if ( (is_punct && ISPUNCT (ch))
+ || (is_space && ISSPACE (ch))
+ || (is_upper && ISUPPER (ch))
+ || (is_xdigit && ISXDIGIT (ch)))
+ SET_LIST_BIT (ch);
+ }
+ had_char_class = true;
+ }
+ else
+ {
+ c1++;
+ while (c1--)
+ PATUNFETCH;
+ SET_LIST_BIT ('[');
+ SET_LIST_BIT (':');
+ had_char_class = false;
+ }
+ }
+ else
+ {
+ had_char_class = false;
+ SET_LIST_BIT (c);
+ }
+ }
+
+ /* Discard any (non)matching list bytes that are all 0 at the
+ end of the map. Decrease the map-length byte too. */
+ while ((int) b[-1] > 0 && b[b[-1] - 1] == 0)
+ b[-1]--;
+ b += b[-1];
+ }
+ break;
+
+
+ case '(':
+ if (syntax & RE_NO_BK_PARENS)
+ goto handle_open;
+ else
+ goto normal_char;
+
+
+ case ')':
+ if (syntax & RE_NO_BK_PARENS)
+ goto handle_close;
+ else
+ goto normal_char;
+
+
+ case '\n':
+ if (syntax & RE_NEWLINE_ALT)
+ goto handle_alt;
+ else
+ goto normal_char;
+
+
+ case '|':
+ if (syntax & RE_NO_BK_VBAR)
+ goto handle_alt;
+ else
+ goto normal_char;
+
+
+ case '{':
+ if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES)
+ goto handle_interval;
+ else
+ goto normal_char;
+
+
+ case '\\':
+ if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+ /* Do not translate the character after the \, so that we can
+ distinguish, e.g., \B from \b, even if we normally would
+ translate, e.g., B to b. */
+ PATFETCH_RAW (c);
+
+ switch (c)
+ {
+ case '(':
+ if (syntax & RE_NO_BK_PARENS)
+ goto normal_backslash;
+
+ handle_open:
+ bufp->re_nsub++;
+ regnum++;
+
+ if (COMPILE_STACK_FULL)
+ {
+ RETALLOC (compile_stack.stack, compile_stack.size << 1,
+ compile_stack_elt_t);
+ if (compile_stack.stack == NULL) return REG_ESPACE;
+
+ compile_stack.size <<= 1;
+ }
+
+ /* These are the values to restore when we hit end of this
+ group. They are all relative offsets, so that if the
+ whole pattern moves because of realloc, they will still
+ be valid. */
+ COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer;
+ COMPILE_STACK_TOP.fixup_alt_jump
+ = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0;
+ COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer;
+ COMPILE_STACK_TOP.regnum = regnum;
+
+ /* We will eventually replace the 0 with the number of
+ groups inner to this one. But do not push a
+ start_memory for groups beyond the last one we can
+ represent in the compiled pattern. */
+ if (regnum <= MAX_REGNUM)
+ {
+ COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2;
+ BUF_PUSH_3 (start_memory, regnum, 0);
+ }
+
+ compile_stack.avail++;
+
+ fixup_alt_jump = 0;
+ laststart = 0;
+ begalt = b;
+ /* If we've reached MAX_REGNUM groups, then this open
+ won't actually generate any code, so we'll have to
+ clear pending_exact explicitly. */
+ pending_exact = 0;
+ break;
+
+
+ case ')':
+ if (syntax & RE_NO_BK_PARENS) goto normal_backslash;
+
+ if (COMPILE_STACK_EMPTY)
+ if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
+ goto normal_backslash;
+ else
+ FREE_STACK_RETURN (REG_ERPAREN);
+
+ handle_close:
+ if (fixup_alt_jump)
+ { /* Push a dummy failure point at the end of the
+ alternative for a possible future
+ `pop_failure_jump' to pop. See comments at
+ `push_dummy_failure' in `re_match_2'. */
+ BUF_PUSH (push_dummy_failure);
+
+ /* We allocated space for this jump when we assigned
+ to `fixup_alt_jump', in the `handle_alt' case below. */
+ STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1);
+ }
+
+ /* See similar code for backslashed left paren above. */
+ if (COMPILE_STACK_EMPTY)
+ if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
+ goto normal_char;
+ else
+ FREE_STACK_RETURN (REG_ERPAREN);
+
+ /* Since we just checked for an empty stack above, this
+ ``can't happen''. */
+ assert (compile_stack.avail != 0);
+ {
+ /* We don't just want to restore into `regnum', because
+ later groups should continue to be numbered higher,
+ as in `(ab)c(de)' -- the second group is #2. */
+ regnum_t this_group_regnum;
+
+ compile_stack.avail--;
+ begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset;
+ fixup_alt_jump
+ = COMPILE_STACK_TOP.fixup_alt_jump
+ ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1
+ : 0;
+ laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset;
+ this_group_regnum = COMPILE_STACK_TOP.regnum;
+ /* If we've reached MAX_REGNUM groups, then this open
+ won't actually generate any code, so we'll have to
+ clear pending_exact explicitly. */
+ pending_exact = 0;
+
+ /* We're at the end of the group, so now we know how many
+ groups were inside this one. */
+ if (this_group_regnum <= MAX_REGNUM)
+ {
+ unsigned char *inner_group_loc
+ = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset;
+
+ *inner_group_loc = regnum - this_group_regnum;
+ BUF_PUSH_3 (stop_memory, this_group_regnum,
+ regnum - this_group_regnum);
+ }
+ }
+ break;
+
+
+ case '|': /* `\|'. */
+ if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR)
+ goto normal_backslash;
+ handle_alt:
+ if (syntax & RE_LIMITED_OPS)
+ goto normal_char;
+
+ /* Insert before the previous alternative a jump which
+ jumps to this alternative if the former fails. */
+ GET_BUFFER_SPACE (3);
+ INSERT_JUMP (on_failure_jump, begalt, b + 6);
+ pending_exact = 0;
+ b += 3;
+
+ /* The alternative before this one has a jump after it
+ which gets executed if it gets matched. Adjust that
+ jump so it will jump to this alternative's analogous
+ jump (put in below, which in turn will jump to the next
+ (if any) alternative's such jump, etc.). The last such
+ jump jumps to the correct final destination. A picture:
+ _____ _____
+ | | | |
+ | v | v
+ a | b | c
+
+ If we are at `b', then fixup_alt_jump right now points to a
+ three-byte space after `a'. We'll put in the jump, set
+ fixup_alt_jump to right after `b', and leave behind three
+ bytes which we'll fill in when we get to after `c'. */
+
+ if (fixup_alt_jump)
+ STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
+
+ /* Mark and leave space for a jump after this alternative,
+ to be filled in later either by next alternative or
+ when know we're at the end of a series of alternatives. */
+ fixup_alt_jump = b;
+ GET_BUFFER_SPACE (3);
+ b += 3;
+
+ laststart = 0;
+ begalt = b;
+ break;
+
+
+ case '{':
+ /* If \{ is a literal. */
+ if (!(syntax & RE_INTERVALS)
+ /* If we're at `\{' and it's not the open-interval
+ operator. */
+ || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
+ || (p - 2 == pattern && p == pend))
+ goto normal_backslash;
+
+ handle_interval:
+ {
+ /* If got here, then the syntax allows intervals. */
+
+ /* At least (most) this many matches must be made. */
+ int lower_bound = -1, upper_bound = -1;
+
+ beg_interval = p - 1;
+
+ if (p == pend)
+ {
+ if (syntax & RE_NO_BK_BRACES)
+ goto unfetch_interval;
+ else
+ FREE_STACK_RETURN (REG_EBRACE);
+ }
+
+ GET_UNSIGNED_NUMBER (lower_bound);
+
+ if (c == ',')
+ {
+ GET_UNSIGNED_NUMBER (upper_bound);
+ if (upper_bound < 0) upper_bound = RE_DUP_MAX;
+ }
+ else
+ /* Interval such as `{1}' => match exactly once. */
+ upper_bound = lower_bound;
+
+ if (lower_bound < 0 || upper_bound > RE_DUP_MAX
+ || lower_bound > upper_bound)
+ {
+ if (syntax & RE_NO_BK_BRACES)
+ goto unfetch_interval;
+ else
+ FREE_STACK_RETURN (REG_BADBR);
+ }
+
+ if (!(syntax & RE_NO_BK_BRACES))
+ {
+ if (c != '\\') FREE_STACK_RETURN (REG_EBRACE);
+
+ PATFETCH (c);
+ }
+
+ if (c != '}')
+ {
+ if (syntax & RE_NO_BK_BRACES)
+ goto unfetch_interval;
+ else
+ FREE_STACK_RETURN (REG_BADBR);
+ }
+
+ /* We just parsed a valid interval. */
+
+ /* If it's invalid to have no preceding re. */
+ if (!laststart)
+ {
+ if (syntax & RE_CONTEXT_INVALID_OPS)
+ FREE_STACK_RETURN (REG_BADRPT);
+ else if (syntax & RE_CONTEXT_INDEP_OPS)
+ laststart = b;
+ else
+ goto unfetch_interval;
+ }
+
+ /* If the upper bound is zero, don't want to succeed at
+ all; jump from `laststart' to `b + 3', which will be
+ the end of the buffer after we insert the jump. */
+ if (upper_bound == 0)
+ {
+ GET_BUFFER_SPACE (3);
+ INSERT_JUMP (jump, laststart, b + 3);
+ b += 3;
+ }
+
+ /* Otherwise, we have a nontrivial interval. When
+ we're all done, the pattern will look like:
+ set_number_at <jump count> <upper bound>
+ set_number_at <succeed_n count> <lower bound>
+ succeed_n <after jump addr> <succeed_n count>
+ <body of loop>
+ jump_n <succeed_n addr> <jump count>
+ (The upper bound and `jump_n' are omitted if
+ `upper_bound' is 1, though.) */
+ else
+ { /* If the upper bound is > 1, we need to insert
+ more at the end of the loop. */
+ unsigned nbytes = 10 + (upper_bound > 1) * 10;
+
+ GET_BUFFER_SPACE (nbytes);
+
+ /* Initialize lower bound of the `succeed_n', even
+ though it will be set during matching by its
+ attendant `set_number_at' (inserted next),
+ because `re_compile_fastmap' needs to know.
+ Jump to the `jump_n' we might insert below. */
+ INSERT_JUMP2 (succeed_n, laststart,
+ b + 5 + (upper_bound > 1) * 5,
+ lower_bound);
+ b += 5;
+
+ /* Code to initialize the lower bound. Insert
+ before the `succeed_n'. The `5' is the last two
+ bytes of this `set_number_at', plus 3 bytes of
+ the following `succeed_n'. */
+ insert_op2 (set_number_at, laststart, 5, lower_bound, b);
+ b += 5;
+
+ if (upper_bound > 1)
+ { /* More than one repetition is allowed, so
+ append a backward jump to the `succeed_n'
+ that starts this interval.
+
+ When we've reached this during matching,
+ we'll have matched the interval once, so
+ jump back only `upper_bound - 1' times. */
+ STORE_JUMP2 (jump_n, b, laststart + 5,
+ upper_bound - 1);
+ b += 5;
+
+ /* The location we want to set is the second
+ parameter of the `jump_n'; that is `b-2' as
+ an absolute address. `laststart' will be
+ the `set_number_at' we're about to insert;
+ `laststart+3' the number to set, the source
+ for the relative address. But we are
+ inserting into the middle of the pattern --
+ so everything is getting moved up by 5.
+ Conclusion: (b - 2) - (laststart + 3) + 5,
+ i.e., b - laststart.
+
+ We insert this at the beginning of the loop
+ so that if we fail during matching, we'll
+ reinitialize the bounds. */
+ insert_op2 (set_number_at, laststart, b - laststart,
+ upper_bound - 1, b);
+ b += 5;
+ }
+ }
+ pending_exact = 0;
+ beg_interval = NULL;
+ }
+ break;
+
+ unfetch_interval:
+ /* If an invalid interval, match the characters as literals. */
+ assert (beg_interval);
+ p = beg_interval;
+ beg_interval = NULL;
+
+ /* normal_char and normal_backslash need `c'. */
+ PATFETCH (c);
+
+ if (!(syntax & RE_NO_BK_BRACES))
+ {
+ if (p > pattern && p[-1] == '\\')
+ goto normal_backslash;
+ }
+ goto normal_char;
+
+#ifdef emacs
+ /* There is no way to specify the before_dot and after_dot
+ operators. rms says this is ok. --karl */
+ case '=':
+ BUF_PUSH (at_dot);
+ break;
+
+ case 's':
+ laststart = b;
+ PATFETCH (c);
+ BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]);
+ break;
+
+ case 'S':
+ laststart = b;
+ PATFETCH (c);
+ BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]);
+ break;
+#endif /* emacs */
+
+
+ case 'w':
+ laststart = b;
+ BUF_PUSH (wordchar);
+ break;
+
+
+ case 'W':
+ laststart = b;
+ BUF_PUSH (notwordchar);
+ break;
+
+
+ case '<':
+ BUF_PUSH (wordbeg);
+ break;
+
+ case '>':
+ BUF_PUSH (wordend);
+ break;
+
+ case 'b':
+ BUF_PUSH (wordbound);
+ break;
+
+ case 'B':
+ BUF_PUSH (notwordbound);
+ break;
+
+ case '`':
+ BUF_PUSH (begbuf);
+ break;
+
+ case '\'':
+ BUF_PUSH (endbuf);
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ if (syntax & RE_NO_BK_REFS)
+ goto normal_char;
+
+ c1 = c - '0';
+
+ if (c1 > regnum)
+ FREE_STACK_RETURN (REG_ESUBREG);
+
+ /* Can't back reference to a subexpression if inside of it. */
+ if (group_in_compile_stack (compile_stack, c1))
+ goto normal_char;
+
+ laststart = b;
+ BUF_PUSH_2 (duplicate, c1);
+ break;
+
+
+ case '+':
+ case '?':
+ if (syntax & RE_BK_PLUS_QM)
+ goto handle_plus;
+ else
+ goto normal_backslash;
+
+ default:
+ normal_backslash:
+ /* You might think it would be useful for \ to mean
+ not to translate; but if we don't translate it
+ it will never match anything. */
+ c = TRANSLATE (c);
+ goto normal_char;
+ }
+ break;
+
+
+ default:
+ /* Expects the character in `c'. */
+ normal_char:
+ /* If no exactn currently being built. */
+ if (!pending_exact
+
+ /* If last exactn not at current position. */
+ || pending_exact + *pending_exact + 1 != b
+
+ /* We have only one byte following the exactn for the count. */
+ || *pending_exact == (1 << BYTEWIDTH) - 1
+
+ /* If followed by a repetition operator. */
+ || *p == '*' || *p == '^'
+ || ((syntax & RE_BK_PLUS_QM)
+ ? *p == '\\' && (p[1] == '+' || p[1] == '?')
+ : (*p == '+' || *p == '?'))
+ || ((syntax & RE_INTERVALS)
+ && ((syntax & RE_NO_BK_BRACES)
+ ? *p == '{'
+ : (p[0] == '\\' && p[1] == '{'))))
+ {
+ /* Start building a new exactn. */
+
+ laststart = b;
+
+ BUF_PUSH_2 (exactn, 0);
+ pending_exact = b - 1;
+ }
+
+ BUF_PUSH (c);
+ (*pending_exact)++;
+ break;
+ } /* switch (c) */
+ } /* while p != pend */
+
+
+ /* Through the pattern now. */
+
+ if (fixup_alt_jump)
+ STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
+
+ if (!COMPILE_STACK_EMPTY)
+ FREE_STACK_RETURN (REG_EPAREN);
+
+ free (compile_stack.stack);
+
+ /* We have succeeded; set the length of the buffer. */
+ bufp->used = b - bufp->buffer;
+
+#ifdef DEBUG
+ if (debug)
+ {
+ DEBUG_PRINT1 ("\nCompiled pattern: \n");
+ print_compiled_pattern (bufp);
+ }
+#endif /* DEBUG */
+
+#ifndef MATCH_MAY_ALLOCATE
+ /* Initialize the failure stack to the largest possible stack. This
+ isn't necessary unless we're trying to avoid calling alloca in
+ the search and match routines. */
+ {
+ int num_regs = bufp->re_nsub + 1;
+
+ /* Since DOUBLE_FAIL_STACK refuses to double only if the current size
+ is strictly greater than re_max_failures, the largest possible stack
+ is 2 * re_max_failures failure points. */
+ if (fail_stack.size < (2 * re_max_failures * MAX_FAILURE_ITEMS))
+ {
+ fail_stack.size = (2 * re_max_failures * MAX_FAILURE_ITEMS);
+
+#ifdef emacs
+ if (! fail_stack.stack)
+ fail_stack.stack
+ = (fail_stack_elt_t *) xmalloc (fail_stack.size
+ * sizeof (fail_stack_elt_t));
+ else
+ fail_stack.stack
+ = (fail_stack_elt_t *) xrealloc (fail_stack.stack,
+ (fail_stack.size
+ * sizeof (fail_stack_elt_t)));
+#else /* not emacs */
+ if (! fail_stack.stack)
+ fail_stack.stack
+ = (fail_stack_elt_t *) malloc (fail_stack.size
+ * sizeof (fail_stack_elt_t));
+ else
+ fail_stack.stack
+ = (fail_stack_elt_t *) realloc (fail_stack.stack,
+ (fail_stack.size
+ * sizeof (fail_stack_elt_t)));
+#endif /* not emacs */
+ }
+
+ /* Initialize some other variables the matcher uses. */
+ RETALLOC_IF (regstart, num_regs, const char *);
+ RETALLOC_IF (regend, num_regs, const char *);
+ RETALLOC_IF (old_regstart, num_regs, const char *);
+ RETALLOC_IF (old_regend, num_regs, const char *);
+ RETALLOC_IF (best_regstart, num_regs, const char *);
+ RETALLOC_IF (best_regend, num_regs, const char *);
+ RETALLOC_IF (reg_info, num_regs, register_info_type);
+ RETALLOC_IF (reg_dummy, num_regs, const char *);
+ RETALLOC_IF (reg_info_dummy, num_regs, register_info_type);
+ }
+#endif
+
+ return REG_NOERROR;
+} /* regex_compile */
+
+/* Subroutines for `regex_compile'. */
+
+/* Store OP at LOC followed by two-byte integer parameter ARG. */
+
+static void
+store_op1 (op, loc, arg)
+ re_opcode_t op;
+ unsigned char *loc;
+ int arg;
+{
+ *loc = (unsigned char) op;
+ STORE_NUMBER (loc + 1, arg);
+}
+
+
+/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */
+
+static void
+store_op2 (op, loc, arg1, arg2)
+ re_opcode_t op;
+ unsigned char *loc;
+ int arg1, arg2;
+{
+ *loc = (unsigned char) op;
+ STORE_NUMBER (loc + 1, arg1);
+ STORE_NUMBER (loc + 3, arg2);
+}
+
+
+/* Copy the bytes from LOC to END to open up three bytes of space at LOC
+ for OP followed by two-byte integer parameter ARG. */
+
+static void
+insert_op1 (op, loc, arg, end)
+ re_opcode_t op;
+ unsigned char *loc;
+ int arg;
+ unsigned char *end;
+{
+ register unsigned char *pfrom = end;
+ register unsigned char *pto = end + 3;
+
+ while (pfrom != loc)
+ *--pto = *--pfrom;
+
+ store_op1 (op, loc, arg);
+}
+
+
+/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */
+
+static void
+insert_op2 (op, loc, arg1, arg2, end)
+ re_opcode_t op;
+ unsigned char *loc;
+ int arg1, arg2;
+ unsigned char *end;
+{
+ register unsigned char *pfrom = end;
+ register unsigned char *pto = end + 5;
+
+ while (pfrom != loc)
+ *--pto = *--pfrom;
+
+ store_op2 (op, loc, arg1, arg2);
+}
+
+
+/* P points to just after a ^ in PATTERN. Return true if that ^ comes
+ after an alternative or a begin-subexpression. We assume there is at
+ least one character before the ^. */
+
+static boolean
+at_begline_loc_p (pattern, p, syntax)
+ const char *pattern, *p;
+ reg_syntax_t syntax;
+{
+ const char *prev = p - 2;
+ boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\';
+
+ return
+ /* After a subexpression? */
+ (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash))
+ /* After an alternative? */
+ || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash));
+}
+
+
+/* The dual of at_begline_loc_p. This one is for $. We assume there is
+ at least one character after the $, i.e., `P < PEND'. */
+
+static boolean
+at_endline_loc_p (p, pend, syntax)
+ const char *p, *pend;
+ int syntax;
+{
+ const char *next = p;
+ boolean next_backslash = *next == '\\';
+ const char *next_next = p + 1 < pend ? p + 1 : NULL;
+
+ return
+ /* Before a subexpression? */
+ (syntax & RE_NO_BK_PARENS ? *next == ')'
+ : next_backslash && next_next && *next_next == ')')
+ /* Before an alternative? */
+ || (syntax & RE_NO_BK_VBAR ? *next == '|'
+ : next_backslash && next_next && *next_next == '|');
+}
+
+
+/* Returns true if REGNUM is in one of COMPILE_STACK's elements and
+ false if it's not. */
+
+static boolean
+group_in_compile_stack (compile_stack, regnum)
+ compile_stack_type compile_stack;
+ regnum_t regnum;
+{
+ int this_element;
+
+ for (this_element = compile_stack.avail - 1;
+ this_element >= 0;
+ this_element--)
+ if (compile_stack.stack[this_element].regnum == regnum)
+ return true;
+
+ return false;
+}
+
+
+/* Read the ending character of a range (in a bracket expression) from the
+ uncompiled pattern *P_PTR (which ends at PEND). We assume the
+ starting character is in `P[-2]'. (`P[-1]' is the character `-'.)
+ Then we set the translation of all bits between the starting and
+ ending characters (inclusive) in the compiled pattern B.
+
+ Return an error code.
+
+ We use these short variable names so we can use the same macros as
+ `regex_compile' itself. */
+
+static reg_errcode_t
+compile_range (p_ptr, pend, translate, syntax, b)
+ const char **p_ptr, *pend;
+ char *translate;
+ reg_syntax_t syntax;
+ unsigned char *b;
+{
+ unsigned this_char;
+
+ const char *p = *p_ptr;
+ int range_start, range_end;
+
+ if (p == pend)
+ return REG_ERANGE;
+
+ /* Even though the pattern is a signed `char *', we need to fetch
+ with unsigned char *'s; if the high bit of the pattern character
+ is set, the range endpoints will be negative if we fetch using a
+ signed char *.
+
+ We also want to fetch the endpoints without translating them; the
+ appropriate translation is done in the bit-setting loop below. */
+ /* The SVR4 compiler on the 3B2 had trouble with unsigned const char *. */
+ range_start = ((const unsigned char *) p)[-2];
+ range_end = ((const unsigned char *) p)[0];
+
+ /* Have to increment the pointer into the pattern string, so the
+ caller isn't still at the ending character. */
+ (*p_ptr)++;
+
+ /* If the start is after the end, the range is empty. */
+ if (range_start > range_end)
+ return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR;
+
+ /* Here we see why `this_char' has to be larger than an `unsigned
+ char' -- the range is inclusive, so if `range_end' == 0xff
+ (assuming 8-bit characters), we would otherwise go into an infinite
+ loop, since all characters <= 0xff. */
+ for (this_char = range_start; this_char <= range_end; this_char++)
+ {
+ SET_LIST_BIT (TRANSLATE (this_char));
+ }
+
+ return REG_NOERROR;
+}
+
+/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in
+ BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible
+ characters can start a string that matches the pattern. This fastmap
+ is used by re_search to skip quickly over impossible starting points.
+
+ The caller must supply the address of a (1 << BYTEWIDTH)-byte data
+ area as BUFP->fastmap.
+
+ We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in
+ the pattern buffer.
+
+ Returns 0 if we succeed, -2 if an internal error. */
+
+int
+re_compile_fastmap (bufp)
+ struct re_pattern_buffer *bufp;
+{
+ int j, k;
+#ifdef MATCH_MAY_ALLOCATE
+ fail_stack_type fail_stack;
+#endif
+#ifndef REGEX_MALLOC
+ char *destination;
+#endif
+ /* We don't push any register information onto the failure stack. */
+ unsigned num_regs = 0;
+
+ register char *fastmap = bufp->fastmap;
+ unsigned char *pattern = bufp->buffer;
+ unsigned long size = bufp->used;
+ unsigned char *p = pattern;
+ register unsigned char *pend = pattern + size;
+
+ /* Assume that each path through the pattern can be null until
+ proven otherwise. We set this false at the bottom of switch
+ statement, to which we get only if a particular path doesn't
+ match the empty string. */
+ boolean path_can_be_null = true;
+
+ /* We aren't doing a `succeed_n' to begin with. */
+ boolean succeed_n_p = false;
+
+ assert (fastmap != NULL && p != NULL);
+
+ INIT_FAIL_STACK ();
+ bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */
+ bufp->fastmap_accurate = 1; /* It will be when we're done. */
+ bufp->can_be_null = 0;
+
+ while (p != pend || !FAIL_STACK_EMPTY ())
+ {
+ if (p == pend)
+ {
+ bufp->can_be_null |= path_can_be_null;
+
+ /* Reset for next path. */
+ path_can_be_null = true;
+
+ p = fail_stack.stack[--fail_stack.avail];
+ }
+
+ /* We should never be about to go beyond the end of the pattern. */
+ assert (p < pend);
+
+#ifdef SWITCH_ENUM_BUG
+ switch ((int) ((re_opcode_t) *p++))
+#else
+ switch ((re_opcode_t) *p++)
+#endif
+ {
+
+ /* I guess the idea here is to simply not bother with a fastmap
+ if a backreference is used, since it's too hard to figure out
+ the fastmap for the corresponding group. Setting
+ `can_be_null' stops `re_search_2' from using the fastmap, so
+ that is all we do. */
+ case duplicate:
+ bufp->can_be_null = 1;
+ return 0;
+
+
+ /* Following are the cases which match a character. These end
+ with `break'. */
+
+ case exactn:
+ fastmap[p[1]] = 1;
+ break;
+
+
+ case charset:
+ for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+ if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
+ fastmap[j] = 1;
+ break;
+
+
+ case charset_not:
+ /* Chars beyond end of map must be allowed. */
+ for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
+ fastmap[j] = 1;
+
+ for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+ if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
+ fastmap[j] = 1;
+ break;
+
+
+ case wordchar:
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ if (SYNTAX (j) == Sword)
+ fastmap[j] = 1;
+ break;
+
+
+ case notwordchar:
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ if (SYNTAX (j) != Sword)
+ fastmap[j] = 1;
+ break;
+
+
+ case anychar:
+ {
+ int fastmap_newline = fastmap['\n'];
+
+ /* `.' matches anything ... */
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ fastmap[j] = 1;
+
+ /* ... except perhaps newline. */
+ if (!(bufp->syntax & RE_DOT_NEWLINE))
+ fastmap['\n'] = fastmap_newline;
+
+ /* Return if we have already set `can_be_null'; if we have,
+ then the fastmap is irrelevant. Something's wrong here. */
+ else if (bufp->can_be_null)
+ return 0;
+
+ /* Otherwise, have to check alternative paths. */
+ break;
+ }
+
+#ifdef emacs
+ case syntaxspec:
+ k = *p++;
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ if (SYNTAX (j) == (enum syntaxcode) k)
+ fastmap[j] = 1;
+ break;
+
+
+ case notsyntaxspec:
+ k = *p++;
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ if (SYNTAX (j) != (enum syntaxcode) k)
+ fastmap[j] = 1;
+ break;
+
+
+ /* All cases after this match the empty string. These end with
+ `continue'. */
+
+
+ case before_dot:
+ case at_dot:
+ case after_dot:
+ continue;
+#endif /* not emacs */
+
+
+ case no_op:
+ case begline:
+ case endline:
+ case begbuf:
+ case endbuf:
+ case wordbound:
+ case notwordbound:
+ case wordbeg:
+ case wordend:
+ case push_dummy_failure:
+ continue;
+
+
+ case jump_n:
+ case pop_failure_jump:
+ case maybe_pop_jump:
+ case jump:
+ case jump_past_alt:
+ case dummy_failure_jump:
+ EXTRACT_NUMBER_AND_INCR (j, p);
+ p += j;
+ if (j > 0)
+ continue;
+
+ /* Jump backward implies we just went through the body of a
+ loop and matched nothing. Opcode jumped to should be
+ `on_failure_jump' or `succeed_n'. Just treat it like an
+ ordinary jump. For a * loop, it has pushed its failure
+ point already; if so, discard that as redundant. */
+ if ((re_opcode_t) *p != on_failure_jump
+ && (re_opcode_t) *p != succeed_n)
+ continue;
+
+ p++;
+ EXTRACT_NUMBER_AND_INCR (j, p);
+ p += j;
+
+ /* If what's on the stack is where we are now, pop it. */
+ if (!FAIL_STACK_EMPTY ()
+ && fail_stack.stack[fail_stack.avail - 1] == p)
+ fail_stack.avail--;
+
+ continue;
+
+
+ case on_failure_jump:
+ case on_failure_keep_string_jump:
+ handle_on_failure_jump:
+ EXTRACT_NUMBER_AND_INCR (j, p);
+
+ /* For some patterns, e.g., `(a?)?', `p+j' here points to the
+ end of the pattern. We don't want to push such a point,
+ since when we restore it above, entering the switch will
+ increment `p' past the end of the pattern. We don't need
+ to push such a point since we obviously won't find any more
+ fastmap entries beyond `pend'. Such a pattern can match
+ the null string, though. */
+ if (p + j < pend)
+ {
+ if (!PUSH_PATTERN_OP (p + j, fail_stack))
+ return -2;
+ }
+ else
+ bufp->can_be_null = 1;
+
+ if (succeed_n_p)
+ {
+ EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */
+ succeed_n_p = false;
+ }
+
+ continue;
+
+
+ case succeed_n:
+ /* Get to the number of times to succeed. */
+ p += 2;
+
+ /* Increment p past the n for when k != 0. */
+ EXTRACT_NUMBER_AND_INCR (k, p);
+ if (k == 0)
+ {
+ p -= 4;
+ succeed_n_p = true; /* Spaghetti code alert. */
+ goto handle_on_failure_jump;
+ }
+ continue;
+
+
+ case set_number_at:
+ p += 4;
+ continue;
+
+
+ case start_memory:
+ case stop_memory:
+ p += 2;
+ continue;
+
+
+ default:
+ abort (); /* We have listed all the cases. */
+ } /* switch *p++ */
+
+ /* Getting here means we have found the possible starting
+ characters for one path of the pattern -- and that the empty
+ string does not match. We need not follow this path further.
+ Instead, look at the next alternative (remembered on the
+ stack), or quit if no more. The test at the top of the loop
+ does these things. */
+ path_can_be_null = false;
+ p = pend;
+ } /* while p */
+
+ /* Set `can_be_null' for the last path (also the first path, if the
+ pattern is empty). */
+ bufp->can_be_null |= path_can_be_null;
+ return 0;
+} /* re_compile_fastmap */
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+ ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use
+ this memory for recording register information. STARTS and ENDS
+ must be allocated using the malloc library routine, and must each
+ be at least NUM_REGS * sizeof (regoff_t) bytes long.
+
+ If NUM_REGS == 0, then subsequent matches should allocate their own
+ register data.
+
+ Unless this function is called, the first search or match using
+ PATTERN_BUFFER will allocate its own register data, without
+ freeing the old data. */
+
+void
+re_set_registers (bufp, regs, num_regs, starts, ends)
+ struct re_pattern_buffer *bufp;
+ struct re_registers *regs;
+ unsigned num_regs;
+ regoff_t *starts, *ends;
+{
+ if (num_regs)
+ {
+ bufp->regs_allocated = REGS_REALLOCATE;
+ regs->num_regs = num_regs;
+ regs->start = starts;
+ regs->end = ends;
+ }
+ else
+ {
+ bufp->regs_allocated = REGS_UNALLOCATED;
+ regs->num_regs = 0;
+ regs->start = regs->end = (regoff_t *) 0;
+ }
+}
+
+/* Searching routines. */
+
+/* Like re_search_2, below, but only one string is specified, and
+ doesn't let you say where to stop matching. */
+
+int
+re_search (bufp, string, size, startpos, range, regs)
+ struct re_pattern_buffer *bufp;
+ const char *string;
+ int size, startpos, range;
+ struct re_registers *regs;
+{
+ return re_search_2 (bufp, NULL, 0, string, size, startpos, range,
+ regs, size);
+}
+
+
+/* Using the compiled pattern in BUFP->buffer, first tries to match the
+ virtual concatenation of STRING1 and STRING2, starting first at index
+ STARTPOS, then at STARTPOS + 1, and so on.
+
+ STRING1 and STRING2 have length SIZE1 and SIZE2, respectively.
+
+ RANGE is how far to scan while trying to match. RANGE = 0 means try
+ only at STARTPOS; in general, the last start tried is STARTPOS +
+ RANGE.
+
+ In REGS, return the indices of the virtual concatenation of STRING1
+ and STRING2 that matched the entire BUFP->buffer and its contained
+ subexpressions.
+
+ Do not consider matching one past the index STOP in the virtual
+ concatenation of STRING1 and STRING2.
+
+ We return either the position in the strings at which the match was
+ found, -1 if no match, or -2 if error (such as failure
+ stack overflow). */
+
+int
+re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
+ struct re_pattern_buffer *bufp;
+ const char *string1, *string2;
+ int size1, size2;
+ int startpos;
+ int range;
+ struct re_registers *regs;
+ int stop;
+{
+ int val;
+ register char *fastmap = bufp->fastmap;
+ register char *translate = bufp->translate;
+ int total_size = size1 + size2;
+ int endpos = startpos + range;
+
+ /* Check for out-of-range STARTPOS. */
+ if (startpos < 0 || startpos > total_size)
+ return -1;
+
+ /* Fix up RANGE if it might eventually take us outside
+ the virtual concatenation of STRING1 and STRING2. */
+ if (endpos < -1)
+ range = -1 - startpos;
+ else if (endpos > total_size)
+ range = total_size - startpos;
+
+ /* If the search isn't to be a backwards one, don't waste time in a
+ search for a pattern that must be anchored. */
+ if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf && range > 0)
+ {
+ if (startpos > 0)
+ return -1;
+ else
+ range = 1;
+ }
+
+ /* Update the fastmap now if not correct already. */
+ if (fastmap && !bufp->fastmap_accurate)
+ if (re_compile_fastmap (bufp) == -2)
+ return -2;
+
+ /* Loop through the string, looking for a place to start matching. */
+ for (;;)
+ {
+ /* If a fastmap is supplied, skip quickly over characters that
+ cannot be the start of a match. If the pattern can match the
+ null string, however, we don't need to skip characters; we want
+ the first null string. */
+ if (fastmap && startpos < total_size && !bufp->can_be_null)
+ {
+ if (range > 0) /* Searching forwards. */
+ {
+ register const char *d;
+ register int lim = 0;
+ int irange = range;
+
+ if (startpos < size1 && startpos + range >= size1)
+ lim = range - (size1 - startpos);
+
+ d = (startpos >= size1 ? string2 - size1 : string1) + startpos;
+
+ /* Written out as an if-else to avoid testing `translate'
+ inside the loop. */
+ if (translate)
+ while (range > lim
+ && !fastmap[(unsigned char)
+ translate[(unsigned char) *d++]])
+ range--;
+ else
+ while (range > lim && !fastmap[(unsigned char) *d++])
+ range--;
+
+ startpos += irange - range;
+ }
+ else /* Searching backwards. */
+ {
+ register char c = (size1 == 0 || startpos >= size1
+ ? string2[startpos - size1]
+ : string1[startpos]);
+
+ if (!fastmap[(unsigned char) TRANSLATE (c)])
+ goto advance;
+ }
+ }
+
+ /* If can't match the null string, and that's all we have left, fail. */
+ if (range >= 0 && startpos == total_size && fastmap
+ && !bufp->can_be_null)
+ return -1;
+
+ val = re_match_2_internal (bufp, string1, size1, string2, size2,
+ startpos, regs, stop);
+#ifndef REGEX_MALLOC
+#ifdef C_ALLOCA
+ alloca (0);
+#endif
+#endif
+
+ if (val >= 0)
+ return startpos;
+
+ if (val == -2)
+ return -2;
+
+ advance:
+ if (!range)
+ break;
+ else if (range > 0)
+ {
+ range--;
+ startpos++;
+ }
+ else
+ {
+ range++;
+ startpos--;
+ }
+ }
+ return -1;
+} /* re_search_2 */
+
+/* Declarations and macros for re_match_2. */
+
+static int bcmp_translate ();
+static boolean alt_match_null_string_p (),
+ common_op_match_null_string_p (),
+ group_match_null_string_p ();
+
+/* This converts PTR, a pointer into one of the search strings `string1'
+ and `string2' into an offset from the beginning of that string. */
+#define POINTER_TO_OFFSET(ptr) \
+ (FIRST_STRING_P (ptr) \
+ ? ((regoff_t) ((ptr) - string1)) \
+ : ((regoff_t) ((ptr) - string2 + size1)))
+
+/* Macros for dealing with the split strings in re_match_2. */
+
+#define MATCHING_IN_FIRST_STRING (dend == end_match_1)
+
+/* Call before fetching a character with *d. This switches over to
+ string2 if necessary. */
+#define PREFETCH() \
+ while (d == dend) \
+ { \
+ /* End of string2 => fail. */ \
+ if (dend == end_match_2) \
+ goto fail; \
+ /* End of string1 => advance to string2. */ \
+ d = string2; \
+ dend = end_match_2; \
+ }
+
+
+/* Test if at very beginning or at very end of the virtual concatenation
+ of `string1' and `string2'. If only one string, it's `string2'. */
+#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2)
+#define AT_STRINGS_END(d) ((d) == end2)
+
+
+/* Test if D points to a character which is word-constituent. We have
+ two special cases to check for: if past the end of string1, look at
+ the first character in string2; and if before the beginning of
+ string2, look at the last character in string1. */
+#define WORDCHAR_P(d) \
+ (SYNTAX ((d) == end1 ? *string2 \
+ : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \
+ == Sword)
+
+/* Test if the character before D and the one at D differ with respect
+ to being word-constituent. */
+#define AT_WORD_BOUNDARY(d) \
+ (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \
+ || WORDCHAR_P (d - 1) != WORDCHAR_P (d))
+
+
+/* Free everything we malloc. */
+#ifdef MATCH_MAY_ALLOCATE
+#ifdef REGEX_MALLOC
+#define FREE_VAR(var) if (var) free (var); var = NULL
+#define FREE_VARIABLES() \
+ do { \
+ FREE_VAR (fail_stack.stack); \
+ FREE_VAR (regstart); \
+ FREE_VAR (regend); \
+ FREE_VAR (old_regstart); \
+ FREE_VAR (old_regend); \
+ FREE_VAR (best_regstart); \
+ FREE_VAR (best_regend); \
+ FREE_VAR (reg_info); \
+ FREE_VAR (reg_dummy); \
+ FREE_VAR (reg_info_dummy); \
+ } while (0)
+#else /* not REGEX_MALLOC */
+/* This used to do alloca (0), but now we do that in the caller. */
+#define FREE_VARIABLES() /* Nothing */
+#endif /* not REGEX_MALLOC */
+#else
+#define FREE_VARIABLES() /* Do nothing! */
+#endif /* not MATCH_MAY_ALLOCATE */
+
+/* These values must meet several constraints. They must not be valid
+ register values; since we have a limit of 255 registers (because
+ we use only one byte in the pattern for the register number), we can
+ use numbers larger than 255. They must differ by 1, because of
+ NUM_FAILURE_ITEMS above. And the value for the lowest register must
+ be larger than the value for the highest register, so we do not try
+ to actually save any registers when none are active. */
+#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH)
+#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1)
+
+/* Matching routines. */
+
+#ifndef emacs /* Emacs never uses this. */
+/* re_match is like re_match_2 except it takes only a single string. */
+
+int
+re_match (bufp, string, size, pos, regs)
+ struct re_pattern_buffer *bufp;
+ const char *string;
+ int size, pos;
+ struct re_registers *regs;
+{
+ int result = re_match_2_internal (bufp, NULL, 0, string, size,
+ pos, regs, size);
+ alloca (0);
+ return result;
+}
+#endif /* not emacs */
+
+
+/* re_match_2 matches the compiled pattern in BUFP against the
+ the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1
+ and SIZE2, respectively). We start matching at POS, and stop
+ matching at STOP.
+
+ If REGS is non-null and the `no_sub' field of BUFP is nonzero, we
+ store offsets for the substring each group matched in REGS. See the
+ documentation for exactly how many groups we fill.
+
+ We return -1 if no match, -2 if an internal error (such as the
+ failure stack overflowing). Otherwise, we return the length of the
+ matched substring. */
+
+int
+re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
+ struct re_pattern_buffer *bufp;
+ const char *string1, *string2;
+ int size1, size2;
+ int pos;
+ struct re_registers *regs;
+ int stop;
+{
+ int result = re_match_2_internal (bufp, string1, size1, string2, size2,
+ pos, regs, stop);
+ alloca (0);
+ return result;
+}
+
+/* This is a separate function so that we can force an alloca cleanup
+ afterwards. */
+static int
+re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
+ struct re_pattern_buffer *bufp;
+ const char *string1, *string2;
+ int size1, size2;
+ int pos;
+ struct re_registers *regs;
+ int stop;
+{
+ /* General temporaries. */
+ int mcnt;
+ unsigned char *p1;
+
+ /* Just past the end of the corresponding string. */
+ const char *end1, *end2;
+
+ /* Pointers into string1 and string2, just past the last characters in
+ each to consider matching. */
+ const char *end_match_1, *end_match_2;
+
+ /* Where we are in the data, and the end of the current string. */
+ const char *d, *dend;
+
+ /* Where we are in the pattern, and the end of the pattern. */
+ unsigned char *p = bufp->buffer;
+ register unsigned char *pend = p + bufp->used;
+
+ /* Mark the opcode just after a start_memory, so we can test for an
+ empty subpattern when we get to the stop_memory. */
+ unsigned char *just_past_start_mem = 0;
+
+ /* We use this to map every character in the string. */
+ char *translate = bufp->translate;
+
+ /* Failure point stack. Each place that can handle a failure further
+ down the line pushes a failure point on this stack. It consists of
+ restart, regend, and reg_info for all registers corresponding to
+ the subexpressions we're currently inside, plus the number of such
+ registers, and, finally, two char *'s. The first char * is where
+ to resume scanning the pattern; the second one is where to resume
+ scanning the strings. If the latter is zero, the failure point is
+ a ``dummy''; if a failure happens and the failure point is a dummy,
+ it gets discarded and the next next one is tried. */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */
+ fail_stack_type fail_stack;
+#endif
+#ifdef DEBUG
+ static unsigned failure_id = 0;
+ unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0;
+#endif
+
+ /* We fill all the registers internally, independent of what we
+ return, for use in backreferences. The number here includes
+ an element for register zero. */
+ unsigned num_regs = bufp->re_nsub + 1;
+
+ /* The currently active registers. */
+ unsigned lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+ unsigned highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+
+ /* Information on the contents of registers. These are pointers into
+ the input strings; they record just what was matched (on this
+ attempt) by a subexpression part of the pattern, that is, the
+ regnum-th regstart pointer points to where in the pattern we began
+ matching and the regnum-th regend points to right after where we
+ stopped matching the regnum-th subexpression. (The zeroth register
+ keeps track of what the whole pattern matches.) */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
+ const char **regstart, **regend;
+#endif
+
+ /* If a group that's operated upon by a repetition operator fails to
+ match anything, then the register for its start will need to be
+ restored because it will have been set to wherever in the string we
+ are when we last see its open-group operator. Similarly for a
+ register's end. */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
+ const char **old_regstart, **old_regend;
+#endif
+
+ /* The is_active field of reg_info helps us keep track of which (possibly
+ nested) subexpressions we are currently in. The matched_something
+ field of reg_info[reg_num] helps us tell whether or not we have
+ matched any of the pattern so far this time through the reg_num-th
+ subexpression. These two fields get reset each time through any
+ loop their register is in. */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */
+ register_info_type *reg_info;
+#endif
+
+ /* The following record the register info as found in the above
+ variables when we find a match better than any we've seen before.
+ This happens as we backtrack through the failure points, which in
+ turn happens only if we have not yet matched the entire string. */
+ unsigned best_regs_set = false;
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
+ const char **best_regstart, **best_regend;
+#endif
+
+ /* Logically, this is `best_regend[0]'. But we don't want to have to
+ allocate space for that if we're not allocating space for anything
+ else (see below). Also, we never need info about register 0 for
+ any of the other register vectors, and it seems rather a kludge to
+ treat `best_regend' differently than the rest. So we keep track of
+ the end of the best match so far in a separate variable. We
+ initialize this to NULL so that when we backtrack the first time
+ and need to test it, it's not garbage. */
+ const char *match_end = NULL;
+
+ /* Used when we pop values we don't care about. */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
+ const char **reg_dummy;
+ register_info_type *reg_info_dummy;
+#endif
+
+#ifdef DEBUG
+ /* Counts the total number of registers pushed. */
+ unsigned num_regs_pushed = 0;
+#endif
+
+ DEBUG_PRINT1 ("\n\nEntering re_match_2.\n");
+
+ INIT_FAIL_STACK ();
+
+#ifdef MATCH_MAY_ALLOCATE
+ /* Do not bother to initialize all the register variables if there are
+ no groups in the pattern, as it takes a fair amount of time. If
+ there are groups, we include space for register 0 (the whole
+ pattern), even though we never use it, since it simplifies the
+ array indexing. We should fix this. */
+ if (bufp->re_nsub)
+ {
+ regstart = REGEX_TALLOC (num_regs, const char *);
+ regend = REGEX_TALLOC (num_regs, const char *);
+ old_regstart = REGEX_TALLOC (num_regs, const char *);
+ old_regend = REGEX_TALLOC (num_regs, const char *);
+ best_regstart = REGEX_TALLOC (num_regs, const char *);
+ best_regend = REGEX_TALLOC (num_regs, const char *);
+ reg_info = REGEX_TALLOC (num_regs, register_info_type);
+ reg_dummy = REGEX_TALLOC (num_regs, const char *);
+ reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type);
+
+ if (!(regstart && regend && old_regstart && old_regend && reg_info
+ && best_regstart && best_regend && reg_dummy && reg_info_dummy))
+ {
+ FREE_VARIABLES ();
+ return -2;
+ }
+ }
+#if defined (REGEX_MALLOC)
+ else
+ {
+ /* We must initialize all our variables to NULL, so that
+ `FREE_VARIABLES' doesn't try to free them. */
+ regstart = regend = old_regstart = old_regend = best_regstart
+ = best_regend = reg_dummy = NULL;
+ reg_info = reg_info_dummy = (register_info_type *) NULL;
+ }
+#endif /* REGEX_MALLOC */
+#endif /* MATCH_MAY_ALLOCATE */
+
+ /* The starting position is bogus. */
+ if (pos < 0 || pos > size1 + size2)
+ {
+ FREE_VARIABLES ();
+ return -1;
+ }
+
+ /* Initialize subexpression text positions to -1 to mark ones that no
+ start_memory/stop_memory has been seen for. Also initialize the
+ register information struct. */
+ for (mcnt = 1; mcnt < num_regs; mcnt++)
+ {
+ regstart[mcnt] = regend[mcnt]
+ = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE;
+
+ REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE;
+ IS_ACTIVE (reg_info[mcnt]) = 0;
+ MATCHED_SOMETHING (reg_info[mcnt]) = 0;
+ EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0;
+ }
+
+ /* We move `string1' into `string2' if the latter's empty -- but not if
+ `string1' is null. */
+ if (size2 == 0 && string1 != NULL)
+ {
+ string2 = string1;
+ size2 = size1;
+ string1 = 0;
+ size1 = 0;
+ }
+ end1 = string1 + size1;
+ end2 = string2 + size2;
+
+ /* Compute where to stop matching, within the two strings. */
+ if (stop <= size1)
+ {
+ end_match_1 = string1 + stop;
+ end_match_2 = string2;
+ }
+ else
+ {
+ end_match_1 = end1;
+ end_match_2 = string2 + stop - size1;
+ }
+
+ /* `p' scans through the pattern as `d' scans through the data.
+ `dend' is the end of the input string that `d' points within. `d'
+ is advanced into the following input string whenever necessary, but
+ this happens before fetching; therefore, at the beginning of the
+ loop, `d' can be pointing at the end of a string, but it cannot
+ equal `string2'. */
+ if (size1 > 0 && pos <= size1)
+ {
+ d = string1 + pos;
+ dend = end_match_1;
+ }
+ else
+ {
+ d = string2 + pos - size1;
+ dend = end_match_2;
+ }
+
+ DEBUG_PRINT1 ("The compiled pattern is: ");
+ DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend);
+ DEBUG_PRINT1 ("The string to match is: `");
+ DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2);
+ DEBUG_PRINT1 ("'\n");
+
+ /* This loops over pattern commands. It exits by returning from the
+ function if the match is complete, or it drops through if the match
+ fails at this starting point in the input data. */
+ for (;;)
+ {
+ DEBUG_PRINT2 ("\n0x%x: ", p);
+
+ if (p == pend)
+ { /* End of pattern means we might have succeeded. */
+ DEBUG_PRINT1 ("end of pattern ... ");
+
+ /* If we haven't matched the entire string, and we want the
+ longest match, try backtracking. */
+ if (d != end_match_2)
+ {
+ /* 1 if this match ends in the same string (string1 or string2)
+ as the best previous match. */
+ boolean same_str_p = (FIRST_STRING_P (match_end)
+ == MATCHING_IN_FIRST_STRING);
+ /* 1 if this match is the best seen so far. */
+ boolean best_match_p;
+
+ /* AIX compiler got confused when this was combined
+ with the previous declaration. */
+ if (same_str_p)
+ best_match_p = d > match_end;
+ else
+ best_match_p = !MATCHING_IN_FIRST_STRING;
+
+ DEBUG_PRINT1 ("backtracking.\n");
+
+ if (!FAIL_STACK_EMPTY ())
+ { /* More failure points to try. */
+
+ /* If exceeds best match so far, save it. */
+ if (!best_regs_set || best_match_p)
+ {
+ best_regs_set = true;
+ match_end = d;
+
+ DEBUG_PRINT1 ("\nSAVING match as best so far.\n");
+
+ for (mcnt = 1; mcnt < num_regs; mcnt++)
+ {
+ best_regstart[mcnt] = regstart[mcnt];
+ best_regend[mcnt] = regend[mcnt];
+ }
+ }
+ goto fail;
+ }
+
+ /* If no failure points, don't restore garbage. And if
+ last match is real best match, don't restore second
+ best one. */
+ else if (best_regs_set && !best_match_p)
+ {
+ restore_best_regs:
+ /* Restore best match. It may happen that `dend ==
+ end_match_1' while the restored d is in string2.
+ For example, the pattern `x.*y.*z' against the
+ strings `x-' and `y-z-', if the two strings are
+ not consecutive in memory. */
+ DEBUG_PRINT1 ("Restoring best registers.\n");
+
+ d = match_end;
+ dend = ((d >= string1 && d <= end1)
+ ? end_match_1 : end_match_2);
+
+ for (mcnt = 1; mcnt < num_regs; mcnt++)
+ {
+ regstart[mcnt] = best_regstart[mcnt];
+ regend[mcnt] = best_regend[mcnt];
+ }
+ }
+ } /* d != end_match_2 */
+
+ DEBUG_PRINT1 ("Accepting match.\n");
+
+ /* If caller wants register contents data back, do it. */
+ if (regs && !bufp->no_sub)
+ {
+ /* Have the register data arrays been allocated? */
+ if (bufp->regs_allocated == REGS_UNALLOCATED)
+ { /* No. So allocate them with malloc. We need one
+ extra element beyond `num_regs' for the `-1' marker
+ GNU code uses. */
+ regs->num_regs = MAX (RE_NREGS, num_regs + 1);
+ regs->start = TALLOC (regs->num_regs, regoff_t);
+ regs->end = TALLOC (regs->num_regs, regoff_t);
+ if (regs->start == NULL || regs->end == NULL)
+ return -2;
+ bufp->regs_allocated = REGS_REALLOCATE;
+ }
+ else if (bufp->regs_allocated == REGS_REALLOCATE)
+ { /* Yes. If we need more elements than were already
+ allocated, reallocate them. If we need fewer, just
+ leave it alone. */
+ if (regs->num_regs < num_regs + 1)
+ {
+ regs->num_regs = num_regs + 1;
+ RETALLOC (regs->start, regs->num_regs, regoff_t);
+ RETALLOC (regs->end, regs->num_regs, regoff_t);
+ if (regs->start == NULL || regs->end == NULL)
+ return -2;
+ }
+ }
+ else
+ {
+ /* These braces fend off a "empty body in an else-statement"
+ warning under GCC when assert expands to nothing. */
+ assert (bufp->regs_allocated == REGS_FIXED);
+ }
+
+ /* Convert the pointer data in `regstart' and `regend' to
+ indices. Register zero has to be set differently,
+ since we haven't kept track of any info for it. */
+ if (regs->num_regs > 0)
+ {
+ regs->start[0] = pos;
+ regs->end[0] = (MATCHING_IN_FIRST_STRING
+ ? ((regoff_t) (d - string1))
+ : ((regoff_t) (d - string2 + size1)));
+ }
+
+ /* Go through the first `min (num_regs, regs->num_regs)'
+ registers, since that is all we initialized. */
+ for (mcnt = 1; mcnt < MIN (num_regs, regs->num_regs); mcnt++)
+ {
+ if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt]))
+ regs->start[mcnt] = regs->end[mcnt] = -1;
+ else
+ {
+ regs->start[mcnt]
+ = (regoff_t) POINTER_TO_OFFSET (regstart[mcnt]);
+ regs->end[mcnt]
+ = (regoff_t) POINTER_TO_OFFSET (regend[mcnt]);
+ }
+ }
+
+ /* If the regs structure we return has more elements than
+ were in the pattern, set the extra elements to -1. If
+ we (re)allocated the registers, this is the case,
+ because we always allocate enough to have at least one
+ -1 at the end. */
+ for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++)
+ regs->start[mcnt] = regs->end[mcnt] = -1;
+ } /* regs && !bufp->no_sub */
+
+ FREE_VARIABLES ();
+ DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n",
+ nfailure_points_pushed, nfailure_points_popped,
+ nfailure_points_pushed - nfailure_points_popped);
+ DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed);
+
+ mcnt = d - pos - (MATCHING_IN_FIRST_STRING
+ ? string1
+ : string2 - size1);
+
+ DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt);
+
+ return mcnt;
+ }
+
+ /* Otherwise match next pattern command. */
+#ifdef SWITCH_ENUM_BUG
+ switch ((int) ((re_opcode_t) *p++))
+#else
+ switch ((re_opcode_t) *p++)
+#endif
+ {
+ /* Ignore these. Used to ignore the n of succeed_n's which
+ currently have n == 0. */
+ case no_op:
+ DEBUG_PRINT1 ("EXECUTING no_op.\n");
+ break;
+
+
+ /* Match the next n pattern characters exactly. The following
+ byte in the pattern defines n, and the n bytes after that
+ are the characters to match. */
+ case exactn:
+ mcnt = *p++;
+ DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt);
+
+ /* This is written out as an if-else so we don't waste time
+ testing `translate' inside the loop. */
+ if (translate)
+ {
+ do
+ {
+ PREFETCH ();
+ if (translate[(unsigned char) *d++] != (char) *p++)
+ goto fail;
+ }
+ while (--mcnt);
+ }
+ else
+ {
+ do
+ {
+ PREFETCH ();
+ if (*d++ != (char) *p++) goto fail;
+ }
+ while (--mcnt);
+ }
+ SET_REGS_MATCHED ();
+ break;
+
+
+ /* Match any character except possibly a newline or a null. */
+ case anychar:
+ DEBUG_PRINT1 ("EXECUTING anychar.\n");
+
+ PREFETCH ();
+
+ if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n')
+ || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000'))
+ goto fail;
+
+ SET_REGS_MATCHED ();
+ DEBUG_PRINT2 (" Matched `%d'.\n", *d);
+ d++;
+ break;
+
+
+ case charset:
+ case charset_not:
+ {
+ register unsigned char c;
+ boolean not = (re_opcode_t) *(p - 1) == charset_not;
+
+ DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : "");
+
+ PREFETCH ();
+ c = TRANSLATE (*d); /* The character to match. */
+
+ /* Cast to `unsigned' instead of `unsigned char' in case the
+ bit list is a full 32 bytes long. */
+ if (c < (unsigned) (*p * BYTEWIDTH)
+ && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+ not = !not;
+
+ p += 1 + *p;
+
+ if (!not) goto fail;
+
+ SET_REGS_MATCHED ();
+ d++;
+ break;
+ }
+
+
+ /* The beginning of a group is represented by start_memory.
+ The arguments are the register number in the next byte, and the
+ number of groups inner to this one in the next. The text
+ matched within the group is recorded (in the internal
+ registers data structure) under the register number. */
+ case start_memory:
+ DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]);
+
+ /* Find out if this group can match the empty string. */
+ p1 = p; /* To send to group_match_null_string_p. */
+
+ if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE)
+ REG_MATCH_NULL_STRING_P (reg_info[*p])
+ = group_match_null_string_p (&p1, pend, reg_info);
+
+ /* Save the position in the string where we were the last time
+ we were at this open-group operator in case the group is
+ operated upon by a repetition operator, e.g., with `(a*)*b'
+ against `ab'; then we want to ignore where we are now in
+ the string in case this attempt to match fails. */
+ old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
+ ? REG_UNSET (regstart[*p]) ? d : regstart[*p]
+ : regstart[*p];
+ DEBUG_PRINT2 (" old_regstart: %d\n",
+ POINTER_TO_OFFSET (old_regstart[*p]));
+
+ regstart[*p] = d;
+ DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p]));
+
+ IS_ACTIVE (reg_info[*p]) = 1;
+ MATCHED_SOMETHING (reg_info[*p]) = 0;
+
+ /* This is the new highest active register. */
+ highest_active_reg = *p;
+
+ /* If nothing was active before, this is the new lowest active
+ register. */
+ if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
+ lowest_active_reg = *p;
+
+ /* Move past the register number and inner group count. */
+ p += 2;
+ just_past_start_mem = p;
+ break;
+
+
+ /* The stop_memory opcode represents the end of a group. Its
+ arguments are the same as start_memory's: the register
+ number, and the number of inner groups. */
+ case stop_memory:
+ DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]);
+
+ /* We need to save the string position the last time we were at
+ this close-group operator in case the group is operated
+ upon by a repetition operator, e.g., with `((a*)*(b*)*)*'
+ against `aba'; then we want to ignore where we are now in
+ the string in case this attempt to match fails. */
+ old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
+ ? REG_UNSET (regend[*p]) ? d : regend[*p]
+ : regend[*p];
+ DEBUG_PRINT2 (" old_regend: %d\n",
+ POINTER_TO_OFFSET (old_regend[*p]));
+
+ regend[*p] = d;
+ DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p]));
+
+ /* This register isn't active anymore. */
+ IS_ACTIVE (reg_info[*p]) = 0;
+
+ /* If this was the only register active, nothing is active
+ anymore. */
+ if (lowest_active_reg == highest_active_reg)
+ {
+ lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+ highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+ }
+ else
+ { /* We must scan for the new highest active register, since
+ it isn't necessarily one less than now: consider
+ (a(b)c(d(e)f)g). When group 3 ends, after the f), the
+ new highest active register is 1. */
+ unsigned char r = *p - 1;
+ while (r > 0 && !IS_ACTIVE (reg_info[r]))
+ r--;
+
+ /* If we end up at register zero, that means that we saved
+ the registers as the result of an `on_failure_jump', not
+ a `start_memory', and we jumped to past the innermost
+ `stop_memory'. For example, in ((.)*) we save
+ registers 1 and 2 as a result of the *, but when we pop
+ back to the second ), we are at the stop_memory 1.
+ Thus, nothing is active. */
+ if (r == 0)
+ {
+ lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+ highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+ }
+ else
+ highest_active_reg = r;
+ }
+
+ /* If just failed to match something this time around with a
+ group that's operated on by a repetition operator, try to
+ force exit from the ``loop'', and restore the register
+ information for this group that we had before trying this
+ last match. */
+ if ((!MATCHED_SOMETHING (reg_info[*p])
+ || just_past_start_mem == p - 1)
+ && (p + 2) < pend)
+ {
+ boolean is_a_jump_n = false;
+
+ p1 = p + 2;
+ mcnt = 0;
+ switch ((re_opcode_t) *p1++)
+ {
+ case jump_n:
+ is_a_jump_n = true;
+ case pop_failure_jump:
+ case maybe_pop_jump:
+ case jump:
+ case dummy_failure_jump:
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ if (is_a_jump_n)
+ p1 += 2;
+ break;
+
+ default:
+ /* do nothing */ ;
+ }
+ p1 += mcnt;
+
+ /* If the next operation is a jump backwards in the pattern
+ to an on_failure_jump right before the start_memory
+ corresponding to this stop_memory, exit from the loop
+ by forcing a failure after pushing on the stack the
+ on_failure_jump's jump in the pattern, and d. */
+ if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump
+ && (re_opcode_t) p1[3] == start_memory && p1[4] == *p)
+ {
+ /* If this group ever matched anything, then restore
+ what its registers were before trying this last
+ failed match, e.g., with `(a*)*b' against `ab' for
+ regstart[1], and, e.g., with `((a*)*(b*)*)*'
+ against `aba' for regend[3].
+
+ Also restore the registers for inner groups for,
+ e.g., `((a*)(b*))*' against `aba' (register 3 would
+ otherwise get trashed). */
+
+ if (EVER_MATCHED_SOMETHING (reg_info[*p]))
+ {
+ unsigned r;
+
+ EVER_MATCHED_SOMETHING (reg_info[*p]) = 0;
+
+ /* Restore this and inner groups' (if any) registers. */
+ for (r = *p; r < *p + *(p + 1); r++)
+ {
+ regstart[r] = old_regstart[r];
+
+ /* xx why this test? */
+ if ((int) old_regend[r] >= (int) regstart[r])
+ regend[r] = old_regend[r];
+ }
+ }
+ p1++;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ PUSH_FAILURE_POINT (p1 + mcnt, d, -2);
+
+ goto fail;
+ }
+ }
+
+ /* Move past the register number and the inner group count. */
+ p += 2;
+ break;
+
+
+ /* \<digit> has been turned into a `duplicate' command which is
+ followed by the numeric value of <digit> as the register number. */
+ case duplicate:
+ {
+ register const char *d2, *dend2;
+ int regno = *p++; /* Get which register to match against. */
+ DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno);
+
+ /* Can't back reference a group which we've never matched. */
+ if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno]))
+ goto fail;
+
+ /* Where in input to try to start matching. */
+ d2 = regstart[regno];
+
+ /* Where to stop matching; if both the place to start and
+ the place to stop matching are in the same string, then
+ set to the place to stop, otherwise, for now have to use
+ the end of the first string. */
+
+ dend2 = ((FIRST_STRING_P (regstart[regno])
+ == FIRST_STRING_P (regend[regno]))
+ ? regend[regno] : end_match_1);
+ for (;;)
+ {
+ /* If necessary, advance to next segment in register
+ contents. */
+ while (d2 == dend2)
+ {
+ if (dend2 == end_match_2) break;
+ if (dend2 == regend[regno]) break;
+
+ /* End of string1 => advance to string2. */
+ d2 = string2;
+ dend2 = regend[regno];
+ }
+ /* At end of register contents => success */
+ if (d2 == dend2) break;
+
+ /* If necessary, advance to next segment in data. */
+ PREFETCH ();
+
+ /* How many characters left in this segment to match. */
+ mcnt = dend - d;
+
+ /* Want how many consecutive characters we can match in
+ one shot, so, if necessary, adjust the count. */
+ if (mcnt > dend2 - d2)
+ mcnt = dend2 - d2;
+
+ /* Compare that many; failure if mismatch, else move
+ past them. */
+ if (translate
+ ? bcmp_translate (d, d2, mcnt, translate)
+ : bcmp (d, d2, mcnt))
+ goto fail;
+ d += mcnt, d2 += mcnt;
+ }
+ }
+ break;
+
+
+ /* begline matches the empty string at the beginning of the string
+ (unless `not_bol' is set in `bufp'), and, if
+ `newline_anchor' is set, after newlines. */
+ case begline:
+ DEBUG_PRINT1 ("EXECUTING begline.\n");
+
+ if (AT_STRINGS_BEG (d))
+ {
+ if (!bufp->not_bol) break;
+ }
+ else if (d[-1] == '\n' && bufp->newline_anchor)
+ {
+ break;
+ }
+ /* In all other cases, we fail. */
+ goto fail;
+
+
+ /* endline is the dual of begline. */
+ case endline:
+ DEBUG_PRINT1 ("EXECUTING endline.\n");
+
+ if (AT_STRINGS_END (d))
+ {
+ if (!bufp->not_eol) break;
+ }
+
+ /* We have to ``prefetch'' the next character. */
+ else if ((d == end1 ? *string2 : *d) == '\n'
+ && bufp->newline_anchor)
+ {
+ break;
+ }
+ goto fail;
+
+
+ /* Match at the very beginning of the data. */
+ case begbuf:
+ DEBUG_PRINT1 ("EXECUTING begbuf.\n");
+ if (AT_STRINGS_BEG (d))
+ break;
+ goto fail;
+
+
+ /* Match at the very end of the data. */
+ case endbuf:
+ DEBUG_PRINT1 ("EXECUTING endbuf.\n");
+ if (AT_STRINGS_END (d))
+ break;
+ goto fail;
+
+
+ /* on_failure_keep_string_jump is used to optimize `.*\n'. It
+ pushes NULL as the value for the string on the stack. Then
+ `pop_failure_point' will keep the current value for the
+ string, instead of restoring it. To see why, consider
+ matching `foo\nbar' against `.*\n'. The .* matches the foo;
+ then the . fails against the \n. But the next thing we want
+ to do is match the \n against the \n; if we restored the
+ string value, we would be back at the foo.
+
+ Because this is used only in specific cases, we don't need to
+ check all the things that `on_failure_jump' does, to make
+ sure the right things get saved on the stack. Hence we don't
+ share its code. The only reason to push anything on the
+ stack at all is that otherwise we would have to change
+ `anychar's code to do something besides goto fail in this
+ case; that seems worse than this. */
+ case on_failure_keep_string_jump:
+ DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump");
+
+ EXTRACT_NUMBER_AND_INCR (mcnt, p);
+ DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt);
+
+ PUSH_FAILURE_POINT (p + mcnt, NULL, -2);
+ break;
+
+
+ /* Uses of on_failure_jump:
+
+ Each alternative starts with an on_failure_jump that points
+ to the beginning of the next alternative. Each alternative
+ except the last ends with a jump that in effect jumps past
+ the rest of the alternatives. (They really jump to the
+ ending jump of the following alternative, because tensioning
+ these jumps is a hassle.)
+
+ Repeats start with an on_failure_jump that points past both
+ the repetition text and either the following jump or
+ pop_failure_jump back to this on_failure_jump. */
+ case on_failure_jump:
+ on_failure:
+ DEBUG_PRINT1 ("EXECUTING on_failure_jump");
+
+ EXTRACT_NUMBER_AND_INCR (mcnt, p);
+ DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt);
+
+ /* If this on_failure_jump comes right before a group (i.e.,
+ the original * applied to a group), save the information
+ for that group and all inner ones, so that if we fail back
+ to this point, the group's information will be correct.
+ For example, in \(a*\)*\1, we need the preceding group,
+ and in \(\(a*\)b*\)\2, we need the inner group. */
+
+ /* We can't use `p' to check ahead because we push
+ a failure point to `p + mcnt' after we do this. */
+ p1 = p;
+
+ /* We need to skip no_op's before we look for the
+ start_memory in case this on_failure_jump is happening as
+ the result of a completed succeed_n, as in \(a\)\{1,3\}b\1
+ against aba. */
+ while (p1 < pend && (re_opcode_t) *p1 == no_op)
+ p1++;
+
+ if (p1 < pend && (re_opcode_t) *p1 == start_memory)
+ {
+ /* We have a new highest active register now. This will
+ get reset at the start_memory we are about to get to,
+ but we will have saved all the registers relevant to
+ this repetition op, as described above. */
+ highest_active_reg = *(p1 + 1) + *(p1 + 2);
+ if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
+ lowest_active_reg = *(p1 + 1);
+ }
+
+ DEBUG_PRINT1 (":\n");
+ PUSH_FAILURE_POINT (p + mcnt, d, -2);
+ break;
+
+
+ /* A smart repeat ends with `maybe_pop_jump'.
+ We change it to either `pop_failure_jump' or `jump'. */
+ case maybe_pop_jump:
+ EXTRACT_NUMBER_AND_INCR (mcnt, p);
+ DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt);
+ {
+ register unsigned char *p2 = p;
+
+ /* Compare the beginning of the repeat with what in the
+ pattern follows its end. If we can establish that there
+ is nothing that they would both match, i.e., that we
+ would have to backtrack because of (as in, e.g., `a*a')
+ then we can change to pop_failure_jump, because we'll
+ never have to backtrack.
+
+ This is not true in the case of alternatives: in
+ `(a|ab)*' we do need to backtrack to the `ab' alternative
+ (e.g., if the string was `ab'). But instead of trying to
+ detect that here, the alternative has put on a dummy
+ failure point which is what we will end up popping. */
+
+ /* Skip over open/close-group commands.
+ If what follows this loop is a ...+ construct,
+ look at what begins its body, since we will have to
+ match at least one of that. */
+ while (1)
+ {
+ if (p2 + 2 < pend
+ && ((re_opcode_t) *p2 == stop_memory
+ || (re_opcode_t) *p2 == start_memory))
+ p2 += 3;
+ else if (p2 + 6 < pend
+ && (re_opcode_t) *p2 == dummy_failure_jump)
+ p2 += 6;
+ else
+ break;
+ }
+
+ p1 = p + mcnt;
+ /* p1[0] ... p1[2] are the `on_failure_jump' corresponding
+ to the `maybe_finalize_jump' of this case. Examine what
+ follows. */
+
+ /* If we're at the end of the pattern, we can change. */
+ if (p2 == pend)
+ {
+ /* Consider what happens when matching ":\(.*\)"
+ against ":/". I don't really understand this code
+ yet. */
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT1
+ (" End of pattern: change to `pop_failure_jump'.\n");
+ }
+
+ else if ((re_opcode_t) *p2 == exactn
+ || (bufp->newline_anchor && (re_opcode_t) *p2 == endline))
+ {
+ register unsigned char c
+ = *p2 == (unsigned char) endline ? '\n' : p2[2];
+
+ if ((re_opcode_t) p1[3] == exactn && p1[5] != c)
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n",
+ c, p1[5]);
+ }
+
+ else if ((re_opcode_t) p1[3] == charset
+ || (re_opcode_t) p1[3] == charset_not)
+ {
+ int not = (re_opcode_t) p1[3] == charset_not;
+
+ if (c < (unsigned char) (p1[4] * BYTEWIDTH)
+ && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+ not = !not;
+
+ /* `not' is equal to 1 if c would match, which means
+ that we can't change to pop_failure_jump. */
+ if (!not)
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
+ }
+ }
+ }
+ else if ((re_opcode_t) *p2 == charset)
+ {
+#ifdef DEBUG
+ register unsigned char c
+ = *p2 == (unsigned char) endline ? '\n' : p2[2];
+#endif
+
+ if ((re_opcode_t) p1[3] == exactn
+ && ! ((int) p2[1] * BYTEWIDTH > (int) p1[4]
+ && (p2[1 + p1[4] / BYTEWIDTH]
+ & (1 << (p1[4] % BYTEWIDTH)))))
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n",
+ c, p1[5]);
+ }
+
+ else if ((re_opcode_t) p1[3] == charset_not)
+ {
+ int idx;
+ /* We win if the charset_not inside the loop
+ lists every character listed in the charset after. */
+ for (idx = 0; idx < (int) p2[1]; idx++)
+ if (! (p2[2 + idx] == 0
+ || (idx < (int) p1[4]
+ && ((p2[2 + idx] & ~ p1[5 + idx]) == 0))))
+ break;
+
+ if (idx == p2[1])
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
+ }
+ }
+ else if ((re_opcode_t) p1[3] == charset)
+ {
+ int idx;
+ /* We win if the charset inside the loop
+ has no overlap with the one after the loop. */
+ for (idx = 0;
+ idx < (int) p2[1] && idx < (int) p1[4];
+ idx++)
+ if ((p2[2 + idx] & p1[5 + idx]) != 0)
+ break;
+
+ if (idx == p2[1] || idx == p1[4])
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
+ }
+ }
+ }
+ }
+ p -= 2; /* Point at relative address again. */
+ if ((re_opcode_t) p[-1] != pop_failure_jump)
+ {
+ p[-1] = (unsigned char) jump;
+ DEBUG_PRINT1 (" Match => jump.\n");
+ goto unconditional_jump;
+ }
+ /* Note fall through. */
+
+
+ /* The end of a simple repeat has a pop_failure_jump back to
+ its matching on_failure_jump, where the latter will push a
+ failure point. The pop_failure_jump takes off failure
+ points put on by this pop_failure_jump's matching
+ on_failure_jump; we got through the pattern to here from the
+ matching on_failure_jump, so didn't fail. */
+ case pop_failure_jump:
+ {
+ /* We need to pass separate storage for the lowest and
+ highest registers, even though we don't care about the
+ actual values. Otherwise, we will restore only one
+ register from the stack, since lowest will == highest in
+ `pop_failure_point'. */
+ unsigned dummy_low_reg, dummy_high_reg;
+ unsigned char *pdummy;
+ const char *sdummy;
+
+ DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n");
+ POP_FAILURE_POINT (sdummy, pdummy,
+ dummy_low_reg, dummy_high_reg,
+ reg_dummy, reg_dummy, reg_info_dummy);
+ }
+ /* Note fall through. */
+
+
+ /* Unconditionally jump (without popping any failure points). */
+ case jump:
+ unconditional_jump:
+ EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */
+ DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt);
+ p += mcnt; /* Do the jump. */
+ DEBUG_PRINT2 ("(to 0x%x).\n", p);
+ break;
+
+
+ /* We need this opcode so we can detect where alternatives end
+ in `group_match_null_string_p' et al. */
+ case jump_past_alt:
+ DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n");
+ goto unconditional_jump;
+
+
+ /* Normally, the on_failure_jump pushes a failure point, which
+ then gets popped at pop_failure_jump. We will end up at
+ pop_failure_jump, also, and with a pattern of, say, `a+', we
+ are skipping over the on_failure_jump, so we have to push
+ something meaningless for pop_failure_jump to pop. */
+ case dummy_failure_jump:
+ DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n");
+ /* It doesn't matter what we push for the string here. What
+ the code at `fail' tests is the value for the pattern. */
+ PUSH_FAILURE_POINT (0, 0, -2);
+ goto unconditional_jump;
+
+
+ /* At the end of an alternative, we need to push a dummy failure
+ point in case we are followed by a `pop_failure_jump', because
+ we don't want the failure point for the alternative to be
+ popped. For example, matching `(a|ab)*' against `aab'
+ requires that we match the `ab' alternative. */
+ case push_dummy_failure:
+ DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n");
+ /* See comments just above at `dummy_failure_jump' about the
+ two zeroes. */
+ PUSH_FAILURE_POINT (0, 0, -2);
+ break;
+
+ /* Have to succeed matching what follows at least n times.
+ After that, handle like `on_failure_jump'. */
+ case succeed_n:
+ EXTRACT_NUMBER (mcnt, p + 2);
+ DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt);
+
+ assert (mcnt >= 0);
+ /* Originally, this is how many times we HAVE to succeed. */
+ if (mcnt > 0)
+ {
+ mcnt--;
+ p += 2;
+ STORE_NUMBER_AND_INCR (p, mcnt);
+ DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p, mcnt);
+ }
+ else if (mcnt == 0)
+ {
+ DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", p+2);
+ p[2] = (unsigned char) no_op;
+ p[3] = (unsigned char) no_op;
+ goto on_failure;
+ }
+ break;
+
+ case jump_n:
+ EXTRACT_NUMBER (mcnt, p + 2);
+ DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt);
+
+ /* Originally, this is how many times we CAN jump. */
+ if (mcnt)
+ {
+ mcnt--;
+ STORE_NUMBER (p + 2, mcnt);
+ goto unconditional_jump;
+ }
+ /* If don't have to jump any more, skip over the rest of command. */
+ else
+ p += 4;
+ break;
+
+ case set_number_at:
+ {
+ DEBUG_PRINT1 ("EXECUTING set_number_at.\n");
+
+ EXTRACT_NUMBER_AND_INCR (mcnt, p);
+ p1 = p + mcnt;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p);
+ DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt);
+ STORE_NUMBER (p1, mcnt);
+ break;
+ }
+
+ case wordbound:
+ DEBUG_PRINT1 ("EXECUTING wordbound.\n");
+ if (AT_WORD_BOUNDARY (d))
+ break;
+ goto fail;
+
+ case notwordbound:
+ DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
+ if (AT_WORD_BOUNDARY (d))
+ goto fail;
+ break;
+
+ case wordbeg:
+ DEBUG_PRINT1 ("EXECUTING wordbeg.\n");
+ if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1)))
+ break;
+ goto fail;
+
+ case wordend:
+ DEBUG_PRINT1 ("EXECUTING wordend.\n");
+ if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1)
+ && (!WORDCHAR_P (d) || AT_STRINGS_END (d)))
+ break;
+ goto fail;
+
+#ifdef emacs
+ case before_dot:
+ DEBUG_PRINT1 ("EXECUTING before_dot.\n");
+ if (PTR_CHAR_POS ((unsigned char *) d) >= point)
+ goto fail;
+ break;
+
+ case at_dot:
+ DEBUG_PRINT1 ("EXECUTING at_dot.\n");
+ if (PTR_CHAR_POS ((unsigned char *) d) != point)
+ goto fail;
+ break;
+
+ case after_dot:
+ DEBUG_PRINT1 ("EXECUTING after_dot.\n");
+ if (PTR_CHAR_POS ((unsigned char *) d) <= point)
+ goto fail;
+ break;
+#if 0 /* not emacs19 */
+ case at_dot:
+ DEBUG_PRINT1 ("EXECUTING at_dot.\n");
+ if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point)
+ goto fail;
+ break;
+#endif /* not emacs19 */
+
+ case syntaxspec:
+ DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt);
+ mcnt = *p++;
+ goto matchsyntax;
+
+ case wordchar:
+ DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n");
+ mcnt = (int) Sword;
+ matchsyntax:
+ PREFETCH ();
+ /* Can't use *d++ here; SYNTAX may be an unsafe macro. */
+ d++;
+ if (SYNTAX (d[-1]) != (enum syntaxcode) mcnt)
+ goto fail;
+ SET_REGS_MATCHED ();
+ break;
+
+ case notsyntaxspec:
+ DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt);
+ mcnt = *p++;
+ goto matchnotsyntax;
+
+ case notwordchar:
+ DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n");
+ mcnt = (int) Sword;
+ matchnotsyntax:
+ PREFETCH ();
+ /* Can't use *d++ here; SYNTAX may be an unsafe macro. */
+ d++;
+ if (SYNTAX (d[-1]) == (enum syntaxcode) mcnt)
+ goto fail;
+ SET_REGS_MATCHED ();
+ break;
+
+#else /* not emacs */
+ case wordchar:
+ DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n");
+ PREFETCH ();
+ if (!WORDCHAR_P (d))
+ goto fail;
+ SET_REGS_MATCHED ();
+ d++;
+ break;
+
+ case notwordchar:
+ DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n");
+ PREFETCH ();
+ if (WORDCHAR_P (d))
+ goto fail;
+ SET_REGS_MATCHED ();
+ d++;
+ break;
+#endif /* not emacs */
+
+ default:
+ abort ();
+ }
+ continue; /* Successfully executed one pattern command; keep going. */
+
+
+ /* We goto here if a matching operation fails. */
+ fail:
+ if (!FAIL_STACK_EMPTY ())
+ { /* A restart point is known. Restore to that state. */
+ DEBUG_PRINT1 ("\nFAIL:\n");
+ POP_FAILURE_POINT (d, p,
+ lowest_active_reg, highest_active_reg,
+ regstart, regend, reg_info);
+
+ /* If this failure point is a dummy, try the next one. */
+ if (!p)
+ goto fail;
+
+ /* If we failed to the end of the pattern, don't examine *p. */
+ assert (p <= pend);
+ if (p < pend)
+ {
+ boolean is_a_jump_n = false;
+
+ /* If failed to a backwards jump that's part of a repetition
+ loop, need to pop this failure point and use the next one. */
+ switch ((re_opcode_t) *p)
+ {
+ case jump_n:
+ is_a_jump_n = true;
+ case maybe_pop_jump:
+ case pop_failure_jump:
+ case jump:
+ p1 = p + 1;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ p1 += mcnt;
+
+ if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n)
+ || (!is_a_jump_n
+ && (re_opcode_t) *p1 == on_failure_jump))
+ goto fail;
+ break;
+ default:
+ /* do nothing */ ;
+ }
+ }
+
+ if (d >= string1 && d <= end1)
+ dend = end_match_1;
+ }
+ else
+ break; /* Matching at this starting point really fails. */
+ } /* for (;;) */
+
+ if (best_regs_set)
+ goto restore_best_regs;
+
+ FREE_VARIABLES ();
+
+ return -1; /* Failure to match. */
+} /* re_match_2 */
+
+/* Subroutine definitions for re_match_2. */
+
+
+/* We are passed P pointing to a register number after a start_memory.
+
+ Return true if the pattern up to the corresponding stop_memory can
+ match the empty string, and false otherwise.
+
+ If we find the matching stop_memory, sets P to point to one past its number.
+ Otherwise, sets P to an undefined byte less than or equal to END.
+
+ We don't handle duplicates properly (yet). */
+
+static boolean
+group_match_null_string_p (p, end, reg_info)
+ unsigned char **p, *end;
+ register_info_type *reg_info;
+{
+ int mcnt;
+ /* Point to after the args to the start_memory. */
+ unsigned char *p1 = *p + 2;
+
+ while (p1 < end)
+ {
+ /* Skip over opcodes that can match nothing, and return true or
+ false, as appropriate, when we get to one that can't, or to the
+ matching stop_memory. */
+
+ switch ((re_opcode_t) *p1)
+ {
+ /* Could be either a loop or a series of alternatives. */
+ case on_failure_jump:
+ p1++;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+
+ /* If the next operation is not a jump backwards in the
+ pattern. */
+
+ if (mcnt >= 0)
+ {
+ /* Go through the on_failure_jumps of the alternatives,
+ seeing if any of the alternatives cannot match nothing.
+ The last alternative starts with only a jump,
+ whereas the rest start with on_failure_jump and end
+ with a jump, e.g., here is the pattern for `a|b|c':
+
+ /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6
+ /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3
+ /exactn/1/c
+
+ So, we have to first go through the first (n-1)
+ alternatives and then deal with the last one separately. */
+
+
+ /* Deal with the first (n-1) alternatives, which start
+ with an on_failure_jump (see above) that jumps to right
+ past a jump_past_alt. */
+
+ while ((re_opcode_t) p1[mcnt-3] == jump_past_alt)
+ {
+ /* `mcnt' holds how many bytes long the alternative
+ is, including the ending `jump_past_alt' and
+ its number. */
+
+ if (!alt_match_null_string_p (p1, p1 + mcnt - 3,
+ reg_info))
+ return false;
+
+ /* Move to right after this alternative, including the
+ jump_past_alt. */
+ p1 += mcnt;
+
+ /* Break if it's the beginning of an n-th alternative
+ that doesn't begin with an on_failure_jump. */
+ if ((re_opcode_t) *p1 != on_failure_jump)
+ break;
+
+ /* Still have to check that it's not an n-th
+ alternative that starts with an on_failure_jump. */
+ p1++;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ if ((re_opcode_t) p1[mcnt-3] != jump_past_alt)
+ {
+ /* Get to the beginning of the n-th alternative. */
+ p1 -= 3;
+ break;
+ }
+ }
+
+ /* Deal with the last alternative: go back and get number
+ of the `jump_past_alt' just before it. `mcnt' contains
+ the length of the alternative. */
+ EXTRACT_NUMBER (mcnt, p1 - 2);
+
+ if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info))
+ return false;
+
+ p1 += mcnt; /* Get past the n-th alternative. */
+ } /* if mcnt > 0 */
+ break;
+
+
+ case stop_memory:
+ assert (p1[1] == **p);
+ *p = p1 + 2;
+ return true;
+
+
+ default:
+ if (!common_op_match_null_string_p (&p1, end, reg_info))
+ return false;
+ }
+ } /* while p1 < end */
+
+ return false;
+} /* group_match_null_string_p */
+
+
+/* Similar to group_match_null_string_p, but doesn't deal with alternatives:
+ It expects P to be the first byte of a single alternative and END one
+ byte past the last. The alternative can contain groups. */
+
+static boolean
+alt_match_null_string_p (p, end, reg_info)
+ unsigned char *p, *end;
+ register_info_type *reg_info;
+{
+ int mcnt;
+ unsigned char *p1 = p;
+
+ while (p1 < end)
+ {
+ /* Skip over opcodes that can match nothing, and break when we get
+ to one that can't. */
+
+ switch ((re_opcode_t) *p1)
+ {
+ /* It's a loop. */
+ case on_failure_jump:
+ p1++;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ p1 += mcnt;
+ break;
+
+ default:
+ if (!common_op_match_null_string_p (&p1, end, reg_info))
+ return false;
+ }
+ } /* while p1 < end */
+
+ return true;
+} /* alt_match_null_string_p */
+
+
+/* Deals with the ops common to group_match_null_string_p and
+ alt_match_null_string_p.
+
+ Sets P to one after the op and its arguments, if any. */
+
+static boolean
+common_op_match_null_string_p (p, end, reg_info)
+ unsigned char **p, *end;
+ register_info_type *reg_info;
+{
+ int mcnt;
+ boolean ret;
+ int reg_no;
+ unsigned char *p1 = *p;
+
+ switch ((re_opcode_t) *p1++)
+ {
+ case no_op:
+ case begline:
+ case endline:
+ case begbuf:
+ case endbuf:
+ case wordbeg:
+ case wordend:
+ case wordbound:
+ case notwordbound:
+#ifdef emacs
+ case before_dot:
+ case at_dot:
+ case after_dot:
+#endif
+ break;
+
+ case start_memory:
+ reg_no = *p1;
+ assert (reg_no > 0 && reg_no <= MAX_REGNUM);
+ ret = group_match_null_string_p (&p1, end, reg_info);
+
+ /* Have to set this here in case we're checking a group which
+ contains a group and a back reference to it. */
+
+ if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE)
+ REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret;
+
+ if (!ret)
+ return false;
+ break;
+
+ /* If this is an optimized succeed_n for zero times, make the jump. */
+ case jump:
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ if (mcnt >= 0)
+ p1 += mcnt;
+ else
+ return false;
+ break;
+
+ case succeed_n:
+ /* Get to the number of times to succeed. */
+ p1 += 2;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+
+ if (mcnt == 0)
+ {
+ p1 -= 4;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ p1 += mcnt;
+ }
+ else
+ return false;
+ break;
+
+ case duplicate:
+ if (!REG_MATCH_NULL_STRING_P (reg_info[*p1]))
+ return false;
+ break;
+
+ case set_number_at:
+ p1 += 4;
+
+ default:
+ /* All other opcodes mean we cannot match the empty string. */
+ return false;
+ }
+
+ *p = p1;
+ return true;
+} /* common_op_match_null_string_p */
+
+
+/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN
+ bytes; nonzero otherwise. */
+
+static int
+bcmp_translate (s1, s2, len, translate)
+ unsigned char *s1, *s2;
+ register int len;
+ char *translate;
+{
+ register unsigned char *p1 = s1, *p2 = s2;
+ while (len)
+ {
+ if (translate[*p1++] != translate[*p2++]) return 1;
+ len--;
+ }
+ return 0;
+}
+
+/* Entry points for GNU code. */
+
+/* re_compile_pattern is the GNU regular expression compiler: it
+ compiles PATTERN (of length SIZE) and puts the result in BUFP.
+ Returns 0 if the pattern was valid, otherwise an error string.
+
+ Assumes the `allocated' (and perhaps `buffer') and `translate' fields
+ are set in BUFP on entry.
+
+ We call regex_compile to do the actual compilation. */
+
+const char *
+re_compile_pattern (pattern, length, bufp)
+ const char *pattern;
+ int length;
+ struct re_pattern_buffer *bufp;
+{
+ reg_errcode_t ret;
+
+ /* GNU code is written to assume at least RE_NREGS registers will be set
+ (and at least one extra will be -1). */
+ bufp->regs_allocated = REGS_UNALLOCATED;
+
+ /* And GNU code determines whether or not to get register information
+ by passing null for the REGS argument to re_match, etc., not by
+ setting no_sub. */
+ bufp->no_sub = 0;
+
+ /* Match anchors at newline. */
+ bufp->newline_anchor = 1;
+
+ ret = regex_compile (pattern, length, re_syntax_options, bufp);
+
+ return re_error_msg[(int) ret];
+}
+
+/* Entry points compatible with 4.2 BSD regex library. We don't define
+ them unless specifically requested. */
+
+#ifdef _REGEX_RE_COMP
+
+/* BSD has one and only one pattern buffer. */
+static struct re_pattern_buffer re_comp_buf;
+
+char *
+re_comp (s)
+ const char *s;
+{
+ reg_errcode_t ret;
+
+ if (!s)
+ {
+ if (!re_comp_buf.buffer)
+ return "No previous regular expression";
+ return 0;
+ }
+
+ if (!re_comp_buf.buffer)
+ {
+ re_comp_buf.buffer = (unsigned char *) malloc (200);
+ if (re_comp_buf.buffer == NULL)
+ return "Memory exhausted";
+ re_comp_buf.allocated = 200;
+
+ re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH);
+ if (re_comp_buf.fastmap == NULL)
+ return "Memory exhausted";
+ }
+
+ /* Since `re_exec' always passes NULL for the `regs' argument, we
+ don't need to initialize the pattern buffer fields which affect it. */
+
+ /* Match anchors at newlines. */
+ re_comp_buf.newline_anchor = 1;
+
+ ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf);
+
+ /* Yes, we're discarding `const' here. */
+ return (char *) re_error_msg[(int) ret];
+}
+
+
+int
+re_exec (s)
+ const char *s;
+{
+ const int len = strlen (s);
+ return
+ 0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0);
+}
+#endif /* _REGEX_RE_COMP */
+
+/* POSIX.2 functions. Don't define these for Emacs. */
+
+#ifndef emacs
+
+/* regcomp takes a regular expression as a string and compiles it.
+
+ PREG is a regex_t *. We do not expect any fields to be initialized,
+ since POSIX says we shouldn't. Thus, we set
+
+ `buffer' to the compiled pattern;
+ `used' to the length of the compiled pattern;
+ `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
+ REG_EXTENDED bit in CFLAGS is set; otherwise, to
+ RE_SYNTAX_POSIX_BASIC;
+ `newline_anchor' to REG_NEWLINE being set in CFLAGS;
+ `fastmap' and `fastmap_accurate' to zero;
+ `re_nsub' to the number of subexpressions in PATTERN.
+
+ PATTERN is the address of the pattern string.
+
+ CFLAGS is a series of bits which affect compilation.
+
+ If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
+ use POSIX basic syntax.
+
+ If REG_NEWLINE is set, then . and [^...] don't match newline.
+ Also, regexec will try a match beginning after every newline.
+
+ If REG_ICASE is set, then we considers upper- and lowercase
+ versions of letters to be equivalent when matching.
+
+ If REG_NOSUB is set, then when PREG is passed to regexec, that
+ routine will report only success or failure, and nothing about the
+ registers.
+
+ It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for
+ the return codes and their meanings.) */
+
+int
+regcomp (preg, pattern, cflags)
+ regex_t *preg;
+ const char *pattern;
+ int cflags;
+{
+ reg_errcode_t ret;
+ unsigned syntax
+ = (cflags & REG_EXTENDED) ?
+ RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC;
+
+ /* regex_compile will allocate the space for the compiled pattern. */
+ preg->buffer = 0;
+ preg->allocated = 0;
+ preg->used = 0;
+
+ /* Don't bother to use a fastmap when searching. This simplifies the
+ REG_NEWLINE case: if we used a fastmap, we'd have to put all the
+ characters after newlines into the fastmap. This way, we just try
+ every character. */
+ preg->fastmap = 0;
+
+ if (cflags & REG_ICASE)
+ {
+ unsigned i;
+
+ preg->translate = (char *) malloc (CHAR_SET_SIZE);
+ if (preg->translate == NULL)
+ return (int) REG_ESPACE;
+
+ /* Map uppercase characters to corresponding lowercase ones. */
+ for (i = 0; i < CHAR_SET_SIZE; i++)
+ preg->translate[i] = ISUPPER (i) ? tolower (i) : i;
+ }
+ else
+ preg->translate = NULL;
+
+ /* If REG_NEWLINE is set, newlines are treated differently. */
+ if (cflags & REG_NEWLINE)
+ { /* REG_NEWLINE implies neither . nor [^...] match newline. */
+ syntax &= ~RE_DOT_NEWLINE;
+ syntax |= RE_HAT_LISTS_NOT_NEWLINE;
+ /* It also changes the matching behavior. */
+ preg->newline_anchor = 1;
+ }
+ else
+ preg->newline_anchor = 0;
+
+ preg->no_sub = !!(cflags & REG_NOSUB);
+
+ /* POSIX says a null character in the pattern terminates it, so we
+ can use strlen here in compiling the pattern. */
+ ret = regex_compile (pattern, strlen (pattern), syntax, preg);
+
+ /* POSIX doesn't distinguish between an unmatched open-group and an
+ unmatched close-group: both are REG_EPAREN. */
+ if (ret == REG_ERPAREN) ret = REG_EPAREN;
+
+ return (int) ret;
+}
+
+
+/* regexec searches for a given pattern, specified by PREG, in the
+ string STRING.
+
+ If NMATCH is zero or REG_NOSUB was set in the cflags argument to
+ `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at
+ least NMATCH elements, and we set them to the offsets of the
+ corresponding matched substrings.
+
+ EFLAGS specifies `execution flags' which affect matching: if
+ REG_NOTBOL is set, then ^ does not match at the beginning of the
+ string; if REG_NOTEOL is set, then $ does not match at the end.
+
+ We return 0 if we find a match and REG_NOMATCH if not. */
+
+int
+regexec (preg, string, nmatch, pmatch, eflags)
+ const regex_t *preg;
+ const char *string;
+ size_t nmatch;
+ regmatch_t pmatch[];
+ int eflags;
+{
+ int ret;
+ struct re_registers regs;
+ regex_t private_preg;
+ int len = strlen (string);
+ boolean want_reg_info = !preg->no_sub && nmatch > 0;
+
+ private_preg = *preg;
+
+ private_preg.not_bol = !!(eflags & REG_NOTBOL);
+ private_preg.not_eol = !!(eflags & REG_NOTEOL);
+
+ /* The user has told us exactly how many registers to return
+ information about, via `nmatch'. We have to pass that on to the
+ matching routines. */
+ private_preg.regs_allocated = REGS_FIXED;
+
+ if (want_reg_info)
+ {
+ regs.num_regs = nmatch;
+ regs.start = TALLOC (nmatch, regoff_t);
+ regs.end = TALLOC (nmatch, regoff_t);
+ if (regs.start == NULL || regs.end == NULL)
+ return (int) REG_NOMATCH;
+ }
+
+ /* Perform the searching operation. */
+ ret = re_search (&private_preg, string, len,
+ /* start: */ 0, /* range: */ len,
+ want_reg_info ? &regs : (struct re_registers *) 0);
+
+ /* Copy the register information to the POSIX structure. */
+ if (want_reg_info)
+ {
+ if (ret >= 0)
+ {
+ unsigned r;
+
+ for (r = 0; r < nmatch; r++)
+ {
+ pmatch[r].rm_so = regs.start[r];
+ pmatch[r].rm_eo = regs.end[r];
+ }
+ }
+
+ /* If we needed the temporary register info, free the space now. */
+ free (regs.start);
+ free (regs.end);
+ }
+
+ /* We want zero return to mean success, unlike `re_search'. */
+ return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH;
+}
+
+
+/* Returns a message corresponding to an error code, ERRCODE, returned
+ from either regcomp or regexec. We don't use PREG here. */
+
+size_t
+regerror (errcode, preg, errbuf, errbuf_size)
+ int errcode;
+ const regex_t *preg;
+ char *errbuf;
+ size_t errbuf_size;
+{
+ const char *msg;
+ size_t msg_size;
+
+ if (errcode < 0
+ || errcode >= (sizeof (re_error_msg) / sizeof (re_error_msg[0])))
+ /* Only error codes returned by the rest of the code should be passed
+ to this routine. If we are given anything else, or if other regex
+ code generates an invalid error code, then the program has a bug.
+ Dump core so we can fix it. */
+ abort ();
+
+ msg = re_error_msg[errcode];
+
+ /* POSIX doesn't require that we do anything in this case, but why
+ not be nice. */
+ if (! msg)
+ msg = "Success";
+
+ msg_size = strlen (msg) + 1; /* Includes the null. */
+
+ if (errbuf_size != 0)
+ {
+ if (msg_size > errbuf_size)
+ {
+ strncpy (errbuf, msg, errbuf_size - 1);
+ errbuf[errbuf_size - 1] = 0;
+ }
+ else
+ strcpy (errbuf, msg);
+ }
+
+ return msg_size;
+}
+
+
+/* Free dynamically allocated space used by PREG. */
+
+void
+regfree (preg)
+ regex_t *preg;
+{
+ if (preg->buffer != NULL)
+ free (preg->buffer);
+ preg->buffer = NULL;
+
+ preg->allocated = 0;
+ preg->used = 0;
+
+ if (preg->fastmap != NULL)
+ free (preg->fastmap);
+ preg->fastmap = NULL;
+ preg->fastmap_accurate = 0;
+
+ if (preg->translate != NULL)
+ free (preg->translate);
+ preg->translate = NULL;
+}
+
+#endif /* not emacs */
+
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
diff --git a/lib/regex.h b/lib/regex.h
new file mode 100644
index 00000000..55927f62
--- /dev/null
+++ b/lib/regex.h
@@ -0,0 +1,487 @@
+/* Definitions for data structures and routines for the regular
+ expression library, version 0.12.
+
+ Copyright (C) 1985, 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __REGEXP_LIBRARY_H__
+#define __REGEXP_LIBRARY_H__
+
+/* POSIX says that <sys/types.h> must be included (by the caller) before
+ <regex.h>. */
+
+#ifdef VMS
+/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
+ should be there. */
+#include <stddef.h>
+#endif
+
+
+/* The following bits are used to determine the regexp syntax we
+ recognize. The set/not-set meanings are chosen so that Emacs syntax
+ remains the value 0. The bits are given in alphabetical order, and
+ the definitions shifted by one from the previous bit; thus, when we
+ add or remove a bit, only one other definition need change. */
+typedef unsigned reg_syntax_t;
+
+/* If this bit is not set, then \ inside a bracket expression is literal.
+ If set, then such a \ quotes the following character. */
+#define RE_BACKSLASH_ESCAPE_IN_LISTS (1)
+
+/* If this bit is not set, then + and ? are operators, and \+ and \? are
+ literals.
+ If set, then \+ and \? are operators and + and ? are literals. */
+#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
+
+/* If this bit is set, then character classes are supported. They are:
+ [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:],
+ [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
+ If not set, then character classes are not supported. */
+#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
+
+/* If this bit is set, then ^ and $ are always anchors (outside bracket
+ expressions, of course).
+ If this bit is not set, then it depends:
+ ^ is an anchor if it is at the beginning of a regular
+ expression or after an open-group or an alternation operator;
+ $ is an anchor if it is at the end of a regular expression, or
+ before a close-group or an alternation operator.
+
+ This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
+ POSIX draft 11.2 says that * etc. in leading positions is undefined.
+ We already implemented a previous draft which made those constructs
+ invalid, though, so we haven't changed the code back. */
+#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
+
+/* If this bit is set, then special characters are always special
+ regardless of where they are in the pattern.
+ If this bit is not set, then special characters are special only in
+ some contexts; otherwise they are ordinary. Specifically,
+ * + ? and intervals are only special when not after the beginning,
+ open-group, or alternation operator. */
+#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+ immediately after an alternation or begin-group operator. */
+#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
+
+/* If this bit is set, then . matches newline.
+ If not set, then it doesn't. */
+#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
+
+/* If this bit is set, then . doesn't match NUL.
+ If not set, then it does. */
+#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+ If not set, they do. */
+#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
+
+/* If this bit is set, either \{...\} or {...} defines an
+ interval, depending on RE_NO_BK_BRACES.
+ If not set, \{, \}, {, and } are literals. */
+#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+ If not set, they are. */
+#define RE_LIMITED_OPS (RE_INTERVALS << 1)
+
+/* If this bit is set, newline is an alternation operator.
+ If not set, newline is literal. */
+#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
+
+/* If this bit is set, then `{...}' defines an interval, and \{ and \}
+ are literals.
+ If not set, then `\{...\}' defines an interval. */
+#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+ If not set, \(...\) defines a group, and ( and ) are literals. */
+#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
+
+/* If this bit is set, then \<digit> matches <digit>.
+ If not set, then \<digit> is a back-reference. */
+#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
+
+/* If this bit is set, then | is an alternation operator, and \| is literal.
+ If not set, then \| is an alternation operator, and | is literal. */
+#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
+
+/* If this bit is set, then an ending range point collating higher
+ than the starting range point, as in [z-a], is invalid.
+ If not set, then when ending range point collates higher than the
+ starting range point, the range is ignored. */
+#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
+
+/* If this bit is set, then an unmatched ) is ordinary.
+ If not set, then an unmatched ) is invalid. */
+#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
+
+/* This global variable defines the particular regexp syntax to use (for
+ some interfaces). When a regexp is compiled, the syntax used is
+ stored in the pattern buffer, so changing this does not affect
+ already-compiled regexps. */
+extern reg_syntax_t re_syntax_options;
+
+/* Define combinations of the above bits for the standard possibilities.
+ (The [[[ comments delimit what gets put into the Texinfo file, so
+ don't delete them!) */
+/* [[[begin syntaxes]]] */
+#define RE_SYNTAX_EMACS 0
+
+#define RE_SYNTAX_AWK \
+ (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+#define RE_SYNTAX_POSIX_AWK \
+ (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS)
+
+#define RE_SYNTAX_GREP \
+ (RE_BK_PLUS_QM | RE_CHAR_CLASSES \
+ | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \
+ | RE_NEWLINE_ALT)
+
+#define RE_SYNTAX_EGREP \
+ (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \
+ | RE_NEWLINE_ALT | RE_NO_BK_PARENS \
+ | RE_NO_BK_VBAR)
+
+#define RE_SYNTAX_POSIX_EGREP \
+ (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
+
+/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
+#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
+
+#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
+
+/* Syntax bits common to both basic and extended POSIX regex syntax. */
+#define _RE_SYNTAX_POSIX_COMMON \
+ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
+ | RE_INTERVALS | RE_NO_EMPTY_RANGES)
+
+#define RE_SYNTAX_POSIX_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
+
+/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
+ RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
+ isn't minimal, since other operators, such as \`, aren't disabled. */
+#define RE_SYNTAX_POSIX_MINIMAL_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
+
+#define RE_SYNTAX_POSIX_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_VBAR \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
+ replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */
+#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD)
+/* [[[end syntaxes]]] */
+
+/* Maximum number of duplicates an interval can allow. Some systems
+ (erroneously) define this in other header files, but we want our
+ value, so remove any previous define. */
+#ifdef RE_DUP_MAX
+#undef RE_DUP_MAX
+#endif
+#define RE_DUP_MAX ((1 << 15) - 1)
+
+
+/* POSIX `cflags' bits (i.e., information for `regcomp'). */
+
+/* If this bit is set, then use extended regular expression syntax.
+ If not set, then use basic regular expression syntax. */
+#define REG_EXTENDED 1
+
+/* If this bit is set, then ignore case when matching.
+ If not set, then case is significant. */
+#define REG_ICASE (REG_EXTENDED << 1)
+
+/* If this bit is set, then anchors do not match at newline
+ characters in the string.
+ If not set, then anchors do match at newlines. */
+#define REG_NEWLINE (REG_ICASE << 1)
+
+/* If this bit is set, then report only success or fail in regexec.
+ If not set, then returns differ between not matching and errors. */
+#define REG_NOSUB (REG_NEWLINE << 1)
+
+
+/* POSIX `eflags' bits (i.e., information for regexec). */
+
+/* If this bit is set, then the beginning-of-line operator doesn't match
+ the beginning of the string (presumably because it's not the
+ beginning of a line).
+ If not set, then the beginning-of-line operator does match the
+ beginning of the string. */
+#define REG_NOTBOL 1
+
+/* Like REG_NOTBOL, except for the end-of-line. */
+#define REG_NOTEOL (1 << 1)
+
+
+/* If any error codes are removed, changed, or added, update the
+ `re_error_msg' table in regex.c. */
+typedef enum
+{
+ REG_NOERROR = 0, /* Success. */
+ REG_NOMATCH, /* Didn't find a match (for regexec). */
+
+ /* POSIX regcomp return error codes. (In the order listed in the
+ standard.) */
+ REG_BADPAT, /* Invalid pattern. */
+ REG_ECOLLATE, /* Not implemented. */
+ REG_ECTYPE, /* Invalid character class name. */
+ REG_EESCAPE, /* Trailing backslash. */
+ REG_ESUBREG, /* Invalid back reference. */
+ REG_EBRACK, /* Unmatched left bracket. */
+ REG_EPAREN, /* Parenthesis imbalance. */
+ REG_EBRACE, /* Unmatched \{. */
+ REG_BADBR, /* Invalid contents of \{\}. */
+ REG_ERANGE, /* Invalid range end. */
+ REG_ESPACE, /* Ran out of memory. */
+ REG_BADRPT, /* No preceding re for repetition op. */
+
+ /* Error codes we've added. */
+ REG_EEND, /* Premature end. */
+ REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
+ REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
+} reg_errcode_t;
+
+/* This data structure represents a compiled pattern. Before calling
+ the pattern compiler, the fields `buffer', `allocated', `fastmap',
+ `translate', and `no_sub' can be set. After the pattern has been
+ compiled, the `re_nsub' field is available. All other fields are
+ private to the regex routines. */
+
+struct re_pattern_buffer
+{
+/* [[[begin pattern_buffer]]] */
+ /* Space that holds the compiled pattern. It is declared as
+ `unsigned char *' because its elements are
+ sometimes used as array indexes. */
+ unsigned char *buffer;
+
+ /* Number of bytes to which `buffer' points. */
+ unsigned long allocated;
+
+ /* Number of bytes actually used in `buffer'. */
+ unsigned long used;
+
+ /* Syntax setting with which the pattern was compiled. */
+ reg_syntax_t syntax;
+
+ /* Pointer to a fastmap, if any, otherwise zero. re_search uses
+ the fastmap, if there is one, to skip over impossible
+ starting points for matches. */
+ char *fastmap;
+
+ /* Either a translate table to apply to all characters before
+ comparing them, or zero for no translation. The translation
+ is applied to a pattern when it is compiled and to a string
+ when it is matched. */
+ char *translate;
+
+ /* Number of subexpressions found by the compiler. */
+ size_t re_nsub;
+
+ /* Zero if this pattern cannot match the empty string, one else.
+ Well, in truth it's used only in `re_search_2', to see
+ whether or not we should use the fastmap, so we don't set
+ this absolutely perfectly; see `re_compile_fastmap' (the
+ `duplicate' case). */
+ unsigned can_be_null : 1;
+
+ /* If REGS_UNALLOCATED, allocate space in the `regs' structure
+ for `max (RE_NREGS, re_nsub + 1)' groups.
+ If REGS_REALLOCATE, reallocate space if necessary.
+ If REGS_FIXED, use what's there. */
+#define REGS_UNALLOCATED 0
+#define REGS_REALLOCATE 1
+#define REGS_FIXED 2
+ unsigned regs_allocated : 2;
+
+ /* Set to zero when `regex_compile' compiles a pattern; set to one
+ by `re_compile_fastmap' if it updates the fastmap. */
+ unsigned fastmap_accurate : 1;
+
+ /* If set, `re_match_2' does not return information about
+ subexpressions. */
+ unsigned no_sub : 1;
+
+ /* If set, a beginning-of-line anchor doesn't match at the
+ beginning of the string. */
+ unsigned not_bol : 1;
+
+ /* Similarly for an end-of-line anchor. */
+ unsigned not_eol : 1;
+
+ /* If true, an anchor at a newline matches. */
+ unsigned newline_anchor : 1;
+
+/* [[[end pattern_buffer]]] */
+};
+
+typedef struct re_pattern_buffer regex_t;
+
+/* Type for byte offsets within the string. POSIX mandates this. */
+typedef int regoff_t;
+
+
+/* This is the structure we store register match data in. See
+ regex.texinfo for a full description of what registers match. */
+struct re_registers
+{
+ unsigned num_regs;
+ regoff_t *start;
+ regoff_t *end;
+};
+
+
+/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
+ `re_match_2' returns information about at least this many registers
+ the first time a `regs' structure is passed. */
+#ifndef RE_NREGS
+#define RE_NREGS 30
+#endif
+
+
+/* POSIX specification for registers. Aside from the different names than
+ `re_registers', POSIX uses an array of structures, instead of a
+ structure of arrays. */
+typedef struct
+{
+ regoff_t rm_so; /* Byte offset from string's start to substring's start. */
+ regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
+} regmatch_t;
+
+/* Declarations for routines. */
+
+/* To avoid duplicating every routine declaration -- once with a
+ prototype (if we are ANSI), and once without (if we aren't) -- we
+ use the following macro to declare argument types. This
+ unfortunately clutters up the declarations a bit, but I think it's
+ worth it. */
+
+#if __STDC__
+
+#define _RE_ARGS(args) args
+
+#else /* not __STDC__ */
+
+#define _RE_ARGS(args) ()
+
+#endif /* not __STDC__ */
+
+/* Sets the current default syntax to SYNTAX, and return the old syntax.
+ You can also simply assign to the `re_syntax_options' variable. */
+extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
+
+/* Compile the regular expression PATTERN, with length LENGTH
+ and syntax given by the global `re_syntax_options', into the buffer
+ BUFFER. Return NULL if successful, and an error string if not. */
+extern const char *re_compile_pattern
+ _RE_ARGS ((const char *pattern, int length,
+ struct re_pattern_buffer *buffer));
+
+
+/* Compile a fastmap for the compiled pattern in BUFFER; used to
+ accelerate searches. Return 0 if successful and -2 if was an
+ internal error. */
+extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
+
+
+/* Search in the string STRING (with length LENGTH) for the pattern
+ compiled into BUFFER. Start searching at position START, for RANGE
+ characters. Return the starting position of the match, -1 for no
+ match, or -2 for an internal error. Also return register
+ information in REGS (if REGS and BUFFER->no_sub are nonzero). */
+extern int re_search
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, int range, struct re_registers *regs));
+
+
+/* Like `re_search', but search in the concatenation of STRING1 and
+ STRING2. Also, stop searching at index START + STOP. */
+extern int re_search_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, int range, struct re_registers *regs, int stop));
+
+
+/* Like `re_search', but return how many characters in STRING the regexp
+ in BUFFER matched, starting at position START. */
+extern int re_match
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, struct re_registers *regs));
+
+
+/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
+extern int re_match_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, struct re_registers *regs, int stop));
+
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+ ENDS. Subsequent matches using BUFFER and REGS will use this memory
+ for recording register information. STARTS and ENDS must be
+ allocated with malloc, and must each be at least `NUM_REGS * sizeof
+ (regoff_t)' bytes long.
+
+ If NUM_REGS == 0, then subsequent matches should allocate their own
+ register data.
+
+ Unless this function is called, the first search or match using
+ PATTERN_BUFFER will allocate its own register data, without
+ freeing the old data. */
+extern void re_set_registers
+ _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
+ unsigned num_regs, regoff_t *starts, regoff_t *ends));
+
+#ifdef _REGEX_RE_COMP
+/* 4.2 bsd compatibility. */
+extern char *re_comp _RE_ARGS ((const char *));
+extern int re_exec _RE_ARGS ((const char *));
+#endif
+
+/* POSIX compatibility. */
+extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags));
+extern int regexec
+ _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch,
+ regmatch_t pmatch[], int eflags));
+extern size_t regerror
+ _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf,
+ size_t errbuf_size));
+extern void regfree _RE_ARGS ((regex_t *preg));
+
+#endif /* not __REGEXP_LIBRARY_H__ */
+
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
diff --git a/lib/savedir.c b/lib/savedir.c
new file mode 100644
index 00000000..1992cf55
--- /dev/null
+++ b/lib/savedir.c
@@ -0,0 +1,131 @@
+/* savedir.c -- save the list of files in a directory in a string
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+#ifdef CLOSEDIR_VOID
+/* Fake a return value. */
+#define CLOSEDIR(d) (closedir (d), 0)
+#else
+#define CLOSEDIR(d) closedir (d)
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#include <string.h>
+#else
+char *malloc ();
+char *realloc ();
+#endif
+#ifndef NULL
+#define NULL 0
+#endif
+
+char *stpcpy ();
+
+/* Return a freshly allocated string containing the filenames
+ in directory DIR, separated by '\0' characters;
+ the end is marked by two '\0' characters in a row.
+ NAME_SIZE is the number of bytes to initially allocate
+ for the string; it will be enlarged as needed.
+ Return NULL if DIR cannot be opened or if out of memory. */
+
+char *
+savedir (dir, name_size)
+ char *dir;
+ unsigned name_size;
+{
+ DIR *dirp;
+ struct dirent *dp;
+ char *name_space;
+ char *namep;
+
+ dirp = opendir (dir);
+ if (dirp == NULL)
+ return NULL;
+
+ name_space = (char *) malloc (name_size);
+ if (name_space == NULL)
+ {
+ closedir (dirp);
+ return NULL;
+ }
+ namep = name_space;
+
+ while ((dp = readdir (dirp)) != NULL)
+ {
+ /* Skip "." and ".." (some NFS filesystems' directories lack them). */
+ if (dp->d_name[0] != '.'
+ || (dp->d_name[1] != '\0'
+ && (dp->d_name[1] != '.' || dp->d_name[2] != '\0')))
+ {
+ unsigned size_needed = (namep - name_space) + NAMLEN (dp) + 2;
+
+ if (size_needed > name_size)
+ {
+ char *new_name_space;
+
+ while (size_needed > name_size)
+ name_size += 1024;
+
+ new_name_space = realloc (name_space, name_size);
+ if (new_name_space == NULL)
+ {
+ closedir (dirp);
+ return NULL;
+ }
+ namep += new_name_space - name_space;
+ name_space = new_name_space;
+ }
+ namep = stpcpy (namep, dp->d_name) + 1;
+ }
+ }
+ *namep = '\0';
+ if (CLOSEDIR (dirp))
+ {
+ free (name_space);
+ return NULL;
+ }
+ return name_space;
+}
diff --git a/lib/stpcpy.c b/lib/stpcpy.c
new file mode 100644
index 00000000..5ca0a2e3
--- /dev/null
+++ b/lib/stpcpy.c
@@ -0,0 +1,32 @@
+/* stpcpy.c -- copy a string and return pointer to end of new string
+ Copyright (C) 1989, 1990 Free Software Foundation.
+
+ 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. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */
+
+char *
+stpcpy (dest, src)
+ char *dest;
+ const char *src;
+{
+ while ((*dest++ = *src++) != '\0')
+ /* Do nothing. */ ;
+ return dest - 1;
+}
diff --git a/lib/strdup.c b/lib/strdup.c
new file mode 100644
index 00000000..1d60f139
--- /dev/null
+++ b/lib/strdup.c
@@ -0,0 +1,43 @@
+/* strdup.c -- return a newly allocated copy of a string
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef STDC_HEADERS
+#include <string.h>
+#include <stdlib.h>
+#else
+char *malloc ();
+char *strcpy ();
+#endif
+
+/* Return a newly allocated copy of STR,
+ or 0 if out of memory. */
+
+char *
+strdup (str)
+ const char *str;
+{
+ char *newstr;
+
+ newstr = (char *) malloc (strlen (str) + 1);
+ if (newstr)
+ strcpy (newstr, str);
+ return newstr;
+}
diff --git a/lib/strftime.c b/lib/strftime.c
new file mode 100644
index 00000000..484852a7
--- /dev/null
+++ b/lib/strftime.c
@@ -0,0 +1,469 @@
+/* strftime - custom formatting of date and/or time
+ Copyright (C) 1989, 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Note: this version of strftime lacks locale support,
+ but it is standalone.
+
+ Performs `%' substitutions similar to those in printf. Except
+ where noted, substituted fields have a fixed size; numeric fields are
+ padded if necessary. Padding is with zeros by default; for fields
+ that display a single number, padding can be changed or inhibited by
+ following the `%' with one of the modifiers described below. Unknown
+ field specifiers are copied as normal characters. All other
+ characters are copied to the output without change.
+
+ Supports a superset of the ANSI C field specifiers.
+
+ Literal character fields:
+ % %
+ n newline
+ t tab
+
+ Numeric modifiers (a nonstandard extension):
+ - do not pad the field
+ _ pad the field with spaces
+
+ Time fields:
+ %H hour (00..23)
+ %I hour (01..12)
+ %k hour ( 0..23)
+ %l hour ( 1..12)
+ %M minute (00..59)
+ %p locale's AM or PM
+ %r time, 12-hour (hh:mm:ss [AP]M)
+ %R time, 24-hour (hh:mm)
+ %s time in seconds since 00:00:00, Jan 1, 1970 (a nonstandard extension)
+ %S second (00..61)
+ %T time, 24-hour (hh:mm:ss)
+ %X locale's time representation (%H:%M:%S)
+ %Z time zone (EDT), or nothing if no time zone is determinable
+
+ Date fields:
+ %a locale's abbreviated weekday name (Sun..Sat)
+ %A locale's full weekday name, variable length (Sunday..Saturday)
+ %b locale's abbreviated month name (Jan..Dec)
+ %B locale's full month name, variable length (January..December)
+ %c locale's date and time (Sat Nov 04 12:02:33 EST 1989)
+ %C century (00..99)
+ %d day of month (01..31)
+ %e day of month ( 1..31)
+ %D date (mm/dd/yy)
+ %h same as %b
+ %j day of year (001..366)
+ %m month (01..12)
+ %U week number of year with Sunday as first day of week (00..53)
+ %w day of week (0..6)
+ %W week number of year with Monday as first day of week (00..53)
+ %x locale's date representation (mm/dd/yy)
+ %y last two digits of year (00..99)
+ %Y year (1970...)
+
+ David MacKenzie <djm@gnu.ai.mit.edu> */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#if defined(TM_IN_SYS_TIME) || (!defined(HAVE_TM_ZONE) && !defined(HAVE_TZNAME))
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+
+#ifndef STDC_HEADERS
+time_t mktime ();
+#endif
+
+#if defined(HAVE_TZNAME)
+extern char *tzname[2];
+#endif
+
+/* Types of padding for numbers in date and time. */
+enum padding
+{
+ none, blank, zero
+};
+
+static char const* const days[] =
+{
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
+};
+
+static char const * const months[] =
+{
+ "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December"
+};
+
+/* Add character C to STRING and increment LENGTH,
+ unless LENGTH would exceed MAX. */
+
+#define add_char(c) \
+ do \
+ { \
+ if (length + 1 <= max) \
+ string[length++] = (c); \
+ } \
+ while (0)
+
+/* Add a 2 digit number to STRING, padding if specified.
+ Return the number of characters added, up to MAX. */
+
+static int
+add_num2 (string, num, max, pad)
+ char *string;
+ int num;
+ int max;
+ enum padding pad;
+{
+ int top = num / 10;
+ int length = 0;
+
+ if (top == 0 && pad == blank)
+ add_char (' ');
+ else if (top != 0 || pad == zero)
+ add_char (top + '0');
+ add_char (num % 10 + '0');
+ return length;
+}
+
+/* Add a 3 digit number to STRING, padding if specified.
+ Return the number of characters added, up to MAX. */
+
+static int
+add_num3 (string, num, max, pad)
+ char *string;
+ int num;
+ int max;
+ enum padding pad;
+{
+ int top = num / 100;
+ int mid = (num - top * 100) / 10;
+ int length = 0;
+
+ if (top == 0 && pad == blank)
+ add_char (' ');
+ else if (top != 0 || pad == zero)
+ add_char (top + '0');
+ if (mid == 0 && top == 0 && pad == blank)
+ add_char (' ');
+ else if (mid != 0 || top != 0 || pad == zero)
+ add_char (mid + '0');
+ add_char (num % 10 + '0');
+ return length;
+}
+
+/* Like strncpy except return the number of characters copied. */
+
+static int
+add_str (to, from, max)
+ char *to;
+ const char *from;
+ int max;
+{
+ int i;
+
+ for (i = 0; from[i] && i <= max; ++i)
+ to[i] = from[i];
+ return i;
+}
+
+static int
+add_num_time_t (string, max, num)
+ char *string;
+ int max;
+ time_t num;
+{
+ /* This buffer is large enough to hold the character representation
+ (including the trailing NUL) of any unsigned decimal quantity
+ whose binary representation fits in 128 bits. */
+ char buf[40];
+ int length;
+
+ if (sizeof (num) > 16)
+ abort ();
+ sprintf (buf, "%lu", (unsigned long) num);
+ length = add_str (string, buf, max);
+ return length;
+}
+
+/* Return the week in the year of the time in TM, with the weeks
+ starting on Sundays. */
+
+static int
+sun_week (tm)
+ struct tm *tm;
+{
+ int dl;
+
+ /* Set `dl' to the day in the year of the last day of the week previous
+ to the one containing the day specified in TM. If the day specified
+ in TM is in the first week of the year, `dl' will be negative or 0.
+ Otherwise, calculate the number of complete weeks before our week
+ (dl / 7) and add any partial week at the start of the year (dl % 7). */
+ dl = tm->tm_yday - tm->tm_wday;
+ return dl <= 0 ? 0 : dl / 7 + (dl % 7 != 0);
+}
+
+/* Return the week in the year of the time in TM, with the weeks
+ starting on Mondays. */
+
+static int
+mon_week (tm)
+ struct tm *tm;
+{
+ int dl, wday;
+
+ if (tm->tm_wday == 0)
+ wday = 6;
+ else
+ wday = tm->tm_wday - 1;
+ dl = tm->tm_yday - wday;
+ return dl <= 0 ? 0 : dl / 7 + (dl % 7 != 0);
+}
+
+#if !defined(HAVE_TM_ZONE) && !defined(HAVE_TZNAME)
+char *
+zone_name (tp)
+ struct tm *tp;
+{
+ char *timezone ();
+ struct timeval tv;
+ struct timezone tz;
+
+ gettimeofday (&tv, &tz);
+ return timezone (tz.tz_minuteswest, tp->tm_isdst);
+}
+#endif
+
+/* Format the time given in TM according to FORMAT, and put the
+ results in STRING.
+ Return the number of characters (not including terminating null)
+ that were put into STRING, or 0 if the length would have
+ exceeded MAX. */
+
+size_t
+strftime (string, max, format, tm)
+ char *string;
+ size_t max;
+ const char *format;
+ const struct tm *tm;
+{
+ enum padding pad; /* Type of padding to apply. */
+ size_t length = 0; /* Characters put in STRING so far. */
+
+ for (; *format && length < max; ++format)
+ {
+ if (*format != '%')
+ add_char (*format);
+ else
+ {
+ ++format;
+ /* Modifiers: */
+ if (*format == '-')
+ {
+ pad = none;
+ ++format;
+ }
+ else if (*format == '_')
+ {
+ pad = blank;
+ ++format;
+ }
+ else
+ pad = zero;
+
+ switch (*format)
+ {
+ /* Literal character fields: */
+ case 0:
+ case '%':
+ add_char ('%');
+ break;
+ case 'n':
+ add_char ('\n');
+ break;
+ case 't':
+ add_char ('\t');
+ break;
+ default:
+ add_char (*format);
+ break;
+
+ /* Time fields: */
+ case 'H':
+ case 'k':
+ length +=
+ add_num2 (&string[length], tm->tm_hour, max - length,
+ *format == 'H' ? pad : blank);
+ break;
+ case 'I':
+ case 'l':
+ {
+ int hour12;
+
+ if (tm->tm_hour == 0)
+ hour12 = 12;
+ else if (tm->tm_hour > 12)
+ hour12 = tm->tm_hour - 12;
+ else
+ hour12 = tm->tm_hour;
+ length +=
+ add_num2 (&string[length], hour12, max - length,
+ *format == 'I' ? pad : blank);
+ }
+ break;
+ case 'M':
+ length +=
+ add_num2 (&string[length], tm->tm_min, max - length, pad);
+ break;
+ case 'p':
+ if (tm->tm_hour < 12)
+ add_char ('A');
+ else
+ add_char ('P');
+ add_char ('M');
+ break;
+ case 'r':
+ length +=
+ strftime (&string[length], max - length, "%I:%M:%S %p", tm);
+ break;
+ case 'R':
+ length +=
+ strftime (&string[length], max - length, "%H:%M", tm);
+ break;
+
+ case 's':
+ {
+ struct tm writable_tm;
+ writable_tm = *tm;
+ length += add_num_time_t (&string[length], max - length,
+ mktime (&writable_tm));
+ }
+ break;
+
+ case 'S':
+ length +=
+ add_num2 (&string[length], tm->tm_sec, max - length, pad);
+ break;
+ case 'T':
+ length +=
+ strftime (&string[length], max - length, "%H:%M:%S", tm);
+ break;
+ case 'X':
+ length +=
+ strftime (&string[length], max - length, "%H:%M:%S", tm);
+ break;
+ case 'Z':
+#ifdef HAVE_TM_ZONE
+ length += add_str (&string[length], tm->tm_zone, max - length);
+#else
+#ifdef HAVE_TZNAME
+ if (tm->tm_isdst && tzname[1] && *tzname[1])
+ length += add_str (&string[length], tzname[1], max - length);
+ else
+ length += add_str (&string[length], tzname[0], max - length);
+#else
+ length += add_str (&string[length], zone_name (tm), max - length);
+#endif
+#endif
+ break;
+
+ /* Date fields: */
+ case 'a':
+ add_char (days[tm->tm_wday][0]);
+ add_char (days[tm->tm_wday][1]);
+ add_char (days[tm->tm_wday][2]);
+ break;
+ case 'A':
+ length +=
+ add_str (&string[length], days[tm->tm_wday], max - length);
+ break;
+ case 'b':
+ case 'h':
+ add_char (months[tm->tm_mon][0]);
+ add_char (months[tm->tm_mon][1]);
+ add_char (months[tm->tm_mon][2]);
+ break;
+ case 'B':
+ length +=
+ add_str (&string[length], months[tm->tm_mon], max - length);
+ break;
+ case 'c':
+ length +=
+ strftime (&string[length], max - length,
+ "%a %b %d %H:%M:%S %Z %Y", tm);
+ break;
+ case 'C':
+ length +=
+ add_num2 (&string[length], (tm->tm_year + 1900) / 100,
+ max - length, pad);
+ break;
+ case 'd':
+ length +=
+ add_num2 (&string[length], tm->tm_mday, max - length, pad);
+ break;
+ case 'e':
+ length +=
+ add_num2 (&string[length], tm->tm_mday, max - length, blank);
+ break;
+ case 'D':
+ length +=
+ strftime (&string[length], max - length, "%m/%d/%y", tm);
+ break;
+ case 'j':
+ length +=
+ add_num3 (&string[length], tm->tm_yday + 1, max - length, pad);
+ break;
+ case 'm':
+ length +=
+ add_num2 (&string[length], tm->tm_mon + 1, max - length, pad);
+ break;
+ case 'U':
+ length +=
+ add_num2 (&string[length], sun_week (tm), max - length, pad);
+ break;
+ case 'w':
+ add_char (tm->tm_wday + '0');
+ break;
+ case 'W':
+ length +=
+ add_num2 (&string[length], mon_week (tm), max - length, pad);
+ break;
+ case 'x':
+ length +=
+ strftime (&string[length], max - length, "%m/%d/%y", tm);
+ break;
+ case 'y':
+ length +=
+ add_num2 (&string[length], tm->tm_year % 100,
+ max - length, pad);
+ break;
+ case 'Y':
+ add_char ((tm->tm_year + 1900) / 1000 + '0');
+ length +=
+ add_num3 (&string[length],
+ (1900 + tm->tm_year) % 1000, max - length, zero);
+ break;
+ }
+ }
+ }
+ add_char (0);
+ return length - 1;
+}
diff --git a/lib/strspn.c b/lib/strspn.c
index 53f3a1fd..01d8d0fc 100644
--- a/lib/strspn.c
+++ b/lib/strspn.c
@@ -1,24 +1,25 @@
/* strspn.c -- return numbers of chars at start of string in a class
- Copyright (C) 1987, 1990, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1990 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
+ 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 3 of the License, or
- (at your option) any later version.
-
+ 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, see <http://www.gnu.org/licenses/>.
-*/
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#ifdef HAVE_CONFIG_H
#include <config.h>
+#endif
-
-#if defined HAVE_STRING_H
+#if defined(HAVE_STRING_H)
#include <string.h>
#else
#include <strings.h>
@@ -27,7 +28,6 @@
#endif
#endif
-#if !defined(HAVE_STRSPN)
int
strspn (str, class)
char *str, *class;
@@ -38,4 +38,3 @@ strspn (str, class)
++st;
return st - str;
}
-#endif
diff --git a/lib/strstr.c b/lib/strstr.c
new file mode 100644
index 00000000..16b748b6
--- /dev/null
+++ b/lib/strstr.c
@@ -0,0 +1,44 @@
+/* strstr.c -- return the offset of one string within another
+ Copyright (C) 1989, 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Mike Rendell <michael@cs.mun.ca>. */
+
+/* Return the starting address of string S2 in S1;
+ return 0 if it is not found. */
+
+char *
+strstr (s1, s2)
+ char *s1;
+ char *s2;
+{
+ int i;
+ char *p1;
+ char *p2;
+ char *s = s1;
+
+ for (p2 = s2, i = 0; *s; p2 = s2, i++, s++)
+ {
+ for (p1 = s; *p1 && *p2 && *p1 == *p2; p1++, p2++)
+ ;
+ if (!*p2)
+ break;
+ }
+ if (!*p2)
+ return s1 + i;
+
+ return 0;
+}
diff --git a/lib/strtol.c b/lib/strtol.c
new file mode 100644
index 00000000..08ef0a47
--- /dev/null
+++ b/lib/strtol.c
@@ -0,0 +1,186 @@
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifndef ULONG_MAX
+#define ULONG_MAX ((unsigned long) ~(unsigned long) 0)
+#endif
+
+#ifndef LONG_MAX
+#define LONG_MAX (~(1 << (sizeof (long) * 8 - 1)))
+#endif
+
+#ifndef LONG_MIN
+#define LONG_MIN (-LONG_MAX - 1)
+#endif
+
+#if STDC_HEADERS
+#include <stddef.h>
+#include <stdlib.h>
+#else
+#define NULL 0
+extern int errno;
+#endif
+
+#ifndef UNSIGNED
+#define UNSIGNED 0
+#endif
+
+/* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
+ If BASE is 0 the base is determined by the presence of a leading
+ zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
+ If BASE is < 2 or > 36, it is reset to 10.
+ If ENDPTR is not NULL, a pointer to the character after the last
+ one converted is stored in *ENDPTR. */
+#if UNSIGNED
+unsigned long int
+#define strtol strtoul
+#else
+long int
+#endif
+strtol (nptr, endptr, base)
+ const char *nptr;
+ char **endptr;
+ int base;
+{
+ int negative;
+ register unsigned long int cutoff;
+ register unsigned int cutlim;
+ register unsigned long int i;
+ register const char *s;
+ register unsigned char c;
+ const char *save;
+ int overflow;
+
+ if (base < 0 || base == 1 || base > 36)
+ base = 10;
+
+ s = nptr;
+
+ /* Skip white space. */
+ while (isspace (*s))
+ ++s;
+ if (*s == '\0')
+ goto noconv;
+
+ /* Check for a sign. */
+ if (*s == '-')
+ {
+ negative = 1;
+ ++s;
+ }
+ else if (*s == '+')
+ {
+ negative = 0;
+ ++s;
+ }
+ else
+ negative = 0;
+
+ if (base == 16 && s[0] == '0' && toupper (s[1]) == 'X')
+ s += 2;
+
+ /* If BASE is zero, figure it out ourselves. */
+ if (base == 0)
+ {
+ if (*s == '0')
+ {
+ if (toupper (s[1]) == 'X')
+ {
+ s += 2;
+ base = 16;
+ }
+ else
+ base = 8;
+ }
+ else
+ base = 10;
+ }
+
+ /* Save the pointer so we can check later if anything happened. */
+ save = s;
+
+ cutoff = ULONG_MAX / (unsigned long int) base;
+ cutlim = ULONG_MAX % (unsigned long int) base;
+
+ overflow = 0;
+ i = 0;
+ for (c = *s; c != '\0'; c = *++s)
+ {
+ if (isdigit (c))
+ c -= '0';
+ else if (isalpha (c))
+ c = toupper (c) - 'A' + 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ /* Check for overflow. */
+ if (i > cutoff || (i == cutoff && c > cutlim))
+ overflow = 1;
+ else
+ {
+ i *= (unsigned long int) base;
+ i += c;
+ }
+ }
+
+ /* Check if anything actually happened. */
+ if (s == save)
+ goto noconv;
+
+ /* Store in ENDPTR the address of one character
+ past the last character we converted. */
+ if (endptr != NULL)
+ *endptr = (char *) s;
+
+#if !UNSIGNED
+ /* Check for a value that is within the range of
+ `unsigned long int', but outside the range of `long int'. */
+ if (i > (negative ?
+ -(unsigned long int) LONG_MIN : (unsigned long int) LONG_MAX))
+ overflow = 1;
+#endif
+
+ if (overflow)
+ {
+ errno = ERANGE;
+#if UNSIGNED
+ return ULONG_MAX;
+#else
+ return negative ? LONG_MIN : LONG_MAX;
+#endif
+ }
+
+ /* Return the result of the appropriate sign. */
+ return (negative ? -i : i);
+
+noconv:;
+ /* There was no number to convert. */
+ if (endptr != NULL)
+ *endptr = (char *) nptr;
+ return 0L;
+}
diff --git a/lib/wait.h b/lib/wait.h
index 94ccd434..b6652886 100644
--- a/lib/wait.h
+++ b/lib/wait.h
@@ -1,19 +1,20 @@
/* wait.h -- POSIX macros for evaluating exit statuses
Copyright (C) 1990 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
+ 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 3 of the License, or
- (at your option) any later version.
-
+ 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, see <http://www.gnu.org/licenses/>.
-*/
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
#include <sys/types.h> /* For pid_t. */
#if HAVE_SYS_WAIT_H
#include <sys/wait.h>
diff --git a/lib/xgetcwd.c b/lib/xgetcwd.c
new file mode 100644
index 00000000..1c1a7bd7
--- /dev/null
+++ b/lib/xgetcwd.c
@@ -0,0 +1,78 @@
+/* xgetcwd.c -- return current directory with unlimited length
+ Copyright (C) 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+#include <sys/types.h>
+#include "pathmax.h"
+
+#ifndef HAVE_GETCWD
+char *getwd ();
+#define getcwd(buf, max) getwd (buf)
+#else
+char *getcwd ();
+#endif
+
+/* Amount to increase buffer size by in each try. */
+#define PATH_INCR 32
+
+char *xmalloc ();
+char *xrealloc ();
+void free ();
+
+/* Return the current directory, newly allocated, arbitrarily long.
+ Return NULL and set errno on error. */
+
+char *
+xgetcwd ()
+{
+ char *cwd;
+ char *ret;
+ unsigned path_max;
+
+ errno = 0;
+ path_max = (unsigned) PATH_MAX;
+ path_max += 2; /* The getcwd docs say to do this. */
+
+ cwd = xmalloc (path_max);
+
+ errno = 0;
+ while ((ret = getcwd (cwd, path_max)) == NULL && errno == ERANGE)
+ {
+ path_max += PATH_INCR;
+ cwd = xrealloc (cwd, path_max);
+ errno = 0;
+ }
+
+ if (ret == NULL)
+ {
+ int save_errno = errno;
+ free (cwd);
+ errno = save_errno;
+ return NULL;
+ }
+ return cwd;
+}
diff --git a/lib/xmalloc.c b/lib/xmalloc.c
new file mode 100644
index 00000000..9f701111
--- /dev/null
+++ b/lib/xmalloc.c
@@ -0,0 +1,95 @@
+/* xmalloc.c -- malloc with out of memory checking
+ Copyright (C) 1990, 91, 92, 93, 94 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. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if __STDC__
+#define VOID void
+#else
+#define VOID char
+#endif
+
+#include <sys/types.h>
+
+#if STDC_HEADERS
+#include <stdlib.h>
+#else
+VOID *malloc ();
+VOID *realloc ();
+void free ();
+#endif
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
+
+/* Exit value when the requested amount of memory is not available.
+ The caller may set it to some other value. */
+int xmalloc_exit_failure = EXIT_FAILURE;
+
+#if __STDC__ && (HAVE_VPRINTF || HAVE_DOPRNT)
+void error (int, int, const char *, ...);
+#else
+void error ();
+#endif
+
+static VOID *
+fixup_null_alloc (n)
+ size_t n;
+{
+ VOID *p;
+
+ p = 0;
+ if (n == 0)
+ p = malloc ((size_t) 1);
+ if (p == 0)
+ error (xmalloc_exit_failure, 0, "memory exhausted");
+ return p;
+}
+
+/* Allocate N bytes of memory dynamically, with error checking. */
+
+VOID *
+xmalloc (n)
+ size_t n;
+{
+ VOID *p;
+
+ p = malloc (n);
+ if (p == 0)
+ p = fixup_null_alloc (n);
+ return p;
+}
+
+/* Change the size of an allocated block of memory P to N bytes,
+ with error checking.
+ If P is NULL, run xmalloc. */
+
+VOID *
+xrealloc (p, n)
+ VOID *p;
+ size_t n;
+{
+ if (p == 0)
+ return xmalloc (n);
+ p = realloc (p, n);
+ if (p == 0)
+ p = fixup_null_alloc (n);
+ return p;
+}
diff --git a/lib/xstrdup.c b/lib/xstrdup.c
new file mode 100644
index 00000000..27cd0c67
--- /dev/null
+++ b/lib/xstrdup.c
@@ -0,0 +1,36 @@
+/* xstrdup.c -- copy a string with out of memory checking
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+char *xmalloc ();
+
+/* Return a newly allocated copy of STRING. */
+
+char *
+xstrdup (string)
+ char *string;
+{
+ return strcpy (xmalloc (strlen (string) + 1), string);
+}
diff --git a/locate/Makefile.am b/locate/Makefile.am
index fd9f1f5a..93bd9088 100644
--- a/locate/Makefile.am
+++ b/locate/Makefile.am
@@ -1,58 +1,42 @@
# The default database to build and search.
-AUTOMAKE_OPTIONS = std-options
LOCATE_DB = $(localstatedir)/locatedb
-localedir = $(datadir)/locale
-AM_INSTALLCHECK_STD_OPTIONS_EXEMPT = \
- frcode$(EXEEXT) \
- code$(EXEEXT) \
- bigram$(EXEEXT)
-bin_PROGRAMS = locate
-libexec_PROGRAMS = frcode code bigram
-bin_SCRIPTS = updatedb
-man_MANS = locate.1 updatedb.1 locatedb.5
-BUILT_SOURCES = dblocation.texi
-EXTRA_DIST = locatedb.h updatedb.sh $(man_MANS)
-CLEANFILES = updatedb dblocation.texi
-locate_SOURCES = locate.c word_io.c
-code_SOURCES = code.c word_io.c
+PROGRAMS = locate
+LIBPROGRAMS = frcode code bigram
+SCRIPTS = updatedb
+MANS = locate.1 updatedb.1 locatedb.5
+CONFIG_HEADER = ../config.h
-INCLUDES = -I$(top_srcdir)/lib -I../gnulib/lib -I$(top_srcdir)/gnulib/lib -I../intl -DLOCATE_DB=\"$(LOCATE_DB)\" -DLOCALEDIR=\"$(localedir)\"
+DIST_OTHER = locatedb.h updatedb.sh
+CLEANFILES = updatedb
-LDADD = ../lib/libfind.a ../gnulib/lib/libgnulib.a @INTLLIBS@
+INCLUDES = -I.. -I$(top_srcdir)/lib -DLOCATE_DB=\"$(LOCATE_DB)\"
-$(PROGRAMS) $(LIBPROGRAMS): ../lib/libfind.a ../gnulib/lib/libgnulib.a
+LDADD = ../find/version.o ../lib/libfind.a
+
+$(PROGRAMS) $(LIBPROGRAMS): ../find/version.o ../lib/libfind.a
updatedb: updatedb.sh
rm -f $@
+ version=`sed -e '/version_string/!d' -e 's/[^0-9.]*\([0-9.]*\).*/\1/' -e q $(top_srcdir)/find/version.c`; \
find=`echo find|sed '$(transform)'`; \
frcode=`echo frcode|sed '$(transform)'`; \
bigram=`echo bigram|sed '$(transform)'`; \
code=`echo code|sed '$(transform)'`; \
sed \
- -e "s,@""bindir""@,$(bindir)," \
- -e "s,@""libexecdir""@,$(libexecdir)," \
- -e "s,@""LOCATE_DB""@,$(LOCATE_DB)," \
- -e "s,@""VERSION""@,@VERSION@," \
- -e "s,@""PACKAGE_NAME""@,@PACKAGE_NAME@," \
- -e "s,@""find""@,$${find}," \
- -e "s,@""frcode""@,$${frcode}," \
- -e "s,@""bigram""@,$${bigram}," \
- -e "s,@""code""@,$${code}," \
- -e "s,@""SORT""@,$(SORT)," \
- -e "s,@""SORT_SUPPORTS_Z""@,$(SORT_SUPPORTS_Z)," \
+ -e "s,@bindir@,$(bindir)," \
+ -e "s,@libexecdir@,$(libexecdir)," \
+ -e "s,@LOCATE_DB@,$(LOCATE_DB)," \
+ -e "s,@version@,$$version," \
+ -e "s,@find@,$$find," \
+ -e "s,@frcode@,$$frcode," \
+ -e "s,@bigram@,$$bigram," \
+ -e "s,@code@,$$code," \
$(srcdir)/updatedb.sh > $@
chmod +x $@
-install-data-hook:
- $(top_srcdir)/build-aux/mkinstalldirs $(DESTDIR)$(localstatedir)
-
-dblocation.texi: Makefile
- echo '@set LOCATE_DB $(LOCATE_DB)' > $@
-
-SUBDIRS = . testsuite
-
-dist-hook: findutils-check-manpages
+install::
+ $(top_srcdir)/mkinstalldirs $(localstatedir)
-findutils-check-manpages:
- $(top_srcdir)/build-aux/man-lint.sh $(srcdir) $(man_MANS)
+frcode.o code.o locate.o: locatedb.h
+locate.o: ../lib/fnmatch.h ../lib/getopt.h
diff --git a/locate/Makefile.in b/locate/Makefile.in
new file mode 100644
index 00000000..5e1d6d4b
--- /dev/null
+++ b/locate/Makefile.in
@@ -0,0 +1,222 @@
+# Makefile.in generated automatically by automake from Makefile.am.
+# Copyright (C) 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = $(exec_prefix)/bin
+sbindir = $(exec_prefix)/sbin
+libexecdir = $(exec_prefix)/libexec
+datadir = $(prefix)/share
+sysconfdir = $(prefix)/etc
+sharedstatedir = $(prefix)/com
+localstatedir = $(prefix)/var
+libdir = $(exec_prefix)/lib
+infodir = $(prefix)/info
+mandir = $(prefix)/man
+includedir = $(prefix)/include
+oldincludedir = /usr/include
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+transform = @program_transform_name@
+
+ALL = ${PROGRAMS} ${LIBPROGRAMS} ${SCRIPTS} ${LIBSCRIPTS} ${LIBFILES}
+CC = @CC@
+LEX = @LEX@
+YACC = @YACC@
+ANSI2KNR = ./ansi2knr
+
+DEFS = @DEFS@
+CPPFLAGS = @CPPFLAGS@
+CFLAGS = @CFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+
+locate_SOURCES = locate.c
+locate_OBJECTS = locate.o
+frcode_SOURCES = frcode.c
+frcode_OBJECTS = frcode.o
+code_SOURCES = code.c
+code_OBJECTS = code.o
+bigram_SOURCES = bigram.c
+bigram_OBJECTS = bigram.o
+NROFF = nroff
+
+SOURCES = locate.c frcode.c code.c bigram.c
+DIST_CONF = Makefile.am Makefile.in
+DIST_FILES = $(DIST_CONF) $(SOURCES) $(TEXINFOS) $(INFOS) $(MANS) $(DIST_OTHER)
+
+# The default database to build and search.
+LOCATE_DB = $(localstatedir)/locatedb
+
+PROGRAMS = locate
+LIBPROGRAMS = frcode code bigram
+SCRIPTS = updatedb
+MANS = locate.1 updatedb.1 locatedb.5
+CONFIG_HEADER = ../config.h
+
+DIST_OTHER = locatedb.h updatedb.sh
+CLEANFILES = updatedb
+
+INCLUDES = -I.. -I$(top_srcdir)/lib -DLOCATE_DB=\"$(LOCATE_DB)\"
+
+LDADD = ../find/version.o ../lib/libfind.a
+
+all:: ${ALL}
+
+.c.o:
+ $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $<
+
+$(locate_OBJECTS): ../config.h
+$(frcode_OBJECTS): ../config.h
+$(code_OBJECTS): ../config.h
+$(bigram_OBJECTS): ../config.h
+install:: install-programs
+
+install-programs: $(PROGRAMS) $(SCRIPTS)
+ $(top_srcdir)/mkinstalldirs $(bindir)
+ for p in $(PROGRAMS) $(SCRIPTS); do \
+ $(INSTALL_PROGRAM) $$p $(bindir)/`echo $$p|sed '$(transform)'`; \
+ done
+
+uninstall:: uninstall-programs
+
+uninstall-programs:
+ for p in $(PROGRAMS) $(SCRIPTS); do \
+ rm -f $(bindir)/`echo $$p|sed '$(transform)'`; \
+ done
+
+install:: install-libprograms
+
+install-libprograms: $(LIBPROGRAMS) $(LIBSCRIPTS)
+ $(top_srcdir)/mkinstalldirs $(libexecdir)
+ for p in $(LIBPROGRAMS) $(LIBSCRIPTS); do \
+ $(INSTALL_PROGRAM) $$p $(libexecdir)/`echo $$p|sed '$(transform)'`; \
+ done
+
+uninstall:: uninstall-libprograms
+
+uninstall-libprograms:
+ for p in $(LIBPROGRAMS) $(LIBSCRIPTS); do \
+ rm -f $(libexecdir)/`echo $$p|sed '$(transform)'`; \
+ done
+
+locate: $(locate_OBJECTS)
+ $(CC) -o $@ $(locate_OBJECTS) $(LDADD) $(LDFLAGS) $(LIBS)
+
+frcode: $(frcode_OBJECTS)
+ $(CC) -o $@ $(frcode_OBJECTS) $(LDADD) $(LDFLAGS) $(LIBS)
+
+code: $(code_OBJECTS)
+ $(CC) -o $@ $(code_OBJECTS) $(LDADD) $(LDFLAGS) $(LIBS)
+
+bigram: $(bigram_OBJECTS)
+ $(CC) -o $@ $(bigram_OBJECTS) $(LDADD) $(LDFLAGS) $(LIBS)
+
+install:: install-man
+
+install-man:
+ for man in $(MANS); do \
+ sect=`echo $$man|sed 's%.*\.\([0-9][a-z]*\)$$%\1%'`; \
+ inst=`basename $$man $$sect|sed '$(transform)'`$$sect; \
+ mdir=$(mandir)/man$$sect; \
+ $(top_srcdir)/mkinstalldirs $$mdir; \
+ echo installing $$man as $$mdir/$$inst; \
+ $(INSTALL_DATA) $(srcdir)/$$man $$mdir/$$inst; \
+ cdir=$(mandir)/cat$$sect; \
+ if test -d $$cdir; then \
+ echo formatting $$man as $$cdir/$$inst; \
+ $(NROFF) -man $(srcdir)/$$man > $$cdir/$$inst; \
+ fi; \
+ done
+
+uninstall:: uninstall-man
+
+uninstall-man:
+ for man in $(MANS); do \
+ sect=`echo $$man|sed 's%.*\(\.[0-9][a-z]*\)$$%\1%'; \
+ inst=`basename $$man $sect|sed '$(transform)'`.$$sect; \
+ mdir=$(mandir)/man$$sect; \
+ cdir=$(mandir)/cat$$sect; \
+ rm -f $$mdir/$$inst $$cdir/$$inst; \
+ done
+
+mostlyclean:
+ rm -f *.o core
+
+clean: mostlyclean
+ rm -f $(PROGRAMS) $(LIBPROGRAMS) $(LIBFILES) $(TEXFILES) $(CLEANFILES)
+
+distclean: clean
+ rm -f Makefile *.tab.c $(DISTCLEANFILES)
+ rm -f config.cache config.log config.status ${CONFIG_HEADER} stamp-h
+
+realclean: distclean
+ rm -f TAGS $(INFOS)
+
+dist: $(DIST_FILES) $(DIST_DIRS)
+ -mkdir ../`cat ../distname`/$(subdir)
+ @for file in $(DIST_FILES); do \
+ echo linking $$file; \
+ ln $(srcdir)/$$file ../`cat ../distname`/$(subdir)/$$file || \
+ { echo copying $$file instead; cp -p $(srcdir)/$$file ../`cat ../distname`/$(subdir)/$$file;}; \
+ done
+
+check dvi info install uninstall::
+
+tags:: TAGS
+
+TAGS::
+ cd $(srcdir); etags $(SOURCES)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
+
+$(PROGRAMS) $(LIBPROGRAMS): ../find/version.o ../lib/libfind.a
+
+updatedb: updatedb.sh
+ rm -f $@
+ version=`sed -e '/version_string/!d' -e 's/[^0-9.]*\([0-9.]*\).*/\1/' -e q $(top_srcdir)/find/version.c`; \
+ find=`echo find|sed '$(transform)'`; \
+ frcode=`echo frcode|sed '$(transform)'`; \
+ bigram=`echo bigram|sed '$(transform)'`; \
+ code=`echo code|sed '$(transform)'`; \
+ sed \
+ -e "s,@bindir@,$(bindir)," \
+ -e "s,@libexecdir@,$(libexecdir)," \
+ -e "s,@LOCATE_DB@,$(LOCATE_DB)," \
+ -e "s,@version@,$$version," \
+ -e "s,@find@,$$find," \
+ -e "s,@frcode@,$$frcode," \
+ -e "s,@bigram@,$$bigram," \
+ -e "s,@code@,$$code," \
+ $(srcdir)/updatedb.sh > $@
+ chmod +x $@
+
+install::
+ $(top_srcdir)/mkinstalldirs $(localstatedir)
+
+frcode.o code.o locate.o: locatedb.h
+locate.o: ../lib/fnmatch.h ../lib/getopt.h
diff --git a/locate/bigram.c b/locate/bigram.c
index c9d76cbe..ed04a81c 100644
--- a/locate/bigram.c
+++ b/locate/bigram.c
@@ -1,19 +1,19 @@
/* bigram -- list bigrams for locate
- Copyright (C) 1994, 2007 Free Software Foundation, Inc.
+ Copyright (C) 1994 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
+ 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 3 of the License, or
- (at your option) any later version.
-
+ 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, see <http://www.gnu.org/licenses/>.
-*/
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Usage: bigram < text > bigrams
Use `code' to encode a file using this output.
@@ -32,7 +32,7 @@
#include <config.h>
#include <stdio.h>
-#if defined HAVE_STRING_H || defined STDC_HEADERS
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
#include <string.h>
#else
#include <strings.h>
@@ -43,8 +43,7 @@
#endif
#include <sys/types.h>
-#include <xalloc.h>
-#include "closeout.h"
+char *xmalloc ();
/* The name this program was run with. */
char *program_name;
@@ -52,7 +51,8 @@ char *program_name;
/* Return the length of the longest common prefix of strings S1 and S2. */
static int
-prefix_length (char *s1, char *s2)
+prefix_length (s1, s2)
+ char *s1, *s2;
{
register char *start;
@@ -61,8 +61,10 @@ prefix_length (char *s1, char *s2)
return s1 - start;
}
-int
-main (int argc, char **argv)
+void
+main (argc, argv)
+ int argc;
+ char **argv;
{
char *path; /* The current input entry. */
char *oldpath; /* The previous input entry. */
@@ -70,17 +72,16 @@ main (int argc, char **argv)
int line_len; /* Length of input line. */
program_name = argv[0];
- (void) argc;
- atexit (close_stdout);
-
- pathsize = oldpathsize = 1026; /* Increased as necessary by getline. */
+
+ pathsize = oldpathsize = 1026; /* Increased as necessary by getstr. */
path = xmalloc (pathsize);
oldpath = xmalloc (oldpathsize);
- /* Set to empty string, to force the first prefix count to 0. */
- oldpath[0] = '\0';
+ /* Set to anything not starting with a slash, to force the first
+ prefix count to 0. */
+ strcpy (oldpath, " ");
- while ((line_len = getline (&path, &pathsize, stdin)) > 0)
+ while ((line_len = getstr (&path, &pathsize, stdin, '\n', 0)) > 0)
{
register int count; /* The prefix length. */
register int j; /* Index into input line. */
@@ -110,5 +111,5 @@ main (int argc, char **argv)
free (path);
free (oldpath);
- return 0;
+ exit (0);
}
diff --git a/locate/code.c b/locate/code.c
index f48885b6..d79e72ce 100644
--- a/locate/code.c
+++ b/locate/code.c
@@ -1,19 +1,19 @@
/* code -- bigram- and front-encode filenames for locate
- Copyright (C) 1994, 2005, 2007 Free Software Foundation, Inc.
+ Copyright (C) 1994 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
+ 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 3 of the License, or
- (at your option) any later version.
-
+ 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, see <http://www.gnu.org/licenses/>.
-*/
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Compress a sorted list.
Works with `find' to encode a filename database to save space
@@ -37,54 +37,32 @@
0-28 likeliest differential counts + offset (14) to make nonnegative
30 escape code for out-of-range count to follow in next halfword
- 128-255 bigram codes (the 128 most common, as determined by `updatedb')
- 32-127 single character (printable) ASCII remainder
+ 128-255 bigram codes (the 128 most common, as determined by `updatedb')
+ 32-127 single character (printable) ASCII remainder
Written by James A. Woods <jwoods@adobe.com>.
- Modified by David MacKenzie <djm@gnu.org>. */
+ Modified by David MacKenzie <djm@gnu.ai.mit.edu>. */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
-#include <string.h>
-#include <errno.h>
-#include <stdbool.h>
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
#ifdef STDC_HEADERS
#include <stdlib.h>
#endif
-#if ENABLE_NLS
-# include <libintl.h>
-# define _(Text) gettext (Text)
-#else
-# define _(Text) Text
-#define textdomain(Domain)
-#define bindtextdomain(Package, Directory)
-#endif
-#ifdef gettext_noop
-# define N_(String) gettext_noop (String)
-#else
-/* See locate.c for explanation as to why not use (String) */
-# define N_(String) String
-#endif
-
#include "locatedb.h"
-#include "closeout.h"
-#include "xalloc.h"
-#include "gnulib-version.h"
-#include "progname.h"
-#include "error.h"
-#include "findutils-version.h"
-
-#ifndef ATTRIBUTE_NORETURN
-# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
-#endif
+char *xmalloc ();
/* The name this program was run with. */
-const char *program_name;
+char *program_name;
/* The 128 most common bigrams in the file list, padded with NULs
if there are fewer. */
@@ -93,7 +71,8 @@ static char bigrams[257] = {0};
/* Return the offset of PATTERN in STRING, or -1 if not found. */
static int
-strindex (char *string, char *pattern)
+strindex (string, pattern)
+ char *string, *pattern;
{
register char *s;
@@ -113,7 +92,8 @@ strindex (char *string, char *pattern)
/* Return the length of the longest common prefix of strings S1 and S2. */
static int
-prefix_length (char *s1, char *s2)
+prefix_length (s1, s2)
+ char *s1, *s2;
{
register char *start;
@@ -122,41 +102,10 @@ prefix_length (char *s1, char *s2)
return s1 - start;
}
-extern char *version_string;
-
-static void
-usage (FILE *stream)
-{
- fprintf (stream, _("\
-Usage: %s [--version | --help]\n\
-or %s most_common_bigrams < file-list > locate-database\n"),
- program_name, program_name);
- fputs (_("\nReport bugs to <bug-findutils@gnu.org>.\n"), stream);
-}
-
-
-static void inerr (const char *filename) ATTRIBUTE_NORETURN;
-static void outerr(void) ATTRIBUTE_NORETURN;
-
-static void
-inerr(const char *filename)
-{
- error(1, errno, "%s", filename);
- /*NOTREACHED*/
- abort();
-}
-
-static void
-outerr(void)
-{
- error(1, errno, _("write error"));
- /*NOTREACHED*/
- abort();
-}
-
-
-int
-main (int argc, char **argv)
+void
+main (argc, argv)
+ int argc;
+ char **argv;
{
char *path; /* The current input entry. */
char *oldpath; /* The previous input entry. */
@@ -167,56 +116,41 @@ main (int argc, char **argv)
FILE *fp; /* Most common bigrams file. */
int line_len; /* Length of input line. */
- set_program_name(argv[0]);
- atexit (close_stdout);
+ program_name = argv[0];
bigram[2] = '\0';
if (argc != 2)
{
- usage(stderr);
- return 2;
- }
-
- if (0 == strcmp(argv[1], "--help"))
- {
- usage(stdout);
- return 0;
- }
- else if (0 == strcmp(argv[1], "--version"))
- {
- display_findutils_version("code");
- return 0;
+ fprintf (stderr, "Usage: %s most_common_bigrams < list > coded_list\n",
+ argv[0]);
+ exit (2);
}
-
+
fp = fopen (argv[1], "r");
if (fp == NULL)
{
fprintf (stderr, "%s: ", argv[0]);
perror (argv[1]);
- return 1;
+ exit (1);
}
-
- pathsize = oldpathsize = 1026; /* Increased as necessary by getline. */
+
+ pathsize = oldpathsize = 1026; /* Increased as necessary by getstr. */
path = xmalloc (pathsize);
oldpath = xmalloc (oldpathsize);
- /* Set to empty string, to force the first prefix count to 0. */
- oldpath[0] = '\0';
+ /* Set to anything not starting with a slash, to force the first
+ prefix count to 0. */
+ strcpy (oldpath, " ");
oldcount = 0;
/* Copy the list of most common bigrams to the output,
padding with NULs if there are <128 of them. */
- if (NULL == fgets (bigrams, 257, fp))
- inerr(argv[1]);
-
- if (256 != fwrite (bigrams, 1, 256, stdout))
- outerr();
+ fgets (bigrams, 257, fp);
+ fwrite (bigrams, 1, 256, stdout);
+ fclose (fp);
- if (EOF == fclose (fp))
- inerr(argv[1]);
-
- while ((line_len = getline (&path, &pathsize, stdin)) > 0)
+ while ((line_len = getstr (&path, &pathsize, stdin, '\n', 0)) > 0)
{
char *pp;
@@ -225,7 +159,8 @@ main (int argc, char **argv)
/* Squelch unprintable chars in path so as not to botch decoding. */
for (pp = path; *pp != '\0'; pp++)
{
- if (!(*pp >= 040 && *pp < 0177))
+ *pp &= 0177;
+ if (*pp < 040 || *pp == 0177)
*pp = '?';
}
@@ -236,19 +171,11 @@ main (int argc, char **argv)
otherwise, two bytes plus a marker noting that fact. */
if (diffcount < -LOCATEDB_OLD_OFFSET || diffcount > LOCATEDB_OLD_OFFSET)
{
- if (EOF ==- putc (LOCATEDB_OLD_ESCAPE, stdout))
- outerr ();
-
- if (!putword (stdout,
- diffcount+LOCATEDB_OLD_OFFSET,
- GetwordEndianStateNative))
- outerr ();
+ putc (LOCATEDB_OLD_ESCAPE, stdout);
+ putw (diffcount + LOCATEDB_OLD_OFFSET, stdout);
}
else
- {
- if (EOF == putc (diffcount + LOCATEDB_OLD_OFFSET, stdout))
- outerr ();
- }
+ putc (diffcount + LOCATEDB_OLD_OFFSET, stdout);
/* Look for bigrams in the remainder of the path. */
for (pp = path + count; *pp != '\0'; pp += 2)
@@ -283,5 +210,5 @@ main (int argc, char **argv)
free (path);
free (oldpath);
- return 0;
+ exit (0);
}
diff --git a/locate/frcode.c b/locate/frcode.c
index 23f9369b..ac250c33 100644
--- a/locate/frcode.c
+++ b/locate/frcode.c
@@ -1,10 +1,10 @@
/* frcode -- front-compress a sorted list
- Copyright (C) 1994,2005,2006,2007 Free Software Foundation, Inc.
+ Copyright (C) 1994 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
+ 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 3 of the License, or
- (at your option) any later version.
+ 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
@@ -12,21 +12,22 @@
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, see <http://www.gnu.org/licenses/>.
-*/
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Usage: frcode < sorted-list > compressed-list
Uses front compression (also known as incremental encoding);
see ";login:", March 1983, p. 8.
- The input is a sorted list of NUL-terminated strings (or
- newline-terminated if the -0 option is not given).
+ The input is a sorted list of NUL-terminated strings.
+ (FIXME newline-terminated, until we figure out how to sort
+ NUL-terminated strings.)
- The output entries are in the same order as the input; each entry
- consists of a signed offset-differential count byte (the additional
- number of characters of prefix of the preceding entry to use beyond
- the number that the preceding entry is using of its predecessor),
+ The output entries are in the same order as the input;
+ each entry consists of an offset-differential count byte
+ (the additional number of characters of prefix of the preceding entry to
+ use beyond the number that the preceding entry is using of its predecessor),
followed by a null-terminated ASCII remainder.
If the offset-differential count is larger than can be stored
@@ -58,21 +59,13 @@
(6 = 14 - 8, and -9 = 5 - 14)
Written by James A. Woods <jwoods@adobe.com>.
- Modified by David MacKenzie <djm@gnu.org>.
- Modified by James Youngman <jay@gnu.org>.
-*/
+ Modified by David MacKenzie <djm@gnu.ai.mit.edu>. */
#include <config.h>
-
-
#include <stdio.h>
-#include <limits.h>
-#include <assert.h>
-#include <errno.h>
#include <sys/types.h>
-#include <stdbool.h>
-#if defined HAVE_STRING_H || defined STDC_HEADERS
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
#include <string.h>
#else
#include <strings.h>
@@ -82,282 +75,96 @@
#include <stdlib.h>
#endif
-#if ENABLE_NLS
-# include <libintl.h>
-# define _(Text) gettext (Text)
-#else
-# define _(Text) Text
-#define textdomain(Domain)
-#define bindtextdomain(Package, Directory)
-#endif
-#ifdef gettext_noop
-# define N_(String) gettext_noop (String)
-#else
-/* We used to use (String) instead of just String, but apparently ISO C
- * doesn't allow this (at least, that's what HP said when someone reported
- * this as a compiler bug). This is HP case number 1205608192. See
- * also http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11250 (which references
- * ANSI 3.5.7p14-15). The Intel icc compiler also rejects constructs
- * like: static const char buf[] = ("string");
- */
-# define N_(String) String
-#endif
-
-
#include "locatedb.h"
-#include <getopt.h>
-#include "error.h"
-#include "closeout.h"
-#include "findutils-version.h"
-char *xmalloc PARAMS((size_t));
+char *xmalloc ();
/* The name this program was run with. */
char *program_name;
-/* Write out a 16-bit int, high byte first (network byte order).
- * Return true iff all went well.
- */
-static int
-put_short (int c, FILE *fp)
+/* Write out a 16-bit int, high byte first (network byte order). */
+
+static void
+put_short (c, fp)
+ int c;
+ FILE *fp;
{
- /* XXX: The value of c may be negative. ANSI C 1989 (section 6.3.7)
- * indicates that the result of shifting a negative value right is
- * implementation defined.
- */
- assert (c <= SHRT_MAX);
- assert (c >= SHRT_MIN);
- return (putc (c >> 8, fp) != EOF) && (putc (c, fp) != EOF);
+ putc (c >> 8, fp);
+ putc (c, fp);
}
/* Return the length of the longest common prefix of strings S1 and S2. */
static int
-prefix_length (char *s1, char *s2)
+prefix_length (s1, s2)
+ char *s1, *s2;
{
register char *start;
- int limit = INT_MAX;
+
for (start = s1; *s1 == *s2 && *s1 != '\0'; s1++, s2++)
- {
- /* Don't emit a prefix length that will not fit into
- * our return type.
- */
- if (0 == --limit)
- break;
- }
+ ;
return s1 - start;
}
-static struct option const longopts[] =
-{
- {"help", no_argument, NULL, 'h'},
- {"version", no_argument, NULL, 'v'},
- {"null", no_argument, NULL, '0'},
- {NULL, no_argument, NULL, 0}
-};
-
-extern char *version_string;
-
-/* The name this program was run with. */
-char *program_name;
-
-
-static void
-usage (FILE *stream)
-{
- fprintf (stream,
- _("Usage: %s [-0 | --null] [--version] [--help]\n"),
- program_name);
- fputs (_("\nReport bugs to <bug-findutils@gnu.org>.\n"), stream);
-}
-
-static long
-get_seclevel(char *s)
-{
- long result;
- char *p;
-
- /* Reset errno in oreder to be able to distinguish LONG_MAX/LONG_MIN
- * from values whichare actually out of range
- */
- errno = 0;
-
- result = strtol(s, &p, 10);
- if ((0==result) && (p == optarg))
- {
- error(1, 0, _("You need to specify a security level as a decimal integer."));
- /*NOTREACHED*/
- return -1;
- }
- else if ((LONG_MIN==result || LONG_MAX==result) && errno)
-
- {
- error(1, 0, _("Security level %s is outside the convertible range."), s);
- /*NOTREACHED*/
- return -1;
- }
- else if (*p)
- {
- /* Some suffix exists */
- error(1, 0, _("Security level %s has unexpected suffix %s."), s, p);
- /*NOTREACHED*/
- return -1;
- }
- else
- {
- return result;
- }
-}
-
-static void
-outerr(void)
-{
- /* Issue the same error message as closeout() would. */
- error(1, errno, _("write error"));
-}
-
-int
-main (int argc, char **argv)
+void
+main (argc, argv)
+ int argc;
+ char **argv;
{
char *path; /* The current input entry. */
char *oldpath; /* The previous input entry. */
size_t pathsize, oldpathsize; /* Amounts allocated for them. */
int count, oldcount, diffcount; /* Their prefix lengths & the difference. */
int line_len; /* Length of input line. */
- int delimiter = '\n';
- int optc;
- int slocate_compat = 0;
- long slocate_seclevel = 0L;
program_name = argv[0];
- if (!program_name)
- program_name = "frcode";
- atexit (close_stdout);
- pathsize = oldpathsize = 1026; /* Increased as necessary by getline. */
+ pathsize = oldpathsize = 1026; /* Increased as necessary by getstr. */
path = xmalloc (pathsize);
oldpath = xmalloc (oldpathsize);
- oldpath[0] = 0;
+ /* Set to anything not starting with a slash, to force the first
+ prefix count to 0. */
+ strcpy (oldpath, " ");
oldcount = 0;
+ fwrite (LOCATEDB_MAGIC, sizeof (LOCATEDB_MAGIC), 1, stdout);
- while ((optc = getopt_long (argc, argv, "hv0S:", longopts, (int *) 0)) != -1)
- switch (optc)
- {
- case '0':
- delimiter = 0;
- break;
-
- case 'S':
- slocate_compat = 1;
- slocate_seclevel = get_seclevel(optarg);
- if (slocate_seclevel < 0 || slocate_seclevel > 1)
- {
- error(1, 0,
- _("slocate security level %ld is unsupported."),
- slocate_seclevel);
- }
- break;
-
- case 'h':
- usage (stdout);
- return 0;
-
- case 'v':
- display_findutils_version("frcode");
- return 0;
-
- default:
- usage (stderr);
- return 1;
- }
-
- /* We expect to have no arguments. */
- if (optind != argc)
- {
- usage (stderr);
- return 1;
- }
-
-
- if (slocate_compat)
- {
- fputc(slocate_seclevel ? '1' : '0', stdout);
- fputc(0, stdout);
-
- }
- else
- {
- /* GNU LOCATE02 format */
- if (fwrite (LOCATEDB_MAGIC, 1, sizeof (LOCATEDB_MAGIC), stdout)
- != sizeof(LOCATEDB_MAGIC))
- {
- error(1, errno, _("Failed to write to standard output"));
- }
- }
-
-
- while ((line_len = getdelim (&path, &pathsize, delimiter, stdin)) > 0)
+ /* FIXME temporary: change the \n to \0 when we figure out how to sort
+ null-terminated strings. */
+ while ((line_len = getstr (&path, &pathsize, stdin, '\n', 0)) > 0)
{
path[line_len - 1] = '\0'; /* FIXME temporary: nuke the newline. */
count = prefix_length (oldpath, path);
diffcount = count - oldcount;
- if ( (diffcount > SHRT_MAX) || (diffcount < SHRT_MIN) )
- {
- /* We do this to prevent overflow of the value we
- * write with put_short()
- */
- count = 0;
- diffcount = (-oldcount);
- }
oldcount = count;
-
- if (slocate_compat)
+ /* If the difference is small, it fits in one byte;
+ otherwise, two bytes plus a marker noting that fact. */
+ if (diffcount < -127 || diffcount > 127)
{
- /* Emit no count for the first pathname. */
- slocate_compat = 0;
+ putc (LOCATEDB_ESCAPE, stdout);
+ put_short (diffcount, stdout);
}
else
- {
- /* If the difference is small, it fits in one byte;
- otherwise, two bytes plus a marker noting that fact. */
- if (diffcount < LOCATEDB_ONEBYTE_MIN
- || diffcount > LOCATEDB_ONEBYTE_MAX)
- {
- if (EOF == putc (LOCATEDB_ESCAPE, stdout))
- outerr();
- if (!put_short (diffcount, stdout))
- outerr();
- }
- else
- {
- if (EOF == putc (diffcount, stdout))
- outerr();
- }
- }
+ putc (diffcount, stdout);
- if ( (EOF == fputs (path + count, stdout))
- || (EOF == putc ('\0', stdout)))
- {
- outerr();
- }
+ fputs (path + count, stdout);
+ putc ('\0', stdout);
- if (1)
- {
- /* Swap path and oldpath and their sizes. */
- char *tmppath = oldpath;
- size_t tmppathsize = oldpathsize;
- oldpath = path;
- oldpathsize = pathsize;
- path = tmppath;
- pathsize = tmppathsize;
- }
+ {
+ /* Swap path and oldpath and their sizes. */
+ char *tmppath = oldpath;
+ size_t tmppathsize = oldpathsize;
+ oldpath = path;
+ oldpathsize = pathsize;
+ path = tmppath;
+ pathsize = tmppathsize;
+ }
}
free (path);
free (oldpath);
- return 0;
+ exit (0);
}
diff --git a/locate/locate.1 b/locate/locate.1
index d774e117..dde9cc63 100644
--- a/locate/locate.1
+++ b/locate/locate.1
@@ -1,13 +1,9 @@
-.TH LOCATE 1 \" -*- nroff -*-
+.TH LOCATE 1L \" -*- nroff -*-
.SH NAME
locate \- list files in databases that match a pattern
.SH SYNOPSIS
.B locate
-[\-d path | \-\-database=path] [\-e | \-E | \-\-[non\-]existing] [\-i
-| \-\-ignore-case] [\-0 | \-\-null] [\-c | \-\-count] [\-w | \-\-wholename]
-|\-b | \-\-basename] [\-l N | \-\-limit=N] [\-S | \-\-statistics] [\-r
-| \-\-regex ] [\-\-max-database-age D] [\-P | \-H | \-\-nofollow] [\-L
-| \-\-follow] [\-\-version] [\-A | \-\-all] [\-p | \-\-print] [\-\-help] pattern...
+[\-d path] [\-\-database=path] [\-\-version] [\-\-help] pattern...
.SH DESCRIPTION
This manual page
documents the GNU version of
@@ -38,52 +34,22 @@ The file name databases contain lists of files that were on the system
when the databases were last updated. The system administrator can
choose the file name of the default database, the frequency with which
the databases are updated, and the directories for which they contain
-entries; see \fBupdatedb\fP(1).
-.P
-If
-.BR locate 's
-output is going to a terminal, unusual characters in the output are
-escaped in the same way as for the \-print action of the
-.B find
-command. If the output is not going to a terminal, file names are
-printed exactly as-is.
-
+entries; see \fBupdatedb\fP(1L).
.SH OPTIONS
.TP
-.I "\-0, \-\-null"
-Use ASCII NUL as a separator, instead of newline.
-.TP
-.I "\-A, \-\-all"
-Print only names which match all non-option arguments, not those matching
-one or more non-option arguments.
-.TP
-.I "\-b, \-\-basename"
-Results are considered to match if the pattern specified matches the
-final component of the name of a file as listed in the database.
-This final component is usually referred to as the `base name'.
-.TP
-.I "\-c, \-\-count"
-Instead of printing the matched filenames, just print the total
-number of matches we found, unless \-\-\fIprint\fP (\-p) is also present.
-.TP
.I "\-d \fIpath\fP, \-\-database=\fIpath\fP"
Instead of searching the default file name database, search the file
name databases in \fIpath\fP, which is a colon-separated list of
database file names. You can also use the environment variable
.B LOCATE_PATH
to set the list of database files to search.
-The option overrides the environment variable if both are used. Empty
-elements in the path are taken to be synonyms for the file name of the
-default database.
-A database can be supplied on stdin, using `\-' as an element
-of \fIpath\fP. If more than one element of \fIpath\fP is `\-',
-later instances are ignored (and a warning message is printed).
-.IP
+The option overrides the environment variable if both are used.
+.P
The file name database format changed starting with GNU
.B find
and
.B locate
-version 4.0 to allow machines with different byte orderings to share
+version 4.0 to allow machines with diffent byte orderings to share
the databases. This version of
.B locate
can automatically recognize and read databases produced for older
@@ -93,167 +59,20 @@ or Unix versions of
.B locate
or
.BR find .
-Support for the old locate database format will be discontinued in a
-future release.
-.TP
-.I "\-e, \-\-existing"
-Only print out such names that currently exist (instead of such names
-that existed when the database was created).
-Note that this may slow down the program a lot, if there are many matches
-in the database. If you are using this option within a program,
-please note that it is possible for the file to be deleted after
-.B locate
-has checked that it exists, but before you use it.
-.TP
-.I "\-E, \-\-non\-existing"
-Only print out such names that currently do not exist (instead of such names
-that existed when the database was created).
-Note that this may slow down the program a lot, if there are many matches
-in the database.
.TP
.I "\-\-help"
Print a summary of the options to
.B locate
and exit.
.TP
-.I "\-i, \-\-ignore-case"
-Ignore case distinctions in both the pattern and the file names.
-.TP
-.I "\-l N, \-\-limit=N"
-Limit the number of matches to N. If a limit is set via this option,
-the number of results printed for the \-c option will never be larger
-than this number.
-.TP
-.I "\-L, \-\-follow"
-If testing for the existence of files (with the \-e or \-E options),
-consider broken symbolic links to be non-existing. This is the default.
-.TP
-.I "\-\-max-database-age D"
-Normally,
-.B locate
-will issue a warning message when it searches a database which is more
-than 8 days old. This option changes that value to something other
-than 8. The effect of specifying a negative value is undefined.
-.TP
-.I "\-m, \-\-mmap"
-Accepted but does nothing, for compatibility with BSD
-.BR locate .
-.TP
-.I "\-P, \-H, \-\-nofollow"
-If testing for the existence of files (with the \-e or \-E options), treat
-broken symbolic links as if they were existing files. The \-H
-form of this option is provided purely for similarity with
-.BR find ;
-the use of \-P is recommended over \-H.
-.TP
-.I "\-p, \-\-print"
-Print search results when they normally would not, because of the presence
-of \-\-statistics (\-S) or \-\-count (\-c).
-.TP
-.I "\-r, \-\-regex "
-The pattern specified on the command line is understood to be a
-regular expression, as opposed to a glob pattern. The Regular
-expressions work in the same was as in
-.B emacs
-and
-.BR find ,
-except for the fact that "." will match a newline.
-Filenames whose full paths match the specified regular expression are
-printed (or, in the case of the \-c option, counted). If you wish to
-anchor your regular expression at the ends of the full path name, then
-as is usual with regular expressions, you should use the characters ^
-and $ to signify this.
-.TP
-.I "\-s, \-\-stdio"
-Accepted but does nothing, for compatibility with BSD
-.BR locate .
-.TP
-.I "\-S, \-\-statistics"
-Print various statistics about each locate database and then exit
-without performing a search, unless non-option arguments are given.
-For compatibility with BSD, \-S is accepted as a synonym
-for \-\-statistics. However, the ouptut of
-.B locate \-S
-is different for the GNU and BSD implementations of
-.BR locate .
-.TP
.I "\-\-version"
Print the version number of
.B locate
and exit.
-.TP
-.I "\-w, \-\-wholename"
-Match against the whole name of the file as listed in the database.
-This is the default.
.SH ENVIRONMENT
.TP
.B LOCATE_PATH
-Colon-separated list of databases to search. If the value has a
-leading or trailing colon, or has two colons in a row, you may get
-results that vary between different versions of
-.BR locate .
-
+Colon-separated list of databases to search.
.SH "SEE ALSO"
-\fBfind\fP(1), \fBlocatedb\fP(5), \fBupdatedb\fP(1), \fBxargs\fP(1),
-\fBglob\fP(3),
+\fBfind\fP(1L), \fBlocatedb\fP(5L), \fBupdatedb\fP(1L), \fBxargs\fP(1L)
\fBFinding Files\fP (on-line in Info, or printed)
-.SH "HISTORY"
-The
-.B locate
-program started life as the BSD fast find program, contributed to BSD
-by James A. Woods. This was described by his paper
-.I Finding Files Fast
-which was published in Usenix
-.IR ;login: ,
-Vol 8, No 1, February/March, 1983, pp. 8-10. When the
-.B find
-program began to assume a default
-.B -print
-action if no action was specified, this changed the interpretation of
-.B find
-.BR pattern .
-The BSD developers therefore moved the fast find functionality into
-.BR locate .
-The GNU implementation of
-.B locate
-appears to be derived from the same code.
-.P
-Significant changes to
-.B locate
-in reverse order:
-.TS
-tab(|);
-LL.
-4.3.7 | Byte-order independent support for old database format
-4.3.3 | locate \fI\-i\fR supports multi-byte characters correctly
- | Introduced \fI\-\-max_db_age\fR
-4.3.2 | Support for the slocate database format
-4.2.22| Introduced the \fI\-\-all\fR option
-4.2.15| Introduced the \fI\-\-regex\fR option
-4.2.14| Introduced options \fI\-L, \-P, \-H\fR
-4.2.12| Empty items in \fBLOCATE_PATH\fR now indicate the default database
-4.2.11| Introduced the \fI\-\-statistics\fR option
-4.2.4 | Introduced \fI\-\-count\fR and \fI\-\-limit\fR
-4.2.0 | Glob characters cause matching against the whole file name
-4.0 | Introduced the LOCATE02 database format
-3.7 | Locate can search multiple databases
-.TE
-.SH "BUGS"
-.P
-The locate database correctly handles filenames containing newlines,
-but only if the system's sort command has a working
-\-z
-option. If you suspect that
-.B locate
-may need to return filenames containing newlines, consider using its
-.I \-\-null
-option.
-.P
-The best way to report a bug is to use the form at
-http://savannah.gnu.org/bugs/?group=findutils.
-The reason for this is that you will then be able to track progress in
-fixing the problem. Other comments about \fBlocate\fP(1) and about
-the findutils package in general can be sent to the
-.I bug-findutils
-mailing list. To join the list, send email to
-.IR bug-findutils-request@gnu.org .
diff --git a/locate/locate.c b/locate/locate.c
index 0f624684..29be0225 100644
--- a/locate/locate.c
+++ b/locate/locate.c
@@ -1,20 +1,19 @@
/* locate -- search databases for filenames that match patterns
- Copyright (C) 1994, 1996, 1998, 1999, 2000, 2003,
- 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+ Copyright (C) 1994 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
+ 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 3 of the License, or
- (at your option) any later version.
-
+ 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, see <http://www.gnu.org/licenses/>.
-*/
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Usage: locate [options] pattern...
@@ -28,1380 +27,309 @@
0-28 likeliest differential counts + offset (14) to make nonnegative
30 escape code for out-of-range count to follow in next halfword
- 128-255 bigram codes (the 128 most common, as determined by `updatedb')
- 32-127 single character (printable) ASCII remainder
+ 128-255 bigram codes (the 128 most common, as determined by `updatedb')
+ 32-127 single character (printable) ASCII remainder
- Earlier versions of GNU locate used to use a novel two-tiered
- string search technique, which was described in Usenix ;login:, Vol
- 8, No 1, February/March, 1983, p. 8.
+ Uses a novel two-tiered string search technique:
- However, latterly code changes to provide additional functionality
- became dificult to make with the existing reading scheme, and so
- we no longer perform the matching as efficiently as we used to (that is,
- we no longer use the same algorithm).
+ First, match a metacharacter-free subpattern and a partial pathname
+ BACKWARDS to avoid full expansion of the pathname list.
+ The time savings is 40-50% over forward matching, which cannot efficiently
+ handle overlapped search patterns and compressed path remainders.
- The old algorithm was:
-
- First, match a metacharacter-free subpattern and a partial
- pathname BACKWARDS to avoid full expansion of the pathname list.
- The time savings is 40-50% over forward matching, which cannot
- efficiently handle overlapped search patterns and compressed
- path remainders.
-
- Then, match the actual shell glob pattern (if in this form)
- against the candidate pathnames using the slower shell filename
- matching routines.
+ Then, match the actual shell glob-style regular expression (if in this form)
+ against the candidate pathnames using the slower shell filename
+ matching routines.
+ Described more fully in Usenix ;login:, Vol 8, No 1,
+ February/March, 1983, p. 8.
Written by James A. Woods <jwoods@adobe.com>.
- Modified by David MacKenzie <djm@gnu.org>.
- Additional work by James Youngman and Bas van Gompel.
-*/
+ Modified by David MacKenzie <djm@gnu.ai.mit.edu>. */
#include <config.h>
-
#include <stdio.h>
-#include <signal.h>
-#include <ctype.h>
#include <sys/types.h>
-#include <grp.h> /* for setgroups() */
#include <sys/stat.h>
#include <time.h>
#include <fnmatch.h>
#include <getopt.h>
-#include <xstrtol.h>
-
-#include <stdbool.h> /* for bool/boolean */
-
-/* The presence of unistd.h is assumed by gnulib these days, so we
- * might as well assume it too.
- */
-/* We need <unistd.h> for isatty(). */
-#include <unistd.h>
-
-#include <fcntl.h>
#define NDEBUG
#include <assert.h>
-#include <string.h>
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
+#include <string.h>
+#else
+#include <strings.h>
+#define strchr index
+#endif
#ifdef STDC_HEADERS
#include <stdlib.h>
+#else
+char *getenv ();
#endif
+#ifdef STDC_HEADERS
#include <errno.h>
-
-#ifdef HAVE_LOCALE_H
-#include <locale.h>
-#endif
-
-#if ENABLE_NLS
-# include <libintl.h>
-# define _(Text) gettext (Text)
-#else
-# define _(Text) Text
-#define textdomain(Domain)
-#define bindtextdomain(Package, Directory)
-#define ngettext(singular,plural,n) ((1==n) ? singular : plural)
-#endif
-#ifdef gettext_noop
-# define N_(String) gettext_noop (String)
+#include <stdlib.h>
#else
-/* We used to use (String) instead of just String, but apparently ISO C
- * doesn't allow this (at least, that's what HP said when someone reported
- * this as a compiler bug). This is HP case number 1205608192. See
- * also http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11250 (which references
- * ANSI 3.5.7p14-15). The Intel icc compiler also rejects constructs
- * like: static const char buf[] = ("string");
- */
-# define N_(String) String
+extern int errno;
#endif
#include "locatedb.h"
-#include "xalloc.h"
-#include "error.h"
-#include "human.h"
-#include "dirname.h"
-#include "closeout.h"
-#include "nextelem.h"
-#include "regex.h"
-#include "quote.h"
-#include "quotearg.h"
-#include "printquoted.h"
-#include "regextype.h"
-#include "findutils-version.h"
-
-/* Note that this evaluates Ch many times. */
-#ifdef _LIBC
-# define TOUPPER(Ch) toupper (Ch)
-# define TOLOWER(Ch) tolower (Ch)
-#else
-# define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
-# define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
-#endif
-/* typedef enum {false, true} boolean; */
+typedef enum {false, true} boolean;
/* Warn if a database is older than this. 8 days allows for a weekly
update that takes up to a day to perform. */
-static unsigned int warn_number_units = 8;
-
-/* Printable name of units used in WARN_SECONDS */
-static const char warn_name_units[] = N_("days");
-#define SECONDS_PER_UNIT (60 * 60 * 24)
-
-enum visit_result
- {
- VISIT_CONTINUE = 1, /* please call the next visitor */
- VISIT_ACCEPTED = 2, /* accepted, call no futher callbacks for this file */
- VISIT_REJECTED = 4, /* rejected, process next file. */
- VISIT_ABORT = 8 /* rejected, process no more files. */
- };
-
-enum ExistenceCheckType
- {
- ACCEPT_EITHER, /* Corresponds to lack of -E/-e option */
- ACCEPT_EXISTING, /* Corresponds to option -e */
- ACCEPT_NON_EXISTING /* Corresponds to option -E */
- };
-
-/* Check for existence of files before printing them out? */
-enum ExistenceCheckType check_existence = ACCEPT_EITHER;
-
-static int follow_symlinks = 1;
-
-/* What to separate the results with. */
-static int separator = '\n';
-
-static struct quoting_options * quote_opts = NULL;
-static bool stdout_is_a_tty;
-static bool print_quoted_filename;
-static bool results_were_filtered;
-
-static const char *selected_secure_db = NULL;
-
-
-/* Change the number of days old the database can be
- * before we complain about it.
- */
-static void
-set_max_db_age(const char *s)
-{
- char *end;
- unsigned long int val;
- /* XXX: we ignore the case where the input is negative, which is allowed(!). */
-
- if (0 == *s)
- {
- error(1, 0,
- _("The argument for option --max-database-age must not be empty"));
- }
-
-
- /* We have to set errno here, otherwise when the function returns ULONG_MAX,
- * we would not be able to tell if that is the correct answer, or whether it
- * signifies an error.
- */
- errno = 0;
- val = strtoul(s, &end, 10);
-
- /* Diagnose number too large, non-numbes and trailing junk. */
- if ((ULONG_MAX == val && ERANGE == errno) ||
- (0 == val && EINVAL == errno))
- {
- error(1, errno,
- _("Invalid argument %s for option --max-database-age"),
- quotearg_n_style(0, locale_quoting_style, s));
- }
- else if (*end)
- {
- /* errno wasn't set, don't print its message */
- error(1, 0,
- _("Invalid argument %s for option --max-database-age"),
- quotearg_n_style(0, locale_quoting_style, s));
- }
- else
- {
- warn_number_units = val;
- }
-}
+#define WARN_SECONDS (60 * 60 * 24 * 8)
+/* Printable version of WARN_SECONDS. */
+#define WARN_MESSAGE "8 days"
+char *next_element ();
+char *xmalloc ();
+char *xrealloc ();
+void error ();
/* Read in a 16-bit int, high byte first (network byte order). */
-static short
-get_short (FILE *fp)
+static int
+get_short (fp)
+ FILE *fp;
{
-
register short x;
- x = (signed char) fgetc (fp) << 8;
- x |= (fgetc (fp) & 0xff);
- return x;
+ x = fgetc (fp);
+ return (x << 8) | (fgetc (fp) & 0xff);
}
-const char * const metacharacters = "*?[]\\";
+/* Return a pointer to the last character in a static copy of the last
+ glob-free subpattern in NAME,
+ with '\0' prepended for a fast backwards pre-match. */
-/* Return nonzero if S contains any shell glob characters.
- */
-static int
-contains_metacharacter(const char *s)
-{
- if (NULL == strpbrk(s, metacharacters))
- return 0;
- else
- return 1;
-}
-
-/* locate_read_str()
- *
- * Read bytes from FP into the buffer at offset OFFSET in (*BUF),
- * until we reach DELIMITER or end-of-file. We reallocate the buffer
- * as necessary, altering (*BUF) and (*SIZ) as appropriate. No assumption
- * is made regarding the content of the data (i.e. the implementation is
- * 8-bit clean, the only delimiter is DELIMITER).
- *
- * Written Fri May 23 18:41:16 2003 by James Youngman, because getstr()
- * has been removed from gnulib.
- *
- * We call the function locate_read_str() to avoid a name clash with the curses
- * function getstr().
- */
-static int
-locate_read_str(char **buf, size_t *siz, FILE *fp, int delimiter, int offs)
+static char *
+last_literal_end (name)
+ char *name;
{
- char * p = NULL;
- size_t sz = 0;
- int nread;
- size_t needed;
+ static char *globfree = NULL; /* A copy of the subpattern in NAME. */
+ static size_t gfalloc = 0; /* Bytes allocated for `globfree'. */
+ register char *subp; /* Return value. */
+ register char *p; /* Search location in NAME. */
- nread = getdelim(&p, &sz, delimiter, fp);
- if (nread >= 0)
+ /* Find the end of the subpattern.
+ Skip trailing metacharacters and [] ranges. */
+ for (p = name + strlen (name) - 1; p >= name && strchr ("*?]", *p) != NULL;
+ p--)
{
- assert(p != NULL);
-
- needed = offs + nread + 1u;
- if (needed > (*siz))
- {
- char *pnew = realloc(*buf, needed);
- if (NULL == pnew)
- {
- return -1; /* FAIL */
- }
- else
- {
- *siz = needed;
- *buf = pnew;
- }
- }
- memcpy((*buf)+offs, p, nread);
- free(p);
+ if (*p == ']')
+ while (p >= name && *p != '[')
+ p--;
}
- return nread;
-}
-
-
-struct locate_limits
-{
- uintmax_t limit;
- uintmax_t items_accepted;
-};
-static struct locate_limits limits;
-
-
-struct locate_stats
-{
- uintmax_t compressed_bytes;
- uintmax_t total_filename_count;
- uintmax_t total_filename_length;
- uintmax_t whitespace_count;
- uintmax_t newline_count;
- uintmax_t highbit_filename_count;
-};
-static struct locate_stats statistics;
-
-
-struct regular_expression
-{
- struct re_pattern_buffer regex; /* for --regex */
-};
-
-
-struct process_data
-{
- int c; /* An input byte. */
- char itemcount; /* Indicates we're at the beginning of an slocate db. */
- int count; /* The length of the prefix shared with the previous database entry. */
- int len;
- char *original_filename; /* The current input database entry. */
- size_t pathsize; /* Amount allocated for it. */
- char *munged_filename; /* path or basename(path) */
- FILE *fp; /* The pathname database. */
- const char *dbfile; /* Its name, or "<stdin>" */
- int slocatedb_format; /* Allows us to cope with slocate's format variant */
- GetwordEndianState endian_state;
- /* for the old database format,
- the first and second characters of the most common bigrams. */
- char bigram1[128];
- char bigram2[128];
-};
+ if (p < name)
+ p = name;
-
-typedef int (*visitfunc)(struct process_data *procdata,
- void *context);
-
-struct visitor
-{
- visitfunc inspector;
- void * context;
- struct visitor *next;
-};
-
-
-static struct visitor *inspectors = NULL;
-static struct visitor *lastinspector = NULL;
-static struct visitor *past_pat_inspector = NULL;
-
-static inline int visit(const struct visitor *p,
- int accept_flags,
- struct process_data *procdata,
- const struct visitor * const stop)
-{
- register int result = accept_flags;
- while ( (accept_flags & result) && (stop != p) )
+ if (p - name + 3 > gfalloc)
{
- result = (p->inspector)(procdata, p->context);
- p = p->next;
+ gfalloc = p - name + 3 + 64; /* Room to grow. */
+ globfree = xrealloc (globfree, gfalloc);
}
- return result;
-}
-
-/* 0 or 1 pattern(s) */
-static int
-process_simple(struct process_data *procdata)
-{
- return visit(inspectors, (VISIT_CONTINUE|VISIT_ACCEPTED), procdata, NULL);
-}
-
-/* Accept if any pattern matches. */
-static int
-process_or (struct process_data *procdata)
-{
- int result;
-
- result = visit(inspectors, (VISIT_CONTINUE|VISIT_REJECTED), procdata, past_pat_inspector);
- if (result == VISIT_CONTINUE)
- result = VISIT_REJECTED;
- if (result & (VISIT_ABORT | VISIT_REJECTED))
- return result;
-
- result = visit(past_pat_inspector, VISIT_CONTINUE, procdata, NULL);
- if (VISIT_CONTINUE == result)
- return VISIT_ACCEPTED;
- else
- return result;
-}
+ subp = globfree;
+ *subp++ = '\0';
-/* Accept if all pattern match. */
-static int
-process_and (struct process_data *procdata)
-{
- int result;
-
- result = visit(inspectors, (VISIT_CONTINUE|VISIT_ACCEPTED), procdata, past_pat_inspector);
- if (result == VISIT_CONTINUE)
- result = VISIT_REJECTED;
- if (result & (VISIT_ABORT | VISIT_REJECTED))
- return result;
-
- result = visit(past_pat_inspector, VISIT_CONTINUE, procdata, NULL);
- if (VISIT_CONTINUE == result)
- return VISIT_ACCEPTED;
- else
- return result;
-}
-
-typedef int (*processfunc)(struct process_data *procdata);
-
-static processfunc mainprocessor = NULL;
-
-static void
-add_visitor(visitfunc fn, void *context)
-{
- struct visitor *p = xmalloc(sizeof(struct visitor));
- p->inspector = fn;
- p->context = context;
- p->next = NULL;
-
- if (NULL == lastinspector)
- {
- lastinspector = inspectors = p;
- }
+ /* If the pattern has only metacharacters, make every path match the
+ subpattern, so it gets checked the slow way. */
+ if (p == name && strchr ("?*[]", *p) != NULL)
+ *subp++ = '/';
else
{
- lastinspector->next = p;
- lastinspector = p;
+ char *endmark;
+ /* Find the start of the metacharacter-free subpattern. */
+ for (endmark = p; p >= name && strchr ("]*?", *p) == NULL; p--)
+ ;
+ /* Copy the subpattern into globfree. */
+ for (++p; p <= endmark; )
+ *subp++ = *p++;
}
-}
+ *subp-- = '\0'; /* Null terminate, though it's not needed. */
-static int
-visit_justprint_quoted(struct process_data *procdata, void *context)
-{
- (void) context;
- print_quoted (stdout, quote_opts, stdout_is_a_tty,
- "%s",
- procdata->original_filename);
- putchar(separator);
- return VISIT_CONTINUE;
-}
-
-static int
-visit_justprint_unquoted(struct process_data *procdata, void *context)
-{
- (void) context;
- fputs(procdata->original_filename, stdout);
- putchar(separator);
- return VISIT_CONTINUE;
+ return subp;
}
-static void
-toolong (struct process_data *procdata)
-{
- error (1, 0,
- _("locate database %s contains a "
- "filename longer than locate can handle"),
- procdata->dbfile);
-}
-
-static void
-extend (struct process_data *procdata, size_t siz1, size_t siz2)
-{
- /* Figure out if the addition operation is safe before performing it. */
- if (SIZE_MAX - siz1 < siz2)
- {
- toolong (procdata);
- }
- else if (procdata->pathsize < (siz1+siz2))
- {
- procdata->pathsize = siz1+siz2;
- procdata->original_filename = x2nrealloc (procdata->original_filename,
- &procdata->pathsize,
- 1);
- }
-}
+/* Print the entries in DBFILE that match shell globbing pattern PATHPART.
+ Return the number of entries printed. */
static int
-visit_old_format(struct process_data *procdata, void *context)
+locate (pathpart, dbfile)
+ char *pathpart, *dbfile;
{
- register size_t i;
- (void) context;
-
- if (EOF == procdata->c)
- return VISIT_ABORT;
-
- /* Get the offset in the path where this path info starts. */
- if (procdata->c == LOCATEDB_OLD_ESCAPE)
- {
- int minval, maxval;
- int word;
-
- procdata->count -= LOCATEDB_OLD_OFFSET;
- minval = (0 - procdata->count);
- if (procdata->count >= 0)
- maxval = (procdata->len - procdata->count);
- else
- maxval = (procdata->len - 0);
- word = getword(procdata->fp, procdata->dbfile,
- minval, maxval, &procdata->endian_state);
- procdata->count += word;
- assert(procdata->count >= 0);
- }
- else
- {
- procdata->count += (procdata->c - LOCATEDB_OLD_OFFSET);
- assert(procdata->count >= 0);
- }
-
- /* Overlay the old path with the remainder of the new. Read
- * more data until we get to the next filename.
- */
- for (i=procdata->count;
- (procdata->c = getc (procdata->fp)) > LOCATEDB_OLD_ESCAPE;)
- {
- if (EOF == procdata->c)
- break;
-
- if (procdata->c < 0200)
- {
- /* An ordinary character. */
- extend (procdata, i, 1u);
- procdata->original_filename[i++] = procdata->c;
- }
- else
- {
- /* Bigram markers have the high bit set. */
- extend (procdata, i, 2u);
- procdata->c &= 0177;
- procdata->original_filename[i++] = procdata->bigram1[procdata->c];
- procdata->original_filename[i++] = procdata->bigram2[procdata->c];
- }
- }
-
- /* Consider the case where we executed the loop body zero times; we
- * still need space for the terminating null byte.
- */
- extend (procdata, i, 1u);
- procdata->original_filename[i] = 0;
- procdata->len = i;
- procdata->munged_filename = procdata->original_filename;
-
- return VISIT_CONTINUE;
-}
-
-static int
-visit_locate02_format(struct process_data *procdata, void *context)
-{
- register char *s;
+ /* The pathname database. */
+ FILE *fp;
+ /* An input byte. */
+ int c;
+ /* Number of bytes read from an entry. */
int nread;
- (void) context;
-
- if (procdata->slocatedb_format)
- {
- if (procdata->itemcount == 0)
- {
- ungetc(procdata->c, procdata->fp);
- procdata->count = 0;
- procdata->len = 0;
- }
- else if (procdata->itemcount == 1)
- {
- procdata->count = procdata->len-1;
- }
- else
- {
- if (procdata->c == LOCATEDB_ESCAPE)
- procdata->count += (short)get_short (procdata->fp);
- else if (procdata->c > 127)
- procdata->count += procdata->c - 256;
- else
- procdata->count += procdata->c;
- }
- }
- else
- {
- if (procdata->c == LOCATEDB_ESCAPE)
- procdata->count += (short)get_short (procdata->fp);
- else if (procdata->c > 127)
- procdata->count += procdata->c - 256;
- else
- procdata->count += procdata->c;
- }
-
- if (procdata->count > procdata->len || procdata->count < 0)
- {
- /* This should not happen generally , but since we're
- * reading in data which is outside our control, we
- * cannot prevent it.
- */
- error(1, 0, _("locate database %s is corrupt or invalid"),
- quotearg_n_style(0, locale_quoting_style, procdata->dbfile));
- }
-
- /* Overlay the old path with the remainder of the new. */
- nread = locate_read_str (&procdata->original_filename,
- &procdata->pathsize,
- procdata->fp, 0, procdata->count);
- if (nread < 0)
- return VISIT_ABORT;
- procdata->c = getc (procdata->fp);
- procdata->len = procdata->count + nread;
- s = procdata->original_filename + procdata->len - 1; /* Move to the last char in path. */
- assert (s[0] != '\0');
- assert (s[1] == '\0'); /* Our terminator. */
- assert (s[2] == '\0'); /* Added by locate_read_str. */
-
- procdata->munged_filename = procdata->original_filename;
-
- if (procdata->slocatedb_format)
- {
- /* Don't increment indefinitely, it might overflow. */
- if (procdata->itemcount < 6)
- {
- ++(procdata->itemcount);
- }
- }
-
-
- return VISIT_CONTINUE;
-}
-
-static int
-visit_basename(struct process_data *procdata, void *context)
-{
- (void) context;
- procdata->munged_filename = last_component (procdata->original_filename);
-
- return VISIT_CONTINUE;
-}
-
-/* visit_existing_follow implements -L -e */
-static int
-visit_existing_follow(struct process_data *procdata, void *context)
-{
- struct stat st;
- (void) context;
-
- /* munged_filename has been converted in some way (to lower case,
- * or is just the base name of the file), and original_filename has not.
- * Hence only original_filename is still actually the name of the file
- * whose existence we would need to check.
- */
- if (stat(procdata->original_filename, &st) != 0)
- {
- return VISIT_REJECTED;
- }
- else
- {
- return VISIT_CONTINUE;
- }
-}
+ /* true if PATHPART contains globbing metacharacters. */
+ boolean globflag;
+ /* The end of the last glob-free subpattern in PATHPART. */
+ char *patend;
+
+ /* The current input database entry. */
+ char *path;
+ /* Amount allocated for it. */
+ size_t pathsize;
+
+ /* The length of the prefix shared with the previous database entry. */
+ int count = 0;
+ /* Where in `path' to stop the backward search for the last character
+ in the subpattern. Set according to `count'. */
+ char *cutoff;
+
+ /* true if we found a fast match (of patend) on the previous path. */
+ boolean prev_fast_match = false;
+ /* The return value. */
+ int printed = 0;
+
+ /* true if reading a bigram-encoded database. */
+ boolean old_format = false;
+ /* For the old database format,
+ the first and second characters of the most common bigrams. */
+ char bigram1[128], bigram2[128];
-/* visit_non_existing_follow implements -L -E */
-static int
-visit_non_existing_follow(struct process_data *procdata, void *context)
-{
+ /* To check the age of the database. */
struct stat st;
- (void) context;
-
- /* munged_filename has been converted in some way (to lower case,
- * or is just the base name of the file), and original_filename has not.
- * Hence only original_filename is still actually the name of the file
- * whose existence we would need to check.
- */
- if (stat(procdata->original_filename, &st) == 0)
- {
- return VISIT_REJECTED;
- }
- else
- {
- return VISIT_CONTINUE;
- }
-}
+ time_t now;
-/* visit_existing_nofollow implements -P -e */
-static int
-visit_existing_nofollow(struct process_data *procdata, void *context)
-{
- struct stat st;
- (void) context;
-
- /* munged_filename has been converted in some way (to lower case,
- * or is just the base name of the file), and original_filename has not.
- * Hence only original_filename is still actually the name of the file
- * whose existence we would need to check.
- */
- if (lstat(procdata->original_filename, &st) != 0)
- {
- return VISIT_REJECTED;
- }
- else
+ if (stat (dbfile, &st) || (fp = fopen (dbfile, "r")) == NULL)
{
- return VISIT_CONTINUE;
- }
-}
-
-/* visit_non_existing_nofollow implements -P -E */
-static int
-visit_non_existing_nofollow(struct process_data *procdata, void *context)
-{
- struct stat st;
- (void) context;
-
- /* munged_filename has been converted in some way (to lower case,
- * or is just the base name of the file), and original_filename has not.
- * Hence only original_filename is still actually the name of the file
- * whose existence we would need to check.
- */
- if (lstat(procdata->original_filename, &st) == 0)
- {
- return VISIT_REJECTED;
- }
- else
- {
- return VISIT_CONTINUE;
- }
-}
-
-static int
-visit_substring_match_nocasefold_wide(struct process_data *procdata, void *context)
-{
- const char *pattern = context;
-
- if (NULL != mbsstr(procdata->munged_filename, pattern))
- return VISIT_ACCEPTED;
- else
- return VISIT_REJECTED;
-}
-
-static int
-visit_substring_match_nocasefold_narrow(struct process_data *procdata, void *context)
-{
- const char *pattern = context;
- assert(MB_CUR_MAX == 1);
- if (NULL != strstr(procdata->munged_filename, pattern))
- return VISIT_ACCEPTED;
- else
- return VISIT_REJECTED;
-}
-
-static int
-visit_substring_match_casefold_wide(struct process_data *procdata, void *context)
-{
- const char *pattern = context;
-
- if (NULL != mbscasestr(procdata->munged_filename, pattern))
- return VISIT_ACCEPTED;
- else
- return VISIT_REJECTED;
-}
-
-
-static int
-visit_substring_match_casefold_narrow(struct process_data *procdata, void *context)
-{
- const char *pattern = context;
-
- assert(MB_CUR_MAX == 1);
- if (NULL != strcasestr(procdata->munged_filename, pattern))
- return VISIT_ACCEPTED;
- else
- return VISIT_REJECTED;
-}
-
-
-static int
-visit_globmatch_nofold(struct process_data *procdata, void *context)
-{
- const char *glob = context;
- if (fnmatch(glob, procdata->munged_filename, 0) != 0)
- return VISIT_REJECTED;
- else
- return VISIT_ACCEPTED;
-}
-
-
-static int
-visit_globmatch_casefold(struct process_data *procdata, void *context)
-{
- const char *glob = context;
- if (fnmatch(glob, procdata->munged_filename, FNM_CASEFOLD) != 0)
- return VISIT_REJECTED;
- else
- return VISIT_ACCEPTED;
-}
-
-
-static int
-visit_regex(struct process_data *procdata, void *context)
-{
- struct regular_expression *p = context;
- const size_t len = strlen(procdata->munged_filename);
-
- int rv = re_search (&p->regex, procdata->munged_filename,
- len, 0, len,
- (struct re_registers *) NULL);
- if (rv < 0)
- {
- return VISIT_REJECTED; /* no match (-1), or internal error (-2) */
+ error (0, errno, "%s", dbfile);
+ return 0;
}
- else
+ time(&now);
+ if (now - st.st_mtime > WARN_SECONDS)
{
- return VISIT_ACCEPTED; /* match */
+ error (0, 0, "warning: database `%s' is more than %s old",
+ dbfile, WARN_MESSAGE);
}
-}
+ pathsize = 1026; /* Increased as necessary by getstr. */
+ path = xmalloc (pathsize);
-static int
-visit_stats(struct process_data *procdata, void *context)
-{
- struct locate_stats *p = context;
- size_t len = strlen(procdata->original_filename);
- const char *s;
- int highbit, whitespace, newline;
-
- ++(p->total_filename_count);
- p->total_filename_length += len;
-
- highbit = whitespace = newline = 0;
- for (s=procdata->original_filename; *s; ++s)
+ nread = fread (path, 1, sizeof (LOCATEDB_MAGIC), fp);
+ if (nread != sizeof (LOCATEDB_MAGIC)
+ || memcmp (path, LOCATEDB_MAGIC, sizeof (LOCATEDB_MAGIC)))
{
- if ( (int)(*s) & 128 )
- highbit = 1;
- if ('\n' == *s)
+ int i;
+ /* Read the list of the most common bigrams in the database. */
+ fseek (fp, 0, 0);
+ for (i = 0; i < 128; i++)
{
- newline = whitespace = 1;
- }
- else if (isspace((unsigned char)*s))
- {
- whitespace = 1;
+ bigram1[i] = getc (fp);
+ bigram2[i] = getc (fp);
}
+ old_format = true;
}
- if (highbit)
- ++(p->highbit_filename_count);
- if (whitespace)
- ++(p->whitespace_count);
- if (newline)
- ++(p->newline_count);
-
- return VISIT_CONTINUE;
-}
-
-
-static int
-visit_limit(struct process_data *procdata, void *context)
-{
- struct locate_limits *p = context;
-
- (void) procdata;
+ globflag = strchr (pathpart, '*') || strchr (pathpart, '?')
+ || strchr (pathpart, '[');
- if (++p->items_accepted >= p->limit)
- return VISIT_ABORT;
- else
- return VISIT_CONTINUE;
-}
+ patend = last_literal_end (pathpart);
-static int
-visit_count(struct process_data *procdata, void *context)
-{
- struct locate_limits *p = context;
-
- (void) procdata;
-
- ++p->items_accepted;
- return VISIT_CONTINUE;
-}
-
-/* Emit the statistics.
- */
-static void
-print_stats(int argc, size_t database_file_size)
-{
- char hbuf1[LONGEST_HUMAN_READABLE + 1];
- char hbuf2[LONGEST_HUMAN_READABLE + 1];
- char hbuf3[LONGEST_HUMAN_READABLE + 1];
- char hbuf4[LONGEST_HUMAN_READABLE + 1];
-
- printf(ngettext("Locate database size: %s byte\n",
- "Locate database size: %s bytes\n",
- database_file_size),
- human_readable ((uintmax_t) database_file_size,
- hbuf1, human_ceiling, 1, 1));
-
- printf( (results_were_filtered ?
- _("Matching Filenames: %s\n") :
- _("All Filenames: %s\n")),
- human_readable (statistics.total_filename_count,
- hbuf1, human_ceiling, 1, 1));
- /* XXX: We would ideally use ngettext() here, but I don't know
- * how to use it to handle more than one possibly-plural thing/
- */
- printf(_("File names have a cumulative length of %s bytes.\n"
- "Of those file names,\n"
- "\n\t%s contain whitespace, "
- "\n\t%s contain newline characters, "
- "\n\tand %s contain characters with the high bit set.\n"),
- human_readable (statistics.total_filename_length, hbuf1, human_ceiling, 1, 1),
- human_readable (statistics.whitespace_count, hbuf2, human_ceiling, 1, 1),
- human_readable (statistics.newline_count, hbuf3, human_ceiling, 1, 1),
- human_readable (statistics.highbit_filename_count, hbuf4, human_ceiling, 1, 1));
-
- if (!argc)
+ c = getc (fp);
+ while (c != EOF)
{
- if (results_were_filtered)
- {
- printf(_("Some filenames may have been filtered out, "
- "so we cannot compute the compression ratio.\n"));
- }
- else
- {
- if (statistics.total_filename_length)
- {
- /* A negative compression ratio just means that the
- * compressed database is larger than the list of
- * filenames. This can happen for example for
- * old-format databases containing a small list of short
- * filenames, because the bigram list is 256 bytes.
- */
- printf(_("Compression ratio %4.2f%% (higher is better)\n"),
- 100.0 * ((double)statistics.total_filename_length
- - (double) database_file_size)
- / (double) statistics.total_filename_length);
- }
- else
- {
- printf(_("Compression ratio is undefined\n"));
- }
- }
- }
- printf("\n");
-}
+ register char *s; /* Scan the path we read in. */
-/*
- * Return nonzero if the data we read in indicates that we are
- * looking at a LOCATE02 locate database.
- */
-static int
-looking_at_gnu_locatedb (const char *data, size_t len)
-{
- if (len < sizeof (LOCATEDB_MAGIC))
- return 0;
- else if (0 == memcmp (data, LOCATEDB_MAGIC, sizeof (LOCATEDB_MAGIC)))
- return 1; /* We saw the magic byte sequence */
- else
- return 0;
-}
-
-/*
- * Return nonzero if the data we read in indicates that we are
- * looking at an slocate database.
- */
-static int
-looking_at_slocate_locatedb (const char *filename,
- const char *data,
- size_t len,
- int *seclevel)
-{
- assert(len <= 2);
-
- if (len < 2)
- {
- return 0;
- }
- else
- {
- /* Check that the magic number is a one-byte string */
- if (0 == data[1])
+ if (old_format)
{
- if (isdigit((unsigned char)data[0]))
- {
- /* looks promising. */
- *seclevel = (data[0] - '0');
-
- if (*seclevel > 1)
- {
- /* Hmm, well it's probably an slocate database
- * of some awsomely huge security level, like 2.
- * We don't know how to handle those.
- */
- error(0, 0,
- _("locate database %s looks like an slocate "
- "database but it seems to have security level %c, "
- "which GNU findutils does not currently support"),
- quotearg_n_style(0, locale_quoting_style, filename),
- data[1]);
- return 1;
- }
- else
- {
- return 1;
- }
- }
+ /* Get the offset in the path where this path info starts. */
+ if (c == LOCATEDB_OLD_ESCAPE)
+ count += getw (fp) - LOCATEDB_OLD_OFFSET;
else
- {
- /* Not a digit. */
- return 0;
- }
+ count += c - LOCATEDB_OLD_OFFSET;
+
+ /* Overlay the old path with the remainder of the new. */
+ for (s = path + count; (c = getc (fp)) > LOCATEDB_OLD_ESCAPE;)
+ if (c < 0200)
+ *s++ = c; /* An ordinary character. */
+ else
+ {
+ /* Bigram markers have the high bit set. */
+ c &= 0177;
+ *s++ = bigram1[c];
+ *s++ = bigram2[c];
+ }
+ *s-- = '\0';
}
else
{
- /* Definitely not slocate. */
- return 0;
- }
- }
-}
-
-
-static int
-i_am_little_endian(void)
-{
- union
- {
- unsigned char uch[4];
- unsigned int ui;
- } u;
- u.ui = 0u;
- u.uch[0] = 1;
- u.uch[1] = u.uch[2] = u.uch[3] = 0;
- return u.ui == 1;
-}
-
-
-
-
-/* Print or count the entries in DBFILE that match shell globbing patterns in
- ARGV. Return the number of entries matched. */
-
-static unsigned long
-search_one_database (int argc,
- char **argv,
- const char *dbfile,
- FILE *fp,
- off_t filesize,
- int ignore_case,
- int enable_print,
- int basename_only,
- int use_limit,
- struct locate_limits *plimit,
- int stats,
- int op_and,
- int regex,
- int regex_options)
-{
- char *pathpart; /* A pattern to consider. */
- int argn; /* Index to current pattern in argv. */
- int nread; /* number of bytes read from an entry. */
- struct process_data procdata; /* Storage for data shared with visitors. */
- int slocate_seclevel;
- int oldformat;
- struct visitor* pvis; /* temp for determining past_pat_inspector. */
- const char *format_name;
- enum ExistenceCheckType do_check_existence;
-
-
- /* We may turn on existence checking for a given database.
- * We ensure that we can return to the previous behaviour
- * by using two variables, do_check_existence (which we act on)
- * and check_existence (whcih indicates the default before we
- * adjust it on the bassis of what kind of database we;re using
- */
- do_check_existence = check_existence;
-
-
- if (ignore_case)
- regex_options |= RE_ICASE;
-
- oldformat = 0;
- procdata.endian_state = GetwordEndianStateInitial;
- procdata.len = procdata.count = 0;
- procdata.slocatedb_format = 0;
- procdata.itemcount = 0;
-
- procdata.dbfile = dbfile;
- procdata.fp = fp;
-
- /* Set up the inspection regime */
- inspectors = NULL;
- lastinspector = NULL;
- past_pat_inspector = NULL;
- results_were_filtered = false;
-#if 0
- procdata.pathsize = 1026; /* Increased as necessary by locate_read_str. */
-#else
- procdata.pathsize = 128; /* Increased as necessary by locate_read_str. */
-#endif
- procdata.original_filename = xmalloc (procdata.pathsize);
-
-
- nread = fread (procdata.original_filename, 1, SLOCATE_DB_MAGIC_LEN,
- procdata.fp);
- slocate_seclevel = 0;
- if (looking_at_slocate_locatedb(procdata.dbfile,
- procdata.original_filename,
- nread,
- &slocate_seclevel))
- {
- error(0, 0,
- _("%s is an slocate database. "
- "Support for these is new, expect problems for now."),
- quotearg_n_style(0, locale_quoting_style, procdata.dbfile));
-
- /* slocate also uses frcode, but with a different header.
- * We handle the header here and then work with the data
- * in the normal way.
- */
- if (slocate_seclevel > 1)
- {
- /* We don't know what those security levels mean,
- * so do nothing further
- */
- error(0, 0,
- _("%s is an slocate database of unsupported security level %d; skipping it."),
- quotearg_n_style(0, locale_quoting_style, procdata.dbfile),
- slocate_seclevel);
- return 0;
- }
- else if (slocate_seclevel > 0)
- {
- /* Don't show the filenames to the user if they don't exist.
- * Showing stats is safe since filenames are only counted
- * after the existence check
- */
- if (ACCEPT_NON_EXISTING == check_existence)
- {
- /* Do not allow the user to see a list of filenames that they
- * cannot stat().
- */
- error(0, 0,
- _("You specified the -E option, but that option "
- "cannot be used with slocate-format databases "
- "with a non-zero security level. No results will be "
- "generated for this database.\n"));
- return 0;
- }
- if (ACCEPT_EXISTING != do_check_existence)
- {
- if (enable_print || stats)
- {
- error(0, 0,
- _("%s is an slocate database. "
- "Turning on the '-e' option."),
- quotearg_n_style(0, locale_quoting_style, procdata.dbfile));
- }
- do_check_existence = ACCEPT_EXISTING;
- }
- }
- add_visitor(visit_locate02_format, NULL);
- format_name = "slocate";
- procdata.slocatedb_format = 1;
- }
- else
- {
- int nread2;
-
- procdata.slocatedb_format = 0;
- extend (&procdata, sizeof(LOCATEDB_MAGIC), 0u);
- nread2 = fread (procdata.original_filename+nread, 1, sizeof (LOCATEDB_MAGIC)-nread,
- procdata.fp);
- if (looking_at_gnu_locatedb(procdata.original_filename, nread+nread2))
- {
- add_visitor(visit_locate02_format, NULL);
- format_name = "GNU LOCATE02";
- }
- else /* Use the old format */
- {
- int i;
-
- nread += nread2;
- extend (&procdata, 256u, 0u);
- /* Read the list of the most common bigrams in the database. */
- if (nread < 256)
- {
- int more_read = fread (procdata.original_filename + nread, 1,
- 256 - nread, procdata.fp);
- if ( (more_read + nread) != 256 )
- {
- error(1, 0,
- _("Old-format locate database %s is "
- "too short to be valid"),
- quotearg_n_style(0, locale_quoting_style, dbfile));
-
- }
- }
-
- for (i = 0; i < 128; i++)
- {
- procdata.bigram1[i] = procdata.original_filename[i << 1];
- procdata.bigram2[i] = procdata.original_filename[(i << 1) + 1];
- }
- format_name = "old";
- oldformat = 1;
- add_visitor(visit_old_format, NULL);
- }
- }
-
- if (basename_only)
- add_visitor(visit_basename, NULL);
-
- /* Add an inspector for each pattern we're looking for. */
- for ( argn = 0; argn < argc; argn++ )
- {
- results_were_filtered = true;
- pathpart = argv[argn];
- if (regex)
- {
- struct regular_expression *p = xmalloc(sizeof(*p));
- const char *error_message = NULL;
-
- memset (&p->regex, 0, sizeof (p->regex));
-
- re_set_syntax(regex_options);
- p->regex.allocated = 100;
- p->regex.buffer = xmalloc (p->regex.allocated);
- p->regex.fastmap = NULL;
- p->regex.syntax = regex_options;
- p->regex.translate = NULL;
-
- error_message = re_compile_pattern (pathpart, strlen (pathpart),
- &p->regex);
- if (error_message)
- {
- error (1, 0, "%s", error_message);
- }
- else
- {
- add_visitor(visit_regex, p);
- }
- }
- else if (contains_metacharacter(pathpart))
- {
- if (ignore_case)
- add_visitor(visit_globmatch_casefold, pathpart);
+ if (c == LOCATEDB_ESCAPE)
+ count += get_short (fp);
+ else if (c > 127)
+ count += c - 256;
else
- add_visitor(visit_globmatch_nofold, pathpart);
- }
- else
- {
- /* No glob characters used. Hence we match on
- * _any part_ of the filename, not just the
- * basename. This seems odd to me, but it is the
- * traditional behaviour.
- * James Youngman <jay@gnu.org>
- */
- visitfunc matcher;
- if (1 == MB_CUR_MAX)
- {
- /* As an optimisation, use a strstr() matcher if we are
- * in a unibyte locale. This can give a x2 speedup in
- * the C locale. Some light testing reveals that
- * glibc's strstr() is somewhere around 40% faster than
- * gnulib's, so we just use strstr().
- */
- matcher = ignore_case ?
- visit_substring_match_casefold_narrow :
- visit_substring_match_nocasefold_narrow;
- }
- else
- {
- matcher = ignore_case ?
- visit_substring_match_casefold_wide :
- visit_substring_match_nocasefold_wide;
- }
- add_visitor(matcher, pathpart);
- }
- }
-
- pvis = lastinspector;
-
- /* We add visit_existing_*() as late as possible to reduce the
- * number of stat() calls.
- */
- switch (do_check_existence)
- {
- case ACCEPT_EXISTING:
- results_were_filtered = true;
- if (follow_symlinks) /* -L, default */
- add_visitor(visit_existing_follow, NULL);
- else /* -P */
- add_visitor(visit_existing_nofollow, NULL);
- break;
-
- case ACCEPT_NON_EXISTING:
- results_were_filtered = true;
- if (follow_symlinks) /* -L, default */
- add_visitor(visit_non_existing_follow, NULL);
- else /* -P */
- add_visitor(visit_non_existing_nofollow, NULL);
- break;
-
- case ACCEPT_EITHER: /* Default, neither -E nor -e */
- /* do nothing; no extra processing. */
- break;
- }
-
- /* Security issue: The stats visitor must be added immediately
- * before the print visitor, because otherwise the -S option would
- * leak information about files that the caller cannot see.
- */
- if (stats)
- add_visitor(visit_stats, &statistics);
-
- if (enable_print)
- {
- if (print_quoted_filename)
- add_visitor(visit_justprint_quoted, NULL);
- else
- add_visitor(visit_justprint_unquoted, NULL);
- }
-
+ count += c;
- if (use_limit)
- add_visitor(visit_limit, plimit);
- else
- add_visitor(visit_count, plimit);
-
-
- if (argc > 1)
- {
- past_pat_inspector = pvis->next;
- if (op_and)
- mainprocessor = process_and;
- else
- mainprocessor = process_or;
- }
- else
- mainprocessor = process_simple;
-
- if (stats)
- {
- printf(_("Database %s is in the %s format.\n"),
- procdata.dbfile,
- format_name);
+ /* Overlay the old path with the remainder of the new. */
+ nread = getstr (&path, &pathsize, fp, '\0', count);
+ if (nread < 0)
+ break;
+ c = getc (fp);
+ s = path + count + nread - 2; /* Move to the last char in path. */
+ assert (s[0] != '\0');
+ assert (s[1] == '\0'); /* Our terminator. */
+ assert (s[2] == '\0'); /* Added by getstr. */
+ }
+
+ /* If the previous path matched, scan the whole path for the last
+ char in the subpattern. If not, the shared prefix doesn't match
+ the pattern, so don't scan it for the last char. */
+ cutoff = prev_fast_match ? path : path + count;
+
+ /* Search backward starting at the end of the path we just read in,
+ for the character at the end of the last glob-free subpattern
+ in PATHPART. */
+ for (prev_fast_match = false; s >= cutoff; s--)
+ /* Fast first char check. */
+ if (*s == *patend)
+ {
+ char *s2; /* Scan the path we read in. */
+ register char *p2; /* Scan `patend'. */
+
+ for (s2 = s - 1, p2 = patend - 1; *p2 != '\0' && *s2 == *p2;
+ s2--, p2--)
+ ;
+ if (*p2 == '\0')
+ {
+ /* Success on the fast match. Compare the whole pattern
+ if it contains globbing characters. */
+ prev_fast_match = true;
+ if (globflag == false || fnmatch (pathpart, path, 0) == 0)
+ {
+ puts (path);
+ ++printed;
+ }
+ break;
+ }
+ }
}
-
- procdata.c = getc (procdata.fp);
- /* If we are searching for filename patterns, the inspector list
- * will contain an entry for each pattern for which we are searching.
- */
- while ( (procdata.c != EOF) &&
- (VISIT_ABORT != (mainprocessor)(&procdata)) )
- {
- /* Do nothing; all the work is done in the visitor functions. */
- }
-
- if (stats)
+ if (ferror (fp))
{
- if (oldformat)
- {
- int host_little_endian = i_am_little_endian();
- const char *little = _("The database has little-endian "
- "machine-word encoding.\n");
- const char *big = _("The database has big-endian "
- "machine-word encoding.\n");
-
- if (GetwordEndianStateNative == procdata.endian_state)
- {
- printf("%s", (host_little_endian ? little : big));
- }
- else if (GetwordEndianStateSwab == procdata.endian_state)
- {
- printf("%s", (host_little_endian ? big : little));
- }
- else
- {
- printf(_("The database machine-word encoding order "
- "is not obvious.\n"));
- }
- }
- if (filesize)
- print_stats(argc, filesize);
+ error (0, errno, "%s", dbfile);
+ return 0;
}
-
- if (ferror (procdata.fp))
+ if (fclose (fp) == EOF)
{
- error (0, errno, "%s",
- quotearg_n_style(0, locale_quoting_style, procdata.dbfile));
+ error (0, errno, "%s", dbfile);
return 0;
}
- return plimit->items_accepted;
-}
-
-
+ return printed;
+}
extern char *version_string;
@@ -1409,533 +337,66 @@ extern char *version_string;
char *program_name;
static void
-usage (FILE *stream)
+usage (stream, status)
+ FILE *stream;
+ int status;
{
- fprintf (stream, _("\
-Usage: %s [-d path | --database=path] [-e | -E | --[non-]existing]\n\
- [-i | --ignore-case] [-w | --wholename] [-b | --basename] \n\
- [--limit=N | -l N] [-S | --statistics] [-0 | --null] [-c | --count]\n\
- [-P | -H | --nofollow] [-L | --follow] [-m | --mmap ] [ -s | --stdio ]\n\
- [-A | --all] [-p | --print] [-r | --regex ] [--regextype=TYPE]\n\
- [--max-database-age D] [--version] [--help]\n\
- pattern...\n"),
+ fprintf (stream, "\
+Usage: %s [-d path] [--database=path] [--version] [--help] pattern...\n",
program_name);
- fputs (_("\nReport bugs to <bug-findutils@gnu.org>.\n"), stream);
+ exit (status);
}
-enum
- {
- REGEXTYPE_OPTION = CHAR_MAX + 1,
- MAX_DB_AGE
- };
-
static struct option const longopts[] =
{
{"database", required_argument, NULL, 'd'},
- {"existing", no_argument, NULL, 'e'},
- {"non-existing", no_argument, NULL, 'E'},
- {"ignore-case", no_argument, NULL, 'i'},
- {"all", no_argument, NULL, 'A'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'v'},
- {"null", no_argument, NULL, '0'},
- {"count", no_argument, NULL, 'c'},
- {"wholename", no_argument, NULL, 'w'},
- {"wholepath", no_argument, NULL, 'w'}, /* Synonym. */
- {"basename", no_argument, NULL, 'b'},
- {"print", no_argument, NULL, 'p'},
- {"stdio", no_argument, NULL, 's'},
- {"mmap", no_argument, NULL, 'm'},
- {"limit", required_argument, NULL, 'l'},
- {"regex", no_argument, NULL, 'r'},
- {"regextype", required_argument, NULL, REGEXTYPE_OPTION},
- {"statistics", no_argument, NULL, 'S'},
- {"follow", no_argument, NULL, 'L'},
- {"nofollow", no_argument, NULL, 'P'},
- {"max-database-age", required_argument, NULL, MAX_DB_AGE},
{NULL, no_argument, NULL, 0}
};
-
-static int
-drop_privs(void)
-{
- const char * what = "failed";
- const uid_t orig_euid = geteuid();
- const uid_t uid = getuid();
- const gid_t gid = getgid();
-
-#if HAVE_SETGROUPS
- /* Use of setgroups() is restricted to root only. */
- if (0 == orig_euid)
- {
- /* We're either root or running setuid-root. */
- gid_t groups[1];
- groups[0] = gid;
- if (0 != setgroups(1u, groups))
- {
- what = _("failed to drop group privileges");
- goto fail;
- }
- }
-#endif
-
- /* Drop any setuid privileges */
- if (uid != orig_euid)
- {
- if (0 == uid)
- {
- /* We're really root anyway, but are setuid to something else. Leave it. */
- }
- else
- {
- errno = 0;
- if (0 != setuid(getuid()))
- {
- what = _("failed to drop setuid privileges");
- goto fail;
- }
-
- /* Defend against the case where the attacker runs us with the
- * capability to call setuid() turned off, which on some systems
- * will cause the above attempt to drop privileges fail (leaving us
- * privileged).
- */
- else
- {
- /* Check that we can no longer switch bask to root */
- if (0 == setuid(0))
- {
- what = _("Failed to fully drop privileges");
- /* The errno value here is not interesting (since
- * the system call we are complaining about
- * succeeded when we wanted it to fail). Arrange
- * for the call to error() not to print the errno
- * value by setting errno=0.
- */
- errno = 0;
- goto fail;
- }
- }
- }
- }
-
- /* Drop any setgid privileges */
- errno = 0;
- if (0 != setgid(gid))
- {
- what = _("failed to drop setgid privileges");
- goto fail;
- }
-
- /* success. */
- return 0;
-
- fail:
- error(1, errno, "%s",
- quotearg_n_style(0, locale_quoting_style, what));
- abort();
- kill(0, SIGKILL);
- _exit(1);
- /*NOTREACHED*/
- /* ... we hope. */
- for (;;)
- {
- /* deliberate infinite loop */
- }
-}
-
-static int
-opendb(const char *name)
-{
- int fd = open(name, O_RDONLY
-#if defined O_LARGEFILE
- |O_LARGEFILE
-#endif
- );
- if (fd >= 0)
- {
- /* Make sure it won't survive an exec */
- if (0 != fcntl(fd, F_SETFD, FD_CLOEXEC))
- {
- close(fd);
- fd = -1;
- }
- }
- return fd;
-}
-
-int
-dolocate (int argc, char **argv, int secure_db_fd)
+void
+main (argc, argv)
+ int argc;
+ char **argv;
{
char *dbpath;
- unsigned long int found = 0uL;
- int ignore_case = 0;
- int print = 0;
- int just_count = 0;
- int basename_only = 0;
- int use_limit = 0;
- int regex = 0;
- int regex_options = RE_SYNTAX_EMACS;
- int stats = 0;
- int op_and = 0;
- const char *e;
- FILE *fp;
- int they_chose_db = 0;
- bool did_stdin = false; /* Set to prevent rereading stdin. */
-
+ int found = 0, optc;
+
program_name = argv[0];
-#ifdef HAVE_SETLOCALE
- setlocale (LC_ALL, "");
-#endif
- bindtextdomain (PACKAGE, LOCALEDIR);
- textdomain (PACKAGE);
- atexit (close_stdout);
-
- limits.limit = 0;
- limits.items_accepted = 0;
-
- quote_opts = clone_quoting_options (NULL);
- print_quoted_filename = true;
-
- /* We cannot simultaneously trust $LOCATE_PATH and use the
- * setuid-access-controlled database,, since that could cause a leak
- * of private data.
- */
dbpath = getenv ("LOCATE_PATH");
- if (dbpath)
- {
- they_chose_db = 1;
- }
-
- check_existence = ACCEPT_EITHER;
-
- for (;;)
- {
- int opti = -1;
- int optc = getopt_long (argc, argv, "Abcd:eEil:prsm0SwHPL", longopts,
- &opti);
- if (optc == -1)
+ if (dbpath == NULL)
+ dbpath = LOCATE_DB;
+
+ while ((optc = getopt_long (argc, argv, "d:", longopts, (int *) 0)) != -1)
+ switch (optc)
+ {
+ case 'd':
+ dbpath = optarg;
break;
- switch (optc)
- {
- case '0':
- separator = 0;
- print_quoted_filename = false; /* print filename 'raw'. */
- break;
-
- case 'A':
- op_and = 1;
- break;
-
- case 'b':
- basename_only = 1;
- break;
-
- case 'c':
- just_count = 1;
- break;
-
- case 'd':
- dbpath = optarg;
- they_chose_db = 1;
- break;
-
- case 'e':
- check_existence = ACCEPT_EXISTING;
- break;
-
- case 'E':
- check_existence = ACCEPT_NON_EXISTING;
- break;
-
- case 'i':
- ignore_case = 1;
- break;
-
- case 'h':
- usage (stdout);
- return 0;
-
- case MAX_DB_AGE:
- /* XXX: nothing in the test suite for this option. */
- set_max_db_age (optarg);
- break;
-
- case 'p':
- print = 1;
- break;
-
- case 'v':
- display_findutils_version ("locate");
- return 0;
-
- case 'w':
- basename_only = 0;
- break;
-
- case 'r':
- regex = 1;
- break;
-
- case REGEXTYPE_OPTION:
- regex_options = get_regex_type (optarg);
- break;
-
- case 'S':
- stats = 1;
- break;
-
- case 'L':
- follow_symlinks = 1;
- break;
-
- /* In find, -P and -H differ in the way they handle paths
- * given on the command line. This is not relevant for
- * locate, but the -H option is supported because it is
- * probably more intuitive to do so.
- */
- case 'P':
- case 'H':
- follow_symlinks = 0;
- break;
-
- case 'l':
- {
- char *end = optarg;
- strtol_error err = xstrtoumax (optarg, &end, 10, &limits.limit,
- NULL);
- if (LONGINT_OK != err)
- xstrtol_fatal (err, opti, optc, longopts, optarg);
- use_limit = 1;
- }
- break;
-
- case 's': /* use stdio */
- case 'm': /* use mmap */
- /* These options are implemented simply for
- * compatibility with FreeBSD
- */
- break;
-
- default:
- usage (stderr);
- return 1;
- }
- }
+ case 'h':
+ usage (stdout, 0);
+ case 'v':
+ printf ("GNU locate version %s\n", version_string);
+ exit (0);
- /* If the user gave the -d option or set LOCATE_PATH,
- * relinquish access to the secure database.
- */
- if (they_chose_db)
- {
- if (secure_db_fd >= 0)
- {
- close(secure_db_fd);
- secure_db_fd = -1;
- }
- }
+ default:
+ usage (stderr, 1);
+ }
- if (!just_count && !stats)
- print = 1;
+ if (optind == argc)
+ usage (stderr, 1);
- if (stats)
+ for (; optind < argc; optind++)
{
- if (optind == argc)
- use_limit = 0;
+ char *e;
+ next_element (dbpath); /* Initialize. */
+ while ((e = next_element ((char *) NULL)) != NULL)
+ found |= locate (argv[optind], e);
}
- else
- {
- if (!just_count && optind == argc)
- {
- usage (stderr);
- return 1;
- }
- }
-
- if (1 == isatty(STDOUT_FILENO))
- stdout_is_a_tty = true;
- else
- stdout_is_a_tty = false;
-
- if (they_chose_db)
- next_element (dbpath, 0); /* Initialize. */
-
- /* Bail out early if limit already reached. */
- while (!use_limit || limits.limit > limits.items_accepted)
- {
- struct stat st;
- int fd;
- off_t filesize;
-
- statistics.compressed_bytes =
- statistics.total_filename_count =
- statistics.total_filename_length =
- statistics.whitespace_count =
- statistics.newline_count =
- statistics.highbit_filename_count = 0u;
-
- if (they_chose_db)
- {
- /* Take the next element from the list of databases */
- e = next_element ((char *) NULL, 0);
- if (NULL == e)
- break;
-
- if (0 == strcmp (e, "-"))
- {
- if (did_stdin)
- {
- error (0, 0,
- _("warning: the locate database can only be read from stdin once."));
- return 0;
- }
- else
- {
- e = "<stdin>";
- fd = 0;
- did_stdin = true;
- }
- }
- else
- {
- if (0 == strlen(e) || 0 == strcmp(e, "."))
- {
- e = LOCATE_DB;
- }
-
- /* open the database */
- fd = opendb(e);
- if (fd < 0)
- {
- error (0, errno, "%s",
- quotearg_n_style(0, locale_quoting_style, e));
- return 0;
- }
- }
- }
- else
- {
- if (-1 == secure_db_fd)
- {
- /* Already searched the database, it's time to exit the loop */
- break;
- }
- else
- {
- e = selected_secure_db;
- fd = secure_db_fd;
- secure_db_fd = -1;
- }
- }
-
- /* Check the database to see if it is old. */
- if (fstat(fd, &st))
- {
- error (0, errno, "%s",
- quotearg_n_style(0, locale_quoting_style, e));
- /* continue anyway */
- filesize = (off_t)0;
- }
- else
- {
- time_t now;
-
- filesize = st.st_size;
-
- if ((time_t)-1 == time(&now))
- {
- /* If we can't tell the time, we don't know how old the
- * database is. But since the message is just advisory,
- * we continue anyway.
- */
- error (0, errno, _("time system call failed"));
- }
- else
- {
- double age = difftime(now, st.st_mtime);
- double warn_seconds = SECONDS_PER_UNIT * warn_number_units;
- if (age > warn_seconds)
- {
- /* For example:
- warning: database `fred' is more than 8 days old (actual age is 10 days)*/
- error (0, 0,
- _("warning: database %s is more than %d %s old (actual age is %.1f %s)"),
- quotearg_n_style(0, locale_quoting_style, e),
- warn_number_units, _(warn_name_units),
- (age/(double)SECONDS_PER_UNIT), _(warn_name_units));
- }
- }
- }
-
- fp = fdopen(fd, "r");
- if (NULL == fp)
- {
- error (0, errno, "%s",
- quotearg_n_style(0, locale_quoting_style, e));
- return 0;
- }
-
- /* Search this database for all patterns simultaneously */
- found = search_one_database (argc - optind, &argv[optind],
- e, fp, filesize,
- ignore_case, print, basename_only,
- use_limit, &limits, stats,
- op_and, regex, regex_options);
-
- /* Close the databsase (even if it is stdin) */
- if (fclose (fp) == EOF)
- {
- error (0, errno, "%s",
- quotearg_n_style(0, locale_quoting_style, e));
- return 0;
- }
- }
-
- if (just_count)
- {
- printf("%ld\n", found);
- }
-
- if (found || (use_limit && (limits.limit==0)) || stats )
- return 0;
- else
- return 1;
-}
-
-#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
-static int
-open_secure_db(void)
-{
- int fd, i;
-
- const char * secure_db_list[] =
- {
- LOCATE_DB,
- "/var/lib/slocate/slocate.db",
- NULL
- };
- for (i=0; secure_db_list[i]; ++i)
- {
- fd = opendb(secure_db_list[i]);
- if (fd >= 0)
- {
- selected_secure_db = secure_db_list[i];
- return fd;
- }
- }
- return -1;
-}
-
-int
-main (int argc, char **argv)
-{
- int dbfd = open_secure_db();
- drop_privs();
-
- return dolocate(argc, argv, dbfd);
+ exit (!found);
}
diff --git a/locate/locatedb.5 b/locate/locatedb.5
index a94905d5..7145feef 100644
--- a/locate/locatedb.5
+++ b/locate/locatedb.5
@@ -1,4 +1,4 @@
-.TH LOCATEDB 5 \" -*- nroff -*-
+.TH LOCATEDB 5L \" -*- nroff -*-
.SH NAME
locatedb \- front-compressed file name database
.SH DESCRIPTION
@@ -10,39 +10,31 @@ particular directory trees when the databases were last updated.
.P
There can be multiple databases. Users can select which databases
\fBlocate\fP searches using an environment variable or command line
-option; see \fBlocate\fP(1). The system administrator can choose the
+option; see \fBlocate\fP(1L). The system administrator can choose the
file name of the default database, the frequency with which the
databases are updated, and the directories for which they contain
entries. Normally, file name databases are updated by running the
\fBupdatedb\fP program periodically, typically nightly; see
-\fBupdatedb\fP(1).
-
-.SH GNU LOCATE02 database format
-This is the default format of databases produced by
-.BR updatedb .
-The
-.B updatedb
-program runs
-.B frcode
-to compress the list of file names using front-compression, which
-reduces the database size by a factor of 4 to 5. Front-compression
-(also known as incremental encoding) works as follows.
+\fBupdatedb\fP(1L).
+.P
+\fBupdatedb\fP runs a program called \fBfrcode\fP to compress the list
+of file names using front-compression, which reduces
+the database size by a factor of 4 to 5. Front-compression (also
+known as incremental encoding) works as follows.
.P
The database entries are a sorted list (case-insensitively, for users'
convenience). Since the list is sorted, each entry is likely to share
a prefix (initial string) with the previous entry. Each database
-entry begins with an signed offset-differential count byte, which is
-the additional number of characters of prefix of the preceding entry
-to use beyond the number that the preceding entry is using of its
+entry begins with an offset-differential count byte, which is the
+additional number of characters of prefix of the preceding entry to
+use beyond the number that the preceding entry is using of its
predecessor. (The counts can be negative.) Following the count is a
null-terminated ASCII remainder \(em the part of the name that follows
the shared prefix.
.P
If the offset-differential count is larger than can be stored in a
-signed byte (+/\-127), the byte has the value 0x80 (binary 10000000)
-and the actual count follows in a 2-byte word, with the high byte
-first (network byte order). This count can also be negative (the sign
-bit being in the first of the two bytes).
+byte (+/\-127), the byte has the value 0x80 and the count follows in a
+2-byte word, with the high byte first (network byte order).
.P
Every database begins with a dummy entry for a file called `LOCATE02',
which \fBlocate\fP checks for to ensure that the database file has the
@@ -51,37 +43,8 @@ correct format; it ignores the entry in doing the search.
Databases can not be concatenated together, even if the first
(dummy) entry is trimmed from all but the first database. This
is because the offset-differential count in the first entry of the
-second and following databases will be wrong.
-.P
-In the future, the data within the locate database may not be sorted
-in any particular order. To obtain sorted results, pipe the output of
-.B locate
-through
-.BR "sort -f" .
-.SH slocate database format
-The
-.B slocate
-program uses a database format similar to, but not quite the same as,
-GNU
-.BR locate .
-The first byte of the database specifies its
-.I security
-.IR level .
-If the security level is 0,
-.B slocate
-will read, match and print filenames on the basis of the information
-in the database only. However, if the security level byte is 1,
-.B slocate
-omits entries from its output if the invoking user is unable to access
-them. The second byte of the database is zero. The second byte is
-followed by the first database entry. The first entry in the database
-is not preceded by any differential count or dummy entry. Instead
-the differential count for the first item is assumed to be zero.
+second and following databases will be wrong.
.P
-Starting with the second entry (if any) in the database, data is
-interpreted as for the GNU LOCATE02 format.
-
-.SH Old Locate Database format
There is also an old database format, used by Unix
.B locate
and
@@ -139,15 +102,5 @@ and count bytes made printable:
(6 = 14 \- 8, and \-9 = 5 \- 14)
.fi
.SH "SEE ALSO"
-\fBfind\fP(1), \fBlocate\fP(1), \fBlocatedb\fP(5), \fBxargs\fP(1),
+\fBfind\fP(1L), \fBlocate\fP(1L), \fBlocatedb\fP(5L), \fBxargs\fP(1L)
\fBFinding Files\fP (on-line in Info, or printed)
-.SH "BUGS"
-.P
-The best way to report a bug is to use the form at
-http://savannah.gnu.org/bugs/?group=findutils.
-The reason for this is that you will then be able to track progress in
-fixing the problem. Other comments about \fBlocate\fP(1) and about
-the findutils package in general can be sent to the
-.I bug-findutils
-mailing list. To join the list, send email to
-.IR bug-findutils-request@gnu.org .
diff --git a/locate/locatedb.h b/locate/locatedb.h
index a4a7289c..e4017651 100644
--- a/locate/locatedb.h
+++ b/locate/locatedb.h
@@ -1,19 +1,19 @@
/* locatedb.h -- declarations for the locate database
Copyright (C) 1994 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
+ 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 3 of the License, or
- (at your option) any later version.
-
+ 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, see <http://www.gnu.org/licenses/>.
-*/
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _LOCATEDB_H
#define _LOCATEDB_H 1
@@ -30,19 +30,6 @@
This value (which is -128) indicates that the difference is
too large to fit into one byte, and a two-byte integer follows. */
#define LOCATEDB_ESCAPE 0x80
-#define LOCATEDB_ONEBYTE_MAX (127)
-#define LOCATEDB_ONEBYTE_MIN (-127)
-
-
-/* If it is ever possible to try to encode LOCATEDB_MAGIC as a
- * single-byte offset, then an unfortunate length of common prefix
- * will produce a spurious escape character, desynchronising the data
- * stream. We use a compile-time check in the preprocessor to prevent
- * this.
- */
-#if LOCATEDB_ESCAPE <= LOCATEDB_ONEBYTE_MAX
-#error "You have a bad combination of LOCATEDB_ESCAPE and LOCATEDB_ONEBYTE_MAX, see above"
-#endif
/* These are used for old, bigram-encoded databases: */
@@ -52,29 +39,4 @@
/* Offset added to differential counts to encode them as positive numbers. */
#define LOCATEDB_OLD_OFFSET 14
-# ifndef PARAMS
-# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
-# define PARAMS(Args) Args
-# else
-# define PARAMS(Args) ()
-# endif
-# endif
-
-typedef enum
- {
- GetwordEndianStateInitial = 0,
- GetwordEndianStateNative = 1,
- GetwordEndianStateSwab = 2
- } GetwordEndianState;
-
-int getword (FILE *fp, const char *filename,
- size_t minvalue, size_t maxvalue,
- GetwordEndianState *endian_state_flag);
-
-bool putword (FILE *fp, int word,
- GetwordEndianState endian_state_flag);
-
-
-#define SLOCATE_DB_MAGIC_LEN 2
-
#endif /* !_LOCATEDB_H */
diff --git a/locate/updatedb.1 b/locate/updatedb.1
index e42ec74c..76726262 100644
--- a/locate/updatedb.1
+++ b/locate/updatedb.1
@@ -1,4 +1,4 @@
-.TH UPDATEDB 1 \" -*- nroff -*-
+.TH UPDATEDB 1L \" -*- nroff -*-
.SH NAME
updatedb \- update a file name database
.SH SYNOPSIS
@@ -23,14 +23,14 @@ the root of each filesystem, containing the entries for that filesystem.
is then run for each filesystem on the fileserver where that
filesystem is on a local disk, to prevent thrashing the network.
Users can select which databases \fBlocate\fP searches using an
-environment variable or command line option; see \fBlocate\fP(1).
+environment variable or command line option; see \fBlocate\fP(1L).
Databases can not be concatenated together.
.P
The file name database format changed starting with GNU
.B find
and
.B locate
-version 4.0 to allow machines with different byte orderings to share
+version 4.0 to allow machines with diffent byte orderings to share
the databases. The new GNU
.B locate
can read both the old and new database formats.
@@ -41,104 +41,38 @@ and
produce incorrect results if given a new-format database.
.SH OPTIONS
.TP
-.B \-\-findoptions='\fI\-option1 \-option2...\fP'
-Global options to pass on to \fBfind\fP.
-The environment variable \fBFINDOPTIONS\fP also sets this value.
-Default is none.
-.TP
.B \-\-localpaths='\fIpath1 path2...\fP'
Non-network directories to put in the database.
Default is /.
.TP
.B \-\-netpaths='\fIpath1 path2...\fP'
Network (NFS, AFS, RFS, etc.) directories to put in the database.
-The environment variable \fBNETPATHS\fP also sets this value.
Default is none.
.TP
.B \-\-prunepaths='\fIpath1 path2...\fP'
Directories to not put in the database, which would otherwise be.
-Remove any trailing slashes from the path names, otherwise
-.B updatedb
-won\'t recognise the paths you want to omit (because it uses them as
-regular expression patterns).
-The environment variable \fBPRUNEPATHS\fP also sets this value.
Default is /tmp /usr/tmp /var/tmp /afs.
.TP
-.B \-\-prunefs='\fIpath...\fP'
-File systems to not put in the database, which would otherwise be.
-Note that files are pruned when a file system is reached;
-Any file system mounted under an undesired file system will be
-ignored.
-The environment variable
-\fBPRUNEFS\fP also sets this value.
-Default is \fInfs NFS proc\fP.
-.TP
.B \-\-output=\fIdbfile\fP
The database file to build.
-Default is system-dependent. In Debian GNU/Linux, the default
-is /var/cache/locate/locatedb.
-.TP
-.B \-\-localuser=\fIuser\fP
-The user to search non-network directories as, using \fBsu\fP(1).
-Default is to search the non-network directories as the current user.
-You can also use the environment variable \fBLOCALUSER\fP to set this user.
+Default is system-dependent, but typically /usr/local/var/locatedb.
.TP
.B \-\-netuser=\fIuser\fP
The user to search network directories as, using \fBsu\fP(1).
Default is \fBdaemon\fP.
-You can also use the environment variable \fBNETUSER\fP to set this user.
.TP
.B \-\-old\-format
-Create the database in the old format. This is a synonym for
-.BR \-\-dbformat=old .
-.TP
-.B \-\-dbformat=F
-Create the database in format F. The default format is called LOCATE02.
-F can be
-.B old
-to select the old database format (this is the same as specifying
-.BR \-\-old\-format ).
-Alternatively the
-.B slocate
-format is also supported. When the
-.B slocate
-format is in use, the database produced is marked as having security
-level 1. If you want to build a system-wide
-.B slocate
-database, you may want to run
-.B updatedb
-as root.
+Create the database in the old format instead of the new one.
.TP
.B \-\-version
Print the version number of
.B updatedb
and exit.
.TP
-.B "\-\-help"
+.I "\-\-help"
Print a summary of the options to
.B updatedb
and exit.
.SH "SEE ALSO"
-\fBfind\fP(1), \fBlocate\fP(1), \fBlocatedb\fP(5), \fBxargs\fP(1)
+\fBfind\fP(1L), \fBlocate\fP(1L), \fBlocatedb\fP(5L), \fBxargs\fP(1L)
\fBFinding Files\fP (on-line in Info, or printed)
-.SH "BUGS"
-.P
-The
-.B updatedb
-program correctly handles filenames containing newlines,
-but only if the system's sort command has a working
-.I \-z
-option. If you suspect that
-.B locate
-may need to return filenames containing newlines, consider using its
-.I \-\-null
-option.
-.P
-The best way to report a bug is to use the form at
-http://savannah.gnu.org/bugs/?group=findutils.
-The reason for this is that you will then be able to track progress in
-fixing the problem. Other comments about \fBupdatedb\fP(1) and about
-the findutils package in general can be sent to the
-.I bug-findutils
-mailing list. To join the list, send email to
-.IR bug-findutils-request@gnu.org .
diff --git a/locate/updatedb.sh b/locate/updatedb.sh
index 9f4e4d94..944791af 100644
--- a/locate/updatedb.sh
+++ b/locate/updatedb.sh
@@ -1,156 +1,51 @@
-#! /bin/sh
+#!/bin/sh
# updatedb -- build a locate pathname database
-# Copyright (C) 1994, 1996, 1997, 2000, 2001, 2003, 2004, 2005, 2006
-# Free Software Foundation, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
+# Copyright (C) 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 3 of the License, or
-# (at your option) any later version.
-#
+# 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, see <http://www.gnu.org/licenses/>.
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# csh original by James Woods; sh conversion by David MacKenzie.
-#exec 2> /tmp/updatedb-trace.txt
-#set -x
-
-version='
-updatedb (@PACKAGE_NAME@) @VERSION@
-Copyright (C) 2007 Free Software Foundation, Inc.
-License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
-This is free software: you are free to change and redistribute it.
-There is NO WARRANTY, to the extent permitted by law.
-
-Written by Eric B. Decker, James Youngman, and Kevin Dalley.
-'
-
-
usage="\
-Usage: $0 [--findoptions='-option1 -option2...']
- [--localpaths='dir1 dir2...'] [--netpaths='dir1 dir2...']
- [--prunepaths='dir1 dir2...'] [--prunefs='fs1 fs2...']
- [--output=dbfile] [--netuser=user] [--localuser=user]
- [--old-format] [--dbformat] [--version] [--help]
+Usage: updatedb [--localpaths='dir1 dir2...'] [--netpaths='dir1 dir2...']
+ [--prunepaths='dir1 dir2...'] [--output=dbfile] [--netuser=user]
+ [--old-format] [--version] [--help]"
-Report bugs to <bug-findutils@gnu.org>."
-changeto=/
old=no
for arg
do
- # If we are unable to fork, the back-tick operator will
- # fail (and the shell will emit an error message). When
- # this happens, we exit with error value 71 (EX_OSERR).
- # Alternative candidate - 75, EX_TEMPFAIL.
- opt=`echo $arg|sed 's/^\([^=]*\).*/\1/'` || exit 71
- val=`echo $arg|sed 's/^[^=]*=\(.*\)/\1/'` || exit 71
+ opt=`echo $arg|sed 's/^\([^=]*\).*/\1/'`
+ val=`echo $arg|sed 's/^[^=]*=\(.*\)/\1/'`
case "$opt" in
- --findoptions) FINDOPTIONS="$val" ;;
--localpaths) SEARCHPATHS="$val" ;;
--netpaths) NETPATHS="$val" ;;
--prunepaths) PRUNEPATHS="$val" ;;
- --prunefs) PRUNEFS="$val" ;;
--output) LOCATE_DB="$val" ;;
--netuser) NETUSER="$val" ;;
- --localuser) LOCALUSER="$val" ;;
--old-format) old=yes ;;
- --changecwd) changeto="$val" ;;
- --dbformat) dbformat="$val" ;;
- --version) fail=0; echo "$version" || fail=1; exit $fail ;;
- --help) fail=0; echo "$usage" || fail=1; exit $fail ;;
+ --version) echo "GNU updatedb version @version@"; exit 0 ;;
+ --help) echo "$usage"; exit 0 ;;
*) echo "updatedb: invalid option $opt
$usage" >&2
exit 1 ;;
esac
done
-
-
-
-case "${dbformat:+yes}_${old}" in
- yes_yes)
- echo "The --dbformat and --old cannot both be specified." >&2
- exit 1
- ;;
- *)
- ;;
-esac
-
-if test "$old" = yes || test "$dbformat" = "old" ; then
- echo "Warning: future versions of findutils will shortly discontinue support for the old locate database format." >&2
- old=yes
- sort="@SORT@"
- print_option="-print"
- frcode_options=""
-else
- frcode_options=""
- case "$dbformat" in
- "")
- # Default, use LOCATE02
- ;;
- LOCATE02)
- ;;
- slocate)
- frcode_options="$frcode_options -S 1"
- ;;
- *)
- echo "Unsupported locate database format ${dbformat}: Supported formats are:" >&2
- echo "LOCATE02, slocate, old" >&2
- exit 1
- esac
-
-
- if @SORT_SUPPORTS_Z@
- then
- sort="@SORT@ -z"
- print_option="-print0"
- frcode_options="$frcode_options -0"
- else
- sort="@SORT@"
- print_option="-print"
- fi
-fi
-
-getuid() {
- # format of "id" output is ...
- # uid=1(daemon) gid=1(other)
- # for `id's that don't understand -u
- id | cut -d'(' -f 1 | cut -d'=' -f2
-}
-
-# figure out if su supports the -s option
-select_shell() {
- if su "$1" -s $SHELL -c false < /dev/null ; then
- # No.
- echo ""
- else
- if su "$1" -s $SHELL -c true < /dev/null ; then
- # Yes.
- echo "-s $SHELL"
- else
- # su is unconditionally failing. We won't be able to
- # figure out what is wrong, so be conservative.
- echo ""
- fi
- fi
-}
-
-
# You can set these in the environment, or use command-line options,
# to override their defaults:
-# Any global options for find?
-: ${FINDOPTIONS=}
-
-# What shell shoud we use? We should use a POSIX-ish sh.
-: ${SHELL="/bin/sh"}
-
# Non-network directories to put in the database.
: ${SEARCHPATHS="/"}
@@ -158,17 +53,7 @@ select_shell() {
: ${NETPATHS=}
# Directories to not put in the database, which would otherwise be.
-: ${PRUNEPATHS="/tmp /usr/tmp /var/tmp /afs /amd /sfs /proc"}
-
-# Trailing slashes result in regex items that are never matched, which
-# is not what the user will expect. Therefore we now reject such
-# constructs.
-for p in $PRUNEPATHS; do
- case "$p" in
- /*/) echo "$0: $p: pruned paths should not contain trailing slashes" >&2
- exit 1
- esac
-done
+: ${PRUNEPATHS="/tmp /usr/tmp /var/tmp /afs"}
# The same, in the form of a regex that find can use.
test -z "$PRUNEREGEX" &&
@@ -180,117 +65,51 @@ test -z "$PRUNEREGEX" &&
# Directory to hold intermediate files.
if test -d /var/tmp; then
: ${TMPDIR=/var/tmp}
-elif test -d /usr/tmp; then
- : ${TMPDIR=/usr/tmp}
else
- : ${TMPDIR=/tmp}
+ : ${TMPDIR=/usr/tmp}
fi
-export TMPDIR
# The user to search network directories as.
: ${NETUSER=daemon}
# The directory containing the subprograms.
-if test -n "$LIBEXECDIR" ; then
- : LIBEXECDIR already set, do nothing
-else
- : ${LIBEXECDIR=@libexecdir@}
-fi
+: ${LIBEXECDIR=@libexecdir@}
# The directory containing find.
-if test -n "$BINDIR" ; then
- : BINDIR already set, do nothing
-else
- : ${BINDIR=@bindir@}
-fi
+: ${BINDIR=@bindir@}
# The names of the utilities to run to build the database.
-: ${find:=${BINDIR}/@find@}
-: ${frcode:=${LIBEXECDIR}/@frcode@}
-: ${bigram:=${LIBEXECDIR}/@bigram@}
-: ${code:=${LIBEXECDIR}/@code@}
-
-
-checkbinary () {
- if test -x "$1" ; then
- : ok
- else
- eval echo "updatedb needs to be able to execute $1, but cannot." >&2
- exit 1
- fi
-}
-
-for binary in $find $frcode $bigram $code
-do
- checkbinary $binary
-done
-
+: ${find=@find@}
+: ${frcode=@frcode@}
+: ${bigram=@bigram@}
+: ${code=@code@}
-PATH=/bin:/usr/bin:${BINDIR}; export PATH
-
-: ${PRUNEFS="nfs NFS proc afs proc smbfs autofs iso9660 ncpfs coda devpts ftpfs devfs mfs sysfs shfs"}
-
-if test -n "$PRUNEFS"; then
-prunefs_exp=`echo $PRUNEFS |sed -e 's/\([^ ][^ ]*\)/-o -fstype \1/g' \
- -e 's/-o //' -e 's/$/ -o/'`
-else
- prunefs_exp=''
-fi
+PATH=$LIBEXECDIR:$BINDIR:/usr/ucb:/bin:/usr/bin:$PATH export PATH
# Make and code the file list.
# Sort case insensitively for users' convenience.
-rm -f $LOCATE_DB.n
-trap 'rm -f $LOCATE_DB.n; exit' HUP TERM
-
if test $old = no; then
-# LOCATE02 or slocate format
-if {
-cd "$changeto"
+
+# FIXME figure out how to sort null-terminated strings, and use -print0.
+{
if test -n "$SEARCHPATHS"; then
- if [ "$LOCALUSER" != "" ]; then
- # : A1
- su $LOCALUSER `select_shell $LOCALUSER` -c \
- "$find $SEARCHPATHS $FINDOPTIONS \
- \\( $prunefs_exp \
- -type d -regex '$PRUNEREGEX' \\) -prune -o $print_option"
- else
- # : A2
- $find $SEARCHPATHS $FINDOPTIONS \
- \( $prunefs_exp \
- -type d -regex "$PRUNEREGEX" \) -prune -o $print_option
- fi
+ $find $SEARCHPATHS \
+ \( -fstype nfs -o -fstype NFS -o -type d -regex "$PRUNEREGEX" \) -prune -o -print
fi
if test -n "$NETPATHS"; then
-myuid=`getuid`
-if [ "$myuid" = 0 ]; then
- # : A3
- su $NETUSER `select_shell $NETUSER` -c \
- "$find $NETPATHS $FINDOPTIONS \\( -type d -regex '$PRUNEREGEX' -prune \\) -o $print_option" ||
- exit $?
- else
- # : A4
- $find $NETPATHS $FINDOPTIONS \( -type d -regex "$PRUNEREGEX" -prune \) -o $print_option ||
- exit $?
- fi
-fi
-} | $sort -f | $frcode $frcode_options > $LOCATE_DB.n
-then
- : OK so far
- true
-else
- rv=$?
- echo "Failed to generate $LOCATE_DB.n" >&2
- rm -f $LOCATE_DB.n
- exit $rv
+ su $NETUSER -c \
+ "$find $NETPATHS \\( -type d -regex \"$PRUNEREGEX\" -prune \\) -o -print"
fi
+} | sort -f | $frcode > $LOCATE_DB.n
# To avoid breaking locate while this script is running, put the
# results in a temp file, then rename it atomically.
if test -s $LOCATE_DB.n; then
- chmod 644 ${LOCATE_DB}.n
- mv ${LOCATE_DB}.n $LOCATE_DB
+ rm -f $LOCATE_DB
+ mv $LOCATE_DB.n $LOCATE_DB
+ chmod 644 $LOCATE_DB
else
echo "updatedb: new database would be empty" >&2
rm -f $LOCATE_DB.n
@@ -298,73 +117,32 @@ fi
else # old
-if ! bigrams=`mktemp -t updatedbXXXXXXXXX`; then
- echo mktemp failed >&2
- exit 1
-fi
+bigrams=$TMPDIR/f.bigrams$$
+filelist=$TMPDIR/f.list$$
+trap 'rm -f $bigrams $filelist; exit' 1 15
-if ! filelist=`mktemp -t updatedbXXXXXXXXX`; then
- echo mktemp failed >&2
- exit 1
-fi
-
-rm -f $LOCATE_DB.n
-trap 'rm -f $bigrams $filelist $LOCATE_DB.n; exit' HUP TERM
-
-# Alphabetize subdirectories before file entries using tr. James Woods says:
+# Alphabetize subdirectories before file entries using tr. James says:
# "to get everything in monotonic collating sequence, to avoid some
# breakage i'll have to think about."
{
-cd "$changeto"
if test -n "$SEARCHPATHS"; then
- if [ "$LOCALUSER" != "" ]; then
- # : A5
- su $LOCALUSER `select_shell $LOCALUSER` -c \
- "$find $SEARCHPATHS $FINDOPTIONS \
- \( $prunefs_exp \
- -type d -regex '$PRUNEREGEX' \) -prune -o $print_option" || exit $?
- else
- # : A6
- $find $SEARCHPATHS $FINDOPTIONS \
- \( $prunefs_exp \
- -type d -regex "$PRUNEREGEX" \) -prune -o $print_option || exit $?
- fi
+ $find $SEARCHPATHS \
+ \( -fstype nfs -o -fstype NFS -o -type d -regex "$PRUNEREGEX" \) -prune -o -print
fi
-
if test -n "$NETPATHS"; then
- myuid=`getuid`
- if [ "$myuid" = 0 ]; then
- # : A7
- su $NETUSER `select_shell $NETUSER` -c \
- "$find $NETPATHS $FINDOPTIONS \\( -type d -regex '$PRUNEREGEX' -prune \\) -o $print_option" ||
- exit $?
- else
- # : A8
- $find $NETPATHS $FINDOPTIONS \( -type d -regex "$PRUNEREGEX" -prune \) -o $print_option ||
- exit $?
- fi
+ su $NETUSER -c \
+ "$find $NETPATHS \\( -type d -regex \"$PRUNEREGEX\" -prune \\) -o -print"
fi
-} | tr / '\001' | $sort -f | tr '\001' / > $filelist
+} | tr / '\001' | sort -f | tr '\001' / > $filelist
# Compute the (at most 128) most common bigrams in the file list.
-$bigram $bigram_opts < $filelist | sort | uniq -c | sort -nr |
+$bigram < $filelist | sort | uniq -c | sort -nr |
awk '{ if (NR <= 128) print $2 }' | tr -d '\012' > $bigrams
# Code the file list.
-$code $bigrams < $filelist > $LOCATE_DB.n
+$code $bigrams < $filelist > $LOCATE_DB
+chmod 644 $LOCATE_DB
-rm -f $bigrams $filelist
+rm -f $bigrams $filelist $errs
-# To reduce the chances of breaking locate while this script is running,
-# put the results in a temp file, then rename it atomically.
-if test -s $LOCATE_DB.n; then
- chmod 644 ${LOCATE_DB}.n
- mv ${LOCATE_DB}.n $LOCATE_DB
-else
- echo "updatedb: new database would be empty" >&2
- rm -f $LOCATE_DB.n
fi
-
-fi
-
-exit 0
diff --git a/mkinstalldirs b/mkinstalldirs
new file mode 100755
index 00000000..91f6d04e
--- /dev/null
+++ b/mkinstalldirs
@@ -0,0 +1,32 @@
+#!/bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Last modified: 1994-03-25
+# Public domain
+
+errstatus=0
+
+for file in ${1+"$@"} ; do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+
+ pathcomp=
+ for d in ${1+"$@"} ; do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp" 1>&2
+ mkdir "$pathcomp" || errstatus=$?
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/stamp-h.in b/stamp-h.in
index 9788f702..81bc61c9 100644
--- a/stamp-h.in
+++ b/stamp-h.in
@@ -1 +1 @@
-timestamp
+Tue Oct 4 11:24:03 EDT 1994
diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
new file mode 100644
index 00000000..c3606000
--- /dev/null
+++ b/testsuite/Makefile.am
@@ -0,0 +1,36 @@
+XARGS = ../xargs/xargs
+XARGSFLAGS =
+
+RUNTEST= runtest
+RUNTESTFLAGS=
+
+DIST_OTHER = config/*.exp inputs/*.xi xargs.*/*.exp xargs.*/*.xo
+DIST_DIRS = config inputs xargs.gnu xargs.posix xargs.sysv
+
+CLEANFILES = *.log *.sum site.exp site.bak
+
+check:: site.exp
+ @echo This only works if you have the DejaGNU runtest program installed...
+ $(RUNTEST) $(RUNTESTFLAGS) --tool xargs XARGS=${XARGS} \
+ XARGSFLAGS="${XARGSFLAGS}" --srcdir $(srcdir)
+
+site.exp:
+ @echo "Making a new site.exp file..."
+ -@rm -f site.bak
+ -@mv site.exp site.bak
+ @echo "## these variables are automatically generated by make ##" > site.exp
+ @echo "# Do not edit here. If you wish to override these values" >> site.exp
+ @echo "# add them to the last section" >> site.exp
+ @echo "set tool xargs" >> site.exp
+ @echo "set srcdir ${srcdir}" >> site.exp
+ @echo "set objdir `pwd`" >> site.exp
+ @echo "## All variables above are generated by configure. Do Not Edit ##" >> site.exp
+ -@sed '1,/^## All variables above are.*##/ d' site.bak >> site.exp
+
+$(DIST_DIRS): FORCE
+ -mkdir ../`cat ../distname`/$(subdir)
+ -for d in $(DIST_DIRS); do \
+ echo mkdir ../`cat ../distname`/$(subdir)/$$d; \
+ mkdir ../`cat ../distname`/$(subdir)/$$d; done
+
+FORCE:
diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in
new file mode 100644
index 00000000..902beef4
--- /dev/null
+++ b/testsuite/Makefile.in
@@ -0,0 +1,118 @@
+# Makefile.in generated automatically by automake from Makefile.am.
+# Copyright (C) 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = $(exec_prefix)/bin
+sbindir = $(exec_prefix)/sbin
+libexecdir = $(exec_prefix)/libexec
+datadir = $(prefix)/share
+sysconfdir = $(prefix)/etc
+sharedstatedir = $(prefix)/com
+localstatedir = $(prefix)/var
+libdir = $(exec_prefix)/lib
+infodir = $(prefix)/info
+mandir = $(prefix)/man
+includedir = $(prefix)/include
+oldincludedir = /usr/include
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+transform = @program_transform_name@
+
+ALL = ${PROGRAMS} ${LIBPROGRAMS} ${SCRIPTS} ${LIBSCRIPTS} ${LIBFILES}
+SOURCES =
+DIST_CONF = Makefile.am Makefile.in
+DIST_FILES = $(DIST_CONF) $(SOURCES) $(TEXINFOS) $(INFOS) $(MANS) $(DIST_OTHER)
+
+XARGS = ../xargs/xargs
+XARGSFLAGS =
+
+RUNTEST= runtest
+RUNTESTFLAGS=
+
+DIST_OTHER = config/*.exp inputs/*.xi xargs.*/*.exp xargs.*/*.xo
+DIST_DIRS = config inputs xargs.gnu xargs.posix xargs.sysv
+
+CLEANFILES = *.log *.sum site.exp site.bak
+
+all:: ${ALL}
+
+mostlyclean:
+ rm -f *.o core
+
+clean: mostlyclean
+ rm -f $(PROGRAMS) $(LIBPROGRAMS) $(LIBFILES) $(TEXFILES) $(CLEANFILES)
+
+distclean: clean
+ rm -f Makefile *.tab.c $(DISTCLEANFILES)
+ rm -f config.cache config.log config.status ${CONFIG_HEADER} stamp-h
+
+realclean: distclean
+ rm -f TAGS $(INFOS)
+
+dist: $(DIST_FILES) $(DIST_DIRS)
+ -mkdir ../`cat ../distname`/$(subdir)
+ @for file in $(DIST_FILES); do \
+ echo linking $$file; \
+ ln $(srcdir)/$$file ../`cat ../distname`/$(subdir)/$$file || \
+ { echo copying $$file instead; cp -p $(srcdir)/$$file ../`cat ../distname`/$(subdir)/$$file;}; \
+ done
+
+check dvi info install uninstall::
+
+tags:: TAGS
+
+TAGS::
+ cd $(srcdir); etags $(SOURCES)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
+
+check:: site.exp
+ @echo This only works if you have the DejaGNU runtest program installed...
+ $(RUNTEST) $(RUNTESTFLAGS) --tool xargs XARGS=${XARGS} \
+ XARGSFLAGS="${XARGSFLAGS}" --srcdir $(srcdir)
+
+site.exp:
+ @echo "Making a new site.exp file..."
+ -@rm -f site.bak
+ -@mv site.exp site.bak
+ @echo "## these variables are automatically generated by make ##" > site.exp
+ @echo "# Do not edit here. If you wish to override these values" >> site.exp
+ @echo "# add them to the last section" >> site.exp
+ @echo "set tool xargs" >> site.exp
+ @echo "set srcdir ${srcdir}" >> site.exp
+ @echo "set objdir `pwd`" >> site.exp
+ @echo "## All variables above are generated by configure. Do Not Edit ##" >> site.exp
+ -@sed '1,/^## All variables above are.*##/ d' site.bak >> site.exp
+
+$(DIST_DIRS): FORCE
+ -mkdir ../`cat ../distname`/$(subdir)
+ -for d in $(DIST_DIRS); do \
+ echo mkdir ../`cat ../distname`/$(subdir)/$$d; \
+ mkdir ../`cat ../distname`/$(subdir)/$$d; done
+
+FORCE:
diff --git a/testsuite/config/unix.exp b/testsuite/config/unix.exp
new file mode 100644
index 00000000..a85d7cdb
--- /dev/null
+++ b/testsuite/config/unix.exp
@@ -0,0 +1,109 @@
+# -*- TCL -*-
+# Test-specific TCL procedures required by DejaGNU.
+# Copyright (C) 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 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.
+
+# Modified by David MacKenzie <djm@gnu.ai.mit.edu> from the gcc files
+# written by Rob Savoye <rob@cygnus.com>.
+
+
+# Called by runtest.
+# Extract and print the version number of xargs.
+proc xargs_version {} {
+ global XARGS
+ global XARGSFLAGS
+
+ if {[which $XARGS] != 0} then {
+ set tmp [ eval exec $XARGS $XARGSFLAGS --version </dev/null ]
+ regexp "version.*$" $tmp version
+ if [info exists version] then {
+ clone_output "[which $XARGS] $version\n"
+ } else {
+ warning "cannot get version from $tmp."
+ }
+ } else {
+ warning "$XARGS, program does not exist"
+ }
+}
+
+# Run xargs and leave the output in $comp_output.
+# Called by individual test scripts.
+proc xargs_start { passfail options infile } {
+ global verbose
+ global XARGS
+ global XARGSFLAGS
+ global comp_output
+
+ if {[which $XARGS] == 0} then {
+ error "$XARGS, program does not exist"
+ exit 1
+ }
+
+ set fail_good [string match "f*" $passfail]
+
+ set scriptname [uplevel {info script}]
+ set testbase [file rootname $scriptname]
+ set testname [file tail $testbase]
+
+ set outfile "$testbase.xo"
+ if {$infile != ""} then {
+ set infile "[file dirname [file dirname $testbase]]/inputs/$infile"
+ } else {
+ set infile /dev/null
+ }
+
+ set cmd "$XARGS $XARGSFLAGS $options < $infile > xargs.out"
+ send_log "$cmd\n"
+ if $verbose>1 then {
+ send_user "Spawning \"$cmd\"\n"
+ }
+
+ catch "exec $cmd" comp_output
+ if {$comp_output != ""} then {
+ send_log "$comp_output\n"
+ if $verbose>1 then {
+ send_user "$comp_output\n"
+ }
+ if $fail_good then {
+ pass "$testname"
+ } else {
+ fail "$testname, $comp_output"
+ }
+ return
+ }
+
+ if [file exists $outfile] then {
+ set cmp_cmd "cmp xargs.out $outfile"
+ send_log "$cmp_cmd\n"
+ catch "exec $cmp_cmd" cmpout
+ if {$cmpout != ""} then {
+ fail "$testname, $cmpout"
+ return
+ }
+ } else {
+ if {[file size xargs.out] != 0} then {
+ fail "$testname, output should be empty"
+ return
+ }
+ }
+ pass "$testname"
+}
+
+# Called by runtest.
+# Clean up (remove temporary files) before runtest exits.
+proc xargs_exit {} {
+ catch "exec rm -f xargs.out"
+}
diff --git a/testsuite/inputs/eof.xi b/testsuite/inputs/eof.xi
new file mode 100644
index 00000000..0a4baec8
--- /dev/null
+++ b/testsuite/inputs/eof.xi
@@ -0,0 +1,5 @@
+firstline
+secondline
+ _
+thirdline
+fourthline
diff --git a/testsuite/inputs/eofstr.xi b/testsuite/inputs/eofstr.xi
new file mode 100644
index 00000000..6e60cfd8
--- /dev/null
+++ b/testsuite/inputs/eofstr.xi
@@ -0,0 +1,5 @@
+firstline
+secondline
+EOF
+thirdline
+fourthline
diff --git a/testsuite/inputs/files.xi b/testsuite/inputs/files.xi
new file mode 100644
index 00000000..5590252c
--- /dev/null
+++ b/testsuite/inputs/files.xi
@@ -0,0 +1,22 @@
+/src/gnu/autoconf-1.11
+/src/gnu/autoconf-1.11/README
+/src/gnu/autoconf-1.11/Makefile.in
+/src/gnu/autoconf-1.11/INSTALL
+/src/gnu/autoconf-1.11/NEWS
+/src/gnu/autoconf-1.11/COPYING
+/src/gnu/autoconf-1.11/ChangeLog
+/src/gnu/autoconf-1.11/autoconf.texi
+/src/gnu/autoconf-1.11/acconfig.h
+/src/gnu/autoconf-1.11/autoconf.sh
+/src/gnu/autoconf-1.11/acgeneral.m4
+/src/gnu/autoconf-1.11/acspecific.m4
+/src/gnu/autoconf-1.11/configure
+/src/gnu/autoconf-1.11/configure.in
+/src/gnu/autoconf-1.11/autoheader.sh
+/src/gnu/autoconf-1.11/mkinstalldirs
+/src/gnu/autoconf-1.11/install.sh
+/src/gnu/autoconf-1.11/autoconf.info
+/src/gnu/autoconf-1.11/standards.texi
+/src/gnu/autoconf-1.11/make-stds.texi
+/src/gnu/autoconf-1.11/standards.info
+/src/gnu/autoconf-1.11/texinfo.tex
diff --git a/testsuite/inputs/files0.xi b/testsuite/inputs/files0.xi
new file mode 100644
index 00000000..08ab0e2f
--- /dev/null
+++ b/testsuite/inputs/files0.xi
Binary files differ
diff --git a/testsuite/inputs/quotes.xi b/testsuite/inputs/quotes.xi
new file mode 100644
index 00000000..031e84fb
--- /dev/null
+++ b/testsuite/inputs/quotes.xi
@@ -0,0 +1,5 @@
+ this is
+"quoted stuff"
+and \
+an embedded newline
+with 'single quotes' as well.
diff --git a/testsuite/xargs.gnu/0n3.exp b/testsuite/xargs.gnu/0n3.exp
new file mode 100644
index 00000000..33e96a8c
--- /dev/null
+++ b/testsuite/xargs.gnu/0n3.exp
@@ -0,0 +1 @@
+xargs_start p {-0 -n3} files0.xi
diff --git a/testsuite/xargs.gnu/0n3.xo b/testsuite/xargs.gnu/0n3.xo
new file mode 100644
index 00000000..e663e645
--- /dev/null
+++ b/testsuite/xargs.gnu/0n3.xo
@@ -0,0 +1,8 @@
+/src/gnu/autoconf-1.11 /src/gnu/autoconf-1.11/README /src/gnu/autoconf-1.11/Makefile.in
+/src/gnu/autoconf-1.11/INSTALL /src/gnu/autoconf-1.11/NEWS /src/gnu/autoconf-1.11/COPYING
+/src/gnu/autoconf-1.11/ChangeLog /src/gnu/autoconf-1.11/autoconf.texi /src/gnu/autoconf-1.11/acconfig.h
+/src/gnu/autoconf-1.11/autoconf.sh /src/gnu/autoconf-1.11/acgeneral.m4 /src/gnu/autoconf-1.11/acspecific.m4
+/src/gnu/autoconf-1.11/configure /src/gnu/autoconf-1.11/configure.in /src/gnu/autoconf-1.11/autoheader.sh
+/src/gnu/autoconf-1.11/mkinstalldirs /src/gnu/autoconf-1.11/install.sh /src/gnu/autoconf-1.11/autoconf.info
+/src/gnu/autoconf-1.11/standards.texi /src/gnu/autoconf-1.11/make-stds.texi /src/gnu/autoconf-1.11/standards.info
+/src/gnu/autoconf-1.11/texinfo.tex
diff --git a/testsuite/xargs.gnu/nothing.exp b/testsuite/xargs.gnu/nothing.exp
new file mode 100644
index 00000000..20c03fdd
--- /dev/null
+++ b/testsuite/xargs.gnu/nothing.exp
@@ -0,0 +1 @@
+xargs_start p {echo this plus that} {}
diff --git a/testsuite/xargs.gnu/nothing.xo b/testsuite/xargs.gnu/nothing.xo
new file mode 100644
index 00000000..b8e9a023
--- /dev/null
+++ b/testsuite/xargs.gnu/nothing.xo
@@ -0,0 +1 @@
+this plus that
diff --git a/testsuite/xargs.gnu/r.exp b/testsuite/xargs.gnu/r.exp
new file mode 100644
index 00000000..8de762fd
--- /dev/null
+++ b/testsuite/xargs.gnu/r.exp
@@ -0,0 +1 @@
+xargs_start p {-r echo this plus that} {}
diff --git a/testsuite/xargs.posix/hithere.exp b/testsuite/xargs.posix/hithere.exp
new file mode 100644
index 00000000..0256d4b4
--- /dev/null
+++ b/testsuite/xargs.posix/hithere.exp
@@ -0,0 +1 @@
+xargs_start p {-s470 echo hi there} files.xi
diff --git a/testsuite/xargs.posix/hithere.xo b/testsuite/xargs.posix/hithere.xo
new file mode 100644
index 00000000..0c6845bd
--- /dev/null
+++ b/testsuite/xargs.posix/hithere.xo
@@ -0,0 +1,2 @@
+hi there /src/gnu/autoconf-1.11 /src/gnu/autoconf-1.11/README /src/gnu/autoconf-1.11/Makefile.in /src/gnu/autoconf-1.11/INSTALL /src/gnu/autoconf-1.11/NEWS /src/gnu/autoconf-1.11/COPYING /src/gnu/autoconf-1.11/ChangeLog /src/gnu/autoconf-1.11/autoconf.texi /src/gnu/autoconf-1.11/acconfig.h /src/gnu/autoconf-1.11/autoconf.sh /src/gnu/autoconf-1.11/acgeneral.m4 /src/gnu/autoconf-1.11/acspecific.m4 /src/gnu/autoconf-1.11/configure
+hi there /src/gnu/autoconf-1.11/configure.in /src/gnu/autoconf-1.11/autoheader.sh /src/gnu/autoconf-1.11/mkinstalldirs /src/gnu/autoconf-1.11/install.sh /src/gnu/autoconf-1.11/autoconf.info /src/gnu/autoconf-1.11/standards.texi /src/gnu/autoconf-1.11/make-stds.texi /src/gnu/autoconf-1.11/standards.info /src/gnu/autoconf-1.11/texinfo.tex
diff --git a/testsuite/xargs.posix/n3.exp b/testsuite/xargs.posix/n3.exp
new file mode 100644
index 00000000..472b6147
--- /dev/null
+++ b/testsuite/xargs.posix/n3.exp
@@ -0,0 +1 @@
+xargs_start p {-n3} files.xi
diff --git a/testsuite/xargs.posix/n3.xo b/testsuite/xargs.posix/n3.xo
new file mode 100644
index 00000000..e663e645
--- /dev/null
+++ b/testsuite/xargs.posix/n3.xo
@@ -0,0 +1,8 @@
+/src/gnu/autoconf-1.11 /src/gnu/autoconf-1.11/README /src/gnu/autoconf-1.11/Makefile.in
+/src/gnu/autoconf-1.11/INSTALL /src/gnu/autoconf-1.11/NEWS /src/gnu/autoconf-1.11/COPYING
+/src/gnu/autoconf-1.11/ChangeLog /src/gnu/autoconf-1.11/autoconf.texi /src/gnu/autoconf-1.11/acconfig.h
+/src/gnu/autoconf-1.11/autoconf.sh /src/gnu/autoconf-1.11/acgeneral.m4 /src/gnu/autoconf-1.11/acspecific.m4
+/src/gnu/autoconf-1.11/configure /src/gnu/autoconf-1.11/configure.in /src/gnu/autoconf-1.11/autoheader.sh
+/src/gnu/autoconf-1.11/mkinstalldirs /src/gnu/autoconf-1.11/install.sh /src/gnu/autoconf-1.11/autoconf.info
+/src/gnu/autoconf-1.11/standards.texi /src/gnu/autoconf-1.11/make-stds.texi /src/gnu/autoconf-1.11/standards.info
+/src/gnu/autoconf-1.11/texinfo.tex
diff --git a/testsuite/xargs.posix/quotes.exp b/testsuite/xargs.posix/quotes.exp
new file mode 100644
index 00000000..574e1ec6
--- /dev/null
+++ b/testsuite/xargs.posix/quotes.exp
@@ -0,0 +1 @@
+xargs_start p {} quotes.xi
diff --git a/testsuite/xargs.posix/quotes.xo b/testsuite/xargs.posix/quotes.xo
new file mode 100644
index 00000000..9b6477f6
--- /dev/null
+++ b/testsuite/xargs.posix/quotes.xo
@@ -0,0 +1,2 @@
+this is quoted stuff and
+an embedded newline with single quotes as well.
diff --git a/testsuite/xargs.posix/s47.exp b/testsuite/xargs.posix/s47.exp
new file mode 100644
index 00000000..0945b08b
--- /dev/null
+++ b/testsuite/xargs.posix/s47.exp
@@ -0,0 +1 @@
+xargs_start f {-s47} files.xi
diff --git a/testsuite/xargs.posix/s47.xo b/testsuite/xargs.posix/s47.xo
new file mode 100644
index 00000000..26eed8f7
--- /dev/null
+++ b/testsuite/xargs.posix/s47.xo
@@ -0,0 +1,18 @@
+/src/gnu/autoconf-1.11
+/src/gnu/autoconf-1.11/README
+/src/gnu/autoconf-1.11/Makefile.in
+/src/gnu/autoconf-1.11/INSTALL
+/src/gnu/autoconf-1.11/NEWS
+/src/gnu/autoconf-1.11/COPYING
+/src/gnu/autoconf-1.11/ChangeLog
+/src/gnu/autoconf-1.11/autoconf.texi
+/src/gnu/autoconf-1.11/acconfig.h
+/src/gnu/autoconf-1.11/autoconf.sh
+/src/gnu/autoconf-1.11/acgeneral.m4
+/src/gnu/autoconf-1.11/acspecific.m4
+/src/gnu/autoconf-1.11/configure
+/src/gnu/autoconf-1.11/configure.in
+/src/gnu/autoconf-1.11/autoheader.sh
+/src/gnu/autoconf-1.11/mkinstalldirs
+/src/gnu/autoconf-1.11/install.sh
+/src/gnu/autoconf-1.11/autoconf.info
diff --git a/testsuite/xargs.posix/s470.exp b/testsuite/xargs.posix/s470.exp
new file mode 100644
index 00000000..0643926d
--- /dev/null
+++ b/testsuite/xargs.posix/s470.exp
@@ -0,0 +1 @@
+xargs_start p {-s470} files.xi
diff --git a/testsuite/xargs.posix/s470.xo b/testsuite/xargs.posix/s470.xo
new file mode 100644
index 00000000..81077256
--- /dev/null
+++ b/testsuite/xargs.posix/s470.xo
@@ -0,0 +1,2 @@
+/src/gnu/autoconf-1.11 /src/gnu/autoconf-1.11/README /src/gnu/autoconf-1.11/Makefile.in /src/gnu/autoconf-1.11/INSTALL /src/gnu/autoconf-1.11/NEWS /src/gnu/autoconf-1.11/COPYING /src/gnu/autoconf-1.11/ChangeLog /src/gnu/autoconf-1.11/autoconf.texi /src/gnu/autoconf-1.11/acconfig.h /src/gnu/autoconf-1.11/autoconf.sh /src/gnu/autoconf-1.11/acgeneral.m4 /src/gnu/autoconf-1.11/acspecific.m4 /src/gnu/autoconf-1.11/configure /src/gnu/autoconf-1.11/configure.in
+/src/gnu/autoconf-1.11/autoheader.sh /src/gnu/autoconf-1.11/mkinstalldirs /src/gnu/autoconf-1.11/install.sh /src/gnu/autoconf-1.11/autoconf.info /src/gnu/autoconf-1.11/standards.texi /src/gnu/autoconf-1.11/make-stds.texi /src/gnu/autoconf-1.11/standards.info /src/gnu/autoconf-1.11/texinfo.tex
diff --git a/testsuite/xargs.posix/s48.exp b/testsuite/xargs.posix/s48.exp
new file mode 100644
index 00000000..506e77b2
--- /dev/null
+++ b/testsuite/xargs.posix/s48.exp
@@ -0,0 +1 @@
+xargs_start p {-s48} files.xi
diff --git a/testsuite/xargs.posix/s48.xo b/testsuite/xargs.posix/s48.xo
new file mode 100644
index 00000000..5590252c
--- /dev/null
+++ b/testsuite/xargs.posix/s48.xo
@@ -0,0 +1,22 @@
+/src/gnu/autoconf-1.11
+/src/gnu/autoconf-1.11/README
+/src/gnu/autoconf-1.11/Makefile.in
+/src/gnu/autoconf-1.11/INSTALL
+/src/gnu/autoconf-1.11/NEWS
+/src/gnu/autoconf-1.11/COPYING
+/src/gnu/autoconf-1.11/ChangeLog
+/src/gnu/autoconf-1.11/autoconf.texi
+/src/gnu/autoconf-1.11/acconfig.h
+/src/gnu/autoconf-1.11/autoconf.sh
+/src/gnu/autoconf-1.11/acgeneral.m4
+/src/gnu/autoconf-1.11/acspecific.m4
+/src/gnu/autoconf-1.11/configure
+/src/gnu/autoconf-1.11/configure.in
+/src/gnu/autoconf-1.11/autoheader.sh
+/src/gnu/autoconf-1.11/mkinstalldirs
+/src/gnu/autoconf-1.11/install.sh
+/src/gnu/autoconf-1.11/autoconf.info
+/src/gnu/autoconf-1.11/standards.texi
+/src/gnu/autoconf-1.11/make-stds.texi
+/src/gnu/autoconf-1.11/standards.info
+/src/gnu/autoconf-1.11/texinfo.tex
diff --git a/testsuite/xargs.posix/s6.exp b/testsuite/xargs.posix/s6.exp
new file mode 100644
index 00000000..d572ae13
--- /dev/null
+++ b/testsuite/xargs.posix/s6.exp
@@ -0,0 +1 @@
+xargs_start f {-s6} files.xi
diff --git a/testsuite/xargs.sysv/eEOF.exp b/testsuite/xargs.sysv/eEOF.exp
new file mode 100644
index 00000000..8ac68aa1
--- /dev/null
+++ b/testsuite/xargs.sysv/eEOF.exp
@@ -0,0 +1 @@
+xargs_start p {-eEOF} eofstr.xi
diff --git a/testsuite/xargs.sysv/eEOF.xo b/testsuite/xargs.sysv/eEOF.xo
new file mode 100644
index 00000000..7f4c1cdb
--- /dev/null
+++ b/testsuite/xargs.sysv/eEOF.xo
@@ -0,0 +1 @@
+firstline secondline
diff --git a/testsuite/xargs.sysv/eof.exp b/testsuite/xargs.sysv/eof.exp
new file mode 100644
index 00000000..73a34265
--- /dev/null
+++ b/testsuite/xargs.sysv/eof.exp
@@ -0,0 +1 @@
+xargs_start p {} eof.xi
diff --git a/testsuite/xargs.sysv/eof.xo b/testsuite/xargs.sysv/eof.xo
new file mode 100644
index 00000000..7f4c1cdb
--- /dev/null
+++ b/testsuite/xargs.sysv/eof.xo
@@ -0,0 +1 @@
+firstline secondline
diff --git a/testsuite/xargs.sysv/iARG.exp b/testsuite/xargs.sysv/iARG.exp
new file mode 100644
index 00000000..2e2ec75a
--- /dev/null
+++ b/testsuite/xargs.sysv/iARG.exp
@@ -0,0 +1 @@
+xargs_start p {-iARG echo ARG is xARGx} files.xi
diff --git a/testsuite/xargs.sysv/iARG.xo b/testsuite/xargs.sysv/iARG.xo
new file mode 100644
index 00000000..f28510b1
--- /dev/null
+++ b/testsuite/xargs.sysv/iARG.xo
@@ -0,0 +1,22 @@
+/src/gnu/autoconf-1.11 is x/src/gnu/autoconf-1.11x
+/src/gnu/autoconf-1.11/README is x/src/gnu/autoconf-1.11/READMEx
+/src/gnu/autoconf-1.11/Makefile.in is x/src/gnu/autoconf-1.11/Makefile.inx
+/src/gnu/autoconf-1.11/INSTALL is x/src/gnu/autoconf-1.11/INSTALLx
+/src/gnu/autoconf-1.11/NEWS is x/src/gnu/autoconf-1.11/NEWSx
+/src/gnu/autoconf-1.11/COPYING is x/src/gnu/autoconf-1.11/COPYINGx
+/src/gnu/autoconf-1.11/ChangeLog is x/src/gnu/autoconf-1.11/ChangeLogx
+/src/gnu/autoconf-1.11/autoconf.texi is x/src/gnu/autoconf-1.11/autoconf.texix
+/src/gnu/autoconf-1.11/acconfig.h is x/src/gnu/autoconf-1.11/acconfig.hx
+/src/gnu/autoconf-1.11/autoconf.sh is x/src/gnu/autoconf-1.11/autoconf.shx
+/src/gnu/autoconf-1.11/acgeneral.m4 is x/src/gnu/autoconf-1.11/acgeneral.m4x
+/src/gnu/autoconf-1.11/acspecific.m4 is x/src/gnu/autoconf-1.11/acspecific.m4x
+/src/gnu/autoconf-1.11/configure is x/src/gnu/autoconf-1.11/configurex
+/src/gnu/autoconf-1.11/configure.in is x/src/gnu/autoconf-1.11/configure.inx
+/src/gnu/autoconf-1.11/autoheader.sh is x/src/gnu/autoconf-1.11/autoheader.shx
+/src/gnu/autoconf-1.11/mkinstalldirs is x/src/gnu/autoconf-1.11/mkinstalldirsx
+/src/gnu/autoconf-1.11/install.sh is x/src/gnu/autoconf-1.11/install.shx
+/src/gnu/autoconf-1.11/autoconf.info is x/src/gnu/autoconf-1.11/autoconf.infox
+/src/gnu/autoconf-1.11/standards.texi is x/src/gnu/autoconf-1.11/standards.texix
+/src/gnu/autoconf-1.11/make-stds.texi is x/src/gnu/autoconf-1.11/make-stds.texix
+/src/gnu/autoconf-1.11/standards.info is x/src/gnu/autoconf-1.11/standards.infox
+/src/gnu/autoconf-1.11/texinfo.tex is x/src/gnu/autoconf-1.11/texinfo.texx
diff --git a/testsuite/xargs.sysv/iquotes.exp b/testsuite/xargs.sysv/iquotes.exp
new file mode 100644
index 00000000..43b88777
--- /dev/null
+++ b/testsuite/xargs.sysv/iquotes.exp
@@ -0,0 +1 @@
+xargs_start p {-i__ echo FIRST __ IS OK} quotes.xi
diff --git a/testsuite/xargs.sysv/iquotes.xo b/testsuite/xargs.sysv/iquotes.xo
new file mode 100644
index 00000000..10ce85cf
--- /dev/null
+++ b/testsuite/xargs.sysv/iquotes.xo
@@ -0,0 +1,5 @@
+FIRST this is IS OK
+FIRST quoted stuff IS OK
+FIRST and
+an embedded newline IS OK
+FIRST with single quotes as well. IS OK
diff --git a/testsuite/xargs.sysv/l1n4.exp b/testsuite/xargs.sysv/l1n4.exp
new file mode 100644
index 00000000..4eef4666
--- /dev/null
+++ b/testsuite/xargs.sysv/l1n4.exp
@@ -0,0 +1 @@
+xargs_start p {-l1 -n4} files.xi
diff --git a/testsuite/xargs.sysv/l1n4.xo b/testsuite/xargs.sysv/l1n4.xo
new file mode 100644
index 00000000..03f29b59
--- /dev/null
+++ b/testsuite/xargs.sysv/l1n4.xo
@@ -0,0 +1,6 @@
+/src/gnu/autoconf-1.11 /src/gnu/autoconf-1.11/README /src/gnu/autoconf-1.11/Makefile.in /src/gnu/autoconf-1.11/INSTALL
+/src/gnu/autoconf-1.11/NEWS /src/gnu/autoconf-1.11/COPYING /src/gnu/autoconf-1.11/ChangeLog /src/gnu/autoconf-1.11/autoconf.texi
+/src/gnu/autoconf-1.11/acconfig.h /src/gnu/autoconf-1.11/autoconf.sh /src/gnu/autoconf-1.11/acgeneral.m4 /src/gnu/autoconf-1.11/acspecific.m4
+/src/gnu/autoconf-1.11/configure /src/gnu/autoconf-1.11/configure.in /src/gnu/autoconf-1.11/autoheader.sh /src/gnu/autoconf-1.11/mkinstalldirs
+/src/gnu/autoconf-1.11/install.sh /src/gnu/autoconf-1.11/autoconf.info /src/gnu/autoconf-1.11/standards.texi /src/gnu/autoconf-1.11/make-stds.texi
+/src/gnu/autoconf-1.11/standards.info /src/gnu/autoconf-1.11/texinfo.tex
diff --git a/testsuite/xargs.sysv/l2.exp b/testsuite/xargs.sysv/l2.exp
new file mode 100644
index 00000000..c50b16ca
--- /dev/null
+++ b/testsuite/xargs.sysv/l2.exp
@@ -0,0 +1 @@
+xargs_start p {-l2} files.xi
diff --git a/testsuite/xargs.sysv/l2.xo b/testsuite/xargs.sysv/l2.xo
new file mode 100644
index 00000000..0fa94248
--- /dev/null
+++ b/testsuite/xargs.sysv/l2.xo
@@ -0,0 +1,11 @@
+/src/gnu/autoconf-1.11 /src/gnu/autoconf-1.11/README
+/src/gnu/autoconf-1.11/Makefile.in /src/gnu/autoconf-1.11/INSTALL
+/src/gnu/autoconf-1.11/NEWS /src/gnu/autoconf-1.11/COPYING
+/src/gnu/autoconf-1.11/ChangeLog /src/gnu/autoconf-1.11/autoconf.texi
+/src/gnu/autoconf-1.11/acconfig.h /src/gnu/autoconf-1.11/autoconf.sh
+/src/gnu/autoconf-1.11/acgeneral.m4 /src/gnu/autoconf-1.11/acspecific.m4
+/src/gnu/autoconf-1.11/configure /src/gnu/autoconf-1.11/configure.in
+/src/gnu/autoconf-1.11/autoheader.sh /src/gnu/autoconf-1.11/mkinstalldirs
+/src/gnu/autoconf-1.11/install.sh /src/gnu/autoconf-1.11/autoconf.info
+/src/gnu/autoconf-1.11/standards.texi /src/gnu/autoconf-1.11/make-stds.texi
+/src/gnu/autoconf-1.11/standards.info /src/gnu/autoconf-1.11/texinfo.tex
diff --git a/xargs/Makefile.am b/xargs/Makefile.am
index 20b4c29c..46e1cd69 100644
--- a/xargs/Makefile.am
+++ b/xargs/Makefile.am
@@ -1,15 +1,9 @@
-AUTOMAKE_OPTIONS = std-options
-localedir = $(datadir)/locale
-bin_PROGRAMS = xargs
-man_MANS = xargs.1
-INCLUDES = -I.. -I../gnulib/lib -I$(top_srcdir)/gnulib/lib -I$(top_srcdir)/lib -I../intl -DLOCALEDIR=\"$(localedir)\"
-LDADD = ../lib/libfind.a ../gnulib/lib/libgnulib.a @INTLLIBS@
-EXTRA_DIST = $(man_MANS)
-SUBDIRS = . testsuite
+PROGRAMS = xargs
+MANS = xargs.1
+INCLUDES = -I.. -I$(top_srcdir)/lib
+LDADD = ../find/version.o ../lib/libfind.a
+CONFIG_HEADER = ../config.h
-$(PROGRAMS): ../lib/libfind.a ../gnulib/lib/libgnulib.a
+$(PROGRAMS): ../find/version.o ../lib/libfind.a
-dist-hook: findutils-check-manpages
-
-findutils-check-manpages:
- $(top_srcdir)/build-aux/man-lint.sh $(srcdir) $(man_MANS)
+xargs.o: ../lib/wait.h
diff --git a/xargs/Makefile.in b/xargs/Makefile.in
new file mode 100644
index 00000000..4d57ef65
--- /dev/null
+++ b/xargs/Makefile.in
@@ -0,0 +1,156 @@
+# Makefile.in generated automatically by automake from Makefile.am.
+# Copyright (C) 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = $(exec_prefix)/bin
+sbindir = $(exec_prefix)/sbin
+libexecdir = $(exec_prefix)/libexec
+datadir = $(prefix)/share
+sysconfdir = $(prefix)/etc
+sharedstatedir = $(prefix)/com
+localstatedir = $(prefix)/var
+libdir = $(exec_prefix)/lib
+infodir = $(prefix)/info
+mandir = $(prefix)/man
+includedir = $(prefix)/include
+oldincludedir = /usr/include
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+transform = @program_transform_name@
+
+ALL = ${PROGRAMS} ${LIBPROGRAMS} ${SCRIPTS} ${LIBSCRIPTS} ${LIBFILES}
+CC = @CC@
+LEX = @LEX@
+YACC = @YACC@
+ANSI2KNR = ./ansi2knr
+
+DEFS = @DEFS@
+CPPFLAGS = @CPPFLAGS@
+CFLAGS = @CFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+
+xargs_SOURCES = xargs.c
+xargs_OBJECTS = xargs.o
+NROFF = nroff
+
+SOURCES = xargs.c
+DIST_CONF = Makefile.am Makefile.in
+DIST_FILES = $(DIST_CONF) $(SOURCES) $(TEXINFOS) $(INFOS) $(MANS) $(DIST_OTHER)
+
+PROGRAMS = xargs
+MANS = xargs.1
+INCLUDES = -I.. -I$(top_srcdir)/lib
+LDADD = ../find/version.o ../lib/libfind.a
+CONFIG_HEADER = ../config.h
+
+all:: ${ALL}
+
+.c.o:
+ $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $<
+
+$(xargs_OBJECTS): ../config.h
+install:: install-programs
+
+install-programs: $(PROGRAMS) $(SCRIPTS)
+ $(top_srcdir)/mkinstalldirs $(bindir)
+ for p in $(PROGRAMS) $(SCRIPTS); do \
+ $(INSTALL_PROGRAM) $$p $(bindir)/`echo $$p|sed '$(transform)'`; \
+ done
+
+uninstall:: uninstall-programs
+
+uninstall-programs:
+ for p in $(PROGRAMS) $(SCRIPTS); do \
+ rm -f $(bindir)/`echo $$p|sed '$(transform)'`; \
+ done
+
+xargs: $(xargs_OBJECTS)
+ $(CC) -o $@ $(xargs_OBJECTS) $(LDADD) $(LDFLAGS) $(LIBS)
+
+install:: install-man
+
+install-man:
+ for man in $(MANS); do \
+ sect=`echo $$man|sed 's%.*\.\([0-9][a-z]*\)$$%\1%'`; \
+ inst=`basename $$man $$sect|sed '$(transform)'`$$sect; \
+ mdir=$(mandir)/man$$sect; \
+ $(top_srcdir)/mkinstalldirs $$mdir; \
+ echo installing $$man as $$mdir/$$inst; \
+ $(INSTALL_DATA) $(srcdir)/$$man $$mdir/$$inst; \
+ cdir=$(mandir)/cat$$sect; \
+ if test -d $$cdir; then \
+ echo formatting $$man as $$cdir/$$inst; \
+ $(NROFF) -man $(srcdir)/$$man > $$cdir/$$inst; \
+ fi; \
+ done
+
+uninstall:: uninstall-man
+
+uninstall-man:
+ for man in $(MANS); do \
+ sect=`echo $$man|sed 's%.*\(\.[0-9][a-z]*\)$$%\1%'; \
+ inst=`basename $$man $sect|sed '$(transform)'`.$$sect; \
+ mdir=$(mandir)/man$$sect; \
+ cdir=$(mandir)/cat$$sect; \
+ rm -f $$mdir/$$inst $$cdir/$$inst; \
+ done
+
+mostlyclean:
+ rm -f *.o core
+
+clean: mostlyclean
+ rm -f $(PROGRAMS) $(LIBPROGRAMS) $(LIBFILES) $(TEXFILES) $(CLEANFILES)
+
+distclean: clean
+ rm -f Makefile *.tab.c $(DISTCLEANFILES)
+ rm -f config.cache config.log config.status ${CONFIG_HEADER} stamp-h
+
+realclean: distclean
+ rm -f TAGS $(INFOS)
+
+dist: $(DIST_FILES) $(DIST_DIRS)
+ -mkdir ../`cat ../distname`/$(subdir)
+ @for file in $(DIST_FILES); do \
+ echo linking $$file; \
+ ln $(srcdir)/$$file ../`cat ../distname`/$(subdir)/$$file || \
+ { echo copying $$file instead; cp -p $(srcdir)/$$file ../`cat ../distname`/$(subdir)/$$file;}; \
+ done
+
+check dvi info install uninstall::
+
+tags:: TAGS
+
+TAGS::
+ cd $(srcdir); etags $(SOURCES)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
+
+$(PROGRAMS): ../find/version.o ../lib/libfind.a
+
+xargs.o: ../lib/wait.h
diff --git a/xargs/xargs.1 b/xargs/xargs.1
index 413b55ec..a9f39a73 100644
--- a/xargs/xargs.1
+++ b/xargs/xargs.1
@@ -1,477 +1,112 @@
-.TH XARGS 1 \" -*- nroff -*-
+.TH XARGS 1L \" -*- nroff -*-
.SH NAME
xargs \- build and execute command lines from standard input
.SH SYNOPSIS
.B xargs
-.nh
-[\fB\-0prtx\fR]
-[\fB\-E \fIeof-str\fR]
-[\fB\-e\fR[\fIeof-str\fR]]
-[\fB\-\-eof\fR[=\fIeof-str\fR]]
-[\fB\-\-null\fR]
-[\fB\-d \fIdelimiter\fR]
-[\fB\-\-delimiter \fIdelimiter\fR]
-[\fB\-I \fIreplace-str\fR]
-[\fB\-i\fR[\fIreplace-str\fR]]
-[\fB\-\-replace\fR[=\fIreplace-str\fR]]
-[\fB\-l\fR[\fImax-lines\fR]]
-[\fB\-L \fImax-lines\fR]
-[\fB\-\-max\-lines\fR[=\fImax-lines\fR]]
-[\fB\-n \fImax-args\fR]
-[\fB\-\-max\-args\fR=\fImax-args\fR]
-[\fB\-s \fImax-chars\fR]
-[\fB\-\-max\-chars\fR=\fImax-chars\fR]
-[\fB\-P \fImax-procs\fR]
-[\fB\-\-max\-procs\fR=\fImax-procs\fR]
-[\fB\-\-interactive\fR]
-[\fB\-\-verbose\fR]
-[\fB\-\-exit\fR]
-[\fB\-\-no\-run\-if\-empty\fR]
-[\fB\-\-arg\-file\fR=\fIfile\fR]
-[\fB\-\-show\-limits\fR]
-[\fB\-\-version\fR]
-[\fB\-\-help\fR]
-[\fIcommand\fR [\fIinitial-arguments\fR]]
-.hy
+[\-0prtx] [\-e[eof-str]] [\-i[replace-str]] [\-l[max-lines]]
+[\-n max-args] [\-s max-chars] [\-P max-procs] [\-\-null] [\-\-eof[=eof-str]]
+[\-\-replace[=replace-str]] [\-\-max-lines[=max-lines]] [\-\-interactive]
+[\-\-max-chars=max-chars] [\-\-verbose] [\-\-exit] [\-\-max-procs=max-procs]
+[\-\-max-args=max-args] [\-\-no-run-if-empty] [\-\-version] [\-\-help]
+[command [initial-arguments]]
.SH DESCRIPTION
This manual page
documents the GNU version of
.BR xargs .
.B xargs
-reads items from the standard input, delimited by blanks (which can be
+reads arguments from the standard input, delimited by blanks (which can be
protected with double or single quotes or a backslash) or newlines,
and executes the
.I command
-(default is
-.IR /bin/echo )
-one or more times with any
+(default is /bin/echo) one or more times with any
.I initial-arguments
-followed by items read from standard input. Blank lines on the
+followed by arguments read from standard input. Blank lines on the
standard input are ignored.
.P
-Because Unix filenames can contain blanks and newlines, this default
-behaviour is often problematic; filenames containing blanks
-and/or newlines are incorrectly processed by
-.BR xargs .
-In these situations it is better to use the
-.B \-0
-option, which
-prevents such problems. When using this option you will need to
-ensure that the program which produces the input for
-.B xargs
-also uses a null character as a separator. If that program is
-GNU
-.B find
-for example, the
-.B \-print0
-option does this for you.
-.P
-If any invocation of the command exits with a status of 255,
-.B xargs
-will stop immediately without reading any further input. An error
-message is issued on stderr when this happens.
-.SH OPTIONS
-.TP
-.PD 0
-.BI "\-\-arg\-file=" file
-.TP
-.PD 0
-.BI "\-a " file
-Read items from
-.I file
-instead of standard input. If you use this option, stdin remains
-unchanged when commands are run. Otherwise, stdin is redirected
-from
-.IR /dev/null .
-
-.TP
-.PD 0
-.B \-\-null
+.B xargs
+exits with the following status:
+.nf
+0 if it succeeds
+123 if any invocation of the command exited with status 1-125
+124 if the command exited with status 255
+125 if the command is killed by a signal
+126 if the command cannot be run
+127 if the command is not found
+1 if some other error occurred.
+.fi
+.SS OPTIONS
.TP
-.PD
-.B \-0
-Input items are terminated by a null character instead of by
+.I "\-\-null, \-0"
+Input filenames are terminated by a null character instead of by
whitespace, and the quotes and backslash are not special (every
character is taken literally). Disables the end of file string, which
-is treated like any other argument. Useful when input items might
+is treated like any other argument. Useful when arguments might
contain white space, quote marks, or backslashes. The GNU find
\-print0 option produces input suitable for this mode.
-
.TP
-.PD 0
-.BI "\-\-delimiter=" delim
-.TP
-.PD
-.BI \-d " delim"
-Input items are terminated by the specified character. Quotes and
-backslash are not special; every character in the input is taken
-literally. Disables the end-of-file string, which is treated like any
-other argument. This can be used when the input consists of simply
-newline-separated items, although it is almost always better to design
-your program to use
-.B \-\-null
-where this is possible. The specified
-delimiter may be a single character, a C-style character escape such
-as
-.BR \en ,
-or an octal or hexadecimal escape code. Octal and hexadecimal
-escape codes are understood as for the
-.B printf
-command. Multibyte characters are not supported.
-
-.TP
-.BI \-E " eof-str"
+.I "\-\-eof[=eof-str], \-e[eof-str]"
Set the end of file string to \fIeof-str\fR. If the end of file
string occurs as a line of input, the rest of the input is ignored.
-If neither
-.B \-E
-nor
-.B \-e
-is used, no end of file string is used.
-.TP
-.PD 0
-.BR "\-\-eof" [\fI=eof-str\fR]
-.TP
-.PD
-.BR \-e [ \fIeof-str\fR]
-This option is a synonym for the
-.B \-E
-option. Use
-.B \-E
-instead,
-because it is POSIX compliant while this option is not. If
-\fIeof-str\fR is omitted, there is no end of file string. If neither
-.B \-E
-nor
-.B \-e
-is used, no end of file string is used.
+If \fIeof-str\fR is omitted, there is no end of file string. If this
+option is not given, the end of file string defaults to "_".
.TP
-.B "\-\-help"
+.I "\-\-help"
Print a summary of the options to
.B xargs
and exit.
.TP
-.BI \-I " replace-str"
-Replace occurrences of \fIreplace-str\fR in the initial-arguments with
-names read from standard input. Also, unquoted blanks do not
-terminate input items; instead the separator is the newline character.
-Implies
-.B \-x
-and
-.B \-L
-1.
-.TP
-.PD 0
-.BR "\-\-replace" [\fI=replace-str\fR]
-.TP
-.PD
-.BR \-i "[\fIreplace-str\fR]"
-This option is a synonym for
-.BI \-I replace-str
-if
-.I replace-str
-is specified, and for
-.BR \-I {}
-otherwise. This option is deprecated; use
-.B \-I
-instead.
-.TP
-.BI \-L " max-lines"
-Use at most \fImax-lines\fR nonblank input lines per command line.
-Trailing blanks cause an input line to be logically continued on the
-next input line. Implies
-.BR \-x .
-.TP
-.PD 0
-.BR \-\-max-lines "[=\fImax-lines\fR]"
-.TP
-.PD
-.BR \-l "[\fImax-lines\fR]"
-Synonym for the
-.B \-L
-option. Unlike
-.BR \-L ,
-the
-.I max-lines
-argument is optional. If
-.I max-lines
-is not specified, it defaults to one. The
-.B \-l
-option is deprecated since the POSIX standard specifies
-.B \-L
-instead.
-.TP
-.PD 0
-.BR "\-\-max\-args" =\fImax-args\fR
-.TP
-.PD
-.BI \-n " max-args"
+.I "\-\-replace[=replace-str], \-i[replace-str]"
+Replace occurences of \fIreplace-str\fR in the initial arguments with
+names read from standard input.
+Also, unquoted blanks do not terminate arguments.
+If \fIreplace-str\fR is omitted, it
+defaults to "{}" (like for `find \-exec'). Implies \fI\-x\fP and
+\fI\-l 1\fP.
+.TP
+.I "\-\-max-lines[=max-lines], -l[max-lines]"
+Use at most \fImax-lines\fR nonblank input lines per command line;
+\fImax-lines\fR defaults to 1 if omitted. Trailing blanks cause an
+input line to be logically continued on the next input line. Implies
+\fI\-x\fR.
+.TP
+.I "\-\-max-args=max-args, \-n max-args"
Use at most \fImax-args\fR arguments per command line. Fewer than
-.I max-args
-arguments will be used if the size (see the
-.B \-s
-option) is exceeded, unless the
-.B \-x
-option is given, in which case
-.B xargs will exit.
-.TP
-.PD 0
-.B \-\-interactive
+\fImax-args\fR arguments will be used if the size (see the \-s option)
+is exceeded, unless the \-x option is given, in which case \fBxargs\fR
+will exit.
.TP
-.PD
-.B \-p
+.I "\-\-interactive, \-p"
Prompt the user about whether to run each command line and read a line
from the terminal. Only run the command line if the response starts
-with `y' or `Y'. Implies
-.BR -t .
+with `y' or `Y'. Implies \fI\-t\fR.
.TP
-.PD 0
-.B \-\-no\-run\-if\-empty
-.TP
-.PD
-.B \-r
+.I "\-\-no-run-if-empty, \-r"
If the standard input does not contain any nonblanks, do not run the
command. Normally, the command is run once even if there is no input.
-This option is a GNU extension.
-.TP
-.PD 0
-.BR \-\-max\-chars "=\fImax-chars\fR"
.TP
-.PD
-.BI \-s " max-chars"
+.I "\-\-max-chars=max-chars, \-s max-chars"
Use at most \fImax-chars\fR characters per command line, including the
-command and initial-arguments and the terminating nulls at the ends of
-the argument strings. The largest allowed value is system-dependent,
-and is calculated as the argument length limit for exec, less the size
-of your environment, less 2048 bytes of headroom. If this value is
-more than 128KiB, 128Kib is used as the default value; otherwise, the
-default value is the maximum. 1KiB is 1024 bytes.
+command and initial arguments and the terminating nulls at the ends of
+the argument strings. The default is as large as possible, up to 20k
+characters.
.TP
-.PD 0
-.B \-\-verbose
-.TP
-.PD
-.B \-t
+.I "\-\-verbose, \-t"
Print the command line on the standard error output before executing
it.
.TP
-.B "\-\-version"
+.I "\-\-version"
Print the version number of
.B xargs
and exit.
.TP
-.B "\-\-show\\-limits"
-Display the limits on the command-line length which are imposed by the
-operating system,
-.BR xargs '
-choice of buffer size and the
-.B \-s
-option. Pipe the input from
-.I /dev/null
-(and perhaps specify
-.BR --no-run-if-empty )
-if you don't want
-.B xargs
-to do anything.
-.TP
-.PD 0
-.B \-\-exit
-.TP
-.PD
-.B \-x
-Exit if the size (see the
-.B \-s
-option) is exceeded.
+.I "\-\-exit, \-x"
+Exit if the size (see the \fI\-s\fR option) is exceeded.
.TP
-.PD 0
-.BR \-\-max\-procs "=\fImax-procs\fR"
-.TP
-.PD
-.BI \-P " max-procs"
-Run up to
-.I max-procs
-processes at a time; the default is 1. If
-.I max-procs
-is 0,
-.B xargs
-will run as many processes as
-possible at a time. Use the
-.B \-n
-option with
-.BR \-P ;
+.I "\-\-max-procs=max-procs, \-P max-procs"
+Run up to \fImax-procs\fR processes at a time; the default is 1. If
+\fImax-procs\fR is 0, \fBxargs\fR will run as many processes as
+possible at a time. Use the \fI\-n\fR option with \fI\-P\fR;
otherwise chances are that only one exec will be done.
-.SH "EXAMPLES"
-.nf
-.B find /tmp \-name core \-type f \-print | xargs /bin/rm \-f
-
-.fi
-Find files named
-.B core
-in or below the directory
-.B /tmp
-and delete them. Note that this will work incorrectly if there are
-any filenames containing newlines or spaces.
-.P
-.B find /tmp \-name core \-type f \-print0 | xargs \-0 /bin/rm \-f
-
-.fi
-Find files named
-.B core
-in or below the directory
-.B /tmp
-and delete them, processing filenames in such a way that file or
-directory names containing spaces or newlines are correctly handled.
-
-.P
-.B find /tmp \-depth \-name core \-type f \-delete
-
-.fi
-Find files named
-.B core
-in or below the directory
-.B /tmp
-and delete them, but more efficiently than in the previous example
-(because we avoid the need to use
-.BR fork (2)
-and
-.BR exec (2)
-to launch
-.B rm
-and we don't need the extra
-.B xargs
-process).
-
-.P
-.nf
-.B cut \-d: \-f1 < /etc/passwd | sort | xargs echo
-
-.fi
-Generates a compact listing of all the users on the system.
-
-.P
-.nf
-.B xargs sh -c 'emacs \(dq$@\(dq < /dev/tty' emacs
-
-.fi
-Launches the minimum number of copies of Emacs needed, one after the
-other, to edit the files listed on
-.BR xargs '
-standard input. This example achieves the same effect as BSD's
-.B -o
-option, but in a more flexible and portable way.
-
-
-
-.SH "EXIT STATUS"
-.B xargs
-exits with the following status:
-.nf
-0 if it succeeds
-123 if any invocation of the command exited with status 1-125
-124 if the command exited with status 255
-125 if the command is killed by a signal
-126 if the command cannot be run
-127 if the command is not found
-1 if some other error occurred.
-.fi
-.P
-Exit codes greater than 128 are used by the shell to indicate that
-a program died due to a fatal signal.
-.SH "STANDARDS CONFORMANCE"
-As of GNU xargs version 4.2.9, the default behaviour of
-.B xargs
-is not to have a logical end-of-file marker. POSIX (IEEE Std 1003.1,
-2004 Edition) allows this.
-.P
-The \-l and \-i options appear in the 1997 version of the POSIX
-standard, but do not appear in the 2004 version of the standard.
-Therefore you should use \-L and \-I instead, respectively.
-.P
-The POSIX stadard allows implementations to have a limit on the size
-of arguments to the
-.B exec
-functions. This limit could be as low as 4096 bytes including the size of the
-environment. For scripts to be portable, they must not rely on a
-larger value. However, I know of no implementation whose actual limit
-is that small. The
-.B \-\-show\-limits
-option can be used to discover the actual limits in force on the
-current system.
-
-
.SH "SEE ALSO"
-\fBfind\fP(1), \fBlocate\fP(1), \fBlocatedb\fP(5), \fBupdatedb\fP(1),
-\fBfork\fP(2), \fBexecvp\fP(3),
+\fBfind\fP(1L), \fBlocate\fP(1L), \fBlocatedb\fP(5L), \fBupdatedb\fP(1)
\fBFinding Files\fP (on-line in Info, or printed)
-.SH "BUGS"
-The
-.B \-L
-option is incompatible with the
-.B \-I
-option, but perhaps should not be.
-.P
-It is not possible for
-.B xargs
-to be used securely, since there will always be a time gap between the
-production of the list of input files and their use in the commands
-that
-.B xargs
-issues. If other users have access to the system, they can manipulate
-the filesystem during this time window to force the action of the
-commands
-.B xargs
-runs to apply to files that you didn't intend. For a more detailed
-discussion of this and related problems, please refer to the
-``Security Considerations'' chapter in the findutils Texinfo
-documentation. The
-.B \-execdir
-option of
-.B find
-can often be used as a more secure alternative.
-
-When you use the
-.B \-I
-option, each line read from the input is buffered
-internally. This means that there is an upper limit on the length
-of input line that
-.B xargs
-will accept when used with the
-.B \-I
-option. To work around this
-limitation, you can use the
-.B \-s
-option to increase the amount of
-buffer space that
-.B xargs
-uses, and you can also use an extra invocation of
-.B xargs
-to ensure that very long lines do not occur.
-For example:
-.P
-.B somecommand | xargs \-s 50000 echo | xargs \-I '{}' \-s 100000 rm '{}'
-.P
-Here, the first invocation of
-.B xargs
-has no input line length limit
-because it doesn't use the
-.B \-i
-option. The second invocation of
-.B xargs
-does have such a limit, but we have ensured that the it never encounters
-a line which is longer than it can handle. This is not an ideal
-solution. Instead, the
-.B \-i
-option should not impose a line length
-limit, which is why this discussion appears in the BUGS section.
-The problem doesn't occur with the output of
-.BR find (1)
-because it emits just one filename per line.
-.P
-The best way to report a bug is to use the form at
-http://savannah.gnu.org/bugs/?group=findutils.
-The reason for this is that you will then be able to track progress in
-fixing the problem. Other comments about \fBxargs\fP(1) and about
-the findutils package in general can be sent to the
-.I bug\-findutils
-mailing list. To join the list, send email to
-.IR bug\-findutils\-request@gnu.org .
diff --git a/xargs/xargs.c b/xargs/xargs.c
index 1365a71f..1a1e89d2 100644
--- a/xargs/xargs.c
+++ b/xargs/xargs.c
@@ -1,38 +1,32 @@
/* xargs -- build and execute command lines from standard input
- Copyright (C) 1990, 91, 92, 93, 94, 2000, 2003, 2004, 2005, 2006,
- 2007, 2008 Free Software Foundation, Inc.
+ Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
+ 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 3 of the License, or
- (at your option) any later version.
-
+ 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, see <http://www.gnu.org/licenses/>.
-*/
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Mike Rendell <michael@cs.mun.ca>
- and David MacKenzie <djm@gnu.org>.
- Modifications by
- James Youngman
- Dmitry V. Levin
-*/
+ and David MacKenzie <djm@gnu.ai.mit.edu>. */
#include <config.h>
-# ifndef PARAMS
-# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
-# define PARAMS(Args) Args
-# else
-# define PARAMS(Args) ()
-# endif
-# endif
+#if __STDC__
+#define P_(s) s
+#else
+#define P_(s) ()
+#endif
+#define _GNU_SOURCE
#include <ctype.h>
#if !defined (isascii) || defined (STDC_HEADERS)
@@ -55,15 +49,10 @@
#include <stdio.h>
#include <errno.h>
#include <getopt.h>
-#include <fcntl.h>
-#if defined STDC_HEADERS
-#include <assert.h>
-#endif
-
-#if defined HAVE_STRING_H || defined STDC_HEADERS
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
#include <string.h>
-#if !defined STDC_HEADERS
+#if !defined(STDC_HEADERS)
#include <memory.h>
#endif
#else
@@ -71,6 +60,9 @@
#define memcpy(dest, source, count) (bcopy((source), (dest), (count)))
#endif
+char *strstr ();
+char *strdup ();
+
#ifndef _POSIX_SOURCE
#include <sys/param.h>
#endif
@@ -79,14 +71,9 @@
#include <limits.h>
#endif
-#ifndef LONG_MAX
-#define LONG_MAX (~(1 << (sizeof (long) * 8 - 1)))
-#endif
-
-/* The presence of unistd.h is assumed by gnulib these days, so we
- * might as well assume it too.
- */
+#ifdef HAVE_UNISTD_H
#include <unistd.h>
+#endif
#include <signal.h>
@@ -94,63 +81,38 @@
#define SIGCHLD SIGCLD
#endif
-#include "verify.h"
+/* COMPAT: SYSV version defaults size (and has a max value of) to 470.
+ We try to make it as large as possible. */
+#if !defined(ARG_MAX) && defined(_SC_ARG_MAX)
+#define ARG_MAX sysconf (_SC_ARG_MAX)
+#endif
+#ifndef ARG_MAX
+#define ARG_MAX NCARGS
+#endif
+
#include "wait.h"
-#include "quotearg.h"
-#include "findutils-version.h"
+/* States for read_line. */
+#define NORM 0
+#define SPACE 1
+#define QUOTE 2
+#define BACKSLASH 3
#ifdef STDC_HEADERS
#include <stdlib.h>
#else
-extern int errno;
-#endif
+char *malloc ();
+void exit ();
+void free ();
+long strtol ();
-#ifdef HAVE_LOCALE_H
-#include <locale.h>
-#endif
-#if ENABLE_NLS
-# include <libintl.h>
-# define _(Text) gettext (Text)
-#else
-# define _(Text) Text
-#define textdomain(Domain)
-#define bindtextdomain(Package, Directory)
-#endif
-#ifdef gettext_noop
-# define N_(String) gettext_noop (String)
-#else
-/* See locate.c for explanation as to why not use (String) */
-# define N_(String) String
+extern int errno;
#endif
-#include "buildcmd.h"
-
-
/* Return nonzero if S is the EOF string. */
#define EOF_STR(s) (eof_str && *eof_str == *s && !strcmp (eof_str, s))
-/* Do multibyte processing if multibyte characters are supported,
- unless multibyte sequences are search safe. Multibyte sequences
- are search safe if searching for a substring using the byte
- comparison function 'strstr' gives no false positives. All 8-bit
- encodings and the UTF-8 multibyte encoding are search safe, but
- the EUC encodings are not.
- BeOS uses the UTF-8 encoding exclusively, so it is search safe. */
-#if defined __BEOS__
-# define MULTIBYTE_IS_SEARCH_SAFE 1
-#endif
-#define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_SEARCH_SAFE)
-
-#if DO_MULTIBYTE
-# if HAVE_MBRLEN
-# include <wchar.h>
-# else
- /* Simulate mbrlen with mblen as best we can. */
-# define mbstate_t int
-# define mbrlen(s, n, ps) mblen (s, n)
-# endif
-#endif
+extern char **environ;
/* Not char because of type promotion; NeXT gcc can't handle it. */
typedef int boolean;
@@ -163,96 +125,110 @@ typedef int boolean;
#define VOID char
#endif
-#include <xalloc.h>
-#include "closein.h"
-#include "gnulib-version.h"
-
-void error PARAMS ((int status, int errnum, char *message,...));
+VOID *xmalloc P_ ((size_t n));
+VOID *xrealloc P_ ((VOID * p, size_t n));
+void error P_ ((int status, int errnum, char *message,...));
extern char *version_string;
/* The name this program was run with. */
char *program_name;
-static FILE *input_stream;
-
-/* Buffer for reading arguments from input. */
+/* Buffer for reading arguments from stdin. */
static char *linebuf;
-static int keep_stdin = 0;
-
/* Line number in stdin since the last command was executed. */
static int lineno = 0;
-static struct buildcmd_state bc_state;
-static struct buildcmd_control bc_ctl;
-
-/* Did we already complain about NUL characters in the input? */
-static int nullwarning_given = 0;
+/* If nonzero, then instead of putting the args from stdin at
+ the end of the command argument list, they are each stuck into the
+ initial args, replacing each occurrence of the `replace_pat' in the
+ initial args. */
+static char *replace_pat = NULL;
+/* The length of `replace_pat'. */
+static size_t rplen = 0;
/* If nonzero, when this string is read on stdin it is treated as
end of file.
- IEEE Std 1003.1, 2004 Edition allows this to be NULL.
- In findutils releases up to and including 4.2.8, this was "_".
-*/
-static char *eof_str = NULL;
+ I don't like this - it should default to NULL. */
+static char *eof_str = "_";
+
+/* If nonzero, the maximum number of nonblank lines from stdin to use
+ per command line. */
+static long lines_per_exec = 0;
+
+/* The maximum number of arguments to use per command line. */
+static long args_per_exec = 1024;
+
+/* If true, exit if lines_per_exec or args_per_exec is exceeded. */
+static boolean exit_if_size_exceeded = false;
+
+/* The maximum number of characters that can be used per command line. */
+static long arg_max;
+
+/* Storage for elements of `cmd_argv'. */
+static char *argbuf;
+
+/* The list of args being built. */
+static char **cmd_argv = NULL;
+
+/* Number of elements allocated for `cmd_argv'. */
+static int cmd_argv_alloc = 0;
+
+/* Number of valid elements in `cmd_argv'. */
+static int cmd_argc = 0;
+
+/* Number of chars being used in `cmd_argv'. */
+static int cmd_argv_chars = 0;
+
+/* Number of initial arguments given on the command line. */
+static int initial_argc = 0;
/* Number of chars in the initial args. */
-/* static int initial_argv_chars = 0; */
+static int initial_argv_chars = 0;
/* true when building up initial arguments in `cmd_argv'. */
static boolean initial_args = true;
/* If nonzero, the maximum number of child processes that can be running
at once. */
-static unsigned long int proc_max = 1uL;
+static int proc_max = 1;
-/* Did we fork a child yet? */
-static boolean procs_executed = false;
+/* Total number of child processes that have been executed. */
+static int procs_executed = 0;
/* The number of elements in `pids'. */
-static unsigned long int procs_executing = 0uL;
+static int procs_executing = 0;
/* List of child processes currently executing. */
static pid_t *pids = NULL;
/* The number of allocated elements in `pids'. */
-static size_t pids_alloc = 0u;
+static int pids_alloc = 0;
/* Exit status; nonzero if any child process exited with a
status of 1-125. */
-static volatile int child_error = 0;
-
-static volatile int original_exit_value;
+static int child_error = 0;
/* If true, print each command on stderr before executing it. */
-static boolean print_command = false; /* Option -t */
+static boolean print_command = false;
/* If true, query the user before executing each command, and only
execute the command if the user responds affirmatively. */
static boolean query_before_executing = false;
-/* The delimiter for input arguments. This is only consulted if the
- * -0 or -d option had been given.
- */
-static char input_delimiter = '\0';
-
-
static struct option const longopts[] =
{
{"null", no_argument, NULL, '0'},
- {"arg-file", required_argument, NULL, 'a'},
- {"delimiter", required_argument, NULL, 'd'},
{"eof", optional_argument, NULL, 'e'},
- {"replace", optional_argument, NULL, 'I'},
+ {"replace", optional_argument, NULL, 'i'},
{"max-lines", optional_argument, NULL, 'l'},
{"max-args", required_argument, NULL, 'n'},
{"interactive", no_argument, NULL, 'p'},
{"no-run-if-empty", no_argument, NULL, 'r'},
{"max-chars", required_argument, NULL, 's'},
{"verbose", no_argument, NULL, 't'},
- {"show-limits", no_argument, NULL, 'S'},
{"exit", no_argument, NULL, 'x'},
{"max-procs", required_argument, NULL, 'P'},
{"version", no_argument, NULL, 'v'},
@@ -260,337 +236,94 @@ static struct option const longopts[] =
{NULL, no_argument, NULL, 0}
};
-static int read_line PARAMS ((void));
-static int read_string PARAMS ((void));
-static boolean print_args PARAMS ((boolean ask));
-/* static void do_exec PARAMS ((void)); */
-static int xargs_do_exec (const struct buildcmd_control *cl, struct buildcmd_state *state);
-static void exec_if_possible PARAMS ((void));
-static void add_proc PARAMS ((pid_t pid));
-static void wait_for_proc PARAMS ((boolean all, unsigned int minreap));
-static void wait_for_proc_all PARAMS ((void));
-static long parse_num PARAMS ((char *str, int option, long min, long max, int fatal));
-static void usage PARAMS ((FILE * stream));
-
-
-
-static char
-get_char_oct_or_hex_escape(const char *s)
-{
- const char * p;
- int base = 8;
- unsigned long val;
- char *endp;
-
- assert ('\\' == s[0]);
-
- if ('x' == s[1])
- {
- /* hex */
- p = s+2;
- base = 16;
- }
- else if (isdigit(s[1]))
- {
- /* octal */
- p = s+1;
- base = 8;
- }
- else
- {
- p = NULL; /* Silence compiler warning. */
- error(1, 0,
- _("Invalid escape sequence %s in input delimiter specification."),
- s);
- }
- errno = 0;
- endp = (char*)p;
- val = strtoul(p, &endp, base);
-
- /* This if condition is carefully constructed to do
- * the right thing if UCHAR_MAX has the same
- * value as ULONG_MAX. IF UCHAR_MAX==ULONG_MAX,
- * then val can never be greater than UCHAR_MAX.
- */
- if ((ULONG_MAX == val && ERANGE == errno)
- || (val > UCHAR_MAX))
- {
- if (16 == base)
- {
- error(1, 0,
- _("Invalid escape sequence %s in input delimiter specification; character values must not exceed %lx."),
- s, (unsigned long)UCHAR_MAX);
- }
- else
- {
- error(1, 0,
- _("Invalid escape sequence %s in input delimiter specification; character values must not exceed %lo."),
- s, (unsigned long)UCHAR_MAX);
- }
- }
-
- /* check for trailing garbage */
- if (0 != *endp)
- {
- error(1, 0,
- _("Invalid escape sequence %s in input delimiter specification; trailing characters %s not recognised."),
- s, endp);
- }
-
- return (char) val;
-}
-
-
-static char
-get_input_delimiter(const char *s)
-{
- if (1 == strlen(s))
- {
- return s[0];
- }
- else
- {
- if ('\\' == s[0])
- {
- /* an escape code */
- switch (s[1])
- {
- case 'a':
- return '\a';
- 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 '\\':
- return '\\';
- default:
- return get_char_oct_or_hex_escape(s);
- }
- }
- else
- {
- error(1, 0,
- _("Invalid input delimiter specification %s: the delimiter must be either a single character or an escape sequence starting with \\."),
- s);
- /*NOTREACHED*/
- return 0;
- }
- }
-}
-
-static void
-noop (void)
-{
- /* does nothing. */
-}
-
-static void
-fail_due_to_env_size (void)
-{
- error (1, 0, _("environment is too large for exec"));
-}
-
-
-int
-main (int argc, char **argv)
+static int read_line P_ ((void));
+static int read_string P_ ((void));
+static void do_insert P_ ((char *arg, size_t arglen, size_t lblen));
+static void push_arg P_ ((char *arg, size_t len));
+static boolean print_args P_ ((boolean ask));
+static void do_exec P_ ((void));
+static void add_proc P_ ((pid_t pid));
+static void wait_for_proc P_ ((boolean all));
+static long parse_num P_ ((char *str, int option, long min, long max));
+static long env_size P_ ((char **envp));
+static void usage P_ ((FILE * stream, int status));
+
+void
+main (argc, argv)
+ int argc;
+ char **argv;
{
int optc;
- int show_limits = 0; /* --show-limits */
int always_run_command = 1;
- char *input_file = "-"; /* "-" is stdin */
+ long orig_arg_max;
char *default_cmd = "/bin/echo";
- int (*read_args) PARAMS ((void)) = read_line;
- void (*act_on_init_result)(void) = noop;
- enum BC_INIT_STATUS bcstatus;
- enum { XARGS_POSIX_HEADROOM = 2048u };
-
+ int (*read_args) P_ ((void)) = read_line;
+
program_name = argv[0];
- original_exit_value = 0;
-
-#ifdef HAVE_SETLOCALE
- setlocale (LC_ALL, "");
-#endif
- bindtextdomain (PACKAGE, LOCALEDIR);
- textdomain (PACKAGE);
- atexit (close_stdin);
- atexit (wait_for_proc_all);
-
- /* xargs is required by POSIX to allow 2048 bytes of headroom
- * for extra environment variables (that perhaps the utliity might
- * want to set before execing something else).
- */
- bcstatus = bc_init_controlinfo(&bc_ctl, XARGS_POSIX_HEADROOM);
-
- /* The bc_init_controlinfo call may have determined that the
- * environment is too big. In that case, we will fail with
- * an error message after processing the command-line options,
- * as "xargs --help" should still work even if the environment is
- * too big.
- *
- * Some of the argument processing depends on the contents of
- * bc_ctl, which will be in an undefined state if bc_init_controlinfo()
- * failed.
- */
- if (BC_INIT_ENV_TOO_BIG == bcstatus)
- {
- act_on_init_result = fail_due_to_env_size;
- }
- else if (BC_INIT_CANNOT_ACCOMODATE_HEADROOM == bcstatus)
- {
- /* All POSIX systems are required to support ARG_MAX of at least
- * 4096. For everything to work the total of (command line +
- * headroom + environment) must fit into this. POSIX requires
- * that we use a headroom of 2048 bytes. The user is in control
- * of the size of the environment.
- *
- * In general if bc_init_controlinfo() returns
- * BC_INIT_CANNOT_ACCOMODATE_HEADROOM, its caller can try again
- * with a smaller headroom. However, in the case of xargs, this
- * would not be POSIX-compliant.
- */
- act_on_init_result = fail_due_to_env_size;
- }
- else
- {
- /* IEEE Std 1003.1, 2003 specifies that the combined argument and
- * environment list shall not exceed {ARG_MAX}-2048 bytes. It also
- * specifies that it shall be at least LINE_MAX.
- */
-#ifdef _SC_ARG_MAX
- long val = sysconf(_SC_ARG_MAX);
- if (val > 0)
- {
- /* Note that val can in fact be greater than ARG_MAX
- * and bc_ctl.arg_max can also be greater than ARG_MAX.
- */
- assert (bc_ctl.arg_max <= (val-XARGS_POSIX_HEADROOM));
- }
- else
- {
-# if defined ARG_MAX
- assert (bc_ctl.arg_max <= (ARG_MAX-XARGS_POSIX_HEADROOM));
-# endif
- }
-#else
- /* No _SC_ARG_MAX */
- assert (bc_ctl.arg_max <= (ARG_MAX-XARGS_POSIX_HEADROOM));
-#endif
+ orig_arg_max = ARG_MAX - 2048; /* POSIX.2 requires subtracting 2048. */
+ arg_max = orig_arg_max;
-#ifdef LINE_MAX
- /* This assertion ensures that this xargs implementation
- * conforms to the POSIX requirement that the default command
- * line length shall be at least LINE_MAX.
- */
- assert (bc_ctl.arg_max >= LINE_MAX);
-#endif
-
- bc_ctl.exec_callback = xargs_do_exec;
-
- /* Start with a reasonable default size, though this can be
- * adjusted via the -s option.
- */
- bc_use_sensible_arg_max(&bc_ctl);
- }
-
- while ((optc = getopt_long (argc, argv, "+0a:E:e::i::I:l::L:n:prs:txP:d:",
+ /* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which
+ have it at 1 meg). Things will work fine with a large ARG_MAX but it
+ will probably hurt the system more than it needs to; an array of this
+ size is allocated. */
+ if (arg_max > 20 * 1024)
+ arg_max = 20 * 1024;
+
+ /* Take the size of the environment into account. */
+ arg_max -= env_size (environ);
+ if (arg_max <= 0)
+ error (1, 0, "environment is too large for exec");
+
+ while ((optc = getopt_long (argc, argv, "+0e::i::l::n:prs:txP:",
longopts, (int *) 0)) != -1)
{
switch (optc)
{
case '0':
read_args = read_string;
- input_delimiter = '\0';
break;
- case 'd':
- read_args = read_string;
- input_delimiter = get_input_delimiter(optarg);
- break;
-
- case 'E': /* POSIX */
- case 'e': /* deprecated */
- if (optarg && (strlen(optarg) > 0))
+ case 'e':
+ if (optarg)
eof_str = optarg;
else
eof_str = 0;
break;
case 'h':
- usage (stdout);
- return 0;
+ usage (stdout, 0);
- case 'I': /* POSIX */
- case 'i': /* deprecated */
+ case 'i':
if (optarg)
- bc_ctl.replace_pat = optarg;
+ replace_pat = optarg;
else
- bc_ctl.replace_pat = "{}";
+ replace_pat = "{}";
/* -i excludes -n -l. */
- bc_ctl.args_per_exec = 0;
- bc_ctl.lines_per_exec = 0;
- break;
-
- case 'L': /* POSIX */
- bc_ctl.lines_per_exec = parse_num (optarg, 'L', 1L, -1L, 1);
- /* -L excludes -i -n. */
- bc_ctl.args_per_exec = 0;
- bc_ctl.replace_pat = NULL;
+ args_per_exec = 0;
+ lines_per_exec = 0;
break;
- case 'l': /* deprecated */
+ case 'l':
if (optarg)
- bc_ctl.lines_per_exec = parse_num (optarg, 'l', 1L, -1L, 1);
+ lines_per_exec = parse_num (optarg, 'l', 1L, -1L);
else
- bc_ctl.lines_per_exec = 1;
+ lines_per_exec = 1;
/* -l excludes -i -n. */
- bc_ctl.args_per_exec = 0;
- bc_ctl.replace_pat = NULL;
+ args_per_exec = 0;
+ replace_pat = NULL;
break;
case 'n':
- bc_ctl.args_per_exec = parse_num (optarg, 'n', 1L, -1L, 1);
+ args_per_exec = parse_num (optarg, 'n', 1L, -1L);
/* -n excludes -i -l. */
- bc_ctl.lines_per_exec = 0;
- if (bc_ctl.args_per_exec == 1 && bc_ctl.replace_pat)
- /* ignore -n1 in '-i -n1' */
- bc_ctl.args_per_exec = 0;
- else
- bc_ctl.replace_pat = NULL;
+ lines_per_exec = 0;
+ replace_pat = NULL;
break;
- /* The POSIX standard specifies that it is not an error
- * for the -s option to specify a size that the implementation
- * cannot support - in that case, the relevant limit is used.
- */
case 's':
- {
- size_t arg_size;
- act_on_init_result();
- arg_size = parse_num (optarg, 's', 1L,
- bc_ctl.posix_arg_size_max, 0);
- if (arg_size > bc_ctl.posix_arg_size_max)
- {
- error (0, 0,
- _("Warning: value %ld for -s option is too large, "
- "using %ld instead"),
- arg_size, bc_ctl.posix_arg_size_max);
- arg_size = bc_ctl.posix_arg_size_max;
- }
- bc_ctl.arg_max = arg_size;
- }
- break;
-
- case 'S':
- show_limits = true;
+ arg_max = parse_num (optarg, 's', 1L, orig_arg_max);
break;
case 't':
@@ -598,7 +331,7 @@ main (int argc, char **argv)
break;
case 'x':
- bc_ctl.exit_if_size_exceeded = true;
+ exit_if_size_exceeded = true;
break;
case 'p':
@@ -611,52 +344,20 @@ main (int argc, char **argv)
break;
case 'P':
- /* Allow only up to LONG_MAX child processes. */
- proc_max = parse_num (optarg, 'P', 0L, LONG_MAX, 1);
+ proc_max = parse_num (optarg, 'P', 0L, -1L);
break;
- case 'a':
- input_file = optarg;
- break;
-
case 'v':
- display_findutils_version("xargs");
- return 0;
+ printf ("GNU xargs version %s\n", version_string);
+ exit (0);
default:
- usage (stderr);
- return 1;
- }
- }
-
- /* If we had deferred failing due to problems in bc_init_controlinfo(),
- * do it now.
- *
- * We issue this error message after processing command line
- * arguments so that it is possible to use "xargs --help" even if
- * the environment is too large.
- */
- act_on_init_result();
- assert (BC_INIT_OK == bcstatus);
-
- if (0 == strcmp (input_file, "-"))
- {
- input_stream = stdin;
- }
- else
- {
- keep_stdin = 1; /* see prep_child_for_exec() */
- input_stream = fopen (input_file, "r");
- if (NULL == input_stream)
- {
- error (1, errno,
- _("Cannot open input file %s"),
- quotearg_n_style(0, locale_quoting_style, input_file));
+ usage (stderr, 1);
}
}
- if (bc_ctl.replace_pat || bc_ctl.lines_per_exec)
- bc_ctl.exit_if_size_exceeded = true;
+ if (replace_pat || lines_per_exec)
+ exit_if_size_exceeded = true;
if (optind == argc)
{
@@ -665,131 +366,58 @@ main (int argc, char **argv)
argv = &default_cmd;
}
- /* We want to be able to print size_t values as unsigned long, so if
- * the cast isn't value-preserving, we have a problem. This isn't a
- * problem in C89, because size_t was known to be no wider than
- * unsigned long. In C99 this is no longer the case, but there are
- * special C99 ways to print such values. Unfortunately this
- * program tries to work on both C89 and C99 systems.
- */
-#if defined SIZE_MAX
-# if SIZE_MAX > ULONG_MAX
-# error "I'm not sure how to print size_t values on your system"
-# endif
-#else
- /* Without SIZE_MAX (i.e. limits.h) this is probably
- * close to the best we can do.
- */
- verify_true (sizeof(size_t) <= sizeof(unsigned long));
-#endif
-
- if (show_limits)
- {
- fprintf(stderr,
- _("Your environment variables take up %lu bytes\n"),
- (unsigned long)bc_size_of_environment());
- fprintf(stderr,
- _("POSIX upper limit on argument length (this system): %lu\n"),
- (unsigned long)bc_ctl.posix_arg_size_max);
- fprintf(stderr,
- _("POSIX smallest allowable upper limit on argument length (all systems): %lu\n"),
- (unsigned long)bc_ctl.posix_arg_size_min);
- fprintf(stderr,
- _("Maximum length of command we could actually use: %ld\n"),
- (unsigned long)(bc_ctl.posix_arg_size_max -
- bc_size_of_environment()));
- fprintf(stderr,
- _("Size of command buffer we are actually using: %lu\n"),
- (unsigned long)bc_ctl.arg_max);
-
- if (isatty(STDIN_FILENO))
- {
- fprintf(stderr,
- _("\n"
- "Execution of xargs will continue now, and it will "
- "try to read its input and run commands; if this is "
- "not what you wanted to happen, please type the "
- "end-of-file keystroke.\n"));
- if (always_run_command)
- {
- fprintf(stderr,
- _("Warning: %s will be run at least once. "
- "If you do not want that to happen, then press "
- "the interrupt keystroke.\n"),
- argv[optind]);
- }
- }
- }
-
- linebuf = xmalloc (bc_ctl.arg_max + 1);
- bc_state.argbuf = xmalloc (bc_ctl.arg_max + 1);
+ linebuf = (char *) xmalloc (arg_max + 1);
+ argbuf = (char *) xmalloc (arg_max + 1);
/* Make sure to listen for the kids. */
signal (SIGCHLD, SIG_DFL);
- if (!bc_ctl.replace_pat)
+ if (!replace_pat)
{
for (; optind < argc; optind++)
- bc_push_arg (&bc_ctl, &bc_state,
- argv[optind], strlen (argv[optind]) + 1,
- NULL, 0,
- initial_args);
+ push_arg (argv[optind], strlen (argv[optind]) + 1);
initial_args = false;
- bc_ctl.initial_argc = bc_state.cmd_argc;
- bc_state.cmd_initial_argv_chars = bc_state.cmd_argv_chars;
+ initial_argc = cmd_argc;
+ initial_argv_chars = cmd_argv_chars;
while ((*read_args) () != -1)
- if (bc_ctl.lines_per_exec && lineno >= bc_ctl.lines_per_exec)
+ if (lines_per_exec && lineno >= lines_per_exec)
{
- xargs_do_exec (&bc_ctl, &bc_state);
+ do_exec ();
lineno = 0;
}
/* SYSV xargs seems to do at least one exec, even if the
input is empty. */
- if (bc_state.cmd_argc != bc_ctl.initial_argc
- || (always_run_command && !procs_executed))
- xargs_do_exec (&bc_ctl, &bc_state);
-
+ if (cmd_argc != initial_argc
+ || (always_run_command && procs_executed == 0))
+ do_exec ();
}
else
{
int i;
size_t len;
- size_t *arglen = xmalloc (sizeof (size_t) * argc);
+ size_t *arglen = (size_t *) xmalloc (sizeof (size_t) * argc);
for (i = optind; i < argc; i++)
arglen[i] = strlen(argv[i]);
- bc_ctl.rplen = strlen (bc_ctl.replace_pat);
+ rplen = strlen (replace_pat);
while ((len = (*read_args) ()) != -1)
{
/* Don't do insert on the command name. */
- bc_clear_args(&bc_ctl, &bc_state);
- bc_state.cmd_argv_chars = 0; /* begin at start of buffer */
-
- bc_push_arg (&bc_ctl, &bc_state,
- argv[optind], arglen[optind] + 1,
- NULL, 0,
- initial_args);
+ push_arg (argv[optind], arglen[optind] + 1);
len--;
- initial_args = false;
-
for (i = optind + 1; i < argc; i++)
- bc_do_insert (&bc_ctl, &bc_state,
- argv[i], arglen[i],
- NULL, 0,
- linebuf, len,
- initial_args);
- xargs_do_exec (&bc_ctl, &bc_state);
+ do_insert (argv[i], arglen[i], len);
+ do_exec ();
}
}
- original_exit_value = child_error;
- return child_error;
+ wait_for_proc (true);
+ exit (child_error);
}
-
-/* Read a line of arguments from the input and add them to the list of
+/* Read a line of arguments from stdin and add them to the list of
arguments to pass to the command. Ignore blank lines and initial blanks.
Single and double quotes and backslashes quote metacharacters and blanks
as they do in the shell.
@@ -797,36 +425,26 @@ main (int argc, char **argv)
otherwise the length of the last string read (including the null). */
static int
-read_line (void)
+read_line ()
{
-/* States for read_line. */
- enum read_line_state
- {
- NORM = 0,
- SPACE = 1,
- QUOTE = 2,
- BACKSLASH = 3
- };
static boolean eof = false;
/* Start out in mode SPACE to always strip leading spaces (even with -i). */
- enum read_line_state state = SPACE; /* The type of character we last read. */
+ int state = SPACE; /* The type of character we last read. */
int prevc; /* The previous value of c. */
int quotc = 0; /* The last quote character read. */
int c = EOF;
boolean first = true; /* true if reading first arg on line. */
- boolean seen_arg = false; /* true if we have seen any arg (or part of one) yet */
int len;
char *p = linebuf;
/* Including the NUL, the args must not grow past this point. */
- char *endbuf = linebuf + bc_ctl.arg_max - bc_state.cmd_initial_argv_chars - 1;
-
+ char *endbuf = linebuf + arg_max - initial_argv_chars - 1;
+
if (eof)
return -1;
while (1)
{
prevc = c;
- c = getc (input_stream);
-
+ c = getc (stdin);
if (c == EOF)
{
/* COMPAT: SYSV seems to ignore stuff on a line that
@@ -836,19 +454,11 @@ read_line (void)
return -1;
*p++ = '\0';
len = p - linebuf;
- if (state == QUOTE)
- {
- exec_if_possible ();
- error (1, 0, _("unmatched %s quote; by default quotes are special to xargs unless you use the -0 option"),
- quotc == '"' ? _("double") : _("single"));
- }
+ /* FIXME we don't check for unterminated quotes here. */
if (first && EOF_STR (linebuf))
return -1;
- if (!bc_ctl.replace_pat)
- bc_push_arg (&bc_ctl, &bc_state,
- linebuf, len,
- NULL, 0,
- initial_args);
+ if (!replace_pat)
+ push_arg (linebuf, len);
return len;
}
switch (state)
@@ -866,16 +476,9 @@ read_line (void)
lineno++; /* For -l. */
if (p == linebuf)
{
- if (seen_arg)
- {
- /* An empty argument, add it to the list as normal. */
- }
- else
- {
- /* Blank line. */
- state = SPACE;
- continue;
- }
+ /* Blank line. */
+ state = SPACE;
+ continue;
}
*p++ = '\0';
len = p - linebuf;
@@ -884,19 +487,11 @@ read_line (void)
eof = true;
return first ? -1 : len;
}
- if (!bc_ctl.replace_pat)
- bc_push_arg (&bc_ctl, &bc_state,
- linebuf, len,
- NULL, 0,
- initial_args);
+ if (!replace_pat)
+ push_arg (linebuf, len);
return len;
}
- seen_arg = true;
-
- /* POSIX: In the POSIX locale, the separators are <SPC> and
- * <TAB>, but not <FF> or <VT>.
- */
- if (!bc_ctl.replace_pat && ISBLANK (c))
+ if (!replace_pat && ISSPACE (c))
{
*p++ = '\0';
len = p - linebuf;
@@ -905,10 +500,7 @@ read_line (void)
eof = true;
return first ? -1 : len;
}
- bc_push_arg (&bc_ctl, &bc_state,
- linebuf, len,
- NULL, 0,
- initial_args);
+ push_arg (linebuf, len);
p = linebuf;
state = SPACE;
first = false;
@@ -930,15 +522,11 @@ read_line (void)
case QUOTE:
if (c == '\n')
- {
- exec_if_possible ();
- error (1, 0, _("unmatched %s quote; by default quotes are special to xargs unless you use the -0 option"),
- quotc == '"' ? _("double") : _("single"));
- }
+ error (1, 0, "unmatched %s quote",
+ quotc == '"' ? "double" : "single");
if (c == quotc)
{
state = NORM;
- seen_arg = true; /* Makes a difference for e.g. just '' or "" as the first arg on a line */
continue;
}
break;
@@ -947,49 +535,31 @@ read_line (void)
state = NORM;
break;
}
-
- if ( (0 == c) && !nullwarning_given )
- {
- /* This is just a warning message. We only issue it once. */
- error (0, 0,
- _("Warning: a NUL character occurred in the input. "
- "It cannot be passed through in the argument list. "
- "Did you mean to use the --null option?"));
- nullwarning_given = 1;
- }
-
-#if 1
if (p >= endbuf)
- {
- exec_if_possible ();
- error (1, 0, _("argument line too long"));
- }
+ error (1, 0, "argument line too long");
*p++ = c;
-#else
- append_char_to_buf(&linebuf, &endbuf, &p, c);
-#endif
}
}
-/* Read a null-terminated string from the input and add it to the list of
+/* Read a null-terminated string from stdin and add it to the list of
arguments to pass to the command.
Return -1 if eof (either physical or logical) is reached,
otherwise the length of the string read (including the null). */
static int
-read_string (void)
+read_string ()
{
static boolean eof = false;
int len;
char *p = linebuf;
/* Including the NUL, the args must not grow past this point. */
- char *endbuf = linebuf + bc_ctl.arg_max - bc_state.cmd_initial_argv_chars - 1;
+ char *endbuf = linebuf + arg_max - initial_argv_chars - 1;
if (eof)
return -1;
while (1)
{
- int c = getc (input_stream);
+ int c = getc (stdin);
if (c == EOF)
{
eof = true;
@@ -997,46 +567,149 @@ read_string (void)
return -1;
*p++ = '\0';
len = p - linebuf;
- if (!bc_ctl.replace_pat)
- bc_push_arg (&bc_ctl, &bc_state,
- linebuf, len,
- NULL, 0,
- initial_args);
+ if (!replace_pat)
+ push_arg (linebuf, len);
return len;
}
- if (c == input_delimiter)
+ if (c == '\0')
{
lineno++; /* For -l. */
*p++ = '\0';
len = p - linebuf;
- if (!bc_ctl.replace_pat)
- bc_push_arg (&bc_ctl, &bc_state,
- linebuf, len,
- NULL, 0,
- initial_args);
+ if (!replace_pat)
+ push_arg (linebuf, len);
return len;
}
if (p >= endbuf)
- {
- exec_if_possible ();
- error (1, 0, _("argument line too long"));
- }
+ error (1, 0, "argument line too long");
*p++ = c;
}
}
+/* Replace all instances of `replace_pat' in ARG with `linebuf',
+ and add the resulting string to the list of arguments for the command
+ to execute.
+ ARGLEN is the length of ARG, not including the null.
+ LBLEN is the length of `linebuf', not including the null.
+
+ COMPAT: insertions on the SYSV version are limited to 255 chars per line,
+ and a max of 5 occurences of replace_pat in the initial-arguments.
+ Those restrictions do not exist here. */
+
+static void
+do_insert (arg, arglen, lblen)
+ char *arg;
+ size_t arglen;
+ size_t lblen;
+{
+ /* Temporary copy of each arg with the replace pattern replaced by the
+ real arg. */
+ static char *insertbuf;
+ char *p;
+ int bytes_left = arg_max - 1; /* Bytes left on the command line. */
+
+ if (!insertbuf)
+ insertbuf = (char *) xmalloc (arg_max + 1);
+ p = insertbuf;
+
+ do
+ {
+ size_t len; /* Length in ARG before `replace_pat'. */
+ char *s = strstr (arg, replace_pat);
+ if (s)
+ len = s - arg;
+ else
+ len = arglen;
+ bytes_left -= len;
+ if (bytes_left <= 0)
+ break;
+
+ strncpy (p, arg, len);
+ p += len;
+ arg += len;
+
+ if (s)
+ {
+ bytes_left -= lblen;
+ if (bytes_left <= 0)
+ break;
+ strcpy (p, linebuf);
+ arg += rplen;
+ p += lblen;
+ }
+ }
+ while (*arg);
+ if (*arg)
+ error (1, 0, "command too long");
+ *p++ = '\0';
+ push_arg (insertbuf, p - insertbuf);
+}
+
+/* Add ARG to the end of the list of arguments `cmd_argv' to pass
+ to the command.
+ LEN is the length of ARG, including the terminating null.
+ If this brings the list up to its maximum size, execute the command. */
+
+static void
+push_arg (arg, len)
+ char *arg;
+ size_t len;
+{
+ if (arg)
+ {
+ if (cmd_argv_chars + len > arg_max)
+ {
+ if (initial_args || cmd_argc == initial_argc)
+ error (1, 0, "can not fit single argument within argument list size limit");
+ if (replace_pat
+ || (exit_if_size_exceeded &&
+ (lines_per_exec || args_per_exec)))
+ error (1, 0, "argument list too long");
+ do_exec ();
+ }
+ if (!initial_args && args_per_exec &&
+ cmd_argc - initial_argc == args_per_exec)
+ do_exec ();
+ }
+
+ if (cmd_argc >= cmd_argv_alloc)
+ {
+ if (!cmd_argv)
+ {
+ cmd_argv_alloc = 64;
+ cmd_argv = (char **) xmalloc (sizeof (char *) * cmd_argv_alloc);
+ }
+ else
+ {
+ cmd_argv_alloc *= 2;
+ cmd_argv = (char **) xrealloc (cmd_argv,
+ sizeof (char *) * cmd_argv_alloc);
+ }
+ }
+
+ if (!arg)
+ cmd_argv[cmd_argc++] = NULL;
+ else
+ {
+ cmd_argv[cmd_argc++] = argbuf + cmd_argv_chars;
+ strcpy (argbuf + cmd_argv_chars, arg);
+ cmd_argv_chars += len;
+ }
+}
+
/* Print the arguments of the command to execute.
If ASK is nonzero, prompt the user for a response, and
if the user responds affirmatively, return true;
otherwise, return false. */
static boolean
-print_args (boolean ask)
+print_args (ask)
+ boolean ask;
{
int i;
- for (i = 0; i < bc_state.cmd_argc - 1; i++)
- fprintf (stderr, "%s ", bc_state.cmd_argv[i]);
+ for (i = 0; i < cmd_argc - 1; i++)
+ fprintf (stderr, "%s ", cmd_argv[i]);
if (ask)
{
static FILE *tty_stream;
@@ -1062,263 +735,132 @@ print_args (boolean ask)
return false;
}
-
-/* Close stdin and attach /dev/null to it.
- * This resolves Savannah bug #3992.
- */
-static void
-prep_child_for_exec (void)
-{
- if (!keep_stdin)
- {
- const char inputfile[] = "/dev/null";
- /* fprintf(stderr, "attaching stdin to /dev/null\n"); */
-
- close(0);
- if (open(inputfile, O_RDONLY) < 0)
- {
- /* This is not entirely fatal, since
- * executing the child with a closed
- * stdin is almost as good as executing it
- * with its stdin attached to /dev/null.
- */
- error (0, errno, "%s", quotearg_n_style(0, locale_quoting_style, inputfile));
- }
- }
-}
-
-
/* Execute the command that has been built in `cmd_argv'. This may involve
waiting for processes that were previously executed. */
-static int
-xargs_do_exec (const struct buildcmd_control *ctl, struct buildcmd_state *state)
+static void
+do_exec ()
{
pid_t child;
- (void) ctl;
- (void) state;
-
- bc_push_arg (&bc_ctl, &bc_state,
- (char *) NULL, 0,
- NULL, 0,
- false); /* Null terminate the arg list. */
-
+ push_arg ((char *) NULL, 0); /* Null terminate the arg list. */
if (!query_before_executing || print_args (true))
{
- if (proc_max)
- {
- if (procs_executing >= proc_max)
- wait_for_proc (false, proc_max - procs_executing + 1);
- assert (procs_executing < proc_max);
- }
+ if (proc_max && procs_executing >= proc_max)
+ wait_for_proc (false);
if (!query_before_executing && print_command)
print_args (false);
-
- /* Before forking, reap any already-exited child. We do this so
- that we don't leave unreaped children around while we build a
- new command line. For example this command will spend most
- of its time waiting for sufficient arguments to launch
- another command line:
-
- seq 1 1000 | fmt | while read x ; do echo $x; sleep 1 ; done |
- ./xargs -P 200 -n 20 sh -c 'echo "$@"; sleep $((1 + $RANDOM % 5))' sleeper
- */
- wait_for_proc (false, 0u);
-
/* If we run out of processes, wait for a child to return and
try again. */
while ((child = fork ()) < 0 && errno == EAGAIN && procs_executing)
- wait_for_proc (false, 1u);
-
+ wait_for_proc (false);
switch (child)
{
case -1:
- error (1, errno, _("cannot fork"));
+ error (1, errno, "cannot fork");
case 0: /* Child. */
- prep_child_for_exec();
- execvp (bc_state.cmd_argv[0], bc_state.cmd_argv);
- error (0, errno, "%s", bc_state.cmd_argv[0]);
+ execvp (cmd_argv[0], cmd_argv);
+ error (0, errno, "%s", cmd_argv[0]);
_exit (errno == ENOENT ? 127 : 126);
- /*NOTREACHED*/
}
add_proc (child);
}
- bc_clear_args(&bc_ctl, &bc_state);
- return 1; /* Success */
-}
-
-/* Execute the command if possible. */
-
-static void
-exec_if_possible (void)
-{
- if (bc_ctl.replace_pat || initial_args ||
- bc_state.cmd_argc == bc_ctl.initial_argc || bc_ctl.exit_if_size_exceeded)
- return;
- xargs_do_exec (&bc_ctl, &bc_state);
+ cmd_argc = initial_argc;
+ cmd_argv_chars = initial_argv_chars;
}
/* Add the process with id PID to the list of processes that have
been executed. */
static void
-add_proc (pid_t pid)
+add_proc (pid)
+ pid_t pid;
{
- unsigned int i, j;
+ int i;
/* Find an empty slot. */
for (i = 0; i < pids_alloc && pids[i]; i++)
;
-
- /* Extend the array if we failed. */
if (i == pids_alloc)
{
- pids = x2nrealloc (pids, &pids_alloc, sizeof *pids);
-
- /* Zero out the new slots. */
- for (j=i; j<pids_alloc; ++j)
- pids[j] = (pid_t)0;
+ if (pids_alloc == 0)
+ {
+ pids_alloc = proc_max ? proc_max : 64;
+ pids = (pid_t *) xmalloc (sizeof (pid_t) * pids_alloc);
+ }
+ else
+ {
+ pids_alloc *= 2;
+ pids = (pid_t *) xrealloc (pids,
+ sizeof (pid_t) * pids_alloc);
+ }
+ memset (&pids[i], '\0', sizeof (pid_t) * (pids_alloc - i));
}
- /* Verify that we are not destroying the record of some existing child. */
- assert (0 == pids[i]);
-
- /* Remember the child. */
pids[i] = pid;
procs_executing++;
- procs_executed = true;
+ procs_executed++;
}
-
/* If ALL is true, wait for all child processes to finish;
- otherwise, wait for at least MINREAP child processes to finish.
+ otherwise, wait for one child process to finish.
Remove the processes that finish from the list of executing processes. */
static void
-wait_for_proc (boolean all, unsigned int minreap)
+wait_for_proc (all)
+ boolean all;
{
- unsigned int reaped = 0;
-
while (procs_executing)
{
- unsigned int i;
- int status;
- pid_t pid;
- int wflags = 0;
-
- if (!all)
- {
- if (reaped >= minreap)
- {
- /* We already reaped enough children. To save system
- * resources, reap any dead children anyway, but do not
- * wait for any currently executing children to exit.
-
- */
- wflags = WNOHANG;
- }
- }
+ int i, status;
do
{
- /* Wait for any child. We used to use wait() here, but it's
- * unlikely that that offers any portability advantage over
- * wait these days.
- */
- while ((pid = waitpid (-1, &status, wflags)) == (pid_t) -1)
- {
- if (errno != EINTR)
- error (1, errno, _("error waiting for child process"));
- }
-
+ pid_t pid;
+
+ pid = wait (&status);
+ if (pid < 0)
+ error (1, errno, "error waiting for child process");
+
/* Find the entry in `pids' for the child process
that exited. */
- if (pid)
- {
- for (i = 0; i < pids_alloc && pid != pids[i]; i++)
- ;
- }
+ for (i = 0; i < pids_alloc && pid != pids[i]; i++)
+ ;
}
- while (pid && i == pids_alloc); /* A child died that we didn't start? */
+ while (i == pids_alloc); /* A child died that we didn't start? */
- if (!pid)
- {
- if (!(wflags & WNOHANG))
- {
- /* Nothing remained to be reaped. This should not
- * happen, because procs_executing should contain the
- * number of child processes still executing, so the
- * loop should have terminated.
- */
- error (0, 0, _("Warning: Lost track of %d child processes"),
- procs_executing);
- }
- else
- {
- /* Children are (probably) executing but are not ready
- * to be reaped at the moment.
- */
- }
- break;
- }
-
/* Remove the child from the list. */
pids[i] = 0;
procs_executing--;
- reaped++;
if (WEXITSTATUS (status) == 126 || WEXITSTATUS (status) == 127)
exit (WEXITSTATUS (status)); /* Can't find or run the command. */
if (WEXITSTATUS (status) == 255)
- error (124, 0, _("%s: exited with status 255; aborting"), bc_state.cmd_argv[0]);
+ error (124, 0, "%s: exited with status 255; aborting", cmd_argv[0]);
if (WIFSTOPPED (status))
- error (125, 0, _("%s: stopped by signal %d"), bc_state.cmd_argv[0], WSTOPSIG (status));
+ error (125, 0, "%s: stopped by signal %d", cmd_argv[0], WSTOPSIG (status));
if (WIFSIGNALED (status))
- error (125, 0, _("%s: terminated by signal %d"), bc_state.cmd_argv[0], WTERMSIG (status));
+ error (125, 0, "%s: terminated by signal %d", cmd_argv[0], WTERMSIG (status));
if (WEXITSTATUS (status) != 0)
child_error = 123;
- }
-}
-/* Wait for all child processes to finish. */
-
-static void
-wait_for_proc_all (void)
-{
- static boolean waiting = false;
-
- if (waiting)
- return;
-
- waiting = true;
- wait_for_proc (true, 0u);
- waiting = false;
-
- if (original_exit_value != child_error)
- {
- /* wait_for_proc() changed the value of child_error(). This
- * function is registered via atexit(), and so may have been
- * called from exit(). We now know that the original value
- * passed to exit() is no longer the exit status we require.
- * The POSIX standard states that the behaviour if exit() is
- * called more than once is undefined. Therefore we now have to
- * exit with _exit() instead of exit().
- */
- _exit(child_error);
+ if (!all)
+ break;
}
-
}
/* Return the value of the number represented in STR.
OPTION is the command line option to which STR is the argument.
If the value does not fall within the boundaries MIN and MAX,
- Print an error message mentioning OPTION. If FATAL is true,
- we also exit. */
+ Print an error message mentioning OPTION and exit. */
static long
-parse_num (char *str, int option, long int min, long int max, int fatal)
+parse_num (str, option, min, max)
+ char *str;
+ int option;
+ long min;
+ long max;
{
char *eptr;
long val;
@@ -1326,55 +868,51 @@ parse_num (char *str, int option, long int min, long int max, int fatal)
val = strtol (str, &eptr, 10);
if (eptr == str || *eptr)
{
- fprintf (stderr, _("%s: invalid number for -%c option\n"),
+ fprintf (stderr, "%s: invalid number for -%c option\n",
program_name, option);
- usage (stderr);
- exit(1);
+ usage (stderr, 1);
}
else if (val < min)
{
- fprintf (stderr, _("%s: value for -%c option should be >= %ld\n"),
+ fprintf (stderr, "%s: value for -%c option must be >= %ld\n",
program_name, option, min);
- if (fatal)
- {
- usage (stderr);
- exit(1);
- }
- else
- {
- val = min;
- }
+ usage (stderr, 1);
}
else if (max >= 0 && val > max)
{
- fprintf (stderr, _("%s: value for -%c option should be < %ld\n"),
+ fprintf (stderr, "%s: value for -%c option must be < %ld\n",
program_name, option, max);
- if (fatal)
- {
- usage (stderr);
- exit(1);
- }
- else
- {
- val = max;
- }
+ usage (stderr, 1);
}
return val;
}
+/* Return how much of ARG_MAX is used by the environment. */
+
+static long
+env_size (envp)
+ char **envp;
+{
+ long len = 0;
+
+ while (*envp)
+ len += strlen (*envp++) + 1;
+
+ return len;
+}
+
static void
-usage (FILE *stream)
+usage (stream, status)
+ FILE *stream;
+ int status;
{
- fprintf (stream, _("\
-Usage: %s [-0prtx] [--interactive] [--null] [-d|--delimiter=delim]\n\
- [-E eof-str] [-e[eof-str]] [--eof[=eof-str]]\n\
- [-L max-lines] [-l[max-lines]] [--max-lines[=max-lines]]\n\
- [-I replace-str] [-i[replace-str]] [--replace[=replace-str]]\n\
- [-n max-args] [--max-args=max-args]\n\
- [-s max-chars] [--max-chars=max-chars]\n\
- [-P max-procs] [--max-procs=max-procs] [--show-limits]\n\
- [--verbose] [--exit] [--no-run-if-empty] [--arg-file=file]\n\
- [--version] [--help] [command [initial-arguments]]\n"),
+ fprintf (stream, "\
+Usage: %s [-0prtx] [-e[eof-str]] [-i[replace-str]] [-l[max-lines]]\n\
+ [-n max-args] [-s max-chars] [-P max-procs] [--null] [--eof[=eof-str]]\n\
+ [--replace[=replace-str]] [--max-lines[=max-lines]] [--interactive]\n\
+ [--max-chars=max-chars] [--verbose] [--exit] [--max-procs=max-procs]\n\
+ [--max-args=max-args] [--no-run-if-empty] [--version] [--help]\n\
+ [command [initial-arguments]]\n",
program_name);
- fputs (_("\nReport bugs to <bug-findutils@gnu.org>.\n"), stream);
+ exit (status);
}