mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Add bash 5.2 to third_party
This commit is contained in:
parent
e1f65d5f2b
commit
f4a2a65cc8
237 changed files with 120739 additions and 1 deletions
3
Makefile
3
Makefile
|
@ -229,7 +229,8 @@ include third_party/libcxx/BUILD.mk # │
|
|||
include third_party/pcre/BUILD.mk # │
|
||||
include third_party/less/BUILD.mk # │
|
||||
include net/https/BUILD.mk # │
|
||||
include third_party/regex/BUILD.mk #─┘
|
||||
include third_party/regex/BUILD.mk # │
|
||||
include third_party/bash/BUILD.mk #─┘
|
||||
include third_party/tidy/BUILD.mk
|
||||
include third_party/BUILD.mk
|
||||
include third_party/nsync/testing/BUILD.mk
|
||||
|
|
1
third_party/BUILD.mk
vendored
1
third_party/BUILD.mk
vendored
|
@ -5,6 +5,7 @@
|
|||
o/$(MODE)/third_party: \
|
||||
o/$(MODE)/third_party/argon2 \
|
||||
o/$(MODE)/third_party/awk \
|
||||
o/$(MODE)/third_party/bash \
|
||||
o/$(MODE)/third_party/bzip2 \
|
||||
o/$(MODE)/third_party/chibicc \
|
||||
o/$(MODE)/third_party/compiler_rt \
|
||||
|
|
97
third_party/bash/BUILD.mk
vendored
Normal file
97
third_party/bash/BUILD.mk
vendored
Normal file
|
@ -0,0 +1,97 @@
|
|||
#-*-mode:bashfile-gbash;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=bash ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
PKGS += THIRD_PARTY_BASH
|
||||
|
||||
THIRD_PARTY_BASH_A = o/$(MODE)/third_party/bash/bash.a
|
||||
THIRD_PARTY_BASH_FILES := $(wildcard third_party/bash/*)
|
||||
THIRD_PARTY_BASH_HDRS = $(filter %.h,$(THIRD_PARTY_BASH_FILES))
|
||||
THIRD_PARTY_BASH_INCS = $(filter %.inc,$(THIRD_PARTY_BASH_FILES))
|
||||
THIRD_PARTY_BASH_SRCS = $(filter %.c,$(THIRD_PARTY_BASH_FILES))
|
||||
THIRD_PARTY_BASH_OBJS = $(THIRD_PARTY_BASH_SRCS:%.c=o/$(MODE)/%.o)
|
||||
THIRD_PARTY_BASH_COMS = o/$(MODE)/third_party/bash/bash.com
|
||||
THIRD_PARTY_BASH_CHECKS = $(THIRD_PARTY_BASH_A).pkg
|
||||
|
||||
THIRD_PARTY_BASH_BINS = \
|
||||
$(THIRD_PARTY_BASH_COMS) \
|
||||
$(THIRD_PARTY_BASH_COMS:%=%.dbg)
|
||||
|
||||
THIRD_PARTY_BASH_DIRECTDEPS = \
|
||||
LIBC_CALLS \
|
||||
LIBC_DNS \
|
||||
LIBC_FMT \
|
||||
LIBC_INTRIN \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_PROC \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_SOCK \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_THREAD \
|
||||
LIBC_TIME \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_NCURSES \
|
||||
THIRD_PARTY_READLINE \
|
||||
THIRD_PARTY_REGEX
|
||||
|
||||
THIRD_PARTY_BASH_DEPS := \
|
||||
$(call uniq,$(foreach x,$(THIRD_PARTY_BASH_DIRECTDEPS),$($(x))))
|
||||
|
||||
$(THIRD_PARTY_BASH_A).pkg: \
|
||||
$(THIRD_PARTY_BASH_OBJS) \
|
||||
$(foreach x,$(THIRD_PARTY_BASH_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
$(THIRD_PARTY_BASH_A): \
|
||||
third_party/bash/ \
|
||||
$(THIRD_PARTY_BASH_A).pkg \
|
||||
$(filter-out %main.o,$(THIRD_PARTY_BASH_OBJS))
|
||||
|
||||
o/$(MODE)/third_party/bash/bash.com.dbg: \
|
||||
$(THIRD_PARTY_BASH_DEPS) \
|
||||
$(THIRD_PARTY_BASH_A) \
|
||||
$(THIRD_PARTY_BASH_A).pkg \
|
||||
o/$(MODE)/third_party/bash/shell.o \
|
||||
$(CRT) \
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
$(THIRD_PARTY_BASH_OBJS): private \
|
||||
CPPFLAGS += \
|
||||
-DHAVE_CONFIG_H \
|
||||
-DSHELL \
|
||||
-DPACKAGE=\"bash\" \
|
||||
-DLOCALEDIR=\"/zip/usr/share/locale\" \
|
||||
-DCONF_HOSTTYPE=\"unknown\" \
|
||||
-DCONF_OSTYPE=\"linux-cosmo\" \
|
||||
-DCONF_MACHTYPE=\"unknown-pc-unknown-cosmo\" \
|
||||
-DCONF_VENDOR=\"pc\"
|
||||
|
||||
$(THIRD_PARTY_BASH_OBJS): private \
|
||||
CFLAGS += \
|
||||
-Wno-unused-but-set-variable \
|
||||
-Wno-discarded-qualifiers \
|
||||
-Wno-maybe-uninitialized \
|
||||
-Wno-pointer-to-int-cast \
|
||||
-Wno-stringop-truncation \
|
||||
-Wno-format-zero-length \
|
||||
-Wno-format-overflow \
|
||||
-Wno-char-subscripts \
|
||||
-Wno-nonnull-compare \
|
||||
-Wno-unused-variable \
|
||||
-Wno-missing-braces \
|
||||
-Wno-unused-label \
|
||||
-Wno-unused-value \
|
||||
-Wno-parentheses \
|
||||
-fportcosmo
|
||||
|
||||
$(THIRD_PARTY_BASH_OBJS): third_party/bash/BUILD.mk
|
||||
|
||||
.PHONY: o/$(MODE)/third_party/bash
|
||||
o/$(MODE)/third_party/bash: \
|
||||
$(THIRD_PARTY_BASH_BINS) \
|
||||
$(THIRD_PARTY_BASH_CHECKS)
|
||||
|
674
third_party/bash/LICENSE
vendored
Normal file
674
third_party/bash/LICENSE
vendored
Normal file
|
@ -0,0 +1,674 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
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
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state 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>
|
||||
|
||||
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.
|
||||
|
||||
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/>.
|
||||
|
||||
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:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program 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".
|
||||
|
||||
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/>.
|
||||
|
||||
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>.
|
15
third_party/bash/README.cosmo
vendored
Normal file
15
third_party/bash/README.cosmo
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
DESCRIPTION
|
||||
|
||||
the bourne again shell
|
||||
|
||||
LICENSE
|
||||
|
||||
GPL v3
|
||||
|
||||
ORIGIN
|
||||
|
||||
https://ftp.gnu.org/gnu/bash/bash-5.2.tar.gz
|
||||
|
||||
LOCAL CHANGES
|
||||
|
||||
- Force disable mkfifo() code
|
594
third_party/bash/alias.c
vendored
Normal file
594
third_party/bash/alias.c
vendored
Normal file
|
@ -0,0 +1,594 @@
|
|||
/* alias.c -- Not a full alias, but just the kind that we use in the
|
||||
shell. Csh style alias is somewhere else (`over there, in a box'). */
|
||||
|
||||
/* Copyright (C) 1987-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (ALIAS)
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "chartypes.h"
|
||||
#include "bashansi.h"
|
||||
#include "command.h"
|
||||
#include "general.h"
|
||||
#include "externs.h"
|
||||
#include "alias.h"
|
||||
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
# include "pcomplete.h"
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR)
|
||||
# include <mbstr.h> /* mbschr */
|
||||
#endif
|
||||
|
||||
#define ALIAS_HASH_BUCKETS 64 /* must be power of two */
|
||||
|
||||
typedef int sh_alias_map_func_t PARAMS((alias_t *));
|
||||
|
||||
static void free_alias_data PARAMS((PTR_T));
|
||||
static alias_t **map_over_aliases PARAMS((sh_alias_map_func_t *));
|
||||
static void sort_aliases PARAMS((alias_t **));
|
||||
static int qsort_alias_compare PARAMS((alias_t **, alias_t **));
|
||||
|
||||
#if defined (READLINE)
|
||||
static int skipquotes PARAMS((char *, int));
|
||||
static int skipws PARAMS((char *, int));
|
||||
static int rd_token PARAMS((char *, int));
|
||||
#endif
|
||||
|
||||
/* Non-zero means expand all words on the line. Otherwise, expand
|
||||
after first expansion if the expansion ends in a space. */
|
||||
int alias_expand_all = 0;
|
||||
|
||||
/* The list of aliases that we have. */
|
||||
HASH_TABLE *aliases = (HASH_TABLE *)NULL;
|
||||
|
||||
void
|
||||
initialize_aliases ()
|
||||
{
|
||||
if (aliases == 0)
|
||||
aliases = hash_create (ALIAS_HASH_BUCKETS);
|
||||
}
|
||||
|
||||
/* Scan the list of aliases looking for one with NAME. Return NULL
|
||||
if the alias doesn't exist, else a pointer to the alias_t. */
|
||||
alias_t *
|
||||
find_alias (name)
|
||||
char *name;
|
||||
{
|
||||
BUCKET_CONTENTS *al;
|
||||
|
||||
if (aliases == 0)
|
||||
return ((alias_t *)NULL);
|
||||
|
||||
al = hash_search (name, aliases, 0);
|
||||
return (al ? (alias_t *)al->data : (alias_t *)NULL);
|
||||
}
|
||||
|
||||
/* Return the value of the alias for NAME, or NULL if there is none. */
|
||||
char *
|
||||
get_alias_value (name)
|
||||
char *name;
|
||||
{
|
||||
alias_t *alias;
|
||||
|
||||
if (aliases == 0)
|
||||
return ((char *)NULL);
|
||||
|
||||
alias = find_alias (name);
|
||||
return (alias ? alias->value : (char *)NULL);
|
||||
}
|
||||
|
||||
/* Make a new alias from NAME and VALUE. If NAME can be found,
|
||||
then replace its value. */
|
||||
void
|
||||
add_alias (name, value)
|
||||
char *name, *value;
|
||||
{
|
||||
BUCKET_CONTENTS *elt;
|
||||
alias_t *temp;
|
||||
int n;
|
||||
|
||||
if (aliases == 0)
|
||||
{
|
||||
initialize_aliases ();
|
||||
temp = (alias_t *)NULL;
|
||||
}
|
||||
else
|
||||
temp = find_alias (name);
|
||||
|
||||
if (temp)
|
||||
{
|
||||
free (temp->value);
|
||||
temp->value = savestring (value);
|
||||
temp->flags &= ~AL_EXPANDNEXT;
|
||||
if (value[0])
|
||||
{
|
||||
n = value[strlen (value) - 1];
|
||||
if (n == ' ' || n == '\t')
|
||||
temp->flags |= AL_EXPANDNEXT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = (alias_t *)xmalloc (sizeof (alias_t));
|
||||
temp->name = savestring (name);
|
||||
temp->value = savestring (value);
|
||||
temp->flags = 0;
|
||||
|
||||
if (value[0])
|
||||
{
|
||||
n = value[strlen (value) - 1];
|
||||
if (n == ' ' || n == '\t')
|
||||
temp->flags |= AL_EXPANDNEXT;
|
||||
}
|
||||
|
||||
elt = hash_insert (savestring (name), aliases, HASH_NOSRCH);
|
||||
elt->data = temp;
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
set_itemlist_dirty (&it_aliases);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete a single alias structure. */
|
||||
static void
|
||||
free_alias_data (data)
|
||||
PTR_T data;
|
||||
{
|
||||
register alias_t *a;
|
||||
|
||||
a = (alias_t *)data;
|
||||
|
||||
if (a->flags & AL_BEINGEXPANDED)
|
||||
clear_string_list_expander (a); /* call back to the parser */
|
||||
|
||||
free (a->value);
|
||||
free (a->name);
|
||||
free (data);
|
||||
}
|
||||
|
||||
/* Remove the alias with name NAME from the alias table. Returns
|
||||
the number of aliases left in the table, or -1 if the alias didn't
|
||||
exist. */
|
||||
int
|
||||
remove_alias (name)
|
||||
char *name;
|
||||
{
|
||||
BUCKET_CONTENTS *elt;
|
||||
|
||||
if (aliases == 0)
|
||||
return (-1);
|
||||
|
||||
elt = hash_remove (name, aliases, 0);
|
||||
if (elt)
|
||||
{
|
||||
free_alias_data (elt->data);
|
||||
free (elt->key); /* alias name */
|
||||
free (elt); /* XXX */
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
set_itemlist_dirty (&it_aliases);
|
||||
#endif
|
||||
return (aliases->nentries);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Delete all aliases. */
|
||||
void
|
||||
delete_all_aliases ()
|
||||
{
|
||||
if (aliases == 0)
|
||||
return;
|
||||
|
||||
hash_flush (aliases, free_alias_data);
|
||||
hash_dispose (aliases);
|
||||
aliases = (HASH_TABLE *)NULL;
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
set_itemlist_dirty (&it_aliases);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return an array of aliases that satisfy the conditions tested by FUNCTION.
|
||||
If FUNCTION is NULL, return all aliases. */
|
||||
static alias_t **
|
||||
map_over_aliases (function)
|
||||
sh_alias_map_func_t *function;
|
||||
{
|
||||
register int i;
|
||||
register BUCKET_CONTENTS *tlist;
|
||||
alias_t *alias, **list;
|
||||
int list_index;
|
||||
|
||||
i = HASH_ENTRIES (aliases);
|
||||
if (i == 0)
|
||||
return ((alias_t **)NULL);
|
||||
|
||||
list = (alias_t **)xmalloc ((i + 1) * sizeof (alias_t *));
|
||||
for (i = list_index = 0; i < aliases->nbuckets; i++)
|
||||
{
|
||||
for (tlist = hash_items (i, aliases); tlist; tlist = tlist->next)
|
||||
{
|
||||
alias = (alias_t *)tlist->data;
|
||||
|
||||
if (!function || (*function) (alias))
|
||||
{
|
||||
list[list_index++] = alias;
|
||||
list[list_index] = (alias_t *)NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (list);
|
||||
}
|
||||
|
||||
static void
|
||||
sort_aliases (array)
|
||||
alias_t **array;
|
||||
{
|
||||
qsort (array, strvec_len ((char **)array), sizeof (alias_t *), (QSFUNC *)qsort_alias_compare);
|
||||
}
|
||||
|
||||
static int
|
||||
qsort_alias_compare (as1, as2)
|
||||
alias_t **as1, **as2;
|
||||
{
|
||||
int result;
|
||||
|
||||
if ((result = (*as1)->name[0] - (*as2)->name[0]) == 0)
|
||||
result = strcmp ((*as1)->name, (*as2)->name);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* Return a sorted list of all defined aliases */
|
||||
alias_t **
|
||||
all_aliases ()
|
||||
{
|
||||
alias_t **list;
|
||||
|
||||
if (aliases == 0 || HASH_ENTRIES (aliases) == 0)
|
||||
return ((alias_t **)NULL);
|
||||
|
||||
list = map_over_aliases ((sh_alias_map_func_t *)NULL);
|
||||
if (list)
|
||||
sort_aliases (list);
|
||||
return (list);
|
||||
}
|
||||
|
||||
char *
|
||||
alias_expand_word (s)
|
||||
char *s;
|
||||
{
|
||||
alias_t *r;
|
||||
|
||||
r = find_alias (s);
|
||||
return (r ? savestring (r->value) : (char *)NULL);
|
||||
}
|
||||
|
||||
/* Readline support functions -- expand all aliases in a line. */
|
||||
|
||||
#if defined (READLINE)
|
||||
|
||||
/* Return non-zero if CHARACTER is a member of the class of characters
|
||||
that are self-delimiting in the shell (this really means that these
|
||||
characters delimit tokens). */
|
||||
#define self_delimiting(character) (member ((character), " \t\n\r;|&()"))
|
||||
|
||||
/* Return non-zero if CHARACTER is a member of the class of characters
|
||||
that delimit commands in the shell. */
|
||||
#define command_separator(character) (member ((character), "\r\n;|&("))
|
||||
|
||||
/* If this is 1, we are checking the next token read for alias expansion
|
||||
because it is the first word in a command. */
|
||||
static int command_word;
|
||||
|
||||
/* This is for skipping quoted strings in alias expansions. */
|
||||
#define quote_char(c) (((c) == '\'') || ((c) == '"'))
|
||||
|
||||
/* Consume a quoted string from STRING, starting at string[START] (so
|
||||
string[START] is the opening quote character), and return the index
|
||||
of the closing quote character matching the opening quote character.
|
||||
This handles single matching pairs of unquoted quotes; it could afford
|
||||
to be a little smarter... This skips words between balanced pairs of
|
||||
quotes, words where the first character is quoted with a `\', and other
|
||||
backslash-escaped characters. */
|
||||
|
||||
static int
|
||||
skipquotes (string, start)
|
||||
char *string;
|
||||
int start;
|
||||
{
|
||||
register int i;
|
||||
int delimiter = string[start];
|
||||
|
||||
/* i starts at START + 1 because string[START] is the opening quote
|
||||
character. */
|
||||
for (i = start + 1 ; string[i] ; i++)
|
||||
{
|
||||
if (string[i] == '\\')
|
||||
{
|
||||
i++; /* skip backslash-quoted quote characters, too */
|
||||
if (string[i] == 0)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string[i] == delimiter)
|
||||
return i;
|
||||
}
|
||||
return (i);
|
||||
}
|
||||
|
||||
/* Skip the white space and any quoted characters in STRING, starting at
|
||||
START. Return the new index into STRING, after zero or more characters
|
||||
have been skipped. */
|
||||
static int
|
||||
skipws (string, start)
|
||||
char *string;
|
||||
int start;
|
||||
{
|
||||
register int i;
|
||||
int pass_next, backslash_quoted_word;
|
||||
unsigned char peekc;
|
||||
|
||||
/* skip quoted strings, in ' or ", and words in which a character is quoted
|
||||
with a `\'. */
|
||||
i = backslash_quoted_word = pass_next = 0;
|
||||
|
||||
/* Skip leading whitespace (or separator characters), and quoted words.
|
||||
But save it in the output. */
|
||||
|
||||
for (i = start; string[i]; i++)
|
||||
{
|
||||
if (pass_next)
|
||||
{
|
||||
pass_next = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (whitespace (string[i]))
|
||||
{
|
||||
backslash_quoted_word = 0; /* we are no longer in a backslash-quoted word */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string[i] == '\\')
|
||||
{
|
||||
peekc = string[i+1];
|
||||
if (peekc == 0)
|
||||
break;
|
||||
if (ISLETTER (peekc))
|
||||
backslash_quoted_word++; /* this is a backslash-quoted word */
|
||||
else
|
||||
pass_next++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* This only handles single pairs of non-escaped quotes. This
|
||||
overloads backslash_quoted_word to also mean that a word like
|
||||
""f is being scanned, so that the quotes will inhibit any expansion
|
||||
of the word. */
|
||||
if (quote_char(string[i]))
|
||||
{
|
||||
i = skipquotes (string, i);
|
||||
/* This could be a line that contains a single quote character,
|
||||
in which case skipquotes () terminates with string[i] == '\0'
|
||||
(the end of the string). Check for that here. */
|
||||
if (string[i] == '\0')
|
||||
break;
|
||||
|
||||
peekc = string[i + 1];
|
||||
if (ISLETTER (peekc))
|
||||
backslash_quoted_word++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we're in the middle of some kind of quoted word, let it
|
||||
pass through. */
|
||||
if (backslash_quoted_word)
|
||||
continue;
|
||||
|
||||
/* If this character is a shell command separator, then set a hint for
|
||||
alias_expand that the next token is the first word in a command. */
|
||||
|
||||
if (command_separator (string[i]))
|
||||
{
|
||||
command_word++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return (i);
|
||||
}
|
||||
|
||||
/* Characters that may appear in a token. Basically, anything except white
|
||||
space and a token separator. */
|
||||
#define token_char(c) (!((whitespace (string[i]) || self_delimiting (string[i]))))
|
||||
|
||||
/* Read from START in STRING until the next separator character, and return
|
||||
the index of that separator. Skip backslash-quoted characters. Call
|
||||
skipquotes () for quoted strings in the middle or at the end of tokens,
|
||||
so all characters show up (e.g. foo'' and foo""bar) */
|
||||
static int
|
||||
rd_token (string, start)
|
||||
char *string;
|
||||
int start;
|
||||
{
|
||||
register int i;
|
||||
|
||||
/* From here to next separator character is a token. */
|
||||
for (i = start; string[i] && token_char (string[i]); i++)
|
||||
{
|
||||
if (string[i] == '\\')
|
||||
{
|
||||
i++; /* skip backslash-escaped character */
|
||||
if (string[i] == 0)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If this character is a quote character, we want to call skipquotes
|
||||
to get the whole quoted portion as part of this word. That word
|
||||
will not generally match an alias, even if te unquoted word would
|
||||
have. The presence of the quotes in the token serves then to
|
||||
inhibit expansion. */
|
||||
if (quote_char (string[i]))
|
||||
{
|
||||
i = skipquotes (string, i);
|
||||
/* This could be a line that contains a single quote character,
|
||||
in which case skipquotes () terminates with string[i] == '\0'
|
||||
(the end of the string). Check for that here. */
|
||||
if (string[i] == '\0')
|
||||
break;
|
||||
|
||||
/* Now string[i] is the matching quote character, and the
|
||||
quoted portion of the token has been scanned. */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return (i);
|
||||
}
|
||||
|
||||
/* Return a new line, with any aliases substituted. */
|
||||
char *
|
||||
alias_expand (string)
|
||||
char *string;
|
||||
{
|
||||
register int i, j, start;
|
||||
char *line, *token;
|
||||
int line_len, tl, real_start, expand_next, expand_this_token;
|
||||
alias_t *alias;
|
||||
|
||||
line_len = strlen (string) + 1;
|
||||
line = (char *)xmalloc (line_len);
|
||||
token = (char *)xmalloc (line_len);
|
||||
|
||||
line[0] = i = 0;
|
||||
expand_next = 0;
|
||||
command_word = 1; /* initialized to expand the first word on the line */
|
||||
|
||||
/* Each time through the loop we find the next word in line. If it
|
||||
has an alias, substitute the alias value. If the value ends in ` ',
|
||||
then try again with the next word. Else, if there is no value, or if
|
||||
the value does not end in space, we are done. */
|
||||
|
||||
for (;;)
|
||||
{
|
||||
|
||||
token[0] = 0;
|
||||
start = i;
|
||||
|
||||
/* Skip white space and quoted characters */
|
||||
i = skipws (string, start);
|
||||
|
||||
if (start == i && string[i] == '\0')
|
||||
{
|
||||
free (token);
|
||||
return (line);
|
||||
}
|
||||
|
||||
/* copy the just-skipped characters into the output string,
|
||||
expanding it if there is not enough room. */
|
||||
j = strlen (line);
|
||||
tl = i - start; /* number of characters just skipped */
|
||||
RESIZE_MALLOCED_BUFFER (line, j, (tl + 1), line_len, (tl + 50));
|
||||
strncpy (line + j, string + start, tl);
|
||||
line[j + tl] = '\0';
|
||||
|
||||
real_start = i;
|
||||
|
||||
command_word = command_word || (command_separator (string[i]));
|
||||
expand_this_token = (command_word || expand_next);
|
||||
expand_next = 0;
|
||||
|
||||
/* Read the next token, and copy it into TOKEN. */
|
||||
start = i;
|
||||
i = rd_token (string, start);
|
||||
|
||||
tl = i - start; /* token length */
|
||||
|
||||
/* If tl == 0, but we're not at the end of the string, then we have a
|
||||
single-character token, probably a delimiter */
|
||||
if (tl == 0 && string[i] != '\0')
|
||||
{
|
||||
tl = 1;
|
||||
i++; /* move past it */
|
||||
}
|
||||
|
||||
strncpy (token, string + start, tl);
|
||||
token [tl] = '\0';
|
||||
|
||||
/* If there is a backslash-escaped character quoted in TOKEN,
|
||||
then we don't do alias expansion. This should check for all
|
||||
other quoting characters, too. */
|
||||
if (mbschr (token, '\\'))
|
||||
expand_this_token = 0;
|
||||
|
||||
/* If we should be expanding here, if we are expanding all words, or if
|
||||
we are in a location in the string where an expansion is supposed to
|
||||
take place, see if this word has a substitution. If it does, then do
|
||||
the expansion. Note that we defer the alias value lookup until we
|
||||
are sure we are expanding this token. */
|
||||
|
||||
if ((token[0]) &&
|
||||
(expand_this_token || alias_expand_all) &&
|
||||
(alias = find_alias (token)))
|
||||
{
|
||||
char *v;
|
||||
int vlen, llen;
|
||||
|
||||
v = alias->value;
|
||||
vlen = strlen (v);
|
||||
llen = strlen (line);
|
||||
|
||||
/* +3 because we possibly add one more character below. */
|
||||
RESIZE_MALLOCED_BUFFER (line, llen, (vlen + 3), line_len, (vlen + 50));
|
||||
|
||||
strcpy (line + llen, v);
|
||||
|
||||
if ((expand_this_token && vlen && whitespace (v[vlen - 1])) ||
|
||||
alias_expand_all)
|
||||
expand_next = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int llen, tlen;
|
||||
|
||||
llen = strlen (line);
|
||||
tlen = i - real_start; /* tlen == strlen(token) */
|
||||
|
||||
RESIZE_MALLOCED_BUFFER (line, llen, (tlen + 1), line_len, (llen + tlen + 50));
|
||||
|
||||
strncpy (line + llen, string + real_start, tlen);
|
||||
line[llen + tlen] = '\0';
|
||||
}
|
||||
command_word = 0;
|
||||
}
|
||||
}
|
||||
#endif /* READLINE */
|
||||
#endif /* ALIAS */
|
73
third_party/bash/alias.h
vendored
Normal file
73
third_party/bash/alias.h
vendored
Normal file
|
@ -0,0 +1,73 @@
|
|||
/* alias.h -- structure definitions. */
|
||||
|
||||
/* Copyright (C) 1987-2020 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (_ALIAS_H_)
|
||||
#define _ALIAS_H_
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
#include "hashlib.h"
|
||||
|
||||
typedef struct alias {
|
||||
char *name;
|
||||
char *value;
|
||||
char flags;
|
||||
} alias_t;
|
||||
|
||||
/* Values for `flags' member of struct alias. */
|
||||
#define AL_EXPANDNEXT 0x1
|
||||
#define AL_BEINGEXPANDED 0x2
|
||||
|
||||
/* The list of known aliases. */
|
||||
extern HASH_TABLE *aliases;
|
||||
|
||||
extern void initialize_aliases PARAMS((void));
|
||||
|
||||
/* Scan the list of aliases looking for one with NAME. Return NULL
|
||||
if the alias doesn't exist, else a pointer to the alias. */
|
||||
extern alias_t *find_alias PARAMS((char *));
|
||||
|
||||
/* Return the value of the alias for NAME, or NULL if there is none. */
|
||||
extern char *get_alias_value PARAMS((char *));
|
||||
|
||||
/* Make a new alias from NAME and VALUE. If NAME can be found,
|
||||
then replace its value. */
|
||||
extern void add_alias PARAMS((char *, char *));
|
||||
|
||||
/* Remove the alias with name NAME from the alias list. Returns
|
||||
the index of the removed alias, or -1 if the alias didn't exist. */
|
||||
extern int remove_alias PARAMS((char *));
|
||||
|
||||
/* Remove all aliases. */
|
||||
extern void delete_all_aliases PARAMS((void));
|
||||
|
||||
/* Return an array of all defined aliases. */
|
||||
extern alias_t **all_aliases PARAMS((void));
|
||||
|
||||
/* Expand a single word for aliases. */
|
||||
extern char *alias_expand_word PARAMS((char *));
|
||||
|
||||
/* Return a new line, with any aliases expanded. */
|
||||
extern char *alias_expand PARAMS((char *));
|
||||
|
||||
/* Helper definition for the parser */
|
||||
extern void clear_string_list_expander PARAMS((alias_t *));
|
||||
|
||||
#endif /* _ALIAS_H_ */
|
54
third_party/bash/ansi_stdlib.h
vendored
Normal file
54
third_party/bash/ansi_stdlib.h
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
/* ansi_stdlib.h -- An ANSI Standard stdlib.h. */
|
||||
/* A minimal stdlib.h containing extern declarations for those functions
|
||||
that bash uses. */
|
||||
|
||||
/* Copyright (C) 1993 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (_STDLIB_H_)
|
||||
#define _STDLIB_H_ 1
|
||||
|
||||
/* String conversion functions. */
|
||||
extern int atoi ();
|
||||
|
||||
extern double atof ();
|
||||
extern double strtod ();
|
||||
|
||||
/* Memory allocation functions. */
|
||||
/* Generic pointer type. */
|
||||
#ifndef PTR_T
|
||||
|
||||
#if defined (__STDC__)
|
||||
# define PTR_T void *
|
||||
#else
|
||||
# define PTR_T char *
|
||||
#endif
|
||||
|
||||
#endif /* PTR_T */
|
||||
|
||||
extern PTR_T malloc ();
|
||||
extern PTR_T realloc ();
|
||||
extern void free ();
|
||||
|
||||
/* Other miscellaneous functions. */
|
||||
extern void abort ();
|
||||
extern void exit ();
|
||||
extern char *getenv ();
|
||||
extern void qsort ();
|
||||
|
||||
#endif /* _STDLIB_H */
|
1303
third_party/bash/array.c
vendored
Normal file
1303
third_party/bash/array.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
182
third_party/bash/array.h
vendored
Normal file
182
third_party/bash/array.h
vendored
Normal file
|
@ -0,0 +1,182 @@
|
|||
/* array.h -- definitions for the interface exported by array.c that allows
|
||||
the rest of the shell to manipulate array variables. */
|
||||
|
||||
/* Copyright (C) 1997-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _ARRAY_H_
|
||||
#define _ARRAY_H_
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
typedef intmax_t arrayind_t;
|
||||
|
||||
typedef struct array {
|
||||
arrayind_t max_index;
|
||||
arrayind_t num_elements;
|
||||
#ifdef ALT_ARRAY_IMPLEMENTATION
|
||||
arrayind_t first_index;
|
||||
arrayind_t alloc_size;
|
||||
struct array_element **elements;
|
||||
#else
|
||||
struct array_element *head;
|
||||
struct array_element *lastref;
|
||||
#endif
|
||||
} ARRAY;
|
||||
|
||||
typedef struct array_element {
|
||||
arrayind_t ind;
|
||||
char *value;
|
||||
#ifndef ALT_ARRAY_IMPLEMENTATION
|
||||
struct array_element *next, *prev;
|
||||
#endif
|
||||
} ARRAY_ELEMENT;
|
||||
|
||||
#define ARRAY_DEFAULT_SIZE 1024
|
||||
|
||||
typedef int sh_ae_map_func_t PARAMS((ARRAY_ELEMENT *, void *));
|
||||
|
||||
/* Basic operations on entire arrays */
|
||||
#ifdef ALT_ARRAY_IMPLEMENTATION
|
||||
extern void array_alloc PARAMS((ARRAY *, arrayind_t));
|
||||
extern void array_resize PARAMS((ARRAY *, arrayind_t));
|
||||
extern void array_expand PARAMS((ARRAY *, arrayind_t));
|
||||
extern void array_dispose_elements PARAMS((ARRAY_ELEMENT **));
|
||||
#endif
|
||||
extern ARRAY *array_create PARAMS((void));
|
||||
extern void array_flush PARAMS((ARRAY *));
|
||||
extern void array_dispose PARAMS((ARRAY *));
|
||||
extern ARRAY *array_copy PARAMS((ARRAY *));
|
||||
#ifndef ALT_ARRAY_IMPLEMENTATION
|
||||
extern ARRAY *array_slice PARAMS((ARRAY *, ARRAY_ELEMENT *, ARRAY_ELEMENT *));
|
||||
#else
|
||||
extern ARRAY *array_slice PARAMS((ARRAY *, arrayind_t, arrayind_t));
|
||||
#endif
|
||||
|
||||
extern void array_walk PARAMS((ARRAY *, sh_ae_map_func_t *, void *));
|
||||
|
||||
#ifndef ALT_ARRAY_IMPLEMENTATION
|
||||
extern ARRAY_ELEMENT *array_shift PARAMS((ARRAY *, int, int));
|
||||
#else
|
||||
extern ARRAY_ELEMENT **array_shift PARAMS((ARRAY *, int, int));
|
||||
#endif
|
||||
extern int array_rshift PARAMS((ARRAY *, int, char *));
|
||||
extern ARRAY_ELEMENT *array_unshift_element PARAMS((ARRAY *));
|
||||
extern int array_shift_element PARAMS((ARRAY *, char *));
|
||||
|
||||
extern ARRAY *array_quote PARAMS((ARRAY *));
|
||||
extern ARRAY *array_quote_escapes PARAMS((ARRAY *));
|
||||
extern ARRAY *array_dequote PARAMS((ARRAY *));
|
||||
extern ARRAY *array_dequote_escapes PARAMS((ARRAY *));
|
||||
extern ARRAY *array_remove_quoted_nulls PARAMS((ARRAY *));
|
||||
|
||||
extern char *array_subrange PARAMS((ARRAY *, arrayind_t, arrayind_t, int, int, int));
|
||||
extern char *array_patsub PARAMS((ARRAY *, char *, char *, int));
|
||||
extern char *array_modcase PARAMS((ARRAY *, char *, int, int));
|
||||
|
||||
/* Basic operations on array elements. */
|
||||
extern ARRAY_ELEMENT *array_create_element PARAMS((arrayind_t, char *));
|
||||
extern ARRAY_ELEMENT *array_copy_element PARAMS((ARRAY_ELEMENT *));
|
||||
extern void array_dispose_element PARAMS((ARRAY_ELEMENT *));
|
||||
|
||||
extern int array_insert PARAMS((ARRAY *, arrayind_t, char *));
|
||||
extern ARRAY_ELEMENT *array_remove PARAMS((ARRAY *, arrayind_t));
|
||||
extern char *array_reference PARAMS((ARRAY *, arrayind_t));
|
||||
|
||||
/* Converting to and from arrays */
|
||||
extern WORD_LIST *array_to_word_list PARAMS((ARRAY *));
|
||||
extern ARRAY *array_from_word_list PARAMS((WORD_LIST *));
|
||||
extern WORD_LIST *array_keys_to_word_list PARAMS((ARRAY *));
|
||||
extern WORD_LIST *array_to_kvpair_list PARAMS((ARRAY *));
|
||||
|
||||
extern ARRAY *array_assign_list PARAMS((ARRAY *, WORD_LIST *));
|
||||
|
||||
extern char **array_to_argv PARAMS((ARRAY *, int *));
|
||||
extern ARRAY *array_from_argv PARAMS((ARRAY *, char **, int));
|
||||
|
||||
extern char *array_to_kvpair PARAMS((ARRAY *, int));
|
||||
extern char *array_to_assign PARAMS((ARRAY *, int));
|
||||
extern char *array_to_string PARAMS((ARRAY *, char *, int));
|
||||
extern ARRAY *array_from_string PARAMS((char *, char *));
|
||||
|
||||
/* Flags for array_shift */
|
||||
#define AS_DISPOSE 0x01
|
||||
|
||||
#define array_num_elements(a) ((a)->num_elements)
|
||||
#define array_max_index(a) ((a)->max_index)
|
||||
#ifndef ALT_ARRAY_IMPLEMENTATION
|
||||
#define array_first_index(a) ((a)->head->next->ind)
|
||||
#define array_head(a) ((a)->head)
|
||||
#define array_alloc_size(a) ((a)->alloc_size)
|
||||
#else
|
||||
#define array_first_index(a) ((a)->first_index)
|
||||
#define array_head(a) ((a)->elements)
|
||||
#endif
|
||||
#define array_empty(a) ((a)->num_elements == 0)
|
||||
|
||||
#define element_value(ae) ((ae)->value)
|
||||
#define element_index(ae) ((ae)->ind)
|
||||
|
||||
#ifndef ALT_ARRAY_IMPLEMENTATION
|
||||
#define element_forw(ae) ((ae)->next)
|
||||
#define element_back(ae) ((ae)->prev)
|
||||
#else
|
||||
extern arrayind_t element_forw PARAMS((ARRAY *, arrayind_t));
|
||||
extern arrayind_t element_back PARAMS((ARRAY *, arrayind_t));
|
||||
#endif
|
||||
|
||||
|
||||
#define set_element_value(ae, val) ((ae)->value = (val))
|
||||
|
||||
#ifdef ALT_ARRAY_IMPLEMENTATION
|
||||
#define set_first_index(a, i) ((a)->first_index = (i))
|
||||
#endif
|
||||
|
||||
#define set_max_index(a, i) ((a)->max_index = (i))
|
||||
#define set_num_elements(a, n) ((a)->num_elements = (n))
|
||||
|
||||
/* Convenience */
|
||||
#define array_push(a,v) \
|
||||
do { array_rshift ((a), 1, (v)); } while (0)
|
||||
#define array_pop(a) \
|
||||
do { array_shift ((a), 1, AS_DISPOSE); } while (0)
|
||||
|
||||
#define GET_ARRAY_FROM_VAR(n, v, a) \
|
||||
do { \
|
||||
(v) = find_variable (n); \
|
||||
(a) = ((v) && array_p ((v))) ? array_cell (v) : (ARRAY *)0; \
|
||||
} while (0)
|
||||
|
||||
#define ARRAY_ELEMENT_REPLACE(ae, v) \
|
||||
do { \
|
||||
free ((ae)->value); \
|
||||
(ae)->value = (v); \
|
||||
} while (0)
|
||||
|
||||
#ifdef ALT_ARRAY_IMPLEMENTATION
|
||||
#define ARRAY_VALUE_REPLACE(a, i, v) \
|
||||
ARRAY_ELEMENT_REPLACE((a)->elements[(i)], (v))
|
||||
#endif
|
||||
|
||||
#define ALL_ELEMENT_SUB(c) ((c) == '@' || (c) == '*')
|
||||
|
||||
/* In eval.c, but uses ARRAY * */
|
||||
extern int execute_array_command PARAMS((ARRAY *, void *));
|
||||
|
||||
#endif /* _ARRAY_H_ */
|
1699
third_party/bash/arrayfunc.c
vendored
Normal file
1699
third_party/bash/arrayfunc.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
140
third_party/bash/arrayfunc.h
vendored
Normal file
140
third_party/bash/arrayfunc.h
vendored
Normal file
|
@ -0,0 +1,140 @@
|
|||
/* arrayfunc.h -- declarations for miscellaneous array functions in arrayfunc.c */
|
||||
|
||||
/* Copyright (C) 2001-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (_ARRAYFUNC_H_)
|
||||
#define _ARRAYFUNC_H_
|
||||
|
||||
/* Must include variables.h before including this file. */
|
||||
|
||||
/* An object to encapsulate the state of an array element. It can describe
|
||||
an array assignment A[KEY]=VALUE or a[IND]=VALUE depending on TYPE, or
|
||||
for passing array subscript references around, where VALUE would be
|
||||
${a[IND]} or ${A[KEY]}. This is not dependent on ARRAY_VARS so we can
|
||||
use it in function parameters. */
|
||||
|
||||
/* values for `type' field */
|
||||
#define ARRAY_INVALID -1
|
||||
#define ARRAY_SCALAR 0
|
||||
#define ARRAY_INDEXED 1
|
||||
#define ARRAY_ASSOC 2
|
||||
|
||||
/* KEY will contain allocated memory if called through the assign_array_element
|
||||
code path because of how assoc_insert works. */
|
||||
typedef struct element_state
|
||||
{
|
||||
short type; /* assoc or indexed, says which fields are valid */
|
||||
short subtype; /* `*', `@', or something else */
|
||||
arrayind_t ind;
|
||||
char *key; /* can be allocated memory */
|
||||
char *value;
|
||||
} array_eltstate_t;
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
|
||||
/* This variable means to not expand associative array subscripts more than
|
||||
once, when performing variable expansion. */
|
||||
extern int assoc_expand_once;
|
||||
|
||||
/* The analog for indexed array subscripts */
|
||||
extern int array_expand_once;
|
||||
|
||||
/* Flags for array_value_internal and callers array_value/get_array_value; also
|
||||
used by array_variable_name and array_variable_part. */
|
||||
#define AV_ALLOWALL 0x001 /* treat a[@] like $@ and a[*] like $* */
|
||||
#define AV_QUOTED 0x002
|
||||
#define AV_USEIND 0x004
|
||||
#define AV_USEVAL 0x008 /* XXX - should move this */
|
||||
#define AV_ASSIGNRHS 0x010 /* no splitting, special case ${a[@]} */
|
||||
#define AV_NOEXPAND 0x020 /* don't run assoc subscripts through word expansion */
|
||||
#define AV_ONEWORD 0x040 /* not used yet */
|
||||
#define AV_ATSTARKEYS 0x080 /* accept a[@] and a[*] but use them as keys, not special values */
|
||||
|
||||
/* Flags for valid_array_reference. Value 1 is reserved for skipsubscript().
|
||||
Also used by unbind_array_element, which is currently the only function
|
||||
that uses VA_ALLOWALL. */
|
||||
#define VA_NOEXPAND 0x001
|
||||
#define VA_ONEWORD 0x002
|
||||
#define VA_ALLOWALL 0x004 /* allow @ to mean all elements of the array */
|
||||
|
||||
extern SHELL_VAR *convert_var_to_array PARAMS((SHELL_VAR *));
|
||||
extern SHELL_VAR *convert_var_to_assoc PARAMS((SHELL_VAR *));
|
||||
|
||||
extern char *make_array_variable_value PARAMS((SHELL_VAR *, arrayind_t, char *, char *, int));
|
||||
|
||||
extern SHELL_VAR *bind_array_variable PARAMS((char *, arrayind_t, char *, int));
|
||||
extern SHELL_VAR *bind_array_element PARAMS((SHELL_VAR *, arrayind_t, char *, int));
|
||||
extern SHELL_VAR *assign_array_element PARAMS((char *, char *, int, array_eltstate_t *));
|
||||
|
||||
extern SHELL_VAR *bind_assoc_variable PARAMS((SHELL_VAR *, char *, char *, char *, int));
|
||||
|
||||
extern SHELL_VAR *find_or_make_array_variable PARAMS((char *, int));
|
||||
|
||||
extern SHELL_VAR *assign_array_from_string PARAMS((char *, char *, int));
|
||||
extern SHELL_VAR *assign_array_var_from_word_list PARAMS((SHELL_VAR *, WORD_LIST *, int));
|
||||
|
||||
extern WORD_LIST *expand_compound_array_assignment PARAMS((SHELL_VAR *, char *, int));
|
||||
extern void assign_compound_array_list PARAMS((SHELL_VAR *, WORD_LIST *, int));
|
||||
extern SHELL_VAR *assign_array_var_from_string PARAMS((SHELL_VAR *, char *, int));
|
||||
|
||||
extern char *expand_and_quote_assoc_word PARAMS((char *, int));
|
||||
extern void quote_compound_array_list PARAMS((WORD_LIST *, int));
|
||||
|
||||
extern int kvpair_assignment_p PARAMS((WORD_LIST *));
|
||||
extern char *expand_and_quote_kvpair_word PARAMS((char *));
|
||||
|
||||
extern int unbind_array_element PARAMS((SHELL_VAR *, char *, int));
|
||||
extern int skipsubscript PARAMS((const char *, int, int));
|
||||
|
||||
extern void print_array_assignment PARAMS((SHELL_VAR *, int));
|
||||
extern void print_assoc_assignment PARAMS((SHELL_VAR *, int));
|
||||
|
||||
extern arrayind_t array_expand_index PARAMS((SHELL_VAR *, char *, int, int));
|
||||
extern int valid_array_reference PARAMS((const char *, int));
|
||||
extern int tokenize_array_reference PARAMS((char *, int, char **));
|
||||
|
||||
extern char *array_value PARAMS((const char *, int, int, array_eltstate_t *));
|
||||
extern char *get_array_value PARAMS((const char *, int, array_eltstate_t *));
|
||||
|
||||
extern char *array_keys PARAMS((char *, int, int));
|
||||
|
||||
extern char *array_variable_name PARAMS((const char *, int, char **, int *));
|
||||
extern SHELL_VAR *array_variable_part PARAMS((const char *, int, char **, int *));
|
||||
|
||||
extern void init_eltstate (array_eltstate_t *);
|
||||
extern void flush_eltstate (array_eltstate_t *);
|
||||
|
||||
#else
|
||||
|
||||
#define AV_ALLOWALL 0
|
||||
#define AV_QUOTED 0
|
||||
#define AV_USEIND 0
|
||||
#define AV_USEVAL 0
|
||||
#define AV_ASSIGNRHS 0
|
||||
#define AV_NOEXPAND 0
|
||||
#define AV_ONEWORD 0
|
||||
#define AV_ATSTARKEYS 0
|
||||
|
||||
#define VA_NOEXPAND 0
|
||||
#define VA_ONEWORD 0
|
||||
#define VA_ALLOWALL 0
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* !_ARRAYFUNC_H_ */
|
611
third_party/bash/assoc.c
vendored
Normal file
611
third_party/bash/assoc.c
vendored
Normal file
|
@ -0,0 +1,611 @@
|
|||
/*
|
||||
* assoc.c - functions to manipulate associative arrays
|
||||
*
|
||||
* Associative arrays are standard shell hash tables.
|
||||
*
|
||||
* Chet Ramey
|
||||
* chet@ins.cwru.edu
|
||||
*/
|
||||
|
||||
/* Copyright (C) 2008,2009,2011-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "bashansi.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "array.h"
|
||||
#include "assoc.h"
|
||||
#include "common.h"
|
||||
|
||||
static WORD_LIST *assoc_to_word_list_internal PARAMS((HASH_TABLE *, int));
|
||||
|
||||
/* assoc_create == hash_create */
|
||||
|
||||
void
|
||||
assoc_dispose (hash)
|
||||
HASH_TABLE *hash;
|
||||
{
|
||||
if (hash)
|
||||
{
|
||||
hash_flush (hash, 0);
|
||||
hash_dispose (hash);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
assoc_flush (hash)
|
||||
HASH_TABLE *hash;
|
||||
{
|
||||
hash_flush (hash, 0);
|
||||
}
|
||||
|
||||
int
|
||||
assoc_insert (hash, key, value)
|
||||
HASH_TABLE *hash;
|
||||
char *key;
|
||||
char *value;
|
||||
{
|
||||
BUCKET_CONTENTS *b;
|
||||
|
||||
b = hash_search (key, hash, HASH_CREATE);
|
||||
if (b == 0)
|
||||
return -1;
|
||||
/* If we are overwriting an existing element's value, we're not going to
|
||||
use the key. Nothing in the array assignment code path frees the key
|
||||
string, so we can free it here to avoid a memory leak. */
|
||||
if (b->key != key)
|
||||
free (key);
|
||||
FREE (b->data);
|
||||
b->data = value ? savestring (value) : (char *)0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Like assoc_insert, but returns b->data instead of freeing it */
|
||||
PTR_T
|
||||
assoc_replace (hash, key, value)
|
||||
HASH_TABLE *hash;
|
||||
char *key;
|
||||
char *value;
|
||||
{
|
||||
BUCKET_CONTENTS *b;
|
||||
PTR_T t;
|
||||
|
||||
b = hash_search (key, hash, HASH_CREATE);
|
||||
if (b == 0)
|
||||
return (PTR_T)0;
|
||||
/* If we are overwriting an existing element's value, we're not going to
|
||||
use the key. Nothing in the array assignment code path frees the key
|
||||
string, so we can free it here to avoid a memory leak. */
|
||||
if (b->key != key)
|
||||
free (key);
|
||||
t = b->data;
|
||||
b->data = value ? savestring (value) : (char *)0;
|
||||
return t;
|
||||
}
|
||||
|
||||
void
|
||||
assoc_remove (hash, string)
|
||||
HASH_TABLE *hash;
|
||||
char *string;
|
||||
{
|
||||
BUCKET_CONTENTS *b;
|
||||
|
||||
b = hash_remove (string, hash, 0);
|
||||
if (b)
|
||||
{
|
||||
free ((char *)b->data);
|
||||
free (b->key);
|
||||
free (b);
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
assoc_reference (hash, string)
|
||||
HASH_TABLE *hash;
|
||||
char *string;
|
||||
{
|
||||
BUCKET_CONTENTS *b;
|
||||
|
||||
if (hash == 0)
|
||||
return (char *)0;
|
||||
|
||||
b = hash_search (string, hash, 0);
|
||||
return (b ? (char *)b->data : 0);
|
||||
}
|
||||
|
||||
/* Quote the data associated with each element of the hash table ASSOC,
|
||||
using quote_string */
|
||||
HASH_TABLE *
|
||||
assoc_quote (h)
|
||||
HASH_TABLE *h;
|
||||
{
|
||||
int i;
|
||||
BUCKET_CONTENTS *tlist;
|
||||
char *t;
|
||||
|
||||
if (h == 0 || assoc_empty (h))
|
||||
return ((HASH_TABLE *)NULL);
|
||||
|
||||
for (i = 0; i < h->nbuckets; i++)
|
||||
for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
|
||||
{
|
||||
t = quote_string ((char *)tlist->data);
|
||||
FREE (tlist->data);
|
||||
tlist->data = t;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
/* Quote escape characters in the data associated with each element
|
||||
of the hash table ASSOC, using quote_escapes */
|
||||
HASH_TABLE *
|
||||
assoc_quote_escapes (h)
|
||||
HASH_TABLE *h;
|
||||
{
|
||||
int i;
|
||||
BUCKET_CONTENTS *tlist;
|
||||
char *t;
|
||||
|
||||
if (h == 0 || assoc_empty (h))
|
||||
return ((HASH_TABLE *)NULL);
|
||||
|
||||
for (i = 0; i < h->nbuckets; i++)
|
||||
for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
|
||||
{
|
||||
t = quote_escapes ((char *)tlist->data);
|
||||
FREE (tlist->data);
|
||||
tlist->data = t;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
HASH_TABLE *
|
||||
assoc_dequote (h)
|
||||
HASH_TABLE *h;
|
||||
{
|
||||
int i;
|
||||
BUCKET_CONTENTS *tlist;
|
||||
char *t;
|
||||
|
||||
if (h == 0 || assoc_empty (h))
|
||||
return ((HASH_TABLE *)NULL);
|
||||
|
||||
for (i = 0; i < h->nbuckets; i++)
|
||||
for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
|
||||
{
|
||||
t = dequote_string ((char *)tlist->data);
|
||||
FREE (tlist->data);
|
||||
tlist->data = t;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
HASH_TABLE *
|
||||
assoc_dequote_escapes (h)
|
||||
HASH_TABLE *h;
|
||||
{
|
||||
int i;
|
||||
BUCKET_CONTENTS *tlist;
|
||||
char *t;
|
||||
|
||||
if (h == 0 || assoc_empty (h))
|
||||
return ((HASH_TABLE *)NULL);
|
||||
|
||||
for (i = 0; i < h->nbuckets; i++)
|
||||
for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
|
||||
{
|
||||
t = dequote_escapes ((char *)tlist->data);
|
||||
FREE (tlist->data);
|
||||
tlist->data = t;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
HASH_TABLE *
|
||||
assoc_remove_quoted_nulls (h)
|
||||
HASH_TABLE *h;
|
||||
{
|
||||
int i;
|
||||
BUCKET_CONTENTS *tlist;
|
||||
char *t;
|
||||
|
||||
if (h == 0 || assoc_empty (h))
|
||||
return ((HASH_TABLE *)NULL);
|
||||
|
||||
for (i = 0; i < h->nbuckets; i++)
|
||||
for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
|
||||
{
|
||||
t = remove_quoted_nulls ((char *)tlist->data);
|
||||
tlist->data = t;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a string whose elements are the members of array H beginning at
|
||||
* the STARTth element and spanning NELEM members. Null elements are counted.
|
||||
*/
|
||||
char *
|
||||
assoc_subrange (hash, start, nelem, starsub, quoted, pflags)
|
||||
HASH_TABLE *hash;
|
||||
arrayind_t start, nelem;
|
||||
int starsub, quoted, pflags;
|
||||
{
|
||||
WORD_LIST *l, *save, *h, *t;
|
||||
int i, j;
|
||||
char *ret;
|
||||
|
||||
if (assoc_empty (hash))
|
||||
return ((char *)NULL);
|
||||
|
||||
save = l = assoc_to_word_list (hash);
|
||||
if (save == 0)
|
||||
return ((char *)NULL);
|
||||
|
||||
for (i = 1; l && i < start; i++)
|
||||
l = l->next;
|
||||
if (l == 0)
|
||||
{
|
||||
dispose_words (save);
|
||||
return ((char *)NULL);
|
||||
}
|
||||
for (j = 0,h = t = l; l && j < nelem; j++)
|
||||
{
|
||||
t = l;
|
||||
l = l->next;
|
||||
}
|
||||
|
||||
t->next = (WORD_LIST *)NULL;
|
||||
|
||||
ret = string_list_pos_params (starsub ? '*' : '@', h, quoted, pflags);
|
||||
|
||||
if (t != l)
|
||||
t->next = l;
|
||||
|
||||
dispose_words (save);
|
||||
return (ret);
|
||||
|
||||
}
|
||||
|
||||
char *
|
||||
assoc_patsub (h, pat, rep, mflags)
|
||||
HASH_TABLE *h;
|
||||
char *pat, *rep;
|
||||
int mflags;
|
||||
{
|
||||
char *t;
|
||||
int pchar, qflags, pflags;
|
||||
WORD_LIST *wl, *save;
|
||||
|
||||
if (h == 0 || assoc_empty (h))
|
||||
return ((char *)NULL);
|
||||
|
||||
wl = assoc_to_word_list (h);
|
||||
if (wl == 0)
|
||||
return (char *)NULL;
|
||||
|
||||
for (save = wl; wl; wl = wl->next)
|
||||
{
|
||||
t = pat_subst (wl->word->word, pat, rep, mflags);
|
||||
FREE (wl->word->word);
|
||||
wl->word->word = t;
|
||||
}
|
||||
|
||||
pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
|
||||
qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
|
||||
pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0;
|
||||
|
||||
t = string_list_pos_params (pchar, save, qflags, pflags);
|
||||
dispose_words (save);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
char *
|
||||
assoc_modcase (h, pat, modop, mflags)
|
||||
HASH_TABLE *h;
|
||||
char *pat;
|
||||
int modop;
|
||||
int mflags;
|
||||
{
|
||||
char *t;
|
||||
int pchar, qflags, pflags;
|
||||
WORD_LIST *wl, *save;
|
||||
|
||||
if (h == 0 || assoc_empty (h))
|
||||
return ((char *)NULL);
|
||||
|
||||
wl = assoc_to_word_list (h);
|
||||
if (wl == 0)
|
||||
return ((char *)NULL);
|
||||
|
||||
for (save = wl; wl; wl = wl->next)
|
||||
{
|
||||
t = sh_modcase (wl->word->word, pat, modop);
|
||||
FREE (wl->word->word);
|
||||
wl->word->word = t;
|
||||
}
|
||||
|
||||
pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
|
||||
qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
|
||||
pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0;
|
||||
|
||||
t = string_list_pos_params (pchar, save, qflags, pflags);
|
||||
dispose_words (save);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
char *
|
||||
assoc_to_kvpair (hash, quoted)
|
||||
HASH_TABLE *hash;
|
||||
int quoted;
|
||||
{
|
||||
char *ret;
|
||||
char *istr, *vstr;
|
||||
int i, rsize, rlen, elen;
|
||||
BUCKET_CONTENTS *tlist;
|
||||
|
||||
if (hash == 0 || assoc_empty (hash))
|
||||
return (char *)0;
|
||||
|
||||
ret = xmalloc (rsize = 128);
|
||||
ret[rlen = 0] = '\0';
|
||||
|
||||
for (i = 0; i < hash->nbuckets; i++)
|
||||
for (tlist = hash_items (i, hash); tlist; tlist = tlist->next)
|
||||
{
|
||||
if (ansic_shouldquote (tlist->key))
|
||||
istr = ansic_quote (tlist->key, 0, (int *)0);
|
||||
else if (sh_contains_shell_metas (tlist->key))
|
||||
istr = sh_double_quote (tlist->key);
|
||||
else if (ALL_ELEMENT_SUB (tlist->key[0]) && tlist->key[1] == '\0')
|
||||
istr = sh_double_quote (tlist->key);
|
||||
else
|
||||
istr = tlist->key;
|
||||
|
||||
vstr = tlist->data ? (ansic_shouldquote ((char *)tlist->data) ?
|
||||
ansic_quote ((char *)tlist->data, 0, (int *)0) :
|
||||
sh_double_quote ((char *)tlist->data))
|
||||
: (char *)0;
|
||||
|
||||
elen = STRLEN (istr) + 4 + STRLEN (vstr);
|
||||
RESIZE_MALLOCED_BUFFER (ret, rlen, (elen+1), rsize, rsize);
|
||||
|
||||
strcpy (ret+rlen, istr);
|
||||
rlen += STRLEN (istr);
|
||||
ret[rlen++] = ' ';
|
||||
if (vstr)
|
||||
{
|
||||
strcpy (ret + rlen, vstr);
|
||||
rlen += STRLEN (vstr);
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy (ret + rlen, "\"\"");
|
||||
rlen += 2;
|
||||
}
|
||||
ret[rlen++] = ' ';
|
||||
|
||||
if (istr != tlist->key)
|
||||
FREE (istr);
|
||||
|
||||
FREE (vstr);
|
||||
}
|
||||
|
||||
RESIZE_MALLOCED_BUFFER (ret, rlen, 1, rsize, 8);
|
||||
ret[rlen] = '\0';
|
||||
|
||||
if (quoted)
|
||||
{
|
||||
vstr = sh_single_quote (ret);
|
||||
free (ret);
|
||||
ret = vstr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *
|
||||
assoc_to_assign (hash, quoted)
|
||||
HASH_TABLE *hash;
|
||||
int quoted;
|
||||
{
|
||||
char *ret;
|
||||
char *istr, *vstr;
|
||||
int i, rsize, rlen, elen;
|
||||
BUCKET_CONTENTS *tlist;
|
||||
|
||||
if (hash == 0 || assoc_empty (hash))
|
||||
return (char *)0;
|
||||
|
||||
ret = xmalloc (rsize = 128);
|
||||
ret[0] = '(';
|
||||
rlen = 1;
|
||||
|
||||
for (i = 0; i < hash->nbuckets; i++)
|
||||
for (tlist = hash_items (i, hash); tlist; tlist = tlist->next)
|
||||
{
|
||||
if (ansic_shouldquote (tlist->key))
|
||||
istr = ansic_quote (tlist->key, 0, (int *)0);
|
||||
else if (sh_contains_shell_metas (tlist->key))
|
||||
istr = sh_double_quote (tlist->key);
|
||||
else if (ALL_ELEMENT_SUB (tlist->key[0]) && tlist->key[1] == '\0')
|
||||
istr = sh_double_quote (tlist->key);
|
||||
else
|
||||
istr = tlist->key;
|
||||
|
||||
vstr = tlist->data ? (ansic_shouldquote ((char *)tlist->data) ?
|
||||
ansic_quote ((char *)tlist->data, 0, (int *)0) :
|
||||
sh_double_quote ((char *)tlist->data))
|
||||
: (char *)0;
|
||||
|
||||
elen = STRLEN (istr) + 8 + STRLEN (vstr);
|
||||
RESIZE_MALLOCED_BUFFER (ret, rlen, (elen+1), rsize, rsize);
|
||||
|
||||
ret[rlen++] = '[';
|
||||
strcpy (ret+rlen, istr);
|
||||
rlen += STRLEN (istr);
|
||||
ret[rlen++] = ']';
|
||||
ret[rlen++] = '=';
|
||||
if (vstr)
|
||||
{
|
||||
strcpy (ret + rlen, vstr);
|
||||
rlen += STRLEN (vstr);
|
||||
}
|
||||
ret[rlen++] = ' ';
|
||||
|
||||
if (istr != tlist->key)
|
||||
FREE (istr);
|
||||
|
||||
FREE (vstr);
|
||||
}
|
||||
|
||||
RESIZE_MALLOCED_BUFFER (ret, rlen, 1, rsize, 8);
|
||||
ret[rlen++] = ')';
|
||||
ret[rlen] = '\0';
|
||||
|
||||
if (quoted)
|
||||
{
|
||||
vstr = sh_single_quote (ret);
|
||||
free (ret);
|
||||
ret = vstr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static WORD_LIST *
|
||||
assoc_to_word_list_internal (h, t)
|
||||
HASH_TABLE *h;
|
||||
int t;
|
||||
{
|
||||
WORD_LIST *list;
|
||||
int i;
|
||||
BUCKET_CONTENTS *tlist;
|
||||
char *w;
|
||||
|
||||
if (h == 0 || assoc_empty (h))
|
||||
return((WORD_LIST *)NULL);
|
||||
list = (WORD_LIST *)NULL;
|
||||
|
||||
for (i = 0; i < h->nbuckets; i++)
|
||||
for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
|
||||
{
|
||||
w = (t == 0) ? (char *)tlist->data : (char *)tlist->key;
|
||||
list = make_word_list (make_bare_word(w), list);
|
||||
}
|
||||
return (REVERSE_LIST(list, WORD_LIST *));
|
||||
}
|
||||
|
||||
WORD_LIST *
|
||||
assoc_to_word_list (h)
|
||||
HASH_TABLE *h;
|
||||
{
|
||||
return (assoc_to_word_list_internal (h, 0));
|
||||
}
|
||||
|
||||
WORD_LIST *
|
||||
assoc_keys_to_word_list (h)
|
||||
HASH_TABLE *h;
|
||||
{
|
||||
return (assoc_to_word_list_internal (h, 1));
|
||||
}
|
||||
|
||||
WORD_LIST *
|
||||
assoc_to_kvpair_list (h)
|
||||
HASH_TABLE *h;
|
||||
{
|
||||
WORD_LIST *list;
|
||||
int i;
|
||||
BUCKET_CONTENTS *tlist;
|
||||
char *k, *v;
|
||||
|
||||
if (h == 0 || assoc_empty (h))
|
||||
return((WORD_LIST *)NULL);
|
||||
list = (WORD_LIST *)NULL;
|
||||
|
||||
for (i = 0; i < h->nbuckets; i++)
|
||||
for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
|
||||
{
|
||||
k = (char *)tlist->key;
|
||||
v = (char *)tlist->data;
|
||||
list = make_word_list (make_bare_word (k), list);
|
||||
list = make_word_list (make_bare_word (v), list);
|
||||
}
|
||||
return (REVERSE_LIST(list, WORD_LIST *));
|
||||
}
|
||||
|
||||
char *
|
||||
assoc_to_string (h, sep, quoted)
|
||||
HASH_TABLE *h;
|
||||
char *sep;
|
||||
int quoted;
|
||||
{
|
||||
BUCKET_CONTENTS *tlist;
|
||||
int i;
|
||||
char *result, *t, *w;
|
||||
WORD_LIST *list, *l;
|
||||
|
||||
if (h == 0)
|
||||
return ((char *)NULL);
|
||||
if (assoc_empty (h))
|
||||
return (savestring (""));
|
||||
|
||||
result = NULL;
|
||||
l = list = NULL;
|
||||
/* This might be better implemented directly, but it's simple to implement
|
||||
by converting to a word list first, possibly quoting the data, then
|
||||
using list_string */
|
||||
for (i = 0; i < h->nbuckets; i++)
|
||||
for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
|
||||
{
|
||||
w = (char *)tlist->data;
|
||||
if (w == 0)
|
||||
continue;
|
||||
t = quoted ? quote_string (w) : savestring (w);
|
||||
list = make_word_list (make_bare_word(t), list);
|
||||
FREE (t);
|
||||
}
|
||||
|
||||
l = REVERSE_LIST(list, WORD_LIST *);
|
||||
|
||||
result = l ? string_list_internal (l, sep) : savestring ("");
|
||||
dispose_words (l);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* ARRAY_VARS */
|
66
third_party/bash/assoc.h
vendored
Normal file
66
third_party/bash/assoc.h
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
/* assoc.h -- definitions for the interface exported by assoc.c that allows
|
||||
the rest of the shell to manipulate associative array variables. */
|
||||
|
||||
/* Copyright (C) 2008,2009-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _ASSOC_H_
|
||||
#define _ASSOC_H_
|
||||
|
||||
#include "stdc.h"
|
||||
#include "hashlib.h"
|
||||
|
||||
#define ASSOC_HASH_BUCKETS 1024
|
||||
|
||||
#define assoc_empty(h) ((h)->nentries == 0)
|
||||
#define assoc_num_elements(h) ((h)->nentries)
|
||||
|
||||
#define assoc_create(n) (hash_create((n)))
|
||||
|
||||
#define assoc_copy(h) (hash_copy((h), 0))
|
||||
|
||||
#define assoc_walk(h, f) (hash_walk((h), (f))
|
||||
|
||||
extern void assoc_dispose PARAMS((HASH_TABLE *));
|
||||
extern void assoc_flush PARAMS((HASH_TABLE *));
|
||||
|
||||
extern int assoc_insert PARAMS((HASH_TABLE *, char *, char *));
|
||||
extern PTR_T assoc_replace PARAMS((HASH_TABLE *, char *, char *));
|
||||
extern void assoc_remove PARAMS((HASH_TABLE *, char *));
|
||||
|
||||
extern char *assoc_reference PARAMS((HASH_TABLE *, char *));
|
||||
|
||||
extern char *assoc_subrange PARAMS((HASH_TABLE *, arrayind_t, arrayind_t, int, int, int));
|
||||
extern char *assoc_patsub PARAMS((HASH_TABLE *, char *, char *, int));
|
||||
extern char *assoc_modcase PARAMS((HASH_TABLE *, char *, int, int));
|
||||
|
||||
extern HASH_TABLE *assoc_quote PARAMS((HASH_TABLE *));
|
||||
extern HASH_TABLE *assoc_quote_escapes PARAMS((HASH_TABLE *));
|
||||
extern HASH_TABLE *assoc_dequote PARAMS((HASH_TABLE *));
|
||||
extern HASH_TABLE *assoc_dequote_escapes PARAMS((HASH_TABLE *));
|
||||
extern HASH_TABLE *assoc_remove_quoted_nulls PARAMS((HASH_TABLE *));
|
||||
|
||||
extern char *assoc_to_kvpair PARAMS((HASH_TABLE *, int));
|
||||
extern char *assoc_to_assign PARAMS((HASH_TABLE *, int));
|
||||
|
||||
extern WORD_LIST *assoc_to_word_list PARAMS((HASH_TABLE *));
|
||||
extern WORD_LIST *assoc_keys_to_word_list PARAMS((HASH_TABLE *));
|
||||
extern WORD_LIST *assoc_to_kvpair_list PARAMS((HASH_TABLE *));
|
||||
|
||||
extern char *assoc_to_string PARAMS((HASH_TABLE *, char *, int));
|
||||
#endif /* _ASSOC_H_ */
|
38
third_party/bash/bashansi.h
vendored
Normal file
38
third_party/bash/bashansi.h
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
/* bashansi.h -- Typically included information required by picky compilers. */
|
||||
|
||||
/* Copyright (C) 1993-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (_BASHANSI_H_)
|
||||
#define _BASHANSI_H_
|
||||
|
||||
#if defined (HAVE_STRING_H)
|
||||
# include <string.h>
|
||||
#endif /* !HAVE_STRING_H */
|
||||
|
||||
#if defined (HAVE_STRINGS_H)
|
||||
# include <strings.h>
|
||||
#endif /* !HAVE_STRINGS_H */
|
||||
|
||||
#if defined (HAVE_STDLIB_H)
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
# include "ansi_stdlib.h"
|
||||
#endif /* !HAVE_STDLIB_H */
|
||||
|
||||
#endif /* !_BASHANSI_H_ */
|
194
third_party/bash/bashgetopt.c
vendored
Normal file
194
third_party/bash/bashgetopt.c
vendored
Normal file
|
@ -0,0 +1,194 @@
|
|||
/* bashgetopt.c -- `getopt' for use by the builtins. */
|
||||
|
||||
/* Copyright (C) 1992-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "chartypes.h"
|
||||
#include <errno.h>
|
||||
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#define ISOPT(s) (((*(s) == '-') || (plus && *(s) == '+')) && (s)[1])
|
||||
#define NOTOPT(s) (((*(s) != '-') && (!plus || *(s) != '+')) || (s)[1] == '\0')
|
||||
|
||||
static int sp;
|
||||
|
||||
char *list_optarg;
|
||||
int list_optflags;
|
||||
int list_optopt;
|
||||
int list_opttype;
|
||||
|
||||
static WORD_LIST *lhead = (WORD_LIST *)NULL;
|
||||
WORD_LIST *lcurrent = (WORD_LIST *)NULL;
|
||||
WORD_LIST *loptend; /* Points to the first non-option argument in the list */
|
||||
|
||||
int
|
||||
internal_getopt(list, opts)
|
||||
WORD_LIST *list;
|
||||
char *opts;
|
||||
{
|
||||
register int c;
|
||||
register char *cp;
|
||||
int plus; /* nonzero means to handle +option */
|
||||
static char errstr[3] = { '-', '\0', '\0' };
|
||||
|
||||
plus = *opts == '+';
|
||||
if (plus)
|
||||
opts++;
|
||||
|
||||
if (list == 0) {
|
||||
list_optarg = (char *)NULL;
|
||||
list_optflags = 0;
|
||||
loptend = (WORD_LIST *)NULL; /* No non-option arguments */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (list != lhead || lhead == 0) {
|
||||
/* Hmmm.... called with a different word list. Reset. */
|
||||
sp = 1;
|
||||
lcurrent = lhead = list;
|
||||
loptend = (WORD_LIST *)NULL;
|
||||
}
|
||||
|
||||
if (sp == 1) {
|
||||
if (lcurrent == 0 || NOTOPT(lcurrent->word->word)) {
|
||||
lhead = (WORD_LIST *)NULL;
|
||||
loptend = lcurrent;
|
||||
return(-1);
|
||||
} else if (ISHELP (lcurrent->word->word)) {
|
||||
lhead = (WORD_LIST *)NULL;
|
||||
loptend = lcurrent;
|
||||
return (GETOPT_HELP);
|
||||
} else if (lcurrent->word->word[0] == '-' &&
|
||||
lcurrent->word->word[1] == '-' &&
|
||||
lcurrent->word->word[2] == 0) {
|
||||
lhead = (WORD_LIST *)NULL;
|
||||
loptend = lcurrent->next;
|
||||
return(-1);
|
||||
}
|
||||
errstr[0] = list_opttype = lcurrent->word->word[0];
|
||||
}
|
||||
|
||||
list_optopt = c = lcurrent->word->word[sp];
|
||||
|
||||
if (c == ':' || (cp = strchr(opts, c)) == NULL) {
|
||||
errstr[1] = c;
|
||||
sh_invalidopt (errstr);
|
||||
if (lcurrent->word->word[++sp] == '\0') {
|
||||
lcurrent = lcurrent->next;
|
||||
sp = 1;
|
||||
}
|
||||
list_optarg = NULL;
|
||||
list_optflags = 0;
|
||||
if (lcurrent)
|
||||
loptend = lcurrent->next;
|
||||
return('?');
|
||||
}
|
||||
|
||||
if (*++cp == ':' || *cp == ';') {
|
||||
/* `:': Option requires an argument. */
|
||||
/* `;': option argument may be missing */
|
||||
/* We allow -l2 as equivalent to -l 2 */
|
||||
if (lcurrent->word->word[sp+1]) {
|
||||
list_optarg = lcurrent->word->word + sp + 1;
|
||||
list_optflags = 0;
|
||||
lcurrent = lcurrent->next;
|
||||
/* If the specifier is `;', don't set optarg if the next
|
||||
argument looks like another option. */
|
||||
#if 0
|
||||
} else if (lcurrent->next && (*cp == ':' || lcurrent->next->word->word[0] != '-')) {
|
||||
#else
|
||||
} else if (lcurrent->next && (*cp == ':' || NOTOPT(lcurrent->next->word->word))) {
|
||||
#endif
|
||||
lcurrent = lcurrent->next;
|
||||
list_optarg = lcurrent->word->word;
|
||||
list_optflags = lcurrent->word->flags;
|
||||
lcurrent = lcurrent->next;
|
||||
} else if (*cp == ';') {
|
||||
list_optarg = (char *)NULL;
|
||||
list_optflags = 0;
|
||||
lcurrent = lcurrent->next;
|
||||
} else { /* lcurrent->next == NULL */
|
||||
errstr[1] = c;
|
||||
sh_needarg (errstr);
|
||||
sp = 1;
|
||||
list_optarg = (char *)NULL;
|
||||
list_optflags = 0;
|
||||
return('?');
|
||||
}
|
||||
sp = 1;
|
||||
} else if (*cp == '#') {
|
||||
/* option requires a numeric argument */
|
||||
if (lcurrent->word->word[sp+1]) {
|
||||
if (DIGIT(lcurrent->word->word[sp+1])) {
|
||||
list_optarg = lcurrent->word->word + sp + 1;
|
||||
list_optflags = 0;
|
||||
lcurrent = lcurrent->next;
|
||||
} else {
|
||||
list_optarg = (char *)NULL;
|
||||
list_optflags = 0;
|
||||
}
|
||||
} else {
|
||||
if (lcurrent->next && legal_number(lcurrent->next->word->word, (intmax_t *)0)) {
|
||||
lcurrent = lcurrent->next;
|
||||
list_optarg = lcurrent->word->word;
|
||||
list_optflags = lcurrent->word->flags;
|
||||
lcurrent = lcurrent->next;
|
||||
} else {
|
||||
errstr[1] = c;
|
||||
sh_neednumarg (errstr);
|
||||
sp = 1;
|
||||
list_optarg = (char *)NULL;
|
||||
list_optflags = 0;
|
||||
return ('?');
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
/* No argument, just return the option. */
|
||||
if (lcurrent->word->word[++sp] == '\0') {
|
||||
sp = 1;
|
||||
lcurrent = lcurrent->next;
|
||||
}
|
||||
list_optarg = (char *)NULL;
|
||||
list_optflags = 0;
|
||||
}
|
||||
|
||||
return(c);
|
||||
}
|
||||
|
||||
/*
|
||||
* reset_internal_getopt -- force the in[ft]ernal getopt to reset
|
||||
*/
|
||||
|
||||
void
|
||||
reset_internal_getopt ()
|
||||
{
|
||||
lhead = lcurrent = loptend = (WORD_LIST *)NULL;
|
||||
sp = 1;
|
||||
}
|
43
third_party/bash/bashgetopt.h
vendored
Normal file
43
third_party/bash/bashgetopt.h
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
/* bashgetopt.h -- extern declarations for stuff defined in bashgetopt.c. */
|
||||
|
||||
/* Copyright (C) 1993-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* See getopt.h for the explanation of these variables. */
|
||||
|
||||
#if !defined (__BASH_GETOPT_H)
|
||||
# define __BASH_GETOPT_H
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
#define GETOPT_EOF -1
|
||||
#define GETOPT_HELP -99
|
||||
|
||||
extern char *list_optarg;
|
||||
extern int list_optflags;
|
||||
|
||||
extern int list_optopt;
|
||||
extern int list_opttype;
|
||||
|
||||
extern WORD_LIST *lcurrent;
|
||||
extern WORD_LIST *loptend;
|
||||
|
||||
extern int internal_getopt PARAMS((WORD_LIST *, char *));
|
||||
extern void reset_internal_getopt PARAMS((void));
|
||||
|
||||
#endif /* !__BASH_GETOPT_H */
|
1079
third_party/bash/bashhist.c
vendored
Normal file
1079
third_party/bash/bashhist.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
89
third_party/bash/bashhist.h
vendored
Normal file
89
third_party/bash/bashhist.h
vendored
Normal file
|
@ -0,0 +1,89 @@
|
|||
/* bashhist.h -- interface to the bash history functions in bashhist.c. */
|
||||
|
||||
/* Copyright (C) 1993-2020 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (_BASHHIST_H_)
|
||||
#define _BASHHIST_H_
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
/* Flag values for history_control */
|
||||
#define HC_IGNSPACE 0x01
|
||||
#define HC_IGNDUPS 0x02
|
||||
#define HC_ERASEDUPS 0x04
|
||||
|
||||
#define HC_IGNBOTH (HC_IGNSPACE|HC_IGNDUPS)
|
||||
|
||||
#if defined (STRICT_POSIX)
|
||||
# undef HISTEXPAND_DEFAULT
|
||||
# define HISTEXPAND_DEFAULT 0
|
||||
#else
|
||||
# if !defined (HISTEXPAND_DEFAULT)
|
||||
# define HISTEXPAND_DEFAULT 1
|
||||
# endif /* !HISTEXPAND_DEFAULT */
|
||||
#endif
|
||||
|
||||
extern int remember_on_history;
|
||||
extern int enable_history_list; /* value for `set -o history' */
|
||||
extern int literal_history; /* controlled by `shopt lithist' */
|
||||
extern int force_append_history;
|
||||
extern int history_lines_this_session;
|
||||
extern int history_lines_in_file;
|
||||
extern int history_expansion;
|
||||
extern int history_control;
|
||||
extern int command_oriented_history;
|
||||
extern int current_command_first_line_saved;
|
||||
extern int current_command_first_line_comment;
|
||||
extern int hist_last_line_added;
|
||||
extern int hist_last_line_pushed;
|
||||
|
||||
extern int dont_save_function_defs;
|
||||
|
||||
# if defined (READLINE)
|
||||
extern int hist_verify;
|
||||
# endif
|
||||
|
||||
# if defined (BANG_HISTORY)
|
||||
extern int history_expansion_inhibited;
|
||||
extern int double_quotes_inhibit_history_expansion;
|
||||
# endif /* BANG_HISTORY */
|
||||
|
||||
extern void bash_initialize_history PARAMS((void));
|
||||
extern void bash_history_reinit PARAMS((int));
|
||||
extern void bash_history_disable PARAMS((void));
|
||||
extern void bash_history_enable PARAMS((void));
|
||||
extern void bash_clear_history PARAMS((void));
|
||||
extern int bash_delete_histent PARAMS((int));
|
||||
extern int bash_delete_history_range PARAMS((int, int));
|
||||
extern int bash_delete_last_history PARAMS((void));
|
||||
extern void load_history PARAMS((void));
|
||||
extern void save_history PARAMS((void));
|
||||
extern int maybe_append_history PARAMS((char *));
|
||||
extern int maybe_save_shell_history PARAMS((void));
|
||||
extern char *pre_process_line PARAMS((char *, int, int));
|
||||
extern void maybe_add_history PARAMS((char *));
|
||||
extern void bash_add_history PARAMS((char *));
|
||||
extern int check_add_history PARAMS((char *, int));
|
||||
extern int history_number PARAMS((void));
|
||||
|
||||
extern void setup_history_ignore PARAMS((char *));
|
||||
|
||||
extern char *last_history_line PARAMS((void));
|
||||
|
||||
#endif /* _BASHHIST_H_ */
|
54
third_party/bash/bashintl.h
vendored
Normal file
54
third_party/bash/bashintl.h
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
/* bashintl.h -- Internationalization functions and defines. */
|
||||
|
||||
/* Copyright (C) 1996-2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (_BASHINTL_H_)
|
||||
#define _BASHINTL_H_
|
||||
|
||||
#if defined (BUILDTOOL)
|
||||
# undef ENABLE_NLS
|
||||
# define ENABLE_NLS 0
|
||||
#endif
|
||||
|
||||
/* Include this *after* config.h */
|
||||
#include "gettext.h"
|
||||
|
||||
#if defined (HAVE_LOCALE_H)
|
||||
# include <locale.h>
|
||||
#endif
|
||||
|
||||
#define _(msgid) gettext(msgid)
|
||||
#define N_(msgid) msgid
|
||||
#define D_(d, msgid) dgettext(d, msgid)
|
||||
|
||||
#define P_(m1, m2, n) ngettext(m1, m2, n)
|
||||
|
||||
#if defined (HAVE_SETLOCALE) && !defined (LC_ALL)
|
||||
# undef HAVE_SETLOCALE
|
||||
#endif
|
||||
|
||||
#if !defined (HAVE_SETLOCALE)
|
||||
# define setlocale(cat, loc)
|
||||
#endif
|
||||
|
||||
#if !defined (HAVE_LOCALE_H) || !defined (HAVE_LOCALECONV)
|
||||
# define locale_decpoint() '.'
|
||||
#endif
|
||||
|
||||
#endif /* !_BASHINTL_H_ */
|
47
third_party/bash/bashjmp.h
vendored
Normal file
47
third_party/bash/bashjmp.h
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* bashjmp.h -- wrapper for setjmp.h with necessary bash definitions. */
|
||||
|
||||
/* Copyright (C) 1987-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _BASHJMP_H_
|
||||
#define _BASHJMP_H_
|
||||
|
||||
#include "posixjmp.h"
|
||||
|
||||
extern procenv_t top_level;
|
||||
extern procenv_t subshell_top_level;
|
||||
extern procenv_t return_catch; /* used by `return' builtin */
|
||||
extern procenv_t wait_intr_buf;
|
||||
|
||||
extern int no_longjmp_on_fatal_error;
|
||||
|
||||
#define SHFUNC_RETURN() sh_longjmp (return_catch, 1)
|
||||
|
||||
#define COPY_PROCENV(old, save) \
|
||||
xbcopy ((char *)old, (char *)save, sizeof (procenv_t));
|
||||
|
||||
/* Values for the second argument to longjmp/siglongjmp. */
|
||||
#define NOT_JUMPED 0 /* Not returning from a longjmp. */
|
||||
#define FORCE_EOF 1 /* We want to stop parsing. */
|
||||
#define DISCARD 2 /* Discard current command. */
|
||||
#define EXITPROG 3 /* Unconditionally exit the program now. */
|
||||
#define ERREXIT 4 /* Exit due to error condition */
|
||||
#define SIGEXIT 5 /* Exit due to fatal terminating signal */
|
||||
#define EXITBLTIN 6 /* Exit due to the exit builtin. */
|
||||
|
||||
#endif /* _BASHJMP_H_ */
|
4839
third_party/bash/bashline.c
vendored
Normal file
4839
third_party/bash/bashline.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
69
third_party/bash/bashline.h
vendored
Normal file
69
third_party/bash/bashline.h
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
/* bashline.h -- interface to the bash readline functions in bashline.c. */
|
||||
|
||||
/* Copyright (C) 1993-2019 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (_BASHLINE_H_)
|
||||
#define _BASHLINE_H_
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
extern int bash_readline_initialized;
|
||||
extern int hostname_list_initialized;
|
||||
|
||||
/* these are controlled via shopt */
|
||||
extern int perform_hostname_completion;
|
||||
extern int no_empty_command_completion;
|
||||
extern int force_fignore;
|
||||
extern int dircomplete_spelling;
|
||||
extern int dircomplete_expand;
|
||||
extern int dircomplete_expand_relpath;
|
||||
extern int complete_fullquote;
|
||||
|
||||
extern void posix_readline_initialize PARAMS((int));
|
||||
extern void reset_completer_word_break_chars PARAMS((void));
|
||||
extern int enable_hostname_completion PARAMS((int));
|
||||
extern void initialize_readline PARAMS((void));
|
||||
extern void bashline_reset PARAMS((void));
|
||||
extern void bashline_reinitialize PARAMS((void));
|
||||
extern int bash_re_edit PARAMS((char *));
|
||||
|
||||
extern void bashline_set_event_hook PARAMS((void));
|
||||
extern void bashline_reset_event_hook PARAMS((void));
|
||||
|
||||
extern int bind_keyseq_to_unix_command PARAMS((char *));
|
||||
extern int bash_execute_unix_command PARAMS((int, int));
|
||||
extern int print_unix_command_map PARAMS((void));
|
||||
extern int unbind_unix_command PARAMS((char *));
|
||||
|
||||
extern char **bash_default_completion PARAMS((const char *, int, int, int, int));
|
||||
|
||||
extern void set_directory_hook PARAMS((void));
|
||||
|
||||
/* Used by programmable completion code. */
|
||||
extern char *command_word_completion_function PARAMS((const char *, int));
|
||||
extern char *bash_groupname_completion_function PARAMS((const char *, int));
|
||||
extern char *bash_servicename_completion_function PARAMS((const char *, int));
|
||||
|
||||
extern char **get_hostname_list PARAMS((void));
|
||||
extern void clear_hostname_list PARAMS((void));
|
||||
|
||||
extern char **bash_directory_completion_matches PARAMS((const char *));
|
||||
extern char *bash_dequote_text PARAMS((const char *));
|
||||
|
||||
#endif /* _BASHLINE_H_ */
|
42
third_party/bash/bashtypes.h
vendored
Normal file
42
third_party/bash/bashtypes.h
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
/* bashtypes.h -- Bash system types. */
|
||||
|
||||
/* Copyright (C) 1993-2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (_BASHTYPES_H_)
|
||||
# define _BASHTYPES_H_
|
||||
|
||||
#if defined (CRAY)
|
||||
# define word __word
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined (CRAY)
|
||||
# undef word
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_INTTYPES_H)
|
||||
# include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_STDINT_H
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#endif /* _BASHTYPES_H_ */
|
221
third_party/bash/bracecomp.c
vendored
Normal file
221
third_party/bash/bracecomp.c
vendored
Normal file
|
@ -0,0 +1,221 @@
|
|||
/* bracecomp.c -- Complete a filename with the possible completions enclosed
|
||||
in csh-style braces such that the list of completions is available to the
|
||||
shell. */
|
||||
|
||||
/* Original version by tromey@cns.caltech.edu, Fri Feb 7 1992. */
|
||||
|
||||
/* Copyright (C) 1993-2020 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (BRACE_EXPANSION) && defined (READLINE)
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "shmbutil.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "third_party/readline/readline.h"
|
||||
|
||||
static int _strcompare PARAMS((char **, char **));
|
||||
|
||||
/* Find greatest common prefix of two strings. */
|
||||
static int
|
||||
string_gcd (s1, s2)
|
||||
char *s1, *s2;
|
||||
{
|
||||
register int i;
|
||||
|
||||
if (s1 == NULL || s2 == NULL)
|
||||
return (0);
|
||||
|
||||
for (i = 0; *s1 && *s2; ++s1, ++s2, ++i)
|
||||
{
|
||||
if (*s1 != *s2)
|
||||
break;
|
||||
}
|
||||
|
||||
return (i);
|
||||
}
|
||||
|
||||
static char *
|
||||
really_munge_braces (array, real_start, real_end, gcd_zero)
|
||||
char **array;
|
||||
int real_start, real_end, gcd_zero;
|
||||
{
|
||||
int start, end, gcd;
|
||||
char *result, *subterm, *x;
|
||||
int result_size, flag, tlen;
|
||||
|
||||
flag = 0;
|
||||
|
||||
if (real_start == real_end)
|
||||
{
|
||||
x = array[real_start] ? sh_backslash_quote (array[real_start] + gcd_zero, 0, 0)
|
||||
: sh_backslash_quote (array[0], 0, 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
result = (char *)xmalloc (result_size = 16);
|
||||
*result = '\0';
|
||||
|
||||
for (start = real_start; start < real_end; start = end + 1)
|
||||
{
|
||||
gcd = strlen (array[start]);
|
||||
for (end = start + 1; end < real_end; end++)
|
||||
{
|
||||
int temp;
|
||||
|
||||
temp = string_gcd (array[start], array[end]);
|
||||
|
||||
if (temp <= gcd_zero)
|
||||
break;
|
||||
|
||||
gcd = temp;
|
||||
}
|
||||
end--;
|
||||
|
||||
if (gcd_zero == 0 && start == real_start && end != (real_end - 1))
|
||||
{
|
||||
/* In this case, add in a leading '{', because we are at
|
||||
top level, and there isn't a consistent prefix. */
|
||||
result_size += 1;
|
||||
result = (char *)xrealloc (result, result_size);
|
||||
result[0] = '{'; result[1] = '\0';
|
||||
flag++;
|
||||
}
|
||||
|
||||
/* Make sure we backslash quote every substring we insert into the
|
||||
resultant brace expression. This is so the default filename
|
||||
quoting function won't inappropriately quote the braces. */
|
||||
if (start == end)
|
||||
{
|
||||
x = savestring (array[start] + gcd_zero);
|
||||
subterm = sh_backslash_quote (x, 0, 0);
|
||||
free (x);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If there is more than one element in the subarray,
|
||||
insert the (quoted) prefix and an opening brace. */
|
||||
tlen = gcd - gcd_zero;
|
||||
x = (char *)xmalloc (tlen + 1);
|
||||
strncpy (x, array[start] + gcd_zero, tlen);
|
||||
x[tlen] = '\0';
|
||||
subterm = sh_backslash_quote (x, 0, 0);
|
||||
free (x);
|
||||
result_size += strlen (subterm) + 1;
|
||||
result = (char *)xrealloc (result, result_size);
|
||||
strcat (result, subterm);
|
||||
free (subterm);
|
||||
strcat (result, "{");
|
||||
subterm = really_munge_braces (array, start, end + 1, gcd);
|
||||
subterm[strlen (subterm) - 1] = '}';
|
||||
}
|
||||
|
||||
result_size += strlen (subterm) + 1;
|
||||
result = (char *)xrealloc (result, result_size);
|
||||
strcat (result, subterm);
|
||||
strcat (result, ",");
|
||||
free (subterm);
|
||||
}
|
||||
|
||||
if (gcd_zero == 0)
|
||||
result[strlen (result) - 1] = flag ? '}' : '\0';
|
||||
return (result);
|
||||
}
|
||||
|
||||
static int
|
||||
_strcompare (s1, s2)
|
||||
char **s1, **s2;
|
||||
{
|
||||
int result;
|
||||
|
||||
result = **s1 - **s2;
|
||||
if (result == 0)
|
||||
result = strcmp (*s1, *s2);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
hack_braces_completion (names)
|
||||
char **names;
|
||||
{
|
||||
register int i;
|
||||
char *temp;
|
||||
|
||||
i = strvec_len (names);
|
||||
if (MB_CUR_MAX > 1 && i > 2)
|
||||
qsort (names+1, i-1, sizeof (char *), (QSFUNC *)_strcompare);
|
||||
|
||||
temp = really_munge_braces (names, 1, i, 0);
|
||||
|
||||
for (i = 0; names[i]; ++i)
|
||||
{
|
||||
free (names[i]);
|
||||
names[i] = NULL;
|
||||
}
|
||||
names[0] = temp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We handle quoting ourselves within hack_braces_completion, so we turn off
|
||||
rl_filename_quoting_desired and rl_filename_quoting_function. */
|
||||
int
|
||||
bash_brace_completion (count, ignore)
|
||||
int count, ignore;
|
||||
{
|
||||
rl_compignore_func_t *orig_ignore_func;
|
||||
rl_compentry_func_t *orig_entry_func;
|
||||
rl_quote_func_t *orig_quoting_func;
|
||||
rl_completion_func_t *orig_attempt_func;
|
||||
int orig_quoting_desired, r;
|
||||
|
||||
orig_ignore_func = rl_ignore_some_completions_function;
|
||||
orig_attempt_func = rl_attempted_completion_function;
|
||||
orig_entry_func = rl_completion_entry_function;
|
||||
orig_quoting_func = rl_filename_quoting_function;
|
||||
orig_quoting_desired = rl_filename_quoting_desired;
|
||||
|
||||
rl_completion_entry_function = rl_filename_completion_function;
|
||||
rl_attempted_completion_function = (rl_completion_func_t *)NULL;
|
||||
rl_ignore_some_completions_function = hack_braces_completion;
|
||||
rl_filename_quoting_function = (rl_quote_func_t *)NULL;
|
||||
rl_filename_quoting_desired = 0;
|
||||
|
||||
r = rl_complete_internal (TAB);
|
||||
|
||||
rl_ignore_some_completions_function = orig_ignore_func;
|
||||
rl_attempted_completion_function = orig_attempt_func;
|
||||
rl_completion_entry_function = orig_entry_func;
|
||||
rl_filename_quoting_function = orig_quoting_func;
|
||||
rl_filename_quoting_desired = orig_quoting_desired;
|
||||
|
||||
return r;
|
||||
}
|
||||
#endif /* BRACE_EXPANSION && READLINE */
|
843
third_party/bash/braces.c
vendored
Normal file
843
third_party/bash/braces.c
vendored
Normal file
|
@ -0,0 +1,843 @@
|
|||
/* braces.c -- code for doing word expansion in curly braces. */
|
||||
|
||||
/* Copyright (C) 1987-2020 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Stuff in curly braces gets expanded before all other shell expansions. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (BRACE_EXPANSION)
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#if defined (SHELL)
|
||||
# include "shell.h"
|
||||
#else
|
||||
# if defined (TEST)
|
||||
typedef char *WORD_DESC;
|
||||
typedef char **WORD_LIST;
|
||||
#define _(X) X
|
||||
# endif /* TEST */
|
||||
#endif /* SHELL */
|
||||
|
||||
#include "typemax.h" /* INTMAX_MIN, INTMAX_MAX */
|
||||
#include "general.h"
|
||||
#include "shmbutil.h"
|
||||
#include "chartypes.h"
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#define brace_whitespace(c) (!(c) || (c) == ' ' || (c) == '\t' || (c) == '\n')
|
||||
|
||||
#define BRACE_SEQ_SPECIFIER ".."
|
||||
|
||||
extern int asprintf PARAMS((char **, const char *, ...)) __attribute__((__format__ (printf, 2, 3)));
|
||||
|
||||
/* Basic idea:
|
||||
|
||||
Segregate the text into 3 sections: preamble (stuff before an open brace),
|
||||
postamble (stuff after the matching close brace) and amble (stuff after
|
||||
preamble, and before postamble). Expand amble, and then tack on the
|
||||
expansions to preamble. Expand postamble, and tack on the expansions to
|
||||
the result so far.
|
||||
*/
|
||||
|
||||
/* The character which is used to separate arguments. */
|
||||
static const int brace_arg_separator = ',';
|
||||
|
||||
#if defined (PARAMS)
|
||||
static int brace_gobbler PARAMS((char *, size_t, int *, int));
|
||||
static char **expand_amble PARAMS((char *, size_t, int));
|
||||
static char **expand_seqterm PARAMS((char *, size_t));
|
||||
static char **mkseq PARAMS((intmax_t, intmax_t, intmax_t, int, int));
|
||||
static char **array_concat PARAMS((char **, char **));
|
||||
#else
|
||||
static int brace_gobbler ();
|
||||
static char **expand_amble ();
|
||||
static char **expand_seqterm ();
|
||||
static char **mkseq();
|
||||
static char **array_concat ();
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static void
|
||||
dump_result (a)
|
||||
char **a;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; a[i]; i++)
|
||||
printf ("dump_result: a[%d] = -%s-\n", i, a[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return an array of strings; the brace expansion of TEXT. */
|
||||
char **
|
||||
brace_expand (text)
|
||||
char *text;
|
||||
{
|
||||
register int start;
|
||||
size_t tlen;
|
||||
char *preamble, *postamble, *amble;
|
||||
size_t alen;
|
||||
char **tack, **result;
|
||||
int i, j, c, c1;
|
||||
|
||||
DECLARE_MBSTATE;
|
||||
|
||||
/* Find the text of the preamble. */
|
||||
tlen = strlen (text);
|
||||
i = 0;
|
||||
#if defined (CSH_BRACE_COMPAT)
|
||||
c = brace_gobbler (text, tlen, &i, '{'); /* } */
|
||||
#else
|
||||
/* Make sure that when we exit this loop, c == 0 or text[i] begins a
|
||||
valid brace expansion sequence. */
|
||||
do
|
||||
{
|
||||
c = brace_gobbler (text, tlen, &i, '{'); /* } */
|
||||
c1 = c;
|
||||
/* Verify that c begins a valid brace expansion word. If it doesn't, we
|
||||
go on. Loop stops when there are no more open braces in the word. */
|
||||
if (c)
|
||||
{
|
||||
start = j = i + 1; /* { */
|
||||
c = brace_gobbler (text, tlen, &j, '}');
|
||||
if (c == 0) /* it's not */
|
||||
{
|
||||
i++;
|
||||
c = c1;
|
||||
continue;
|
||||
}
|
||||
else /* it is */
|
||||
{
|
||||
c = c1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
while (c);
|
||||
#endif /* !CSH_BRACE_COMPAT */
|
||||
|
||||
preamble = (char *)xmalloc (i + 1);
|
||||
if (i > 0)
|
||||
strncpy (preamble, text, i);
|
||||
preamble[i] = '\0';
|
||||
|
||||
result = (char **)xmalloc (2 * sizeof (char *));
|
||||
result[0] = preamble;
|
||||
result[1] = (char *)NULL;
|
||||
|
||||
/* Special case. If we never found an exciting character, then
|
||||
the preamble is all of the text, so just return that. */
|
||||
if (c != '{')
|
||||
return (result);
|
||||
|
||||
/* Find the amble. This is the stuff inside this set of braces. */
|
||||
start = ++i;
|
||||
c = brace_gobbler (text, tlen, &i, '}');
|
||||
|
||||
/* What if there isn't a matching close brace? */
|
||||
if (c == 0)
|
||||
{
|
||||
#if defined (NOTDEF)
|
||||
/* Well, if we found an unquoted BRACE_ARG_SEPARATOR between START
|
||||
and I, then this should be an error. Otherwise, it isn't. */
|
||||
j = start;
|
||||
while (j < i)
|
||||
{
|
||||
if (text[j] == '\\')
|
||||
{
|
||||
j++;
|
||||
ADVANCE_CHAR (text, tlen, j);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (text[j] == brace_arg_separator)
|
||||
{ /* { */
|
||||
strvec_dispose (result);
|
||||
set_exit_status (EXECUTION_FAILURE);
|
||||
report_error ("no closing `%c' in %s", '}', text);
|
||||
throw_to_top_level ();
|
||||
}
|
||||
ADVANCE_CHAR (text, tlen, j);
|
||||
}
|
||||
#endif
|
||||
free (preamble); /* Same as result[0]; see initialization. */
|
||||
result[0] = savestring (text);
|
||||
return (result);
|
||||
}
|
||||
|
||||
#if defined (SHELL)
|
||||
amble = substring (text, start, i);
|
||||
alen = i - start;
|
||||
#else
|
||||
amble = (char *)xmalloc (1 + (i - start));
|
||||
strncpy (amble, &text[start], (i - start));
|
||||
alen = i - start;
|
||||
amble[alen] = '\0';
|
||||
#endif
|
||||
|
||||
#if defined (SHELL)
|
||||
INITIALIZE_MBSTATE;
|
||||
|
||||
/* If the amble does not contain an unquoted BRACE_ARG_SEPARATOR, then
|
||||
just return without doing any expansion. */
|
||||
j = 0;
|
||||
while (amble[j])
|
||||
{
|
||||
if (amble[j] == '\\')
|
||||
{
|
||||
j++;
|
||||
ADVANCE_CHAR (amble, alen, j);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (amble[j] == brace_arg_separator)
|
||||
break;
|
||||
|
||||
ADVANCE_CHAR (amble, alen, j);
|
||||
}
|
||||
|
||||
if (amble[j] == 0)
|
||||
{
|
||||
tack = expand_seqterm (amble, alen);
|
||||
if (tack)
|
||||
goto add_tack;
|
||||
else if (text[i + 1])
|
||||
{
|
||||
/* If the sequence expansion fails (e.g., because the integers
|
||||
overflow), but there is more in the string, try and process
|
||||
the rest of the string, which may contain additional brace
|
||||
expansions. Treat the unexpanded sequence term as a simple
|
||||
string (including the braces). */
|
||||
tack = strvec_create (2);
|
||||
tack[0] = savestring (text+start-1);
|
||||
tack[0][i-start+2] = '\0';
|
||||
tack[1] = (char *)0;
|
||||
goto add_tack;
|
||||
}
|
||||
else
|
||||
{
|
||||
free (amble);
|
||||
free (preamble);
|
||||
result[0] = savestring (text);
|
||||
return (result);
|
||||
}
|
||||
}
|
||||
#endif /* SHELL */
|
||||
|
||||
tack = expand_amble (amble, alen, 0);
|
||||
add_tack:
|
||||
result = array_concat (result, tack);
|
||||
free (amble);
|
||||
if (tack != result)
|
||||
strvec_dispose (tack);
|
||||
|
||||
postamble = text + i + 1;
|
||||
|
||||
if (postamble && *postamble)
|
||||
{
|
||||
tack = brace_expand (postamble);
|
||||
result = array_concat (result, tack);
|
||||
if (tack != result)
|
||||
strvec_dispose (tack);
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* Expand the text found inside of braces. We simply try to split the
|
||||
text at BRACE_ARG_SEPARATORs into separate strings. We then brace
|
||||
expand each slot which needs it, until there are no more slots which
|
||||
need it. */
|
||||
static char **
|
||||
expand_amble (text, tlen, flags)
|
||||
char *text;
|
||||
size_t tlen;
|
||||
int flags;
|
||||
{
|
||||
char **result, **partial, **tresult;
|
||||
char *tem;
|
||||
int start, i, c;
|
||||
|
||||
#if defined (SHELL)
|
||||
DECLARE_MBSTATE;
|
||||
#endif
|
||||
|
||||
result = (char **)NULL;
|
||||
|
||||
start = i = 0;
|
||||
c = 1;
|
||||
while (c)
|
||||
{
|
||||
c = brace_gobbler (text, tlen, &i, brace_arg_separator);
|
||||
#if defined (SHELL)
|
||||
tem = substring (text, start, i);
|
||||
#else
|
||||
tem = (char *)xmalloc (1 + (i - start));
|
||||
strncpy (tem, &text[start], (i - start));
|
||||
tem[i - start] = '\0';
|
||||
#endif
|
||||
|
||||
partial = brace_expand (tem);
|
||||
|
||||
if (!result)
|
||||
result = partial;
|
||||
else
|
||||
{
|
||||
register int lr, lp, j;
|
||||
|
||||
lr = strvec_len (result);
|
||||
lp = strvec_len (partial);
|
||||
|
||||
tresult = strvec_mresize (result, lp + lr + 1);
|
||||
if (tresult == 0)
|
||||
{
|
||||
internal_error (_("brace expansion: cannot allocate memory for %s"), tem);
|
||||
free (tem);
|
||||
strvec_dispose (partial);
|
||||
strvec_dispose (result);
|
||||
result = (char **)NULL;
|
||||
return result;
|
||||
}
|
||||
else
|
||||
result = tresult;
|
||||
|
||||
for (j = 0; j < lp; j++)
|
||||
result[lr + j] = partial[j];
|
||||
|
||||
result[lr + j] = (char *)NULL;
|
||||
free (partial);
|
||||
}
|
||||
free (tem);
|
||||
#if defined (SHELL)
|
||||
ADVANCE_CHAR (text, tlen, i);
|
||||
#else
|
||||
i++;
|
||||
#endif
|
||||
start = i;
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
#define ST_BAD 0
|
||||
#define ST_INT 1
|
||||
#define ST_CHAR 2
|
||||
#define ST_ZINT 3
|
||||
|
||||
static char **
|
||||
mkseq (start, end, incr, type, width)
|
||||
intmax_t start, end, incr;
|
||||
int type, width;
|
||||
{
|
||||
intmax_t n, prevn;
|
||||
int i, nelem;
|
||||
char **result, *t;
|
||||
|
||||
if (incr == 0)
|
||||
incr = 1;
|
||||
|
||||
if (start > end && incr > 0)
|
||||
incr = -incr;
|
||||
else if (start < end && incr < 0)
|
||||
{
|
||||
if (incr == INTMAX_MIN) /* Don't use -INTMAX_MIN */
|
||||
return ((char **)NULL);
|
||||
incr = -incr;
|
||||
}
|
||||
|
||||
/* Check that end-start will not overflow INTMAX_MIN, INTMAX_MAX. The +3
|
||||
and -2, not strictly necessary, are there because of the way the number
|
||||
of elements and value passed to strvec_create() are calculated below. */
|
||||
if (SUBOVERFLOW (end, start, INTMAX_MIN+3, INTMAX_MAX-2))
|
||||
return ((char **)NULL);
|
||||
|
||||
prevn = sh_imaxabs (end - start);
|
||||
/* Need to check this way in case INT_MAX == INTMAX_MAX */
|
||||
if (INT_MAX == INTMAX_MAX && (ADDOVERFLOW (prevn, 2, INT_MIN, INT_MAX)))
|
||||
return ((char **)NULL);
|
||||
/* Make sure the assignment to nelem below doesn't end up <= 0 due to
|
||||
intmax_t overflow */
|
||||
else if (ADDOVERFLOW ((prevn/sh_imaxabs(incr)), 1, INTMAX_MIN, INTMAX_MAX))
|
||||
return ((char **)NULL);
|
||||
|
||||
/* XXX - TOFIX: potentially allocating a lot of extra memory if
|
||||
imaxabs(incr) != 1 */
|
||||
/* Instead of a simple nelem = prevn + 1, something like:
|
||||
nelem = (prevn / imaxabs(incr)) + 1;
|
||||
would work */
|
||||
if ((prevn / sh_imaxabs (incr)) > INT_MAX - 3) /* check int overflow */
|
||||
return ((char **)NULL);
|
||||
nelem = (prevn / sh_imaxabs(incr)) + 1;
|
||||
result = strvec_mcreate (nelem + 1);
|
||||
if (result == 0)
|
||||
{
|
||||
internal_error (_("brace expansion: failed to allocate memory for %u elements"), (unsigned int)nelem);
|
||||
return ((char **)NULL);
|
||||
}
|
||||
|
||||
/* Make sure we go through the loop at least once, so {3..3} prints `3' */
|
||||
i = 0;
|
||||
n = start;
|
||||
do
|
||||
{
|
||||
#if defined (SHELL)
|
||||
if (ISINTERRUPT)
|
||||
{
|
||||
result[i] = (char *)NULL;
|
||||
strvec_dispose (result);
|
||||
result = (char **)NULL;
|
||||
}
|
||||
QUIT;
|
||||
#endif
|
||||
if (type == ST_INT)
|
||||
result[i++] = t = itos (n);
|
||||
else if (type == ST_ZINT)
|
||||
{
|
||||
int len, arg;
|
||||
arg = n;
|
||||
len = asprintf (&t, "%0*d", width, arg);
|
||||
result[i++] = t;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (t = (char *)malloc (2))
|
||||
{
|
||||
t[0] = n;
|
||||
t[1] = '\0';
|
||||
}
|
||||
result[i++] = t;
|
||||
}
|
||||
|
||||
/* We failed to allocate memory for this number, so we bail. */
|
||||
if (t == 0)
|
||||
{
|
||||
char *p, lbuf[INT_STRLEN_BOUND(intmax_t) + 1];
|
||||
|
||||
/* Easier to do this than mess around with various intmax_t printf
|
||||
formats (%ld? %lld? %jd?) and PRIdMAX. */
|
||||
p = inttostr (n, lbuf, sizeof (lbuf));
|
||||
internal_error (_("brace expansion: failed to allocate memory for `%s'"), p);
|
||||
strvec_dispose (result);
|
||||
return ((char **)NULL);
|
||||
}
|
||||
|
||||
/* Handle overflow and underflow of n+incr */
|
||||
if (ADDOVERFLOW (n, incr, INTMAX_MIN, INTMAX_MAX))
|
||||
break;
|
||||
|
||||
n += incr;
|
||||
|
||||
if ((incr < 0 && n < end) || (incr > 0 && n > end))
|
||||
break;
|
||||
}
|
||||
while (1);
|
||||
|
||||
result[i] = (char *)0;
|
||||
return (result);
|
||||
}
|
||||
|
||||
static char **
|
||||
expand_seqterm (text, tlen)
|
||||
char *text;
|
||||
size_t tlen;
|
||||
{
|
||||
char *t, *lhs, *rhs;
|
||||
int lhs_t, rhs_t, lhs_l, rhs_l, width;
|
||||
intmax_t lhs_v, rhs_v, incr;
|
||||
intmax_t tl, tr;
|
||||
char **result, *ep, *oep;
|
||||
|
||||
t = strstr (text, BRACE_SEQ_SPECIFIER);
|
||||
if (t == 0)
|
||||
return ((char **)NULL);
|
||||
|
||||
lhs_l = t - text; /* index of start of BRACE_SEQ_SPECIFIER */
|
||||
lhs = substring (text, 0, lhs_l);
|
||||
rhs = substring (text, lhs_l + sizeof(BRACE_SEQ_SPECIFIER) - 1, tlen);
|
||||
|
||||
if (lhs[0] == 0 || rhs[0] == 0)
|
||||
{
|
||||
free (lhs);
|
||||
free (rhs);
|
||||
return ((char **)NULL);
|
||||
}
|
||||
|
||||
/* Now figure out whether LHS and RHS are integers or letters. Both
|
||||
sides have to match. */
|
||||
lhs_t = (legal_number (lhs, &tl)) ? ST_INT :
|
||||
((ISALPHA (lhs[0]) && lhs[1] == 0) ? ST_CHAR : ST_BAD);
|
||||
|
||||
/* Decide on rhs and whether or not it looks like the user specified
|
||||
an increment */
|
||||
ep = 0;
|
||||
if (ISDIGIT (rhs[0]) || ((rhs[0] == '+' || rhs[0] == '-') && ISDIGIT (rhs[1])))
|
||||
{
|
||||
rhs_t = ST_INT;
|
||||
errno = 0;
|
||||
tr = strtoimax (rhs, &ep, 10);
|
||||
if (errno == ERANGE || (ep && *ep != 0 && *ep != '.'))
|
||||
rhs_t = ST_BAD; /* invalid */
|
||||
}
|
||||
else if (ISALPHA (rhs[0]) && (rhs[1] == 0 || rhs[1] == '.'))
|
||||
{
|
||||
rhs_t = ST_CHAR;
|
||||
ep = rhs + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
rhs_t = ST_BAD;
|
||||
ep = 0;
|
||||
}
|
||||
|
||||
incr = 1;
|
||||
if (rhs_t != ST_BAD)
|
||||
{
|
||||
oep = ep;
|
||||
errno = 0;
|
||||
if (ep && *ep == '.' && ep[1] == '.' && ep[2])
|
||||
incr = strtoimax (ep + 2, &ep, 10);
|
||||
if (*ep != 0 || errno == ERANGE)
|
||||
rhs_t = ST_BAD; /* invalid incr or overflow */
|
||||
tlen -= ep - oep;
|
||||
}
|
||||
|
||||
if (lhs_t != rhs_t || lhs_t == ST_BAD || rhs_t == ST_BAD)
|
||||
{
|
||||
free (lhs);
|
||||
free (rhs);
|
||||
return ((char **)NULL);
|
||||
}
|
||||
|
||||
/* OK, we have something. It's either a sequence of integers, ascending
|
||||
or descending, or a sequence or letters, ditto. Generate the sequence,
|
||||
put it into a string vector, and return it. */
|
||||
|
||||
if (lhs_t == ST_CHAR)
|
||||
{
|
||||
lhs_v = (unsigned char)lhs[0];
|
||||
rhs_v = (unsigned char)rhs[0];
|
||||
width = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
lhs_v = tl; /* integer truncation */
|
||||
rhs_v = tr;
|
||||
|
||||
/* Decide whether or not the terms need zero-padding */
|
||||
rhs_l = tlen - lhs_l - sizeof (BRACE_SEQ_SPECIFIER) + 1;
|
||||
width = 0;
|
||||
if (lhs_l > 1 && lhs[0] == '0')
|
||||
width = lhs_l, lhs_t = ST_ZINT;
|
||||
if (lhs_l > 2 && lhs[0] == '-' && lhs[1] == '0')
|
||||
width = lhs_l, lhs_t = ST_ZINT;
|
||||
if (rhs_l > 1 && rhs[0] == '0' && width < rhs_l)
|
||||
width = rhs_l, lhs_t = ST_ZINT;
|
||||
if (rhs_l > 2 && rhs[0] == '-' && rhs[1] == '0' && width < rhs_l)
|
||||
width = rhs_l, lhs_t = ST_ZINT;
|
||||
|
||||
if (width < lhs_l && lhs_t == ST_ZINT)
|
||||
width = lhs_l;
|
||||
if (width < rhs_l && lhs_t == ST_ZINT)
|
||||
width = rhs_l;
|
||||
}
|
||||
|
||||
result = mkseq (lhs_v, rhs_v, incr, lhs_t, width);
|
||||
|
||||
free (lhs);
|
||||
free (rhs);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* Start at INDEX, and skip characters in TEXT. Set INDEX to the
|
||||
index of the character matching SATISFY. This understands about
|
||||
quoting. Return the character that caused us to stop searching;
|
||||
this is either the same as SATISFY, or 0. */
|
||||
/* If SATISFY is `}', we are looking for a brace expression, so we
|
||||
should enforce the rules that govern valid brace expansions:
|
||||
1) to count as an arg separator, a comma or `..' has to be outside
|
||||
an inner set of braces.
|
||||
*/
|
||||
static int
|
||||
brace_gobbler (text, tlen, indx, satisfy)
|
||||
char *text;
|
||||
size_t tlen;
|
||||
int *indx;
|
||||
int satisfy;
|
||||
{
|
||||
register int i, c, quoted, level, commas, pass_next;
|
||||
#if defined (SHELL)
|
||||
int si;
|
||||
char *t;
|
||||
#endif
|
||||
DECLARE_MBSTATE;
|
||||
|
||||
level = quoted = pass_next = 0;
|
||||
#if defined (CSH_BRACE_COMPAT)
|
||||
commas = 1;
|
||||
#else
|
||||
commas = (satisfy == '}') ? 0 : 1;
|
||||
#endif
|
||||
|
||||
i = *indx;
|
||||
while (c = text[i])
|
||||
{
|
||||
if (pass_next)
|
||||
{
|
||||
pass_next = 0;
|
||||
#if defined (SHELL)
|
||||
ADVANCE_CHAR (text, tlen, i);
|
||||
#else
|
||||
i++;
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
/* A backslash escapes the next character. This allows backslash to
|
||||
escape the quote character in a double-quoted string. */
|
||||
if (c == '\\' && (quoted == 0 || quoted == '"' || quoted == '`'))
|
||||
{
|
||||
pass_next = 1;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
#if defined (SHELL)
|
||||
/* If compiling for the shell, treat ${...} like \{...} */
|
||||
if (c == '$' && text[i+1] == '{' && quoted != '\'') /* } */
|
||||
{
|
||||
pass_next = 1;
|
||||
i++;
|
||||
if (quoted == 0)
|
||||
level++;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (quoted)
|
||||
{
|
||||
if (c == quoted)
|
||||
quoted = 0;
|
||||
#if defined (SHELL)
|
||||
/* The shell allows quoted command substitutions */
|
||||
if (quoted == '"' && c == '$' && text[i+1] == '(') /*)*/
|
||||
goto comsub;
|
||||
#endif
|
||||
#if defined (SHELL)
|
||||
ADVANCE_CHAR (text, tlen, i);
|
||||
#else
|
||||
i++;
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '"' || c == '\'' || c == '`')
|
||||
{
|
||||
quoted = c;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
#if defined (SHELL)
|
||||
/* Pass new-style command and process substitutions through unchanged. */
|
||||
if ((c == '$' || c == '<' || c == '>') && text[i+1] == '(') /* ) */
|
||||
{
|
||||
comsub:
|
||||
si = i + 2;
|
||||
t = extract_command_subst (text, &si, 0);
|
||||
i = si;
|
||||
free (t);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (c == satisfy && level == 0 && quoted == 0 && commas > 0)
|
||||
{
|
||||
/* We ignore an open brace surrounded by whitespace, and also
|
||||
an open brace followed immediately by a close brace preceded
|
||||
by whitespace. */
|
||||
if (c == '{' &&
|
||||
((!i || brace_whitespace (text[i - 1])) &&
|
||||
(brace_whitespace (text[i + 1]) || text[i + 1] == '}')))
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == '{')
|
||||
level++;
|
||||
else if (c == '}' && level)
|
||||
level--;
|
||||
#if !defined (CSH_BRACE_COMPAT)
|
||||
else if (satisfy == '}' && c == brace_arg_separator && level == 0)
|
||||
commas++;
|
||||
else if (satisfy == '}' && STREQN (text+i, BRACE_SEQ_SPECIFIER, 2) &&
|
||||
text[i+2] != satisfy && level == 0)
|
||||
commas++;
|
||||
#endif
|
||||
|
||||
#if defined (SHELL)
|
||||
ADVANCE_CHAR (text, tlen, i);
|
||||
#else
|
||||
i++;
|
||||
#endif
|
||||
}
|
||||
|
||||
*indx = i;
|
||||
return (c);
|
||||
}
|
||||
|
||||
/* Return a new array of strings which is the result of appending each
|
||||
string in ARR2 to each string in ARR1. The resultant array is
|
||||
len (arr1) * len (arr2) long. For convenience, ARR1 (and its contents)
|
||||
are free ()'ed. ARR1 can be NULL, in that case, a new version of ARR2
|
||||
is returned. */
|
||||
static char **
|
||||
array_concat (arr1, arr2)
|
||||
char **arr1, **arr2;
|
||||
{
|
||||
register int i, j, len, len1, len2;
|
||||
register char **result;
|
||||
|
||||
if (arr1 == 0)
|
||||
return (arr2); /* XXX - see if we can get away without copying? */
|
||||
|
||||
if (arr2 == 0)
|
||||
return (arr1); /* XXX - caller expects us to free arr1 */
|
||||
|
||||
/* We can only short-circuit if the array consists of a single null element;
|
||||
otherwise we need to replicate the contents of the other array and
|
||||
prefix (or append, below) an empty element to each one. */
|
||||
if (arr1[0] && arr1[0][0] == 0 && arr1[1] == 0)
|
||||
{
|
||||
strvec_dispose (arr1);
|
||||
return (arr2); /* XXX - use flags to see if we can avoid copying here */
|
||||
}
|
||||
|
||||
if (arr2[0] && arr2[0][0] == 0 && arr2[1] == 0)
|
||||
return (arr1); /* XXX - rather than copying and freeing it */
|
||||
|
||||
len1 = strvec_len (arr1);
|
||||
len2 = strvec_len (arr2);
|
||||
|
||||
result = (char **)malloc ((1 + (len1 * len2)) * sizeof (char *));
|
||||
if (result == 0)
|
||||
return (result);
|
||||
|
||||
len = 0;
|
||||
for (i = 0; i < len1; i++)
|
||||
{
|
||||
int strlen_1 = strlen (arr1[i]);
|
||||
|
||||
for (j = 0; j < len2; j++)
|
||||
{
|
||||
result[len] = (char *)xmalloc (1 + strlen_1 + strlen (arr2[j]));
|
||||
strcpy (result[len], arr1[i]);
|
||||
strcpy (result[len] + strlen_1, arr2[j]);
|
||||
len++;
|
||||
}
|
||||
free (arr1[i]);
|
||||
}
|
||||
free (arr1);
|
||||
|
||||
result[len] = (char *)NULL;
|
||||
return (result);
|
||||
}
|
||||
|
||||
#if defined (TEST)
|
||||
#include <stdio.h>
|
||||
|
||||
void *
|
||||
xmalloc(n)
|
||||
size_t n;
|
||||
{
|
||||
return (malloc (n));
|
||||
}
|
||||
|
||||
void *
|
||||
xrealloc(p, n)
|
||||
void *p;
|
||||
size_t n;
|
||||
{
|
||||
return (realloc (p, n));
|
||||
}
|
||||
|
||||
int
|
||||
internal_error (format, arg1, arg2)
|
||||
char *format, *arg1, *arg2;
|
||||
{
|
||||
fprintf (stderr, format, arg1, arg2);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
main ()
|
||||
{
|
||||
char example[256];
|
||||
|
||||
for (;;)
|
||||
{
|
||||
char **result;
|
||||
int i;
|
||||
|
||||
fprintf (stderr, "brace_expand> ");
|
||||
|
||||
if ((!fgets (example, 256, stdin)) ||
|
||||
(strncmp (example, "quit", 4) == 0))
|
||||
break;
|
||||
|
||||
if (strlen (example))
|
||||
example[strlen (example) - 1] = '\0';
|
||||
|
||||
result = brace_expand (example);
|
||||
|
||||
for (i = 0; result[i]; i++)
|
||||
printf ("%s\n", result[i]);
|
||||
|
||||
strvec_dispose (result);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* compile-command: "gcc -g -Bstatic -DTEST -o brace_expand braces.c general.o"
|
||||
* end:
|
||||
*/
|
||||
|
||||
#endif /* TEST */
|
||||
#endif /* BRACE_EXPANSION */
|
104
third_party/bash/break.c
vendored
Normal file
104
third_party/bash/break.c
vendored
Normal file
|
@ -0,0 +1,104 @@
|
|||
/* break.c, created from break.def. */
|
||||
#line 22 "./break.def"
|
||||
|
||||
#line 34 "./break.def"
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "execute_cmd.h"
|
||||
#include "common.h"
|
||||
|
||||
static int check_loop_level PARAMS((void));
|
||||
|
||||
/* The depth of while's and until's. */
|
||||
int loop_level = 0;
|
||||
|
||||
/* Non-zero when a "break" instruction is encountered. */
|
||||
int breaking = 0;
|
||||
|
||||
/* Non-zero when we have encountered a continue instruction. */
|
||||
int continuing = 0;
|
||||
|
||||
/* Set up to break x levels, where x defaults to 1, but can be specified
|
||||
as the first argument. */
|
||||
int
|
||||
break_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
intmax_t newbreak;
|
||||
|
||||
CHECK_HELPOPT (list);
|
||||
|
||||
if (check_loop_level () == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
(void)get_numeric_arg (list, 1, &newbreak);
|
||||
|
||||
if (newbreak <= 0)
|
||||
{
|
||||
sh_erange (list->word->word, _("loop count"));
|
||||
breaking = loop_level;
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (newbreak > loop_level)
|
||||
newbreak = loop_level;
|
||||
|
||||
breaking = newbreak;
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
#line 101 "./break.def"
|
||||
|
||||
/* Set up to continue x levels, where x defaults to 1, but can be specified
|
||||
as the first argument. */
|
||||
int
|
||||
continue_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
intmax_t newcont;
|
||||
|
||||
CHECK_HELPOPT (list);
|
||||
|
||||
if (check_loop_level () == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
(void)get_numeric_arg (list, 1, &newcont);
|
||||
|
||||
if (newcont <= 0)
|
||||
{
|
||||
sh_erange (list->word->word, _("loop count"));
|
||||
breaking = loop_level;
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (newcont > loop_level)
|
||||
newcont = loop_level;
|
||||
|
||||
continuing = newcont;
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Return non-zero if a break or continue command would be okay.
|
||||
Print an error message if break or continue is meaningless here. */
|
||||
static int
|
||||
check_loop_level ()
|
||||
{
|
||||
#if defined (BREAK_COMPLAINS)
|
||||
if (loop_level == 0 && posixly_correct == 0)
|
||||
builtin_error (_("only meaningful in a `for', `while', or `until' loop"));
|
||||
#endif /* BREAK_COMPLAINS */
|
||||
|
||||
return (loop_level);
|
||||
}
|
188
third_party/bash/builtext.h
vendored
Normal file
188
third_party/bash/builtext.h
vendored
Normal file
|
@ -0,0 +1,188 @@
|
|||
/* builtext.h - The list of builtins found in libbuiltins.a. */
|
||||
#if defined (ALIAS)
|
||||
extern int alias_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const alias_doc[];
|
||||
#endif /* ALIAS */
|
||||
#if defined (ALIAS)
|
||||
extern int unalias_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const unalias_doc[];
|
||||
#endif /* ALIAS */
|
||||
#if defined (READLINE)
|
||||
extern int bind_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const bind_doc[];
|
||||
#endif /* READLINE */
|
||||
extern int break_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const break_doc[];
|
||||
extern int continue_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const continue_doc[];
|
||||
extern int builtin_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const builtin_doc[];
|
||||
#if defined (DEBUGGER)
|
||||
extern int caller_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const caller_doc[];
|
||||
#endif /* DEBUGGER */
|
||||
extern int cd_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const cd_doc[];
|
||||
extern int pwd_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const pwd_doc[];
|
||||
extern int colon_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const colon_doc[];
|
||||
extern int colon_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const true_doc[];
|
||||
extern int false_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const false_doc[];
|
||||
extern int command_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const command_doc[];
|
||||
extern int declare_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const declare_doc[];
|
||||
extern int declare_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const typeset_doc[];
|
||||
extern int local_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const local_doc[];
|
||||
#if defined (V9_ECHO)
|
||||
extern int echo_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const echo_doc[];
|
||||
#endif /* V9_ECHO */
|
||||
#if !defined (V9_ECHO)
|
||||
extern int echo_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const echo_doc[];
|
||||
#endif /* !V9_ECHO */
|
||||
extern int enable_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const enable_doc[];
|
||||
extern int eval_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const eval_doc[];
|
||||
extern int getopts_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const getopts_doc[];
|
||||
extern int exec_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const exec_doc[];
|
||||
extern int exit_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const exit_doc[];
|
||||
extern int logout_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const logout_doc[];
|
||||
#if defined (HISTORY)
|
||||
extern int fc_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const fc_doc[];
|
||||
#endif /* HISTORY */
|
||||
#if defined (JOB_CONTROL)
|
||||
extern int fg_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const fg_doc[];
|
||||
#endif /* JOB_CONTROL */
|
||||
#if defined (JOB_CONTROL)
|
||||
extern int bg_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const bg_doc[];
|
||||
#endif /* JOB_CONTROL */
|
||||
extern int hash_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const hash_doc[];
|
||||
#if defined (HELP_BUILTIN)
|
||||
extern int help_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const help_doc[];
|
||||
#endif /* HELP_BUILTIN */
|
||||
#if defined (HISTORY)
|
||||
extern int history_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const history_doc[];
|
||||
#endif /* HISTORY */
|
||||
#if defined (JOB_CONTROL)
|
||||
extern int jobs_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const jobs_doc[];
|
||||
#endif /* JOB_CONTROL */
|
||||
#if defined (JOB_CONTROL)
|
||||
extern int disown_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const disown_doc[];
|
||||
#endif /* JOB_CONTROL */
|
||||
extern int kill_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const kill_doc[];
|
||||
extern int let_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const let_doc[];
|
||||
extern int read_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const read_doc[];
|
||||
extern int return_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const return_doc[];
|
||||
extern int set_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const set_doc[];
|
||||
extern int unset_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const unset_doc[];
|
||||
extern int export_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const export_doc[];
|
||||
extern int readonly_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const readonly_doc[];
|
||||
extern int shift_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const shift_doc[];
|
||||
extern int source_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const source_doc[];
|
||||
extern int source_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const dot_doc[];
|
||||
#if defined (JOB_CONTROL)
|
||||
extern int suspend_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const suspend_doc[];
|
||||
#endif /* JOB_CONTROL */
|
||||
extern int test_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const test_doc[];
|
||||
extern int test_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const test_bracket_doc[];
|
||||
extern int times_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const times_doc[];
|
||||
extern int trap_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const trap_doc[];
|
||||
extern int type_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const type_doc[];
|
||||
#if !defined (_MINIX)
|
||||
extern int ulimit_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const ulimit_doc[];
|
||||
#endif /* !_MINIX */
|
||||
extern int umask_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const umask_doc[];
|
||||
#if defined (JOB_CONTROL)
|
||||
extern int wait_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const wait_doc[];
|
||||
#endif /* JOB_CONTROL */
|
||||
#if !defined (JOB_CONTROL)
|
||||
extern int wait_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const wait_doc[];
|
||||
#endif /* !JOB_CONTROL */
|
||||
extern char * const for_doc[];
|
||||
extern char * const arith_for_doc[];
|
||||
extern char * const select_doc[];
|
||||
extern char * const time_doc[];
|
||||
extern char * const case_doc[];
|
||||
extern char * const if_doc[];
|
||||
extern char * const while_doc[];
|
||||
extern char * const until_doc[];
|
||||
extern char * const coproc_doc[];
|
||||
extern char * const function_doc[];
|
||||
extern char * const grouping_braces_doc[];
|
||||
extern char * const fg_percent_doc[];
|
||||
extern char * const arith_doc[];
|
||||
extern char * const conditional_doc[];
|
||||
extern char * const variable_help_doc[];
|
||||
#if defined (PUSHD_AND_POPD)
|
||||
extern int pushd_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const pushd_doc[];
|
||||
#endif /* PUSHD_AND_POPD */
|
||||
#if defined (PUSHD_AND_POPD)
|
||||
extern int popd_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const popd_doc[];
|
||||
#endif /* PUSHD_AND_POPD */
|
||||
#if defined (PUSHD_AND_POPD)
|
||||
extern int dirs_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const dirs_doc[];
|
||||
#endif /* PUSHD_AND_POPD */
|
||||
extern int shopt_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const shopt_doc[];
|
||||
extern int printf_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const printf_doc[];
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
extern int complete_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const complete_doc[];
|
||||
#endif /* PROGRAMMABLE_COMPLETION */
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
extern int compgen_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const compgen_doc[];
|
||||
#endif /* PROGRAMMABLE_COMPLETION */
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
extern int compopt_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const compopt_doc[];
|
||||
#endif /* PROGRAMMABLE_COMPLETION */
|
||||
extern int mapfile_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const mapfile_doc[];
|
||||
extern int mapfile_builtin PARAMS((WORD_LIST *));
|
||||
extern char * const readarray_doc[];
|
2093
third_party/bash/builtins.c
vendored
Normal file
2093
third_party/bash/builtins.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
68
third_party/bash/builtins.h
vendored
Normal file
68
third_party/bash/builtins.h
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
/* builtins.h -- What a builtin looks like, and where to find them. */
|
||||
|
||||
/* Copyright (C) 1987-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef BUILTINS_H
|
||||
#define BUILTINS_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "command.h"
|
||||
#include "general.h"
|
||||
|
||||
#if defined (ALIAS)
|
||||
#include "alias.h"
|
||||
#endif
|
||||
|
||||
/* Flags describing various things about a builtin. */
|
||||
#define BUILTIN_ENABLED 0x01 /* This builtin is enabled. */
|
||||
#define BUILTIN_DELETED 0x02 /* This has been deleted with enable -d. */
|
||||
#define STATIC_BUILTIN 0x04 /* This builtin is not dynamically loaded. */
|
||||
#define SPECIAL_BUILTIN 0x08 /* This is a Posix `special' builtin. */
|
||||
#define ASSIGNMENT_BUILTIN 0x10 /* This builtin takes assignment statements. */
|
||||
#define POSIX_BUILTIN 0x20 /* This builtins is special in the Posix command search order. */
|
||||
#define LOCALVAR_BUILTIN 0x40 /* This builtin creates local variables */
|
||||
#define ARRAYREF_BUILTIN 0x80 /* This builtin takes array references as arguments */
|
||||
|
||||
#define BASE_INDENT 4
|
||||
|
||||
/* The thing that we build the array of builtins out of. */
|
||||
struct builtin {
|
||||
char *name; /* The name that the user types. */
|
||||
sh_builtin_func_t *function; /* The address of the invoked function. */
|
||||
int flags; /* One of the #defines above. */
|
||||
char * const *long_doc; /* NULL terminated array of strings. */
|
||||
const char *short_doc; /* Short version of documentation. */
|
||||
char *handle; /* for future use */
|
||||
};
|
||||
|
||||
/* Found in builtins.c, created by builtins/mkbuiltins. */
|
||||
extern int num_shell_builtins; /* Number of shell builtins. */
|
||||
extern struct builtin static_shell_builtins[];
|
||||
extern struct builtin *shell_builtins;
|
||||
extern struct builtin *current_builtin;
|
||||
|
||||
#endif /* BUILTINS_H */
|
192
third_party/bash/builtins_alias.c
vendored
Normal file
192
third_party/bash/builtins_alias.c
vendored
Normal file
|
@ -0,0 +1,192 @@
|
|||
/* alias.c, created from alias.def. */
|
||||
#line 42 "./alias.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (ALIAS)
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
# include "bashansi.h"
|
||||
# include "bashintl.h"
|
||||
|
||||
# include <stdio.h>
|
||||
# include "shell.h"
|
||||
# include "alias.h"
|
||||
# include "common.h"
|
||||
# include "bashgetopt.h"
|
||||
|
||||
/* Flags for print_alias */
|
||||
#define AL_REUSABLE 0x01
|
||||
|
||||
static void print_alias PARAMS((alias_t *, int));
|
||||
|
||||
/* Hack the alias command in a Korn shell way. */
|
||||
int
|
||||
alias_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int any_failed, offset, pflag, dflags;
|
||||
alias_t **alias_list, *t;
|
||||
char *name, *value;
|
||||
|
||||
dflags = posixly_correct ? 0 : AL_REUSABLE;
|
||||
pflag = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((offset = internal_getopt (list, "p")) != -1)
|
||||
{
|
||||
switch (offset)
|
||||
{
|
||||
case 'p':
|
||||
pflag = 1;
|
||||
dflags |= AL_REUSABLE;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
if (list == 0 || pflag)
|
||||
{
|
||||
if (aliases == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
alias_list = all_aliases ();
|
||||
|
||||
if (alias_list == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
for (offset = 0; alias_list[offset]; offset++)
|
||||
print_alias (alias_list[offset], dflags);
|
||||
|
||||
free (alias_list); /* XXX - Do not free the strings. */
|
||||
|
||||
if (list == 0)
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
any_failed = 0;
|
||||
while (list)
|
||||
{
|
||||
name = list->word->word;
|
||||
|
||||
for (offset = 0; name[offset] && name[offset] != '='; offset++)
|
||||
;
|
||||
|
||||
if (offset && name[offset] == '=')
|
||||
{
|
||||
name[offset] = '\0';
|
||||
value = name + offset + 1;
|
||||
|
||||
if (legal_alias_name (name, 0) == 0)
|
||||
{
|
||||
builtin_error (_("`%s': invalid alias name"), name);
|
||||
any_failed++;
|
||||
}
|
||||
else
|
||||
add_alias (name, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
t = find_alias (name);
|
||||
if (t)
|
||||
print_alias (t, dflags);
|
||||
else
|
||||
{
|
||||
sh_notfound (name);
|
||||
any_failed++;
|
||||
}
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
|
||||
}
|
||||
#endif /* ALIAS */
|
||||
|
||||
#line 166 "./alias.def"
|
||||
|
||||
#if defined (ALIAS)
|
||||
/* Remove aliases named in LIST from the aliases database. */
|
||||
int
|
||||
unalias_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
register alias_t *alias;
|
||||
int opt, aflag;
|
||||
|
||||
aflag = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "a")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'a':
|
||||
aflag = 1;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
if (aflag)
|
||||
{
|
||||
delete_all_aliases ();
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
aflag = 0;
|
||||
while (list)
|
||||
{
|
||||
alias = find_alias (list->word->word);
|
||||
|
||||
if (alias)
|
||||
remove_alias (alias->name);
|
||||
else
|
||||
{
|
||||
sh_notfound (list->word->word);
|
||||
aflag++;
|
||||
}
|
||||
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
return (aflag ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Output ALIAS in such a way as to allow it to be read back in. */
|
||||
static void
|
||||
print_alias (alias, flags)
|
||||
alias_t *alias;
|
||||
int flags;
|
||||
{
|
||||
char *value;
|
||||
|
||||
value = sh_single_quote (alias->value);
|
||||
if (flags & AL_REUSABLE)
|
||||
printf ("alias %s", (alias->name && alias->name[0] == '-') ? "-- " : "");
|
||||
printf ("%s=%s\n", alias->name, value);
|
||||
free (value);
|
||||
|
||||
fflush (stdout);
|
||||
}
|
||||
#endif /* ALIAS */
|
349
third_party/bash/builtins_bind.c
vendored
Normal file
349
third_party/bash/builtins_bind.c
vendored
Normal file
|
@ -0,0 +1,349 @@
|
|||
/* bind.c, created from bind.def. */
|
||||
#line 22 "./bind.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#line 63 "./bind.def"
|
||||
|
||||
#if defined (READLINE)
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
#include "third_party/readline/readline.h"
|
||||
#include "third_party/readline/history.h"
|
||||
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "bashline.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
static int query_bindings PARAMS((char *));
|
||||
static int unbind_command PARAMS((char *));
|
||||
static int unbind_keyseq PARAMS((char *));
|
||||
|
||||
#define BIND_RETURN(x) do { return_code = x; goto bind_exit; } while (0)
|
||||
|
||||
#define LFLAG 0x0001
|
||||
#define PFLAG 0x0002
|
||||
#define FFLAG 0x0004
|
||||
#define VFLAG 0x0008
|
||||
#define QFLAG 0x0010
|
||||
#define MFLAG 0x0020
|
||||
#define RFLAG 0x0040
|
||||
#define PPFLAG 0x0080
|
||||
#define VVFLAG 0x0100
|
||||
#define SFLAG 0x0200
|
||||
#define SSFLAG 0x0400
|
||||
#define UFLAG 0x0800
|
||||
#define XFLAG 0x1000
|
||||
#define XXFLAG 0x2000
|
||||
|
||||
int
|
||||
bind_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int return_code;
|
||||
Keymap kmap, saved_keymap;
|
||||
int flags, opt;
|
||||
char *initfile, *map_name, *fun_name, *unbind_name, *remove_seq, *cmd_seq, *t;
|
||||
|
||||
if (no_line_editing)
|
||||
{
|
||||
#if 0
|
||||
builtin_error (_("line editing not enabled"));
|
||||
return (EXECUTION_FAILURE);
|
||||
#else
|
||||
builtin_warning (_("line editing not enabled"));
|
||||
#endif
|
||||
}
|
||||
|
||||
kmap = saved_keymap = (Keymap) NULL;
|
||||
flags = 0;
|
||||
initfile = map_name = fun_name = unbind_name = remove_seq = cmd_seq = (char *)NULL;
|
||||
return_code = EXECUTION_SUCCESS;
|
||||
|
||||
if (bash_readline_initialized == 0)
|
||||
initialize_readline ();
|
||||
|
||||
begin_unwind_frame ("bind_builtin");
|
||||
unwind_protect_var (rl_outstream);
|
||||
|
||||
rl_outstream = stdout;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "lvpVPsSXf:q:u:m:r:x:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'l':
|
||||
flags |= LFLAG;
|
||||
break;
|
||||
case 'v':
|
||||
flags |= VFLAG;
|
||||
break;
|
||||
case 'p':
|
||||
flags |= PFLAG;
|
||||
break;
|
||||
case 'f':
|
||||
flags |= FFLAG;
|
||||
initfile = list_optarg;
|
||||
break;
|
||||
case 'm':
|
||||
flags |= MFLAG;
|
||||
map_name = list_optarg;
|
||||
break;
|
||||
case 'q':
|
||||
flags |= QFLAG;
|
||||
fun_name = list_optarg;
|
||||
break;
|
||||
case 'u':
|
||||
flags |= UFLAG;
|
||||
unbind_name = list_optarg;
|
||||
break;
|
||||
case 'r':
|
||||
flags |= RFLAG;
|
||||
remove_seq = list_optarg;
|
||||
break;
|
||||
case 'V':
|
||||
flags |= VVFLAG;
|
||||
break;
|
||||
case 'P':
|
||||
flags |= PPFLAG;
|
||||
break;
|
||||
case 's':
|
||||
flags |= SFLAG;
|
||||
break;
|
||||
case 'S':
|
||||
flags |= SSFLAG;
|
||||
break;
|
||||
case 'x':
|
||||
flags |= XFLAG;
|
||||
cmd_seq = list_optarg;
|
||||
break;
|
||||
case 'X':
|
||||
flags |= XXFLAG;
|
||||
break;
|
||||
case GETOPT_HELP:
|
||||
default:
|
||||
builtin_usage ();
|
||||
BIND_RETURN (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
/* First, see if we need to install a special keymap for this
|
||||
command. Then start on the arguments. */
|
||||
|
||||
if ((flags & MFLAG) && map_name)
|
||||
{
|
||||
kmap = rl_get_keymap_by_name (map_name);
|
||||
if (kmap == 0)
|
||||
{
|
||||
builtin_error (_("`%s': invalid keymap name"), map_name);
|
||||
BIND_RETURN (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (kmap)
|
||||
{
|
||||
saved_keymap = rl_get_keymap ();
|
||||
rl_set_keymap (kmap);
|
||||
}
|
||||
|
||||
/* XXX - we need to add exclusive use tests here. It doesn't make sense
|
||||
to use some of these options together. */
|
||||
/* Now hack the option arguments */
|
||||
if (flags & LFLAG)
|
||||
rl_list_funmap_names ();
|
||||
|
||||
if (flags & PFLAG)
|
||||
rl_function_dumper (1);
|
||||
|
||||
if (flags & PPFLAG)
|
||||
rl_function_dumper (0);
|
||||
|
||||
if (flags & SFLAG)
|
||||
rl_macro_dumper (1);
|
||||
|
||||
if (flags & SSFLAG)
|
||||
rl_macro_dumper (0);
|
||||
|
||||
if (flags & VFLAG)
|
||||
rl_variable_dumper (1);
|
||||
|
||||
if (flags & VVFLAG)
|
||||
rl_variable_dumper (0);
|
||||
|
||||
if ((flags & FFLAG) && initfile)
|
||||
{
|
||||
if (rl_read_init_file (initfile) != 0)
|
||||
{
|
||||
t = printable_filename (initfile, 0);
|
||||
builtin_error (_("%s: cannot read: %s"), t, strerror (errno));
|
||||
if (t != initfile)
|
||||
free (t);
|
||||
BIND_RETURN (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & QFLAG) && fun_name)
|
||||
return_code = query_bindings (fun_name);
|
||||
|
||||
if ((flags & UFLAG) && unbind_name)
|
||||
return_code = unbind_command (unbind_name);
|
||||
|
||||
if ((flags & RFLAG) && remove_seq)
|
||||
{
|
||||
opt = unbind_keyseq (remove_seq);
|
||||
BIND_RETURN (opt);
|
||||
}
|
||||
|
||||
if (flags & XFLAG)
|
||||
return_code = bind_keyseq_to_unix_command (cmd_seq);
|
||||
|
||||
if (flags & XXFLAG)
|
||||
return_code = print_unix_command_map ();
|
||||
|
||||
/* Process the rest of the arguments as binding specifications. */
|
||||
while (list)
|
||||
{
|
||||
int olen, nlen, d, i;
|
||||
char **obindings, **nbindings;
|
||||
|
||||
obindings = rl_invoking_keyseqs (bash_execute_unix_command);
|
||||
olen = obindings ? strvec_len (obindings) : 0;
|
||||
|
||||
rl_parse_and_bind (list->word->word);
|
||||
|
||||
nbindings = rl_invoking_keyseqs (bash_execute_unix_command);
|
||||
nlen = nbindings ? strvec_len (nbindings) : 0;
|
||||
|
||||
if (nlen < olen) /* fewer bind -x bindings */
|
||||
for (d = olen - nlen, i = 0; i < olen && d > 0; i++)
|
||||
if (nlen == 0 || strvec_search (nbindings, obindings[i]) < 0)
|
||||
{
|
||||
unbind_unix_command (obindings[i]);
|
||||
d--;
|
||||
}
|
||||
|
||||
strvec_dispose (obindings);
|
||||
strvec_dispose (nbindings);
|
||||
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
bind_exit:
|
||||
if (saved_keymap)
|
||||
rl_set_keymap (saved_keymap);
|
||||
|
||||
run_unwind_frame ("bind_builtin");
|
||||
|
||||
if (return_code < 0)
|
||||
return_code = EXECUTION_FAILURE;
|
||||
|
||||
return (sh_chkwrite (return_code));
|
||||
}
|
||||
|
||||
static int
|
||||
query_bindings (name)
|
||||
char *name;
|
||||
{
|
||||
rl_command_func_t *function;
|
||||
char **keyseqs;
|
||||
int j;
|
||||
|
||||
function = rl_named_function (name);
|
||||
if (function == 0)
|
||||
{
|
||||
builtin_error (_("`%s': unknown function name"), name);
|
||||
return EXECUTION_FAILURE;
|
||||
}
|
||||
|
||||
keyseqs = rl_invoking_keyseqs (function);
|
||||
|
||||
if (!keyseqs)
|
||||
{
|
||||
printf (_("%s is not bound to any keys.\n"), name);
|
||||
return EXECUTION_FAILURE;
|
||||
}
|
||||
|
||||
printf (_("%s can be invoked via "), name);
|
||||
for (j = 0; j < 5 && keyseqs[j]; j++)
|
||||
printf ("\"%s\"%s", keyseqs[j], keyseqs[j + 1] ? ", " : ".\n");
|
||||
if (keyseqs[j])
|
||||
printf ("...\n");
|
||||
strvec_dispose (keyseqs);
|
||||
return EXECUTION_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
unbind_command (name)
|
||||
char *name;
|
||||
{
|
||||
rl_command_func_t *function;
|
||||
|
||||
function = rl_named_function (name);
|
||||
if (function == 0)
|
||||
{
|
||||
builtin_error (_("`%s': unknown function name"), name);
|
||||
return EXECUTION_FAILURE;
|
||||
}
|
||||
|
||||
rl_unbind_function_in_map (function, rl_get_keymap ());
|
||||
return EXECUTION_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
unbind_keyseq (seq)
|
||||
char *seq;
|
||||
{
|
||||
char *kseq;
|
||||
int kslen, type;
|
||||
rl_command_func_t *f;
|
||||
|
||||
kseq = (char *)xmalloc ((2 * strlen (seq)) + 1);
|
||||
if (rl_translate_keyseq (seq, kseq, &kslen))
|
||||
{
|
||||
free (kseq);
|
||||
builtin_error (_("`%s': cannot unbind"), seq);
|
||||
return EXECUTION_FAILURE;
|
||||
}
|
||||
if ((f = rl_function_of_keyseq_len (kseq, kslen, (Keymap)0, &type)) == 0)
|
||||
{
|
||||
free (kseq);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
if (type == ISKMAP)
|
||||
f = ((Keymap) f)[ANYOTHERKEY].function;
|
||||
|
||||
/* I wish this didn't have to translate the key sequence again, but readline
|
||||
doesn't have a binding function that takes a translated key sequence as
|
||||
an argument. */
|
||||
if (rl_bind_keyseq (seq, (rl_command_func_t *)NULL) != 0)
|
||||
{
|
||||
free (kseq);
|
||||
builtin_error (_("`%s': cannot unbind"), seq);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (f == bash_execute_unix_command)
|
||||
unbind_unix_command (seq);
|
||||
|
||||
free (kseq);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
#endif /* READLINE */
|
104
third_party/bash/builtins_break.c
vendored
Normal file
104
third_party/bash/builtins_break.c
vendored
Normal file
|
@ -0,0 +1,104 @@
|
|||
/* break.c, created from break.def. */
|
||||
#line 22 "./break.def"
|
||||
|
||||
#line 34 "./break.def"
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "execute_cmd.h"
|
||||
#include "common.h"
|
||||
|
||||
static int check_loop_level PARAMS((void));
|
||||
|
||||
/* The depth of while's and until's. */
|
||||
int loop_level = 0;
|
||||
|
||||
/* Non-zero when a "break" instruction is encountered. */
|
||||
int breaking = 0;
|
||||
|
||||
/* Non-zero when we have encountered a continue instruction. */
|
||||
int continuing = 0;
|
||||
|
||||
/* Set up to break x levels, where x defaults to 1, but can be specified
|
||||
as the first argument. */
|
||||
int
|
||||
break_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
intmax_t newbreak;
|
||||
|
||||
CHECK_HELPOPT (list);
|
||||
|
||||
if (check_loop_level () == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
(void)get_numeric_arg (list, 1, &newbreak);
|
||||
|
||||
if (newbreak <= 0)
|
||||
{
|
||||
sh_erange (list->word->word, _("loop count"));
|
||||
breaking = loop_level;
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (newbreak > loop_level)
|
||||
newbreak = loop_level;
|
||||
|
||||
breaking = newbreak;
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
#line 101 "./break.def"
|
||||
|
||||
/* Set up to continue x levels, where x defaults to 1, but can be specified
|
||||
as the first argument. */
|
||||
int
|
||||
continue_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
intmax_t newcont;
|
||||
|
||||
CHECK_HELPOPT (list);
|
||||
|
||||
if (check_loop_level () == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
(void)get_numeric_arg (list, 1, &newcont);
|
||||
|
||||
if (newcont <= 0)
|
||||
{
|
||||
sh_erange (list->word->word, _("loop count"));
|
||||
breaking = loop_level;
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (newcont > loop_level)
|
||||
newcont = loop_level;
|
||||
|
||||
continuing = newcont;
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Return non-zero if a break or continue command would be okay.
|
||||
Print an error message if break or continue is meaningless here. */
|
||||
static int
|
||||
check_loop_level ()
|
||||
{
|
||||
#if defined (BREAK_COMPLAINS)
|
||||
if (loop_level == 0 && posixly_correct == 0)
|
||||
builtin_error (_("only meaningful in a `for', `while', or `until' loop"));
|
||||
#endif /* BREAK_COMPLAINS */
|
||||
|
||||
return (loop_level);
|
||||
}
|
54
third_party/bash/builtins_builtin.c
vendored
Normal file
54
third_party/bash/builtins_builtin.c
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
/* builtin.c, created from builtin.def. */
|
||||
#line 22 "./builtin.def"
|
||||
|
||||
#line 36 "./builtin.def"
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "shell.h"
|
||||
#include "execute_cmd.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
/* Run the command mentioned in list directly, without going through the
|
||||
normal alias/function/builtin/filename lookup process. */
|
||||
int
|
||||
builtin_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
sh_builtin_func_t *function;
|
||||
register char *command;
|
||||
|
||||
if (no_options (list))
|
||||
return (EX_USAGE);
|
||||
list = loptend; /* skip over possible `--' */
|
||||
|
||||
if (list == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
command = list->word->word;
|
||||
#if defined (DISABLED_BUILTINS)
|
||||
function = builtin_address (command);
|
||||
#else /* !DISABLED_BUILTINS */
|
||||
function = find_shell_builtin (command);
|
||||
#endif /* !DISABLED_BUILTINS */
|
||||
|
||||
if (function == 0)
|
||||
{
|
||||
sh_notbuiltin (command);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
this_command_name = command;
|
||||
this_shell_builtin = function; /* overwrite "builtin" as this builtin */
|
||||
list = list->next;
|
||||
return ((*function) (list));
|
||||
}
|
||||
}
|
120
third_party/bash/builtins_caller.c
vendored
Normal file
120
third_party/bash/builtins_caller.c
vendored
Normal file
|
@ -0,0 +1,120 @@
|
|||
/* caller.c, created from caller.def. */
|
||||
#line 23 "./caller.def"
|
||||
|
||||
#line 41 "./caller.def"
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include "chartypes.h"
|
||||
#include "bashtypes.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
#include "builtext.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#ifdef LOADABLE_BUILTIN
|
||||
# include "builtins.h"
|
||||
#endif
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
int
|
||||
caller_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
#if !defined (ARRAY_VARS)
|
||||
printf ("1 NULL\n");
|
||||
return (EXECUTION_FAILURE);
|
||||
#else
|
||||
SHELL_VAR *funcname_v, *bash_source_v, *bash_lineno_v;
|
||||
ARRAY *funcname_a, *bash_source_a, *bash_lineno_a;
|
||||
char *funcname_s, *source_s, *lineno_s;
|
||||
intmax_t num;
|
||||
|
||||
CHECK_HELPOPT (list);
|
||||
|
||||
GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a);
|
||||
GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a);
|
||||
GET_ARRAY_FROM_VAR ("BASH_LINENO", bash_lineno_v, bash_lineno_a);
|
||||
|
||||
if (bash_lineno_a == 0 || array_empty (bash_lineno_a))
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
if (bash_source_a == 0 || array_empty (bash_source_a))
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
if (no_options (list))
|
||||
return (EX_USAGE);
|
||||
list = loptend; /* skip over possible `--' */
|
||||
|
||||
/* If there is no argument list, then give short form: line filename. */
|
||||
if (list == 0)
|
||||
{
|
||||
lineno_s = array_reference (bash_lineno_a, 0);
|
||||
source_s = array_reference (bash_source_a, 1);
|
||||
printf("%s %s\n", lineno_s ? lineno_s : "NULL", source_s ? source_s : "NULL");
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
if (funcname_a == 0 || array_empty (funcname_a))
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
if (legal_number (list->word->word, &num))
|
||||
{
|
||||
lineno_s = array_reference (bash_lineno_a, num);
|
||||
source_s = array_reference (bash_source_a, num+1);
|
||||
funcname_s = array_reference (funcname_a, num+1);
|
||||
|
||||
if (lineno_s == NULL|| source_s == NULL || funcname_s == NULL)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
printf("%s %s %s\n", lineno_s, funcname_s, source_s);
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_invalidnum (list->word->word);
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef LOADABLE_BUILTIN
|
||||
static char *caller_doc[] = {
|
||||
N_("Returns the context of the current subroutine call.\n\
|
||||
\n\
|
||||
Without EXPR, returns \"$line $filename\". With EXPR, returns\n\
|
||||
\"$line $subroutine $filename\"; this extra information can be used to\n\
|
||||
provide a stack trace.\n\
|
||||
\n\
|
||||
The value of EXPR indicates how many call frames to go back before the\n\
|
||||
current one; the top frame is frame 0."),
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin caller_struct = {
|
||||
"caller",
|
||||
caller_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
caller_doc,
|
||||
"caller [EXPR]",
|
||||
0
|
||||
};
|
||||
|
||||
#endif /* LOADABLE_BUILTIN */
|
613
third_party/bash/builtins_cd.c
vendored
Normal file
613
third_party/bash/builtins_cd.c
vendored
Normal file
|
@ -0,0 +1,613 @@
|
|||
/* cd.c, created from cd.def. */
|
||||
#line 22 "./cd.def"
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashtypes.h"
|
||||
#include "posixdir.h"
|
||||
#include "posixstat.h"
|
||||
#if defined (HAVE_SYS_PARAM_H)
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include "tilde.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "flags.h"
|
||||
#include "maxpath.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
extern const char * const bash_getcwd_errstr;
|
||||
|
||||
static int bindpwd PARAMS((int));
|
||||
static int setpwd PARAMS((char *));
|
||||
static char *resetpwd PARAMS((char *));
|
||||
static int change_to_directory PARAMS((char *, int, int));
|
||||
|
||||
static int cdxattr PARAMS((char *, char **));
|
||||
static void resetxattr PARAMS((void));
|
||||
|
||||
/* Change this to 1 to get cd spelling correction by default. */
|
||||
int cdspelling = 0;
|
||||
|
||||
int cdable_vars;
|
||||
|
||||
static int eflag; /* file scope so bindpwd() can see it */
|
||||
static int xattrflag; /* O_XATTR support for openat */
|
||||
static int xattrfd = -1;
|
||||
|
||||
#line 115 "./cd.def"
|
||||
|
||||
/* Just set $PWD, don't change OLDPWD. Used by `pwd -P' in posix mode. */
|
||||
static int
|
||||
setpwd (dirname)
|
||||
char *dirname;
|
||||
{
|
||||
int old_anm;
|
||||
SHELL_VAR *tvar;
|
||||
|
||||
old_anm = array_needs_making;
|
||||
tvar = bind_variable ("PWD", dirname ? dirname : "", 0);
|
||||
if (tvar && readonly_p (tvar))
|
||||
return EXECUTION_FAILURE;
|
||||
if (tvar && old_anm == 0 && array_needs_making && exported_p (tvar))
|
||||
{
|
||||
update_export_env_inplace ("PWD=", 4, dirname ? dirname : "");
|
||||
array_needs_making = 0;
|
||||
}
|
||||
return EXECUTION_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
bindpwd (no_symlinks)
|
||||
int no_symlinks;
|
||||
{
|
||||
char *dirname, *pwdvar;
|
||||
int old_anm, r, canon_failed;
|
||||
SHELL_VAR *tvar;
|
||||
|
||||
r = sh_chkwrite (EXECUTION_SUCCESS);
|
||||
|
||||
#define tcwd the_current_working_directory
|
||||
dirname = tcwd ? (no_symlinks ? sh_physpath (tcwd, 0) : tcwd)
|
||||
: get_working_directory ("cd");
|
||||
#undef tcwd
|
||||
|
||||
/* If canonicalization fails, reset dirname to the_current_working_directory */
|
||||
canon_failed = 0;
|
||||
if (dirname == 0)
|
||||
{
|
||||
canon_failed = 1;
|
||||
dirname = the_current_working_directory;
|
||||
}
|
||||
|
||||
old_anm = array_needs_making;
|
||||
pwdvar = get_string_value ("PWD");
|
||||
|
||||
tvar = bind_variable ("OLDPWD", pwdvar, 0);
|
||||
if (tvar && readonly_p (tvar))
|
||||
r = EXECUTION_FAILURE;
|
||||
|
||||
if (old_anm == 0 && array_needs_making && exported_p (tvar))
|
||||
{
|
||||
update_export_env_inplace ("OLDPWD=", 7, pwdvar);
|
||||
array_needs_making = 0;
|
||||
}
|
||||
|
||||
if (setpwd (dirname) == EXECUTION_FAILURE)
|
||||
r = EXECUTION_FAILURE;
|
||||
if (canon_failed && eflag)
|
||||
r = EXECUTION_FAILURE;
|
||||
|
||||
if (dirname && dirname != the_current_working_directory)
|
||||
free (dirname);
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
||||
/* Call get_working_directory to reset the value of
|
||||
the_current_working_directory () */
|
||||
static char *
|
||||
resetpwd (caller)
|
||||
char *caller;
|
||||
{
|
||||
char *tdir;
|
||||
|
||||
FREE (the_current_working_directory);
|
||||
the_current_working_directory = (char *)NULL;
|
||||
tdir = get_working_directory (caller);
|
||||
return (tdir);
|
||||
}
|
||||
|
||||
static int
|
||||
cdxattr (dir, ndirp)
|
||||
char *dir; /* don't assume we can always free DIR */
|
||||
char **ndirp; /* return new constructed directory name */
|
||||
{
|
||||
#if defined (O_XATTR)
|
||||
int apfd, fd, r, e;
|
||||
char buf[11+40+40]; /* construct new `fake' path for pwd */
|
||||
|
||||
apfd = openat (AT_FDCWD, dir, O_RDONLY|O_NONBLOCK);
|
||||
if (apfd < 0)
|
||||
return -1;
|
||||
fd = openat (apfd, ".", O_XATTR);
|
||||
e = errno;
|
||||
close (apfd); /* ignore close error for now */
|
||||
errno = e;
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
r = fchdir (fd); /* assume fchdir exists everywhere with O_XATTR */
|
||||
if (r < 0)
|
||||
{
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
/* NFSv4 and ZFS extended attribute directories do not have names which are
|
||||
visible in the standard Unix directory tree structure. To ensure we have
|
||||
a valid name for $PWD, we synthesize one under /proc, but to keep that
|
||||
path valid, we need to keep the file descriptor open as long as we are in
|
||||
this directory. This imposes a certain structure on /proc. */
|
||||
if (ndirp)
|
||||
{
|
||||
sprintf (buf, "/proc/%d/fd/%d", getpid(), fd);
|
||||
*ndirp = savestring (buf);
|
||||
}
|
||||
|
||||
if (xattrfd >= 0)
|
||||
close (xattrfd);
|
||||
xattrfd = fd;
|
||||
|
||||
return r;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Clean up the O_XATTR baggage. Currently only closes xattrfd */
|
||||
static void
|
||||
resetxattr ()
|
||||
{
|
||||
#if defined (O_XATTR)
|
||||
if (xattrfd >= 0)
|
||||
{
|
||||
close (xattrfd);
|
||||
xattrfd = -1;
|
||||
}
|
||||
#else
|
||||
xattrfd = -1; /* not strictly necessary */
|
||||
#endif
|
||||
}
|
||||
|
||||
#define LCD_DOVARS 0x001
|
||||
#define LCD_DOSPELL 0x002
|
||||
#define LCD_PRINTPATH 0x004
|
||||
#define LCD_FREEDIRNAME 0x008
|
||||
|
||||
/* This builtin is ultimately the way that all user-visible commands should
|
||||
change the current working directory. It is called by cd_to_string (),
|
||||
so the programming interface is simple, and it handles errors and
|
||||
restrictions properly. */
|
||||
int
|
||||
cd_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *dirname, *cdpath, *path, *temp;
|
||||
int path_index, no_symlinks, opt, lflag, e;
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
if (restricted)
|
||||
{
|
||||
sh_restricted ((char *)NULL);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif /* RESTRICTED_SHELL */
|
||||
|
||||
eflag = 0;
|
||||
no_symlinks = no_symbolic_links;
|
||||
xattrflag = 0;
|
||||
reset_internal_getopt ();
|
||||
#if defined (O_XATTR)
|
||||
while ((opt = internal_getopt (list, "eLP@")) != -1)
|
||||
#else
|
||||
while ((opt = internal_getopt (list, "eLP")) != -1)
|
||||
#endif
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'P':
|
||||
no_symlinks = 1;
|
||||
break;
|
||||
case 'L':
|
||||
no_symlinks = 0;
|
||||
break;
|
||||
case 'e':
|
||||
eflag = 1;
|
||||
break;
|
||||
#if defined (O_XATTR)
|
||||
case '@':
|
||||
xattrflag = 1;
|
||||
break;
|
||||
#endif
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
lflag = (cdable_vars ? LCD_DOVARS : 0) |
|
||||
((interactive && cdspelling) ? LCD_DOSPELL : 0);
|
||||
if (eflag && no_symlinks == 0)
|
||||
eflag = 0;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
/* `cd' without arguments is equivalent to `cd $HOME' */
|
||||
dirname = get_string_value ("HOME");
|
||||
|
||||
if (dirname == 0)
|
||||
{
|
||||
builtin_error (_("HOME not set"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
lflag = 0;
|
||||
}
|
||||
#if defined (CD_COMPLAINS)
|
||||
else if (list->next)
|
||||
{
|
||||
builtin_error (_("too many arguments"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
else if (list->word->word[0] == '\0')
|
||||
{
|
||||
builtin_error (_("null directory"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif
|
||||
else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
|
||||
{
|
||||
/* This is `cd -', equivalent to `cd $OLDPWD' */
|
||||
dirname = get_string_value ("OLDPWD");
|
||||
|
||||
if (dirname == 0)
|
||||
{
|
||||
builtin_error (_("OLDPWD not set"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#if 0
|
||||
lflag = interactive ? LCD_PRINTPATH : 0;
|
||||
#else
|
||||
lflag = LCD_PRINTPATH; /* According to SUSv3 */
|
||||
#endif
|
||||
}
|
||||
else if (absolute_pathname (list->word->word))
|
||||
dirname = list->word->word;
|
||||
else if (privileged_mode == 0 && (cdpath = get_string_value ("CDPATH")))
|
||||
{
|
||||
dirname = list->word->word;
|
||||
|
||||
/* Find directory in $CDPATH. */
|
||||
path_index = 0;
|
||||
while (path = extract_colon_unit (cdpath, &path_index))
|
||||
{
|
||||
/* OPT is 1 if the path element is non-empty */
|
||||
opt = path[0] != '\0';
|
||||
temp = sh_makepath (path, dirname, MP_DOTILDE);
|
||||
free (path);
|
||||
|
||||
if (change_to_directory (temp, no_symlinks, xattrflag))
|
||||
{
|
||||
/* POSIX.2 says that if a nonempty directory from CDPATH
|
||||
is used to find the directory to change to, the new
|
||||
directory name is echoed to stdout, whether or not
|
||||
the shell is interactive. */
|
||||
if (opt && (path = no_symlinks ? temp : the_current_working_directory))
|
||||
printf ("%s\n", path);
|
||||
|
||||
free (temp);
|
||||
#if 0
|
||||
/* Posix.2 says that after using CDPATH, the resultant
|
||||
value of $PWD will not contain `.' or `..'. */
|
||||
return (bindpwd (posixly_correct || no_symlinks));
|
||||
#else
|
||||
return (bindpwd (no_symlinks));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
free (temp);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* changed for bash-4.2 Posix cd description steps 5-6 */
|
||||
/* POSIX.2 says that if `.' does not appear in $CDPATH, we don't
|
||||
try the current directory, so we just punt now with an error
|
||||
message if POSIXLY_CORRECT is non-zero. The check for cdpath[0]
|
||||
is so we don't mistakenly treat a CDPATH value of "" as not
|
||||
specifying the current directory. */
|
||||
if (posixly_correct && cdpath[0])
|
||||
{
|
||||
builtin_error ("%s: %s", dirname, strerror (ENOENT));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
dirname = list->word->word;
|
||||
|
||||
/* When we get here, DIRNAME is the directory to change to. If we
|
||||
chdir successfully, just return. */
|
||||
if (change_to_directory (dirname, no_symlinks, xattrflag))
|
||||
{
|
||||
if (lflag & LCD_PRINTPATH)
|
||||
printf ("%s\n", dirname);
|
||||
return (bindpwd (no_symlinks));
|
||||
}
|
||||
|
||||
/* If the user requests it, then perhaps this is the name of
|
||||
a shell variable, whose value contains the directory to
|
||||
change to. */
|
||||
if (lflag & LCD_DOVARS)
|
||||
{
|
||||
temp = get_string_value (dirname);
|
||||
if (temp && change_to_directory (temp, no_symlinks, xattrflag))
|
||||
{
|
||||
printf ("%s\n", temp);
|
||||
return (bindpwd (no_symlinks));
|
||||
}
|
||||
}
|
||||
|
||||
/* If the user requests it, try to find a directory name similar in
|
||||
spelling to the one requested, in case the user made a simple
|
||||
typo. This is similar to the UNIX 8th and 9th Edition shells. */
|
||||
if (lflag & LCD_DOSPELL)
|
||||
{
|
||||
temp = dirspell (dirname);
|
||||
if (temp && change_to_directory (temp, no_symlinks, xattrflag))
|
||||
{
|
||||
printf ("%s\n", temp);
|
||||
free (temp);
|
||||
return (bindpwd (no_symlinks));
|
||||
}
|
||||
else
|
||||
FREE (temp);
|
||||
}
|
||||
|
||||
e = errno;
|
||||
temp = printable_filename (dirname, 0);
|
||||
builtin_error ("%s: %s", temp, strerror (e));
|
||||
if (temp != dirname)
|
||||
free (temp);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
#line 478 "./cd.def"
|
||||
|
||||
/* Non-zero means that pwd always prints the physical directory, without
|
||||
symbolic links. */
|
||||
static int verbatim_pwd;
|
||||
|
||||
/* Print the name of the current working directory. */
|
||||
int
|
||||
pwd_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *directory;
|
||||
int opt, pflag;
|
||||
|
||||
verbatim_pwd = no_symbolic_links;
|
||||
pflag = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "LP")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'P':
|
||||
verbatim_pwd = pflag = 1;
|
||||
break;
|
||||
case 'L':
|
||||
verbatim_pwd = 0;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
#define tcwd the_current_working_directory
|
||||
|
||||
directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd)
|
||||
: get_working_directory ("pwd");
|
||||
|
||||
/* Try again using getcwd() if canonicalization fails (for instance, if
|
||||
the file system has changed state underneath bash). */
|
||||
if ((tcwd && directory == 0) ||
|
||||
(posixly_correct && same_file (".", tcwd, (struct stat *)0, (struct stat *)0) == 0))
|
||||
{
|
||||
if (directory && directory != tcwd)
|
||||
free (directory);
|
||||
directory = resetpwd ("pwd");
|
||||
}
|
||||
|
||||
#undef tcwd
|
||||
|
||||
if (directory)
|
||||
{
|
||||
opt = EXECUTION_SUCCESS;
|
||||
printf ("%s\n", directory);
|
||||
/* This is dumb but posix-mandated. */
|
||||
if (posixly_correct && pflag)
|
||||
opt = setpwd (directory);
|
||||
if (directory != the_current_working_directory)
|
||||
free (directory);
|
||||
return (sh_chkwrite (opt));
|
||||
}
|
||||
else
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* Do the work of changing to the directory NEWDIR. Handle symbolic
|
||||
link following, etc. This function *must* return with
|
||||
the_current_working_directory either set to NULL (in which case
|
||||
getcwd() will eventually be called), or set to a string corresponding
|
||||
to the working directory. Return 1 on success, 0 on failure. */
|
||||
|
||||
static int
|
||||
change_to_directory (newdir, nolinks, xattr)
|
||||
char *newdir;
|
||||
int nolinks, xattr;
|
||||
{
|
||||
char *t, *tdir, *ndir;
|
||||
int err, canon_failed, r, ndlen;
|
||||
|
||||
tdir = (char *)NULL;
|
||||
|
||||
if (the_current_working_directory == 0)
|
||||
{
|
||||
t = get_working_directory ("chdir");
|
||||
FREE (t);
|
||||
}
|
||||
|
||||
t = make_absolute (newdir, the_current_working_directory);
|
||||
|
||||
/* TDIR is either the canonicalized absolute pathname of NEWDIR
|
||||
(nolinks == 0) or the absolute physical pathname of NEWDIR
|
||||
(nolinks != 0). */
|
||||
tdir = nolinks ? sh_physpath (t, 0)
|
||||
: sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
|
||||
|
||||
ndlen = strlen (newdir);
|
||||
|
||||
/* Use the canonicalized version of NEWDIR, or, if canonicalization
|
||||
failed, use the non-canonical form. */
|
||||
canon_failed = 0;
|
||||
if (tdir && *tdir)
|
||||
free (t);
|
||||
else
|
||||
{
|
||||
FREE (tdir);
|
||||
tdir = t;
|
||||
canon_failed = 1;
|
||||
}
|
||||
|
||||
/* In POSIX mode, if we're resolving symlinks logically and sh_canonpath
|
||||
returns NULL (because it checks the path, it will return NULL if the
|
||||
resolved path doesn't exist), fail immediately. */
|
||||
#if defined (ENAMETOOLONG)
|
||||
if (posixly_correct && nolinks == 0 && canon_failed && (errno != ENAMETOOLONG || ndlen > PATH_MAX))
|
||||
#else
|
||||
if (posixly_correct && nolinks == 0 && canon_failed && ndlen > PATH_MAX)
|
||||
#endif
|
||||
{
|
||||
#if defined ENAMETOOLONG
|
||||
if (errno != ENOENT && errno != ENAMETOOLONG)
|
||||
#else
|
||||
if (errno != ENOENT)
|
||||
#endif
|
||||
errno = ENOTDIR;
|
||||
free (tdir);
|
||||
return (0);
|
||||
}
|
||||
|
||||
#if defined (O_XATTR)
|
||||
if (xattrflag)
|
||||
{
|
||||
r = cdxattr (nolinks ? newdir : tdir, &ndir);
|
||||
if (r >= 0)
|
||||
{
|
||||
canon_failed = 0;
|
||||
free (tdir);
|
||||
tdir = ndir;
|
||||
}
|
||||
else
|
||||
{
|
||||
err = errno;
|
||||
free (tdir);
|
||||
errno = err;
|
||||
return (0); /* no xattr */
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
r = chdir (nolinks ? newdir : tdir);
|
||||
if (r >= 0)
|
||||
resetxattr ();
|
||||
}
|
||||
|
||||
/* If the chdir succeeds, update the_current_working_directory. */
|
||||
if (r == 0)
|
||||
{
|
||||
/* If canonicalization failed, but the chdir succeeded, reset the
|
||||
shell's idea of the_current_working_directory. */
|
||||
if (canon_failed)
|
||||
{
|
||||
t = resetpwd ("cd");
|
||||
if (t == 0)
|
||||
set_working_directory (tdir);
|
||||
else
|
||||
free (t);
|
||||
}
|
||||
else
|
||||
set_working_directory (tdir);
|
||||
|
||||
free (tdir);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* We failed to change to the appropriate directory name. If we tried
|
||||
what the user passed (nolinks != 0), punt now. */
|
||||
if (nolinks)
|
||||
{
|
||||
free (tdir);
|
||||
return (0);
|
||||
}
|
||||
|
||||
err = errno;
|
||||
|
||||
/* We're not in physical mode (nolinks == 0), but we failed to change to
|
||||
the canonicalized directory name (TDIR). Try what the user passed
|
||||
verbatim. If we succeed, reinitialize the_current_working_directory.
|
||||
POSIX requires that we just fail here, so we do in posix mode. */
|
||||
if (posixly_correct == 0 && chdir (newdir) == 0)
|
||||
{
|
||||
t = resetpwd ("cd");
|
||||
if (t == 0)
|
||||
set_working_directory (tdir);
|
||||
else
|
||||
free (t);
|
||||
|
||||
r = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = err;
|
||||
r = 0;
|
||||
}
|
||||
|
||||
free (tdir);
|
||||
return r;
|
||||
}
|
33
third_party/bash/builtins_colon.c
vendored
Normal file
33
third_party/bash/builtins_colon.c
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* colon.c, created from colon.def. */
|
||||
#line 22 "./colon.def"
|
||||
|
||||
#line 34 "./colon.def"
|
||||
|
||||
#line 43 "./colon.def"
|
||||
|
||||
#line 52 "./colon.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "shell.h"
|
||||
|
||||
/* Return a successful result. */
|
||||
int
|
||||
colon_builtin (ignore)
|
||||
WORD_LIST *ignore;
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Return an unsuccessful result. */
|
||||
int
|
||||
false_builtin (ignore)
|
||||
WORD_LIST *ignore;
|
||||
{
|
||||
return (1);
|
||||
}
|
107
third_party/bash/builtins_command.c
vendored
Normal file
107
third_party/bash/builtins_command.c
vendored
Normal file
|
@ -0,0 +1,107 @@
|
|||
/* command.c, created from command.def. */
|
||||
#line 22 "./command.def"
|
||||
|
||||
#line 41 "./command.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "execute_cmd.h"
|
||||
#include "flags.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#if defined (_CS_PATH) && defined (HAVE_CONFSTR) && !HAVE_DECL_CONFSTR
|
||||
extern size_t confstr PARAMS((int, char *, size_t));
|
||||
#endif
|
||||
|
||||
/* Run the commands mentioned in LIST without paying attention to shell
|
||||
functions. */
|
||||
int
|
||||
command_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int result, verbose, use_standard_path, opt;
|
||||
COMMAND *command;
|
||||
|
||||
verbose = use_standard_path = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "pvV")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'p':
|
||||
use_standard_path = CDESC_STDPATH;
|
||||
break;
|
||||
case 'V':
|
||||
verbose = CDESC_SHORTDESC|CDESC_ABSPATH; /* look in common.h for constants */
|
||||
break;
|
||||
case 'v':
|
||||
verbose = CDESC_REUSABLE; /* ditto */
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
if (use_standard_path && restricted)
|
||||
{
|
||||
sh_restricted ("-p");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
int found, any_found;
|
||||
|
||||
for (any_found = 0; list; list = list->next)
|
||||
{
|
||||
found = describe_command (list->word->word, verbose|use_standard_path);
|
||||
|
||||
if (found == 0 && verbose != CDESC_REUSABLE)
|
||||
sh_notfound (list->word->word);
|
||||
|
||||
any_found += found;
|
||||
}
|
||||
|
||||
return (any_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
begin_unwind_frame ("command_builtin");
|
||||
|
||||
#define COMMAND_BUILTIN_FLAGS (CMD_NO_FUNCTIONS | CMD_INHIBIT_EXPANSION | CMD_COMMAND_BUILTIN | (use_standard_path ? CMD_STDPATH : 0))
|
||||
|
||||
INTERNAL_DEBUG (("command_builtin: running execute_command for `%s'", list->word->word));
|
||||
|
||||
/* We don't want this to be reparsed (consider command echo 'foo &'), so
|
||||
just make a simple_command structure and call execute_command with it. */
|
||||
command = make_bare_simple_command ();
|
||||
command->value.Simple->words = (WORD_LIST *)copy_word_list (list);
|
||||
command->value.Simple->redirects = (REDIRECT *)NULL;
|
||||
command->flags |= COMMAND_BUILTIN_FLAGS;
|
||||
command->value.Simple->flags |= COMMAND_BUILTIN_FLAGS;
|
||||
|
||||
add_unwind_protect ((char *)dispose_command, command);
|
||||
result = execute_command (command);
|
||||
|
||||
run_unwind_frame ("command_builtin");
|
||||
|
||||
return (result);
|
||||
}
|
805
third_party/bash/builtins_complete.c
vendored
Normal file
805
third_party/bash/builtins_complete.c
vendored
Normal file
|
@ -0,0 +1,805 @@
|
|||
/* complete.c, created from complete.def. */
|
||||
#line 22 "./complete.def"
|
||||
|
||||
#line 51 "./complete.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bashtypes.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "builtins.h"
|
||||
#include "pcomplete.h"
|
||||
#include "bashline.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#include "third_party/readline/readline.h"
|
||||
|
||||
#define STRDUP(x) ((x) ? savestring (x) : (char *)NULL)
|
||||
|
||||
/* Structure containing all the non-action (binary) options; filled in by
|
||||
build_actions(). */
|
||||
struct _optflags {
|
||||
int pflag;
|
||||
int rflag;
|
||||
int Dflag;
|
||||
int Eflag;
|
||||
int Iflag;
|
||||
};
|
||||
|
||||
static int find_compact PARAMS((char *));
|
||||
static int find_compopt PARAMS((char *));
|
||||
|
||||
static int build_actions PARAMS((WORD_LIST *, struct _optflags *, unsigned long *, unsigned long *));
|
||||
|
||||
static int remove_cmd_completions PARAMS((WORD_LIST *));
|
||||
|
||||
static int print_one_completion PARAMS((char *, COMPSPEC *));
|
||||
static int print_compitem PARAMS((BUCKET_CONTENTS *));
|
||||
static void print_compopts PARAMS((const char *, COMPSPEC *, int));
|
||||
static void print_all_completions PARAMS((void));
|
||||
static int print_cmd_completions PARAMS((WORD_LIST *));
|
||||
|
||||
static void print_compoptions PARAMS((unsigned long, int));
|
||||
static void print_compactions PARAMS((unsigned long));
|
||||
static void print_arg PARAMS((const char *, const char *, int));
|
||||
static void print_cmd_name PARAMS((const char *));
|
||||
|
||||
static char *Garg, *Warg, *Parg, *Sarg, *Xarg, *Farg, *Carg;
|
||||
|
||||
static const struct _compacts {
|
||||
const char * const actname;
|
||||
unsigned long actflag;
|
||||
int actopt;
|
||||
} compacts[] = {
|
||||
{ "alias", CA_ALIAS, 'a' },
|
||||
{ "arrayvar", CA_ARRAYVAR, 0 },
|
||||
{ "binding", CA_BINDING, 0 },
|
||||
{ "builtin", CA_BUILTIN, 'b' },
|
||||
{ "command", CA_COMMAND, 'c' },
|
||||
{ "directory", CA_DIRECTORY, 'd' },
|
||||
{ "disabled", CA_DISABLED, 0 },
|
||||
{ "enabled", CA_ENABLED, 0 },
|
||||
{ "export", CA_EXPORT, 'e' },
|
||||
{ "file", CA_FILE, 'f' },
|
||||
{ "function", CA_FUNCTION, 0 },
|
||||
{ "helptopic", CA_HELPTOPIC, 0 },
|
||||
{ "hostname", CA_HOSTNAME, 0 },
|
||||
{ "group", CA_GROUP, 'g' },
|
||||
{ "job", CA_JOB, 'j' },
|
||||
{ "keyword", CA_KEYWORD, 'k' },
|
||||
{ "running", CA_RUNNING, 0 },
|
||||
{ "service", CA_SERVICE, 's' },
|
||||
{ "setopt", CA_SETOPT, 0 },
|
||||
{ "shopt", CA_SHOPT, 0 },
|
||||
{ "signal", CA_SIGNAL, 0 },
|
||||
{ "stopped", CA_STOPPED, 0 },
|
||||
{ "user", CA_USER, 'u' },
|
||||
{ "variable", CA_VARIABLE, 'v' },
|
||||
{ (char *)NULL, 0, 0 },
|
||||
};
|
||||
|
||||
/* This should be a STRING_INT_ALIST */
|
||||
static const struct _compopt {
|
||||
const char * const optname;
|
||||
unsigned long optflag;
|
||||
} compopts[] = {
|
||||
{ "bashdefault", COPT_BASHDEFAULT },
|
||||
{ "default", COPT_DEFAULT },
|
||||
{ "dirnames", COPT_DIRNAMES },
|
||||
{ "filenames",COPT_FILENAMES},
|
||||
{ "noquote", COPT_NOQUOTE },
|
||||
{ "nosort", COPT_NOSORT },
|
||||
{ "nospace", COPT_NOSPACE },
|
||||
{ "plusdirs", COPT_PLUSDIRS },
|
||||
{ (char *)NULL, 0 },
|
||||
};
|
||||
|
||||
static int
|
||||
find_compact (name)
|
||||
char *name;
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; compacts[i].actname; i++)
|
||||
if (STREQ (name, compacts[i].actname))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
find_compopt (name)
|
||||
char *name;
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; compopts[i].optname; i++)
|
||||
if (STREQ (name, compopts[i].optname))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Build the actions and compspec options from the options specified in LIST.
|
||||
ACTP is a pointer to an unsigned long in which to place the bitmap of
|
||||
actions. OPTP is a pointer to an unsigned long in which to place the
|
||||
bitmap of compspec options (arguments to `-o'). PP, if non-null, gets 1
|
||||
if -p is supplied; RP, if non-null, gets 1 if -r is supplied.
|
||||
If either is null, the corresponding option generates an error.
|
||||
This also sets variables corresponding to options that take arguments as
|
||||
a side effect; the caller should ensure that those variables are set to
|
||||
NULL before calling build_actions. Return value:
|
||||
EX_USAGE = bad option
|
||||
EXECUTION_SUCCESS = some options supplied
|
||||
EXECUTION_FAILURE = no options supplied
|
||||
*/
|
||||
|
||||
static int
|
||||
build_actions (list, flagp, actp, optp)
|
||||
WORD_LIST *list;
|
||||
struct _optflags *flagp;
|
||||
unsigned long *actp, *optp;
|
||||
{
|
||||
int opt, ind, opt_given;
|
||||
unsigned long acts, copts;
|
||||
WORD_DESC w;
|
||||
|
||||
acts = copts = (unsigned long)0L;
|
||||
opt_given = 0;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "abcdefgjko:prsuvA:G:W:P:S:X:F:C:DEI")) != -1)
|
||||
{
|
||||
opt_given = 1;
|
||||
switch (opt)
|
||||
{
|
||||
case 'r':
|
||||
if (flagp)
|
||||
{
|
||||
flagp->rflag = 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_invalidopt ("-r");
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
case 'p':
|
||||
if (flagp)
|
||||
{
|
||||
flagp->pflag = 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_invalidopt ("-p");
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
case 'a':
|
||||
acts |= CA_ALIAS;
|
||||
break;
|
||||
case 'b':
|
||||
acts |= CA_BUILTIN;
|
||||
break;
|
||||
case 'c':
|
||||
acts |= CA_COMMAND;
|
||||
break;
|
||||
case 'd':
|
||||
acts |= CA_DIRECTORY;
|
||||
break;
|
||||
case 'e':
|
||||
acts |= CA_EXPORT;
|
||||
break;
|
||||
case 'f':
|
||||
acts |= CA_FILE;
|
||||
break;
|
||||
case 'g':
|
||||
acts |= CA_GROUP;
|
||||
break;
|
||||
case 'j':
|
||||
acts |= CA_JOB;
|
||||
break;
|
||||
case 'k':
|
||||
acts |= CA_KEYWORD;
|
||||
break;
|
||||
case 's':
|
||||
acts |= CA_SERVICE;
|
||||
break;
|
||||
case 'u':
|
||||
acts |= CA_USER;
|
||||
break;
|
||||
case 'v':
|
||||
acts |= CA_VARIABLE;
|
||||
break;
|
||||
case 'o':
|
||||
ind = find_compopt (list_optarg);
|
||||
if (ind < 0)
|
||||
{
|
||||
sh_invalidoptname (list_optarg);
|
||||
return (EX_USAGE);
|
||||
}
|
||||
copts |= compopts[ind].optflag;
|
||||
break;
|
||||
case 'A':
|
||||
ind = find_compact (list_optarg);
|
||||
if (ind < 0)
|
||||
{
|
||||
builtin_error (_("%s: invalid action name"), list_optarg);
|
||||
return (EX_USAGE);
|
||||
}
|
||||
acts |= compacts[ind].actflag;
|
||||
break;
|
||||
case 'C':
|
||||
Carg = list_optarg;
|
||||
break;
|
||||
case 'D':
|
||||
if (flagp)
|
||||
{
|
||||
flagp->Dflag = 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_invalidopt ("-D");
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
case 'E':
|
||||
if (flagp)
|
||||
{
|
||||
flagp->Eflag = 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_invalidopt ("-E");
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
case 'I':
|
||||
if (flagp)
|
||||
{
|
||||
flagp->Iflag = 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_invalidopt ("-I");
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
case 'F':
|
||||
w.word = Farg = list_optarg;
|
||||
w.flags = 0;
|
||||
if (check_identifier (&w, posixly_correct) == 0 || strpbrk (Farg, shell_break_chars) != 0)
|
||||
{
|
||||
sh_invalidid (Farg);
|
||||
return (EX_USAGE);
|
||||
}
|
||||
break;
|
||||
case 'G':
|
||||
Garg = list_optarg;
|
||||
break;
|
||||
case 'P':
|
||||
Parg = list_optarg;
|
||||
break;
|
||||
case 'S':
|
||||
Sarg = list_optarg;
|
||||
break;
|
||||
case 'W':
|
||||
Warg = list_optarg;
|
||||
break;
|
||||
case 'X':
|
||||
Xarg = list_optarg;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
*actp = acts;
|
||||
*optp = copts;
|
||||
|
||||
return (opt_given ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* Add, remove, and display completion specifiers. */
|
||||
int
|
||||
complete_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt_given, rval;
|
||||
unsigned long acts, copts;
|
||||
COMPSPEC *cs;
|
||||
struct _optflags oflags;
|
||||
WORD_LIST *l, *wl;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
print_all_completions ();
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
opt_given = oflags.pflag = oflags.rflag = 0;
|
||||
oflags.Dflag = oflags.Eflag = oflags.Iflag = 0;
|
||||
|
||||
acts = copts = (unsigned long)0L;
|
||||
Garg = Warg = Parg = Sarg = Xarg = Farg = Carg = (char *)NULL;
|
||||
cs = (COMPSPEC *)NULL;
|
||||
|
||||
/* Build the actions from the arguments. Also sets the [A-Z]arg variables
|
||||
as a side effect if they are supplied as options. */
|
||||
rval = build_actions (list, &oflags, &acts, &copts);
|
||||
if (rval == EX_USAGE)
|
||||
return (rval);
|
||||
opt_given = rval != EXECUTION_FAILURE;
|
||||
|
||||
list = loptend;
|
||||
|
||||
if (oflags.Dflag)
|
||||
wl = make_word_list (make_bare_word (DEFAULTCMD), (WORD_LIST *)NULL);
|
||||
else if (oflags.Eflag)
|
||||
wl = make_word_list (make_bare_word (EMPTYCMD), (WORD_LIST *)NULL);
|
||||
else if (oflags.Iflag)
|
||||
wl = make_word_list (make_bare_word (INITIALWORD), (WORD_LIST *)NULL);
|
||||
else
|
||||
wl = (WORD_LIST *)NULL;
|
||||
|
||||
/* -p overrides everything else */
|
||||
if (oflags.pflag || (list == 0 && opt_given == 0))
|
||||
{
|
||||
if (wl)
|
||||
{
|
||||
rval = print_cmd_completions (wl);
|
||||
dispose_words (wl);
|
||||
return rval;
|
||||
}
|
||||
else if (list == 0)
|
||||
{
|
||||
print_all_completions ();
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
return (print_cmd_completions (list));
|
||||
}
|
||||
|
||||
/* next, -r overrides everything else. */
|
||||
if (oflags.rflag)
|
||||
{
|
||||
if (wl)
|
||||
{
|
||||
rval = remove_cmd_completions (wl);
|
||||
dispose_words (wl);
|
||||
return rval;
|
||||
}
|
||||
else if (list == 0)
|
||||
{
|
||||
progcomp_flush ();
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
return (remove_cmd_completions (list));
|
||||
}
|
||||
|
||||
if (wl == 0 && list == 0 && opt_given)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
/* If we get here, we need to build a compspec and add it for each
|
||||
remaining argument. */
|
||||
cs = compspec_create ();
|
||||
cs->actions = acts;
|
||||
cs->options = copts;
|
||||
|
||||
cs->globpat = STRDUP (Garg);
|
||||
cs->words = STRDUP (Warg);
|
||||
cs->prefix = STRDUP (Parg);
|
||||
cs->suffix = STRDUP (Sarg);
|
||||
cs->funcname = STRDUP (Farg);
|
||||
cs->command = STRDUP (Carg);
|
||||
cs->filterpat = STRDUP (Xarg);
|
||||
|
||||
for (rval = EXECUTION_SUCCESS, l = wl ? wl : list ; l; l = l->next)
|
||||
{
|
||||
/* Add CS as the compspec for the specified commands. */
|
||||
if (progcomp_insert (l->word->word, cs) == 0)
|
||||
rval = EXECUTION_FAILURE;
|
||||
}
|
||||
|
||||
dispose_words (wl);
|
||||
return (rval);
|
||||
}
|
||||
|
||||
static int
|
||||
remove_cmd_completions (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
WORD_LIST *l;
|
||||
int ret;
|
||||
|
||||
for (ret = EXECUTION_SUCCESS, l = list; l; l = l->next)
|
||||
{
|
||||
if (progcomp_remove (l->word->word) == 0)
|
||||
{
|
||||
builtin_error (_("%s: no completion specification"), l->word->word);
|
||||
ret = EXECUTION_FAILURE;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
print_compoptions (copts, full)
|
||||
unsigned long copts;
|
||||
int full;
|
||||
{
|
||||
const struct _compopt *co;
|
||||
|
||||
for (co = compopts; co->optname; co++)
|
||||
if (copts & co->optflag)
|
||||
printf ("-o %s ", co->optname);
|
||||
else if (full)
|
||||
printf ("+o %s ", co->optname);
|
||||
}
|
||||
|
||||
static void
|
||||
print_compactions (acts)
|
||||
unsigned long acts;
|
||||
{
|
||||
const struct _compacts *ca;
|
||||
|
||||
/* simple flags first */
|
||||
for (ca = compacts; ca->actname; ca++)
|
||||
if (ca->actopt && (acts & ca->actflag))
|
||||
printf ("-%c ", ca->actopt);
|
||||
|
||||
/* then the rest of the actions */
|
||||
for (ca = compacts; ca->actname; ca++)
|
||||
if (ca->actopt == 0 && (acts & ca->actflag))
|
||||
printf ("-A %s ", ca->actname);
|
||||
}
|
||||
|
||||
static void
|
||||
print_arg (arg, flag, quote)
|
||||
const char *arg, *flag;
|
||||
int quote;
|
||||
{
|
||||
char *x;
|
||||
|
||||
if (arg)
|
||||
{
|
||||
x = quote ? sh_single_quote (arg) : (char *)arg;
|
||||
printf ("%s %s ", flag, x);
|
||||
if (x != arg)
|
||||
free (x);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_cmd_name (cmd)
|
||||
const char *cmd;
|
||||
{
|
||||
char *x;
|
||||
|
||||
if (STREQ (cmd, DEFAULTCMD))
|
||||
printf ("-D");
|
||||
else if (STREQ (cmd, EMPTYCMD))
|
||||
printf ("-E");
|
||||
else if (STREQ (cmd, INITIALWORD))
|
||||
printf ("-I");
|
||||
else if (*cmd == 0) /* XXX - can this happen? */
|
||||
printf ("''");
|
||||
else if (sh_contains_shell_metas (cmd))
|
||||
{
|
||||
x = sh_single_quote (cmd);
|
||||
printf ("%s", x);
|
||||
free (x);
|
||||
}
|
||||
else
|
||||
printf ("%s", cmd);
|
||||
}
|
||||
|
||||
static int
|
||||
print_one_completion (cmd, cs)
|
||||
char *cmd;
|
||||
COMPSPEC *cs;
|
||||
{
|
||||
printf ("complete ");
|
||||
|
||||
print_compoptions (cs->options, 0);
|
||||
print_compactions (cs->actions);
|
||||
|
||||
/* now the rest of the arguments */
|
||||
|
||||
/* arguments that require quoting */
|
||||
print_arg (cs->globpat, "-G", 1);
|
||||
print_arg (cs->words, "-W", 1);
|
||||
print_arg (cs->prefix, "-P", 1);
|
||||
print_arg (cs->suffix, "-S", 1);
|
||||
print_arg (cs->filterpat, "-X", 1);
|
||||
|
||||
print_arg (cs->command, "-C", 1);
|
||||
|
||||
/* simple arguments that don't require quoting */
|
||||
print_arg (cs->funcname, "-F", sh_contains_shell_metas (cs->funcname) != 0);
|
||||
|
||||
print_cmd_name (cmd);
|
||||
printf ("\n");
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
print_compopts (cmd, cs, full)
|
||||
const char *cmd;
|
||||
COMPSPEC *cs;
|
||||
int full;
|
||||
{
|
||||
printf ("compopt ");
|
||||
|
||||
print_compoptions (cs->options, full);
|
||||
print_cmd_name (cmd);
|
||||
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
static int
|
||||
print_compitem (item)
|
||||
BUCKET_CONTENTS *item;
|
||||
{
|
||||
COMPSPEC *cs;
|
||||
char *cmd;
|
||||
|
||||
cmd = item->key;
|
||||
cs = (COMPSPEC *)item->data;
|
||||
|
||||
return (print_one_completion (cmd, cs));
|
||||
}
|
||||
|
||||
static void
|
||||
print_all_completions ()
|
||||
{
|
||||
progcomp_walk (print_compitem);
|
||||
}
|
||||
|
||||
static int
|
||||
print_cmd_completions (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
WORD_LIST *l;
|
||||
COMPSPEC *cs;
|
||||
int ret;
|
||||
|
||||
for (ret = EXECUTION_SUCCESS, l = list; l; l = l->next)
|
||||
{
|
||||
cs = progcomp_search (l->word->word);
|
||||
if (cs)
|
||||
print_one_completion (l->word->word, cs);
|
||||
else
|
||||
{
|
||||
builtin_error (_("%s: no completion specification"), l->word->word);
|
||||
ret = EXECUTION_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return (sh_chkwrite (ret));
|
||||
}
|
||||
|
||||
#line 663 "./complete.def"
|
||||
|
||||
int
|
||||
compgen_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int rval;
|
||||
unsigned long acts, copts;
|
||||
COMPSPEC *cs;
|
||||
STRINGLIST *sl;
|
||||
char *word, **matches;
|
||||
char *old_line;
|
||||
int old_ind;
|
||||
|
||||
if (list == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
acts = copts = (unsigned long)0L;
|
||||
Garg = Warg = Parg = Sarg = Xarg = Farg = Carg = (char *)NULL;
|
||||
cs = (COMPSPEC *)NULL;
|
||||
|
||||
/* Build the actions from the arguments. Also sets the [A-Z]arg variables
|
||||
as a side effect if they are supplied as options. */
|
||||
rval = build_actions (list, (struct _optflags *)NULL, &acts, &copts);
|
||||
if (rval == EX_USAGE)
|
||||
return (rval);
|
||||
if (rval == EXECUTION_FAILURE)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
list = loptend;
|
||||
|
||||
word = (list && list->word) ? list->word->word : "";
|
||||
|
||||
if (Farg)
|
||||
builtin_error (_("warning: -F option may not work as you expect"));
|
||||
if (Carg)
|
||||
builtin_error (_("warning: -C option may not work as you expect"));
|
||||
|
||||
/* If we get here, we need to build a compspec and evaluate it. */
|
||||
cs = compspec_create ();
|
||||
cs->actions = acts;
|
||||
cs->options = copts;
|
||||
cs->refcount = 1;
|
||||
|
||||
cs->globpat = STRDUP (Garg);
|
||||
cs->words = STRDUP (Warg);
|
||||
cs->prefix = STRDUP (Parg);
|
||||
cs->suffix = STRDUP (Sarg);
|
||||
cs->funcname = STRDUP (Farg);
|
||||
cs->command = STRDUP (Carg);
|
||||
cs->filterpat = STRDUP (Xarg);
|
||||
|
||||
rval = EXECUTION_FAILURE;
|
||||
|
||||
/* probably don't have to save these, just being safe */
|
||||
old_line = pcomp_line;
|
||||
old_ind = pcomp_ind;
|
||||
pcomp_line = (char *)NULL;
|
||||
pcomp_ind = 0;
|
||||
sl = gen_compspec_completions (cs, "compgen", word, 0, 0, 0);
|
||||
pcomp_line = old_line;
|
||||
pcomp_ind = old_ind;
|
||||
|
||||
/* If the compspec wants the bash default completions, temporarily
|
||||
turn off programmable completion and call the bash completion code. */
|
||||
if ((sl == 0 || sl->list_len == 0) && (copts & COPT_BASHDEFAULT))
|
||||
{
|
||||
matches = bash_default_completion (word, 0, 0, 0, 0);
|
||||
sl = completions_to_stringlist (matches);
|
||||
strvec_dispose (matches);
|
||||
}
|
||||
|
||||
/* This isn't perfect, but it's the best we can do, given what readline
|
||||
exports from its set of completion utility functions. */
|
||||
if ((sl == 0 || sl->list_len == 0) && (copts & COPT_DEFAULT))
|
||||
{
|
||||
matches = rl_completion_matches (word, rl_filename_completion_function);
|
||||
strlist_dispose (sl);
|
||||
sl = completions_to_stringlist (matches);
|
||||
strvec_dispose (matches);
|
||||
}
|
||||
|
||||
if (sl)
|
||||
{
|
||||
if (sl->list && sl->list_len)
|
||||
{
|
||||
rval = EXECUTION_SUCCESS;
|
||||
strlist_print (sl, (char *)NULL);
|
||||
}
|
||||
strlist_dispose (sl);
|
||||
}
|
||||
|
||||
compspec_dispose (cs);
|
||||
return (rval);
|
||||
}
|
||||
|
||||
#line 788 "./complete.def"
|
||||
|
||||
int
|
||||
compopt_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opts_on, opts_off, *opts, opt, oind, ret, Dflag, Eflag, Iflag;
|
||||
WORD_LIST *l, *wl;
|
||||
COMPSPEC *cs;
|
||||
|
||||
opts_on = opts_off = Eflag = Dflag = Iflag = 0;
|
||||
ret = EXECUTION_SUCCESS;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "+o:DEI")) != -1)
|
||||
{
|
||||
opts = (list_opttype == '-') ? &opts_on : &opts_off;
|
||||
|
||||
switch (opt)
|
||||
{
|
||||
case 'o':
|
||||
oind = find_compopt (list_optarg);
|
||||
if (oind < 0)
|
||||
{
|
||||
sh_invalidoptname (list_optarg);
|
||||
return (EX_USAGE);
|
||||
}
|
||||
*opts |= compopts[oind].optflag;
|
||||
break;
|
||||
case 'D':
|
||||
Dflag = 1;
|
||||
break;
|
||||
case 'E':
|
||||
Eflag = 1;
|
||||
break;
|
||||
case 'I':
|
||||
Iflag = 1;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (Dflag)
|
||||
wl = make_word_list (make_bare_word (DEFAULTCMD), (WORD_LIST *)NULL);
|
||||
else if (Eflag)
|
||||
wl = make_word_list (make_bare_word (EMPTYCMD), (WORD_LIST *)NULL);
|
||||
else if (Iflag)
|
||||
wl = make_word_list (make_bare_word (INITIALWORD), (WORD_LIST *)NULL);
|
||||
else
|
||||
wl = (WORD_LIST *)NULL;
|
||||
|
||||
if (list == 0 && wl == 0)
|
||||
{
|
||||
if (RL_ISSTATE (RL_STATE_COMPLETING) == 0 || pcomp_curcs == 0)
|
||||
{
|
||||
builtin_error (_("not currently executing completion function"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
cs = pcomp_curcs;
|
||||
|
||||
if (opts_on == 0 && opts_off == 0)
|
||||
{
|
||||
print_compopts (pcomp_curcmd, cs, 1);
|
||||
return (sh_chkwrite (ret));
|
||||
}
|
||||
|
||||
/* Set the compspec options */
|
||||
pcomp_set_compspec_options (cs, opts_on, 1);
|
||||
pcomp_set_compspec_options (cs, opts_off, 0);
|
||||
|
||||
/* And change the readline variables the options control */
|
||||
pcomp_set_readline_variables (opts_on, 1);
|
||||
pcomp_set_readline_variables (opts_off, 0);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
for (l = wl ? wl : list; l; l = l->next)
|
||||
{
|
||||
cs = progcomp_search (l->word->word);
|
||||
if (cs == 0)
|
||||
{
|
||||
builtin_error (_("%s: no completion specification"), l->word->word);
|
||||
ret = EXECUTION_FAILURE;
|
||||
continue;
|
||||
}
|
||||
if (opts_on == 0 && opts_off == 0)
|
||||
{
|
||||
print_compopts (l->word->word, cs, 1);
|
||||
continue; /* XXX -- fill in later */
|
||||
}
|
||||
|
||||
/* Set the compspec options */
|
||||
pcomp_set_compspec_options (cs, opts_on, 1);
|
||||
pcomp_set_compspec_options (cs, opts_off, 0);
|
||||
}
|
||||
|
||||
if (wl)
|
||||
dispose_words (wl);
|
||||
|
||||
return (ret);
|
||||
}
|
969
third_party/bash/builtins_declare.c
vendored
Normal file
969
third_party/bash/builtins_declare.c
vendored
Normal file
|
@ -0,0 +1,969 @@
|
|||
/* declare.c, created from declare.def. */
|
||||
#line 22 "./declare.def"
|
||||
|
||||
#line 64 "./declare.def"
|
||||
|
||||
#line 72 "./declare.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "flags.h"
|
||||
#include "common.h"
|
||||
#include "builtext.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
static SHELL_VAR *declare_find_variable PARAMS((const char *, int, int));
|
||||
static char *declare_build_newname PARAMS((char *, char *, int, char *, int));
|
||||
static char *declare_transform_name PARAMS((char *, int, int));
|
||||
|
||||
static int declare_internal PARAMS((register WORD_LIST *, int));
|
||||
|
||||
/* Declare or change variable attributes. */
|
||||
int
|
||||
declare_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
return (declare_internal (list, 0));
|
||||
}
|
||||
|
||||
#line 122 "./declare.def"
|
||||
int
|
||||
local_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
/* Catch a straight `local --help' before checking function context */
|
||||
if (list && list->word && STREQ (list->word->word, "--help"))
|
||||
{
|
||||
builtin_help ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
if (variable_context)
|
||||
return (declare_internal (list, 1));
|
||||
else
|
||||
{
|
||||
builtin_error (_("can only be used in a function"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
# define DECLARE_OPTS "+acfgilnprtuxAFGI"
|
||||
#else
|
||||
# define DECLARE_OPTS "+cfgilnprtuxFGI"
|
||||
#endif
|
||||
|
||||
static SHELL_VAR *
|
||||
declare_find_variable (name, mkglobal, chklocal)
|
||||
const char *name;
|
||||
int mkglobal, chklocal;
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
|
||||
if (mkglobal == 0)
|
||||
return (find_variable (name));
|
||||
else if (chklocal)
|
||||
{
|
||||
var = find_variable (name);
|
||||
if (var && local_p (var) && var->context == variable_context)
|
||||
return var;
|
||||
return (find_global_variable (name));
|
||||
}
|
||||
else
|
||||
return (find_global_variable (name));
|
||||
}
|
||||
|
||||
/* Build a new string
|
||||
NAME[SUBSCRIPT][[+]=VALUE]
|
||||
from expanding a nameref into NAME */
|
||||
static char *
|
||||
declare_build_newname (name, subscript_start, offset, value, aflags)
|
||||
char *name, *subscript_start;
|
||||
int offset;
|
||||
char *value;
|
||||
int aflags;
|
||||
{
|
||||
size_t namelen, savelen;
|
||||
char *ret;
|
||||
|
||||
savelen = namelen = strlen (name);
|
||||
if (subscript_start)
|
||||
{
|
||||
*subscript_start = '['; /* ] */
|
||||
namelen += strlen (subscript_start);
|
||||
}
|
||||
ret = xmalloc (namelen + 2 + strlen (value) + 1);
|
||||
strcpy (ret, name);
|
||||
if (subscript_start)
|
||||
strcpy (ret + savelen, subscript_start);
|
||||
if (offset)
|
||||
{
|
||||
if (aflags & ASS_APPEND)
|
||||
ret[namelen++] = '+';
|
||||
ret[namelen++] = '=';
|
||||
if (value && *value)
|
||||
strcpy (ret + namelen, value);
|
||||
else
|
||||
ret[namelen] = '\0';
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static char *
|
||||
declare_transform_name (name, flags_on, flags_off)
|
||||
char *name;
|
||||
int flags_on, flags_off;
|
||||
{
|
||||
SHELL_VAR *var, *v;
|
||||
char *newname;
|
||||
|
||||
var = find_variable (name);
|
||||
if (var == 0)
|
||||
newname = nameref_transform_name (name, ASS_MKLOCAL);
|
||||
else if ((flags_on & att_nameref) == 0 && (flags_off & att_nameref) == 0)
|
||||
{
|
||||
/* Ok, we're following namerefs here, so let's make sure that if
|
||||
we followed one, it was at the same context (see below for
|
||||
more details). */
|
||||
v = find_variable_last_nameref (name, 1);
|
||||
newname = (v && v->context != variable_context) ? name : name_cell (var);
|
||||
}
|
||||
else
|
||||
newname = name; /* dealing with nameref attribute */
|
||||
|
||||
return (newname);
|
||||
}
|
||||
|
||||
/* The workhorse function. */
|
||||
static int
|
||||
declare_internal (list, local_var)
|
||||
register WORD_LIST *list;
|
||||
int local_var;
|
||||
{
|
||||
int flags_on, flags_off, *flags;
|
||||
int any_failed, assign_error, pflag, nodefs, opt, onref, offref;
|
||||
int mkglobal, chklocal, inherit_flag;
|
||||
char *t, *subscript_start;
|
||||
SHELL_VAR *var, *refvar, *v;
|
||||
FUNCTION_DEF *shell_fn;
|
||||
|
||||
flags_on = flags_off = any_failed = assign_error = pflag = nodefs = 0;
|
||||
mkglobal = chklocal = inherit_flag = 0;
|
||||
refvar = (SHELL_VAR *)NULL;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, DECLARE_OPTS)) != -1)
|
||||
{
|
||||
flags = list_opttype == '+' ? &flags_off : &flags_on;
|
||||
|
||||
/* If you add options here, see whether or not they need to be added to
|
||||
the loop in subst.c:shell_expand_word_list() */
|
||||
switch (opt)
|
||||
{
|
||||
case 'a':
|
||||
#if defined (ARRAY_VARS)
|
||||
*flags |= att_array;
|
||||
break;
|
||||
#else
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
#endif
|
||||
case 'A':
|
||||
#if defined (ARRAY_VARS)
|
||||
*flags |= att_assoc;
|
||||
break;
|
||||
#else
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
#endif
|
||||
case 'p':
|
||||
pflag++;
|
||||
break;
|
||||
case 'F':
|
||||
nodefs++;
|
||||
*flags |= att_function;
|
||||
break;
|
||||
case 'f':
|
||||
*flags |= att_function;
|
||||
break;
|
||||
case 'G':
|
||||
if (flags == &flags_on)
|
||||
chklocal = 1;
|
||||
/*FALLTHROUGH*/
|
||||
case 'g':
|
||||
if (flags == &flags_on)
|
||||
mkglobal = 1;
|
||||
break;
|
||||
case 'i':
|
||||
*flags |= att_integer;
|
||||
break;
|
||||
case 'n':
|
||||
*flags |= att_nameref;
|
||||
break;
|
||||
case 'r':
|
||||
*flags |= att_readonly;
|
||||
break;
|
||||
case 't':
|
||||
*flags |= att_trace;
|
||||
break;
|
||||
case 'x':
|
||||
*flags |= att_exported;
|
||||
array_needs_making = 1;
|
||||
break;
|
||||
#if defined (CASEMOD_ATTRS)
|
||||
# if defined (CASEMOD_CAPCASE)
|
||||
case 'c':
|
||||
*flags |= att_capcase;
|
||||
if (flags == &flags_on)
|
||||
flags_off |= att_uppercase|att_lowercase;
|
||||
break;
|
||||
# endif
|
||||
case 'l':
|
||||
*flags |= att_lowercase;
|
||||
if (flags == &flags_on)
|
||||
flags_off |= att_capcase|att_uppercase;
|
||||
break;
|
||||
case 'u':
|
||||
*flags |= att_uppercase;
|
||||
if (flags == &flags_on)
|
||||
flags_off |= att_capcase|att_lowercase;
|
||||
break;
|
||||
#endif /* CASEMOD_ATTRS */
|
||||
case 'I':
|
||||
inherit_flag = MKLOC_INHERIT;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
/* If there are no more arguments left, then we just want to show
|
||||
some variables. */
|
||||
if (list == 0) /* declare -[aAfFilnrtux] */
|
||||
{
|
||||
/* Show local variables defined at this context level if this is
|
||||
the `local' builtin. */
|
||||
if (local_var)
|
||||
show_local_var_attributes (0, nodefs); /* XXX - fix up args later */
|
||||
else if (pflag && (flags_on == 0 || flags_on == att_function))
|
||||
show_all_var_attributes (flags_on == 0, nodefs);
|
||||
else if (flags_on == 0)
|
||||
return (set_builtin ((WORD_LIST *)NULL));
|
||||
else
|
||||
set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs);
|
||||
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
if (pflag) /* declare -p [-aAfFilnrtux] [name ...] */
|
||||
{
|
||||
for (any_failed = 0; list; list = list->next)
|
||||
{
|
||||
if (flags_on & att_function)
|
||||
pflag = show_func_attributes (list->word->word, nodefs);
|
||||
else if (local_var)
|
||||
pflag = show_localname_attributes (list->word->word, nodefs);
|
||||
else
|
||||
pflag = show_name_attributes (list->word->word, nodefs);
|
||||
if (pflag)
|
||||
{
|
||||
sh_notfound (list->word->word);
|
||||
any_failed++;
|
||||
}
|
||||
}
|
||||
return (sh_chkwrite (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
/* Some option combinations that don't make any sense */
|
||||
if ((flags_on & att_function) && (flags_on & (att_array|att_assoc|att_integer|att_nameref)))
|
||||
{
|
||||
char *optchar;
|
||||
|
||||
if (flags_on & att_nameref)
|
||||
optchar = "-n";
|
||||
else if (flags_on & att_integer)
|
||||
optchar = "-i";
|
||||
else if (flags_on & att_assoc)
|
||||
optchar = "-A";
|
||||
else if (flags_on & att_array)
|
||||
optchar = "-a";
|
||||
|
||||
sh_invalidopt (optchar);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
#define NEXT_VARIABLE() free (name); list = list->next; continue
|
||||
|
||||
/* There are arguments left, so we are making variables. */
|
||||
while (list) /* declare [-aAfFilnrtux] name[=value] [name[=value] ...] */
|
||||
{
|
||||
char *value, *name, *newname;
|
||||
int offset, aflags, wflags, created_var;
|
||||
int assoc_noexpand;
|
||||
#if defined (ARRAY_VARS)
|
||||
int making_array_special, compound_array_assign, simple_array_assign;
|
||||
int var_exists, array_exists, creating_array, array_subscript_assignment;
|
||||
#endif
|
||||
|
||||
name = savestring (list->word->word);
|
||||
wflags = list->word->flags;
|
||||
#if defined (ARRAY_VARS)
|
||||
assoc_noexpand = assoc_expand_once && (wflags & W_ASSIGNMENT);
|
||||
#else
|
||||
assoc_noexpand = 0;
|
||||
#endif
|
||||
/* XXX - we allow unbalanced brackets if assoc_noexpand is set, we count
|
||||
brackets and make sure they match if assoc_noexpand is not set. So we
|
||||
need to make sure we're checking assoc_noexpand and expand_once_flag
|
||||
for backwards compatibility. We also use assoc_noexpand below when
|
||||
we call assign_array_element, so we need to make sure they're
|
||||
consistent in how they count brackets. */
|
||||
offset = assignment (name, assoc_noexpand ? 2 : 0);
|
||||
aflags = 0;
|
||||
created_var = 0;
|
||||
|
||||
if (local_var && variable_context && STREQ (name, "-"))
|
||||
{
|
||||
var = make_local_variable ("-", 0);
|
||||
FREE (value_cell (var)); /* just in case */
|
||||
value = get_current_options ();
|
||||
var_setvalue (var, value);
|
||||
VSETATTR (var, att_invisible);
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* If we are declaring a function, then complain about it in some way.
|
||||
We don't let people make functions by saying `typeset -f foo=bar'. */
|
||||
|
||||
/* Can't define functions using assignment statements */
|
||||
if (offset && (flags_on & att_function)) /* declare -f [-rix] foo=bar */
|
||||
{
|
||||
builtin_error (_("cannot use `-f' to make functions"));
|
||||
free (name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* There should be a way, however, to let people look at a particular
|
||||
function definition by saying `typeset -f foo'. This is the only
|
||||
place in this builtin where we deal with functions. */
|
||||
|
||||
if (flags_on & att_function)
|
||||
{
|
||||
/* Should we restrict this when the shell is in posix mode even if
|
||||
the function was created before the shell entered posix mode?
|
||||
Previous versions of the shell enforced the restriction. */
|
||||
if (posixly_correct && legal_identifier (name) == 0)
|
||||
{
|
||||
sh_invalidid (name);
|
||||
assign_error++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
var = find_function (name);
|
||||
|
||||
if (var)
|
||||
{
|
||||
if (readonly_p (var) && (flags_off & att_readonly))
|
||||
{
|
||||
builtin_error (_("%s: readonly function"), name);
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
/* declare -[Ff] name [name...] */
|
||||
if (flags_on == att_function && flags_off == 0)
|
||||
{
|
||||
#if defined (DEBUGGER)
|
||||
if (nodefs && debugging_mode)
|
||||
{
|
||||
shell_fn = find_function_def (name_cell (var));
|
||||
if (shell_fn)
|
||||
printf ("%s %d %s\n", name_cell (var), shell_fn->line, shell_fn->source_file);
|
||||
else
|
||||
printf ("%s\n", name_cell (var));
|
||||
}
|
||||
else
|
||||
#endif /* DEBUGGER */
|
||||
{
|
||||
t = nodefs ? name_cell (var) : named_function_string (name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL);
|
||||
printf ("%s\n", t);
|
||||
any_failed = sh_chkwrite (any_failed);
|
||||
}
|
||||
}
|
||||
else /* declare -[fF] -[rx] name [name...] */
|
||||
{
|
||||
VSETATTR (var, flags_on);
|
||||
flags_off &= ~att_function; /* makes no sense */
|
||||
VUNSETATTR (var, flags_off);
|
||||
}
|
||||
}
|
||||
else
|
||||
any_failed++;
|
||||
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
if (offset) /* declare [-aAfFirx] name=value */
|
||||
{
|
||||
name[offset] = '\0';
|
||||
value = name + offset + 1;
|
||||
if (name[offset - 1] == '+')
|
||||
{
|
||||
aflags |= ASS_APPEND;
|
||||
name[offset - 1] = '\0';
|
||||
}
|
||||
}
|
||||
else
|
||||
value = "";
|
||||
|
||||
/* Do some lexical error checking on the LHS and RHS of the assignment
|
||||
that is specific to nameref variables. */
|
||||
if (flags_on & att_nameref)
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
if (valid_array_reference (name, 0))
|
||||
{
|
||||
builtin_error (_("%s: reference variable cannot be an array"), name);
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
/* disallow self references at global scope, warn at function scope */
|
||||
if (check_selfref (name, value, 0))
|
||||
{
|
||||
if (variable_context == 0)
|
||||
{
|
||||
builtin_error (_("%s: nameref variable self references not allowed"), name);
|
||||
assign_error++; /* XXX any_failed++ instead? */
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
else
|
||||
builtin_warning (_("%s: circular name reference"), name);
|
||||
}
|
||||
if (value && *value && (aflags & ASS_APPEND) == 0 && valid_nameref_value (value, 1) == 0)
|
||||
{
|
||||
builtin_error (_("`%s': invalid variable name for name reference"), value);
|
||||
assign_error++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
}
|
||||
|
||||
restart_new_var_name:
|
||||
|
||||
/* The rest of the loop body deals with declare -[aAlinrtux] name [name...]
|
||||
where each NAME can be an assignment statement. */
|
||||
|
||||
subscript_start = (char *)NULL; /* used below */
|
||||
#if defined (ARRAY_VARS)
|
||||
/* Determine whether we are creating or assigning an array variable */
|
||||
var_exists = array_exists = creating_array = 0;
|
||||
compound_array_assign = simple_array_assign = 0;
|
||||
array_subscript_assignment = 0;
|
||||
if (t = strchr (name, '[')) /* ] */
|
||||
{
|
||||
/* If offset != 0 we have already validated any array reference
|
||||
because assignment() calls skipsubscript() */
|
||||
if (offset == 0 && valid_array_reference (name, 0) == 0)
|
||||
{
|
||||
sh_invalidid (name);
|
||||
assign_error++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
subscript_start = t;
|
||||
*t = '\0';
|
||||
making_array_special = 1; /* XXX - should this check offset? */
|
||||
array_subscript_assignment = offset != 0;
|
||||
}
|
||||
else
|
||||
making_array_special = 0;
|
||||
#endif
|
||||
|
||||
/* Ensure the argument is a valid, well-formed shell identifier. */
|
||||
if (legal_identifier (name) == 0)
|
||||
{
|
||||
sh_invalidid (name);
|
||||
assign_error++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* If VARIABLE_CONTEXT has a non-zero value, then we are executing
|
||||
inside of a function. This means we should make local variables,
|
||||
not global ones. */
|
||||
|
||||
/* XXX - this has consequences when we're making a local copy of a
|
||||
variable that was in the temporary environment. Watch out
|
||||
for this. */
|
||||
refvar = (SHELL_VAR *)NULL;
|
||||
if (variable_context && mkglobal == 0)
|
||||
{
|
||||
/* We don't check newname for validity here. We should not have an
|
||||
invalid name assigned as the value of a nameref, but this could
|
||||
cause problems. */
|
||||
newname = declare_transform_name (name, flags_on, flags_off);
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
/* Pass 1 as second argument to make_local_{assoc,array}_variable
|
||||
return an existing {array,assoc} variable to be flagged as an
|
||||
error below. */
|
||||
if (flags_on & att_assoc)
|
||||
var = make_local_assoc_variable (newname, MKLOC_ARRAYOK|inherit_flag);
|
||||
else if ((flags_on & att_array) || making_array_special)
|
||||
var = make_local_array_variable (newname, MKLOC_ASSOCOK|inherit_flag);
|
||||
else
|
||||
#endif
|
||||
if (offset == 0 && (flags_on & att_nameref))
|
||||
{
|
||||
/* First look for refvar at current scope */
|
||||
refvar = find_variable_last_nameref (name, 1);
|
||||
/* VARIABLE_CONTEXT != 0, so we are attempting to create or modify
|
||||
the attributes for a local variable at the same scope. If we've
|
||||
used a reference from a previous context to resolve VAR, we
|
||||
want to throw REFVAR and VAR away and create a new local var. */
|
||||
if (refvar && refvar->context != variable_context)
|
||||
{
|
||||
refvar = 0;
|
||||
var = make_local_variable (name, inherit_flag);
|
||||
}
|
||||
else if (refvar && refvar->context == variable_context)
|
||||
var = refvar;
|
||||
/* Maybe we just want to create a new local variable */
|
||||
else if ((var = find_variable (name)) == 0 || var->context != variable_context)
|
||||
var = make_local_variable (name, inherit_flag);
|
||||
/* otherwise we have a var at the right context */
|
||||
}
|
||||
else
|
||||
/* XXX - check name for validity here with valid_nameref_value? */
|
||||
var = make_local_variable ((flags_on & att_nameref) ? name : newname, inherit_flag); /* sets att_invisible for new vars */
|
||||
|
||||
if (var == 0)
|
||||
{
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
if (var && nameref_p (var) && readonly_p (var) && nameref_cell (var) && (flags_off & att_nameref))
|
||||
{
|
||||
sh_readonly (name);
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
}
|
||||
else
|
||||
var = (SHELL_VAR *)NULL;
|
||||
|
||||
/* VAR is non-null if we just created or fetched a local variable. */
|
||||
|
||||
/* Here's what ksh93 seems to do as of the 2012 version: if we are
|
||||
using declare -n to modify the value of an existing nameref
|
||||
variable, don't follow the nameref chain at all and just search
|
||||
for a nameref at the current context. If we have a nameref,
|
||||
modify its value (changing which variable it references). */
|
||||
if (var == 0 && (flags_on & att_nameref))
|
||||
{
|
||||
/* See if we are trying to modify an existing nameref variable,
|
||||
but don't follow the nameref chain. */
|
||||
var = mkglobal ? find_global_variable_noref (name) : find_variable_noref (name);
|
||||
if (var && nameref_p (var) == 0)
|
||||
var = 0;
|
||||
}
|
||||
|
||||
/* However, if we're turning off the nameref attribute on an existing
|
||||
nameref variable, we first follow the nameref chain to the end,
|
||||
modify the value of the variable this nameref variable references
|
||||
if there is an assignment statement argument,
|
||||
*CHANGING ITS VALUE AS A SIDE EFFECT*, then turn off the nameref
|
||||
flag *LEAVING THE NAMEREF VARIABLE'S VALUE UNCHANGED* */
|
||||
else if (var == 0 && (flags_off & att_nameref))
|
||||
{
|
||||
/* See if we are trying to modify an existing nameref variable */
|
||||
refvar = mkglobal ? find_global_variable_last_nameref (name, 0) : find_variable_last_nameref (name, 0);
|
||||
if (refvar && nameref_p (refvar) == 0)
|
||||
refvar = 0;
|
||||
/* If the nameref is readonly but doesn't have a value, ksh93
|
||||
allows the nameref attribute to be removed. If it's readonly
|
||||
and has a value, even if the value doesn't reference an
|
||||
existing variable, we disallow the modification */
|
||||
if (refvar && nameref_cell (refvar) && readonly_p (refvar))
|
||||
{
|
||||
sh_readonly (name);
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* If all we're doing is turning off the nameref attribute, don't
|
||||
bother with VAR at all, whether it exists or not. Just turn it
|
||||
off and go on. */
|
||||
if (refvar && flags_on == 0 && offset == 0 && flags_off == att_nameref)
|
||||
{
|
||||
VUNSETATTR (refvar, att_nameref);
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
if (refvar)
|
||||
var = declare_find_variable (nameref_cell (refvar), mkglobal, 0);
|
||||
}
|
||||
#if defined (ARRAY_VARS)
|
||||
/* If we have an array assignment to a nameref, remove the nameref
|
||||
attribute and go on. This handles
|
||||
declare -n xref[=value]; declare [-a] xref[1]=one */
|
||||
else if (var == 0 && offset && array_subscript_assignment)
|
||||
{
|
||||
var = mkglobal ? find_global_variable_noref (name) : find_variable_noref (name);
|
||||
if (var && nameref_p (var))
|
||||
{
|
||||
internal_warning (_("%s: removing nameref attribute"), name);
|
||||
FREE (value_cell (var)); /* XXX - bash-4.3 compat */
|
||||
var_setvalue (var, (char *)NULL);
|
||||
VUNSETATTR (var, att_nameref);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* See if we are trying to set flags or value (or create) for an
|
||||
existing nameref that points to a non-existent variable: e.g.,
|
||||
declare -n foo=bar
|
||||
unset foo # unsets bar
|
||||
declare -i foo
|
||||
foo=4+4
|
||||
declare -p foo
|
||||
*/
|
||||
if (var == 0 && (mkglobal || flags_on || flags_off || offset))
|
||||
{
|
||||
refvar = mkglobal ? find_global_variable_last_nameref (name, 0) : find_variable_last_nameref (name, 0);
|
||||
if (refvar && nameref_p (refvar) == 0)
|
||||
refvar = 0;
|
||||
if (refvar)
|
||||
var = declare_find_variable (nameref_cell (refvar), mkglobal, 0);
|
||||
if (refvar && var == 0)
|
||||
{
|
||||
/* I'm not sure subscript_start is ever non-null here. In any
|
||||
event, build a new name from the nameref value, including any
|
||||
subscript, and add the [[+]=value] if offset != 0 */
|
||||
newname = declare_build_newname (nameref_cell (refvar), subscript_start, offset, value, aflags);
|
||||
free (name);
|
||||
name = newname;
|
||||
|
||||
if (offset)
|
||||
{
|
||||
offset = assignment (name, 0);
|
||||
/* If offset was valid previously, but substituting the
|
||||
the nameref value results in an invalid assignment,
|
||||
throw an invalid identifier error */
|
||||
if (offset == 0)
|
||||
{
|
||||
sh_invalidid (name);
|
||||
assign_error++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
name[(aflags & ASS_APPEND) ? offset - 1 : offset] = '\0';
|
||||
value = name + offset + 1;
|
||||
}
|
||||
|
||||
/* OK, let's turn off the nameref attribute.
|
||||
Now everything else applies to VAR. */
|
||||
if (flags_off & att_nameref)
|
||||
VUNSETATTR (refvar, att_nameref);
|
||||
|
||||
goto restart_new_var_name;
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
if (var == 0)
|
||||
var = declare_find_variable (name, mkglobal, chklocal);
|
||||
|
||||
/* At this point, VAR is the variable we are dealing with; REFVAR is the
|
||||
nameref variable we dereferenced to get VAR, if any. */
|
||||
#if defined (ARRAY_VARS)
|
||||
var_exists = var != 0;
|
||||
array_exists = var && (array_p (var) || assoc_p (var));
|
||||
creating_array = flags_on & (att_array|att_assoc);
|
||||
#endif
|
||||
|
||||
/* Make a new variable if we need to. */
|
||||
if (var == 0)
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
if (flags_on & att_assoc)
|
||||
var = make_new_assoc_variable (name);
|
||||
else if ((flags_on & att_array) || making_array_special)
|
||||
var = make_new_array_variable (name);
|
||||
else
|
||||
#endif
|
||||
var = mkglobal ? bind_global_variable (name, (char *)NULL, ASS_FORCE) : bind_variable (name, (char *)NULL, ASS_FORCE);
|
||||
|
||||
if (var == 0)
|
||||
{
|
||||
/* Has to appear in brackets */
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
if (offset == 0)
|
||||
VSETATTR (var, att_invisible);
|
||||
created_var = 1;
|
||||
}
|
||||
|
||||
/* Nameref variable error checking. */
|
||||
|
||||
/* Can't take an existing array variable and make it a nameref */
|
||||
else if ((array_p (var) || assoc_p (var)) && (flags_on & att_nameref))
|
||||
{
|
||||
builtin_error (_("%s: reference variable cannot be an array"), name);
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
/* Can't have an invalid identifier as nameref value */
|
||||
else if (nameref_p (var) && (flags_on & att_nameref) == 0 && (flags_off & att_nameref) == 0 && offset && valid_nameref_value (value, 1) == 0)
|
||||
{
|
||||
builtin_error (_("`%s': invalid variable name for name reference"), value);
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
/* Can't make an existing variable a nameref if its current value is not
|
||||
a valid identifier. Check of offset is to allow an assignment to a
|
||||
nameref var as part of the declare word to override existing value. */
|
||||
else if ((flags_on & att_nameref) && nameref_p (var) == 0 && var_isset (var) && offset == 0 && valid_nameref_value (value_cell (var), 0) == 0)
|
||||
{
|
||||
builtin_error (_("`%s': invalid variable name for name reference"), value_cell (var));
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
/* Can't make an existing readonly variable a nameref. */
|
||||
else if ((flags_on & att_nameref) && readonly_p (var))
|
||||
{
|
||||
sh_readonly (name);
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* Readonly variable error checking. */
|
||||
|
||||
/* Cannot use declare +r to turn off readonly attribute. */
|
||||
if (readonly_p (var) && (flags_off & att_readonly))
|
||||
{
|
||||
sh_readonly (name_cell (var));
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
/* Cannot use declare to assign value to readonly or noassign variable. */
|
||||
else if ((readonly_p (var) || noassign_p (var)) && offset)
|
||||
{
|
||||
if (readonly_p (var))
|
||||
sh_readonly (name);
|
||||
assign_error++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
/* Array variable error checking. */
|
||||
|
||||
/* Cannot use declare +a name or declare +A name to remove an array variable. */
|
||||
if (((flags_off & att_array) && array_p (var)) || ((flags_off & att_assoc) && assoc_p (var)))
|
||||
{
|
||||
builtin_error (_("%s: cannot destroy array variables in this way"), name);
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
else if ((flags_on & att_array) && assoc_p (var))
|
||||
{
|
||||
builtin_error (_("%s: cannot convert associative to indexed array"), name);
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
else if ((flags_on & att_assoc) && array_p (var))
|
||||
{
|
||||
builtin_error (_("%s: cannot convert indexed to associative array"), name);
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* make declare A[2]=foo as similar to A[2]=foo as possible if A is
|
||||
already an array or assoc variable. */
|
||||
if (array_subscript_assignment && array_exists && creating_array == 0)
|
||||
simple_array_assign = 1;
|
||||
else if ((making_array_special || creating_array || array_exists) && offset)
|
||||
{
|
||||
int vlen;
|
||||
vlen = STRLEN (value);
|
||||
/*itrace("declare_builtin: name = %s value = %s flags = %d", name, value, wflags);*/
|
||||
|
||||
if (shell_compatibility_level > 43 && (wflags & W_COMPASSIGN) == 0 &&
|
||||
value[0] == '(' && value[vlen-1] == ')')
|
||||
{
|
||||
/* I don't believe this warning is printed any more.
|
||||
We use creating_array to allow things like
|
||||
declare -a foo$bar='(abc)'
|
||||
to work as they have in the past. */
|
||||
if (array_exists == 0 && creating_array == 0)
|
||||
internal_warning (_("%s: quoted compound array assignment deprecated"), list->word->word);
|
||||
compound_array_assign = array_exists || creating_array;
|
||||
simple_array_assign = making_array_special;
|
||||
}
|
||||
else if (value[0] == '(' && value[vlen-1] == ')' && (shell_compatibility_level < 44 || (wflags & W_COMPASSIGN)))
|
||||
compound_array_assign = 1;
|
||||
else
|
||||
simple_array_assign = 1;
|
||||
}
|
||||
|
||||
/* declare -A name[[n]] makes name an associative array variable. */
|
||||
if (flags_on & att_assoc)
|
||||
{
|
||||
if (assoc_p (var) == 0)
|
||||
var = convert_var_to_assoc (var);
|
||||
}
|
||||
/* declare -a name[[n]] or declare name[n] makes NAME an indexed
|
||||
array variable. */
|
||||
else if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0 && assoc_p (var) == 0)
|
||||
var = convert_var_to_array (var);
|
||||
#endif /* ARRAY_VARS */
|
||||
|
||||
/* ksh93 compat: turning on nameref attribute turns off -ilu */
|
||||
if (flags_on & att_nameref)
|
||||
VUNSETATTR (var, att_integer|att_uppercase|att_lowercase|att_capcase);
|
||||
|
||||
/* XXX - we note that we are turning on nameref attribute and defer
|
||||
setting it until the assignment has been made so we don't do an
|
||||
inadvertent nameref lookup. Might have to do the same thing for
|
||||
flags_off&att_nameref. */
|
||||
/* XXX - ksh93 makes it an error to set a readonly nameref variable
|
||||
using a single typeset command. */
|
||||
onref = (flags_on & att_nameref);
|
||||
flags_on &= ~att_nameref;
|
||||
#if defined (ARRAY_VARS)
|
||||
/* I don't believe this condition ever tests true, but array variables
|
||||
may not be namerefs */
|
||||
if (array_p (var) || assoc_p (var) || compound_array_assign || simple_array_assign)
|
||||
onref = 0;
|
||||
#endif
|
||||
|
||||
/* ksh93 seems to do this */
|
||||
offref = (flags_off & att_nameref);
|
||||
flags_off &= ~att_nameref;
|
||||
|
||||
VSETATTR (var, flags_on);
|
||||
VUNSETATTR (var, flags_off);
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if (offset && compound_array_assign)
|
||||
assign_array_var_from_string (var, value, aflags|ASS_FORCE);
|
||||
else if (simple_array_assign && subscript_start)
|
||||
{
|
||||
int local_aflags;
|
||||
|
||||
/* declare [-aA] name[N]=value */
|
||||
*subscript_start = '['; /* ] */
|
||||
/* XXX - problem here with appending */
|
||||
local_aflags = aflags&ASS_APPEND;
|
||||
local_aflags |= assoc_noexpand ? ASS_NOEXPAND : 0;
|
||||
local_aflags |= ASS_ALLOWALLSUB; /* allow declare a[@]=at */
|
||||
var = assign_array_element (name, value, local_aflags, (array_eltstate_t *)0); /* XXX - not aflags */
|
||||
*subscript_start = '\0';
|
||||
if (var == 0) /* some kind of assignment error */
|
||||
{
|
||||
assign_error++;
|
||||
flags_on |= onref;
|
||||
flags_off |= offref;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
}
|
||||
else if (simple_array_assign)
|
||||
{
|
||||
/* let bind_{array,assoc}_variable take care of this. */
|
||||
if (assoc_p (var))
|
||||
bind_assoc_variable (var, name, savestring ("0"), value, aflags|ASS_FORCE);
|
||||
else
|
||||
bind_array_variable (name, 0, value, aflags|ASS_FORCE);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
/* XXX - no ASS_FORCE here */
|
||||
/* bind_variable_value duplicates the essential internals of bind_variable() */
|
||||
if (offset)
|
||||
{
|
||||
if (onref || nameref_p (var))
|
||||
aflags |= ASS_NAMEREF;
|
||||
v = bind_variable_value (var, value, aflags);
|
||||
if (v == 0 && (onref || nameref_p (var)))
|
||||
{
|
||||
if (valid_nameref_value (value, 1) == 0)
|
||||
sh_invalidid (value);
|
||||
assign_error++;
|
||||
/* XXX - unset this variable? or leave it as normal var? */
|
||||
if (created_var)
|
||||
delete_var (name_cell (var), mkglobal ? global_variables : shell_variables);
|
||||
flags_on |= onref; /* undo change from above */
|
||||
flags_off |= offref;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
}
|
||||
|
||||
/* If we found this variable in the temporary environment, as with
|
||||
`var=value declare -x var', make sure it is treated identically
|
||||
to `var=value export var'. Do the same for `declare -r' and
|
||||
`readonly'. Preserve the attributes, except for att_tempvar. */
|
||||
/* XXX -- should this create a variable in the global scope, or
|
||||
modify the local variable flags? ksh93 has it modify the
|
||||
global scope.
|
||||
Need to handle case like in set_var_attribute where a temporary
|
||||
variable is in the same table as the function local vars. */
|
||||
if ((flags_on & (att_exported|att_readonly)) && tempvar_p (var))
|
||||
{
|
||||
SHELL_VAR *tv;
|
||||
char *tvalue;
|
||||
|
||||
tv = find_tempenv_variable (name_cell (var));
|
||||
if (tv)
|
||||
{
|
||||
tvalue = var_isset (var) ? savestring (value_cell (var)) : savestring ("");
|
||||
tv = bind_variable (name_cell (var), tvalue, 0);
|
||||
if (tv)
|
||||
{
|
||||
tv->attributes |= var->attributes & ~att_tempvar;
|
||||
if (tv->context > 0)
|
||||
VSETATTR (tv, att_propagate);
|
||||
}
|
||||
free (tvalue);
|
||||
}
|
||||
VSETATTR (var, att_propagate);
|
||||
}
|
||||
|
||||
/* Turn on nameref attribute we deferred above. */
|
||||
VSETATTR (var, onref);
|
||||
flags_on |= onref;
|
||||
VUNSETATTR (var, offref);
|
||||
flags_off |= offref;
|
||||
|
||||
/* Yuck. ksh93 compatibility. XXX - need to investigate more but
|
||||
definitely happens when turning off nameref attribute on nameref
|
||||
(see comments above). Under no circumstances allow this to turn
|
||||
off readonly attribute on readonly nameref variable. */
|
||||
if (refvar)
|
||||
{
|
||||
if (flags_off & att_readonly)
|
||||
flags_off &= ~att_readonly;
|
||||
VUNSETATTR (refvar, flags_off);
|
||||
}
|
||||
|
||||
stupidly_hack_special_variables (name);
|
||||
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
return (assign_error ? EX_BADASSIGN
|
||||
: ((any_failed == 0) ? EXECUTION_SUCCESS
|
||||
: EXECUTION_FAILURE));
|
||||
}
|
133
third_party/bash/builtins_echo.c
vendored
Normal file
133
third_party/bash/builtins_echo.c
vendored
Normal file
|
@ -0,0 +1,133 @@
|
|||
/* echo.c, created from echo.def. */
|
||||
#line 22 "./echo.def"
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "shell.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#line 73 "./echo.def"
|
||||
|
||||
#line 88 "./echo.def"
|
||||
|
||||
#if defined (V9_ECHO)
|
||||
# define VALID_ECHO_OPTIONS "neE"
|
||||
#else /* !V9_ECHO */
|
||||
# define VALID_ECHO_OPTIONS "n"
|
||||
#endif /* !V9_ECHO */
|
||||
|
||||
/* System V machines already have a /bin/sh with a v9 behaviour. We
|
||||
give Bash the identical behaviour for these machines so that the
|
||||
existing system shells won't barf. Regrettably, the SUS v2 has
|
||||
standardized the Sys V echo behavior. This variable is external
|
||||
so that we can have a `shopt' variable to control it at runtime. */
|
||||
#if defined (DEFAULT_ECHO_TO_XPG) || defined (STRICT_POSIX)
|
||||
int xpg_echo = 1;
|
||||
#else
|
||||
int xpg_echo = 0;
|
||||
#endif /* DEFAULT_ECHO_TO_XPG */
|
||||
|
||||
/* Print the words in LIST to standard output. If the first word is
|
||||
`-n', then don't print a trailing newline. We also support the
|
||||
echo syntax from Version 9 Unix systems. */
|
||||
int
|
||||
echo_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int display_return, do_v9, i, len;
|
||||
char *temp, *s;
|
||||
|
||||
do_v9 = xpg_echo;
|
||||
display_return = 1;
|
||||
|
||||
if (posixly_correct && xpg_echo)
|
||||
goto just_echo;
|
||||
|
||||
for (; list && (temp = list->word->word) && *temp == '-'; list = list->next)
|
||||
{
|
||||
/* If it appears that we are handling options, then make sure that
|
||||
all of the options specified are actually valid. Otherwise, the
|
||||
string should just be echoed. */
|
||||
temp++;
|
||||
|
||||
for (i = 0; temp[i]; i++)
|
||||
{
|
||||
if (strchr (VALID_ECHO_OPTIONS, temp[i]) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* echo - and echo -<nonopt> both mean to just echo the arguments. */
|
||||
if (*temp == 0 || temp[i])
|
||||
break;
|
||||
|
||||
/* All of the options in TEMP are valid options to ECHO.
|
||||
Handle them. */
|
||||
while (i = *temp++)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 'n':
|
||||
display_return = 0;
|
||||
break;
|
||||
#if defined (V9_ECHO)
|
||||
case 'e':
|
||||
do_v9 = 1;
|
||||
break;
|
||||
case 'E':
|
||||
do_v9 = 0;
|
||||
break;
|
||||
#endif /* V9_ECHO */
|
||||
default:
|
||||
goto just_echo; /* XXX */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
just_echo:
|
||||
|
||||
clearerr (stdout); /* clear error before writing and testing success */
|
||||
|
||||
while (list)
|
||||
{
|
||||
i = len = 0;
|
||||
temp = do_v9 ? ansicstr (list->word->word, STRLEN (list->word->word), 1, &i, &len)
|
||||
: list->word->word;
|
||||
if (temp)
|
||||
{
|
||||
if (do_v9)
|
||||
{
|
||||
for (s = temp; len > 0; len--)
|
||||
putchar (*s++);
|
||||
}
|
||||
else
|
||||
printf ("%s", temp);
|
||||
#if defined (SunOS5)
|
||||
fflush (stdout); /* Fix for bug in SunOS 5.5 printf(3) */
|
||||
#endif
|
||||
}
|
||||
QUIT;
|
||||
if (do_v9 && temp)
|
||||
free (temp);
|
||||
list = list->next;
|
||||
if (i)
|
||||
{
|
||||
display_return = 0;
|
||||
break;
|
||||
}
|
||||
if (list)
|
||||
putchar(' ');
|
||||
QUIT;
|
||||
}
|
||||
|
||||
if (display_return)
|
||||
putchar ('\n');
|
||||
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
541
third_party/bash/builtins_enable.c
vendored
Normal file
541
third_party/bash/builtins_enable.c
vendored
Normal file
|
@ -0,0 +1,541 @@
|
|||
/* enable.c, created from enable.def. */
|
||||
#line 22 "./enable.def"
|
||||
|
||||
#line 50 "./enable.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "builtins.h"
|
||||
#include "flags.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "findcmd.h"
|
||||
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
# include "pcomplete.h"
|
||||
#endif
|
||||
|
||||
#define ENABLED 1
|
||||
#define DISABLED 2
|
||||
#define SPECIAL 4
|
||||
#define SILENT 8 /* affects dyn_load_builtin behavior */
|
||||
|
||||
#define AFLAG 0x01
|
||||
#define DFLAG 0x02
|
||||
#define FFLAG 0x04
|
||||
#define NFLAG 0x08
|
||||
#define PFLAG 0x10
|
||||
#define SFLAG 0x20
|
||||
|
||||
#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
|
||||
static int dyn_load_builtin PARAMS((WORD_LIST *, int, char *));
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_DLCLOSE)
|
||||
static int dyn_unload_builtin PARAMS((char *));
|
||||
static void delete_builtin PARAMS((struct builtin *));
|
||||
static int local_dlclose PARAMS((void *));
|
||||
#endif
|
||||
|
||||
#define STRUCT_SUFFIX "_struct"
|
||||
/* for now */
|
||||
#define LOAD_SUFFIX "_builtin_load"
|
||||
#define UNLOAD_SUFFIX "_builtin_unload"
|
||||
|
||||
static void list_some_builtins PARAMS((int));
|
||||
static int enable_shell_command PARAMS((char *, int));
|
||||
|
||||
/* Enable/disable shell commands present in LIST. If list is not specified,
|
||||
then print out a list of shell commands showing which are enabled and
|
||||
which are disabled. */
|
||||
int
|
||||
enable_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int result, flags;
|
||||
int opt, filter;
|
||||
WORD_LIST *next;
|
||||
#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
|
||||
char *filename;
|
||||
#endif
|
||||
|
||||
result = EXECUTION_SUCCESS;
|
||||
flags = 0;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "adnpsf:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'a':
|
||||
flags |= AFLAG;
|
||||
break;
|
||||
case 'n':
|
||||
flags |= NFLAG;
|
||||
break;
|
||||
case 'p':
|
||||
flags |= PFLAG;
|
||||
break;
|
||||
case 's':
|
||||
flags |= SFLAG;
|
||||
break;
|
||||
case 'f':
|
||||
#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
|
||||
flags |= FFLAG;
|
||||
filename = list_optarg;
|
||||
break;
|
||||
#else
|
||||
builtin_error (_("dynamic loading not available"));
|
||||
return (EX_USAGE);
|
||||
#endif
|
||||
#if defined (HAVE_DLCLOSE)
|
||||
case 'd':
|
||||
flags |= DFLAG;
|
||||
break;
|
||||
#else
|
||||
builtin_error (_("dynamic loading not available"));
|
||||
return (EX_USAGE);
|
||||
#endif /* HAVE_DLCLOSE */
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
/* Restricted shells cannot load new builtins. */
|
||||
if (restricted && (flags & (FFLAG|DFLAG)))
|
||||
{
|
||||
sh_restricted ((char *)NULL);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (list == 0 || (flags & PFLAG))
|
||||
{
|
||||
filter = (flags & AFLAG) ? (ENABLED | DISABLED)
|
||||
: (flags & NFLAG) ? DISABLED : ENABLED;
|
||||
|
||||
if (flags & SFLAG)
|
||||
filter |= SPECIAL;
|
||||
|
||||
list_some_builtins (filter);
|
||||
result = sh_chkwrite (EXECUTION_SUCCESS);
|
||||
}
|
||||
#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
|
||||
else if (flags & FFLAG)
|
||||
{
|
||||
filter = (flags & NFLAG) ? DISABLED : ENABLED;
|
||||
if (flags & SFLAG)
|
||||
filter |= SPECIAL;
|
||||
|
||||
result = dyn_load_builtin (list, filter, filename);
|
||||
if (result != EXECUTION_SUCCESS)
|
||||
result = EXECUTION_FAILURE; /* normalize return value */
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
set_itemlist_dirty (&it_builtins);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#if defined (HAVE_DLCLOSE)
|
||||
else if (flags & DFLAG)
|
||||
{
|
||||
while (list)
|
||||
{
|
||||
opt = dyn_unload_builtin (list->word->word);
|
||||
if (opt == EXECUTION_FAILURE)
|
||||
result = EXECUTION_FAILURE;
|
||||
list = list->next;
|
||||
}
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
set_itemlist_dirty (&it_builtins);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
while (list)
|
||||
{
|
||||
opt = enable_shell_command (list->word->word, flags & NFLAG);
|
||||
next = list->next;
|
||||
|
||||
#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
|
||||
/* If we try to enable a non-existent builtin, and we have dynamic
|
||||
loading, try the equivalent of `enable -f name name'. */
|
||||
if (opt == EX_NOTFOUND)
|
||||
{
|
||||
int dflags, r;
|
||||
|
||||
dflags = ENABLED|SILENT|((flags & SFLAG) ? SPECIAL : 0);
|
||||
|
||||
list->next = 0;
|
||||
r = dyn_load_builtin (list, dflags, list->word->word);
|
||||
list->next = next;
|
||||
if (r == EXECUTION_SUCCESS)
|
||||
opt = r;
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
set_itemlist_dirty (&it_builtins);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
if (opt == EX_NOTFOUND)
|
||||
{
|
||||
sh_notbuiltin (list->word->word);
|
||||
result = EXECUTION_FAILURE;
|
||||
}
|
||||
else if (opt != EXECUTION_SUCCESS)
|
||||
result = EXECUTION_FAILURE;
|
||||
|
||||
list = next;
|
||||
}
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* List some builtins.
|
||||
FILTER is a mask with two slots: ENABLED and DISABLED. */
|
||||
static void
|
||||
list_some_builtins (filter)
|
||||
int filter;
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; i < num_shell_builtins; i++)
|
||||
{
|
||||
if (shell_builtins[i].function == 0 || (shell_builtins[i].flags & BUILTIN_DELETED))
|
||||
continue;
|
||||
|
||||
if ((filter & SPECIAL) &&
|
||||
(shell_builtins[i].flags & SPECIAL_BUILTIN) == 0)
|
||||
continue;
|
||||
|
||||
if ((filter & ENABLED) && (shell_builtins[i].flags & BUILTIN_ENABLED))
|
||||
printf ("enable %s\n", shell_builtins[i].name);
|
||||
else if ((filter & DISABLED) &&
|
||||
((shell_builtins[i].flags & BUILTIN_ENABLED) == 0))
|
||||
printf ("enable -n %s\n", shell_builtins[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable the shell command NAME. If DISABLE_P is non-zero, then
|
||||
disable NAME instead. */
|
||||
static int
|
||||
enable_shell_command (name, disable_p)
|
||||
char *name;
|
||||
int disable_p;
|
||||
{
|
||||
struct builtin *b;
|
||||
|
||||
b = builtin_address_internal (name, 1);
|
||||
if (b == 0)
|
||||
return (EX_NOTFOUND);
|
||||
|
||||
if (disable_p)
|
||||
b->flags &= ~BUILTIN_ENABLED;
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
else if (restricted && ((b->flags & BUILTIN_ENABLED) == 0))
|
||||
{
|
||||
sh_restricted ((char *)NULL);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
b->flags |= BUILTIN_ENABLED;
|
||||
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
set_itemlist_dirty (&it_enabled);
|
||||
set_itemlist_dirty (&it_disabled);
|
||||
#endif
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
|
||||
|
||||
#if defined (HAVE_DLFCN_H)
|
||||
# include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
static int
|
||||
dyn_load_builtin (list, flags, filename)
|
||||
WORD_LIST *list;
|
||||
int flags;
|
||||
char *filename;
|
||||
{
|
||||
WORD_LIST *l;
|
||||
void *handle;
|
||||
|
||||
int total, size, new, replaced, r;
|
||||
char *struct_name, *name, *funcname;
|
||||
sh_load_func_t *loadfunc;
|
||||
struct builtin **new_builtins, *b, *new_shell_builtins, *old_builtin;
|
||||
char *loadables_path, *load_path;
|
||||
|
||||
if (list == 0)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
#ifndef RTLD_LAZY
|
||||
#define RTLD_LAZY 1
|
||||
#endif
|
||||
|
||||
handle = 0;
|
||||
if (absolute_program (filename) == 0)
|
||||
{
|
||||
loadables_path = get_string_value ("BASH_LOADABLES_PATH");
|
||||
if (loadables_path)
|
||||
{
|
||||
load_path = find_in_path (filename, loadables_path, FS_NODIRS|FS_EXEC_PREFERRED);
|
||||
if (load_path)
|
||||
{
|
||||
#if defined (_AIX)
|
||||
handle = dlopen (load_path, RTLD_NOW|RTLD_GLOBAL);
|
||||
#else
|
||||
handle = dlopen (load_path, RTLD_LAZY);
|
||||
#endif /* !_AIX */
|
||||
free (load_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Fall back to current directory for now */
|
||||
if (handle == 0)
|
||||
#if defined (_AIX)
|
||||
handle = dlopen (filename, RTLD_NOW|RTLD_GLOBAL);
|
||||
#else
|
||||
handle = dlopen (filename, RTLD_LAZY);
|
||||
#endif /* !_AIX */
|
||||
|
||||
if (handle == 0)
|
||||
{
|
||||
/* If we've been told to be quiet, don't complain about not finding the
|
||||
specified shared object. */
|
||||
if ((flags & SILENT) == 0)
|
||||
{
|
||||
name = printable_filename (filename, 0);
|
||||
builtin_error (_("cannot open shared object %s: %s"), name, dlerror ());
|
||||
if (name != filename)
|
||||
free (name);
|
||||
}
|
||||
return (EX_NOTFOUND);
|
||||
}
|
||||
|
||||
for (new = 0, l = list; l; l = l->next, new++)
|
||||
;
|
||||
new_builtins = (struct builtin **)xmalloc (new * sizeof (struct builtin *));
|
||||
|
||||
/* For each new builtin in the shared object, find it and its describing
|
||||
structure. If this is overwriting an existing builtin, do so, otherwise
|
||||
save the loaded struct for creating the new list of builtins. */
|
||||
for (replaced = new = 0; list; list = list->next)
|
||||
{
|
||||
name = list->word->word;
|
||||
|
||||
size = strlen (name);
|
||||
struct_name = (char *)xmalloc (size + 8);
|
||||
strcpy (struct_name, name);
|
||||
strcpy (struct_name + size, STRUCT_SUFFIX);
|
||||
|
||||
old_builtin = builtin_address_internal (name, 1);
|
||||
|
||||
b = (struct builtin *)dlsym (handle, struct_name);
|
||||
if (b == 0)
|
||||
{
|
||||
name = printable_filename (filename, 0);
|
||||
builtin_error (_("cannot find %s in shared object %s: %s"),
|
||||
struct_name, name, dlerror ());
|
||||
if (name != filename)
|
||||
free (name);
|
||||
free (struct_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
funcname = xrealloc (struct_name, size + sizeof (LOAD_SUFFIX) + 1);
|
||||
strcpy (funcname, name);
|
||||
strcpy (funcname + size, LOAD_SUFFIX);
|
||||
|
||||
loadfunc = (sh_load_func_t *)dlsym (handle, funcname);
|
||||
if (loadfunc)
|
||||
{
|
||||
/* Add warning if running an init function more than once */
|
||||
if (old_builtin && (old_builtin->flags & STATIC_BUILTIN) == 0)
|
||||
builtin_warning (_("%s: dynamic builtin already loaded"), name);
|
||||
r = (*loadfunc) (name);
|
||||
if (r == 0)
|
||||
{
|
||||
builtin_error (_("load function for %s returns failure (%d): not loaded"), name, r);
|
||||
free (funcname);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
free (funcname);
|
||||
|
||||
b->flags &= ~STATIC_BUILTIN;
|
||||
if (flags & SPECIAL)
|
||||
b->flags |= SPECIAL_BUILTIN;
|
||||
b->handle = handle;
|
||||
|
||||
if (old_builtin)
|
||||
{
|
||||
replaced++;
|
||||
FASTCOPY ((char *)b, (char *)old_builtin, sizeof (struct builtin));
|
||||
}
|
||||
else
|
||||
new_builtins[new++] = b;
|
||||
}
|
||||
|
||||
if (replaced == 0 && new == 0)
|
||||
{
|
||||
free (new_builtins);
|
||||
dlclose (handle);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (new)
|
||||
{
|
||||
total = num_shell_builtins + new;
|
||||
size = (total + 1) * sizeof (struct builtin);
|
||||
|
||||
new_shell_builtins = (struct builtin *)xmalloc (size);
|
||||
FASTCOPY ((char *)shell_builtins, (char *)new_shell_builtins,
|
||||
num_shell_builtins * sizeof (struct builtin));
|
||||
for (replaced = 0; replaced < new; replaced++)
|
||||
FASTCOPY ((char *)new_builtins[replaced],
|
||||
(char *)&new_shell_builtins[num_shell_builtins + replaced],
|
||||
sizeof (struct builtin));
|
||||
|
||||
new_shell_builtins[total].name = (char *)0;
|
||||
new_shell_builtins[total].function = (sh_builtin_func_t *)0;
|
||||
new_shell_builtins[total].flags = 0;
|
||||
|
||||
if (shell_builtins != static_shell_builtins)
|
||||
free (shell_builtins);
|
||||
|
||||
shell_builtins = new_shell_builtins;
|
||||
num_shell_builtins = total;
|
||||
initialize_shell_builtins ();
|
||||
}
|
||||
|
||||
free (new_builtins);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_DLCLOSE)
|
||||
static void
|
||||
delete_builtin (b)
|
||||
struct builtin *b;
|
||||
{
|
||||
int ind, size;
|
||||
struct builtin *new_shell_builtins;
|
||||
|
||||
/* XXX - funky pointer arithmetic - XXX */
|
||||
#ifdef __STDC__
|
||||
ind = b - shell_builtins;
|
||||
#else
|
||||
ind = ((int)b - (int)shell_builtins) / sizeof (struct builtin);
|
||||
#endif
|
||||
size = num_shell_builtins * sizeof (struct builtin);
|
||||
new_shell_builtins = (struct builtin *)xmalloc (size);
|
||||
|
||||
/* Copy shell_builtins[0]...shell_builtins[ind - 1] to new_shell_builtins */
|
||||
if (ind)
|
||||
FASTCOPY ((char *)shell_builtins, (char *)new_shell_builtins,
|
||||
ind * sizeof (struct builtin));
|
||||
/* Copy shell_builtins[ind+1]...shell_builtins[num_shell_builtins to
|
||||
new_shell_builtins, starting at ind. */
|
||||
FASTCOPY ((char *)(&shell_builtins[ind+1]),
|
||||
(char *)(&new_shell_builtins[ind]),
|
||||
(num_shell_builtins - ind) * sizeof (struct builtin));
|
||||
|
||||
if (shell_builtins != static_shell_builtins)
|
||||
free (shell_builtins);
|
||||
|
||||
/* The result is still sorted. */
|
||||
num_shell_builtins--;
|
||||
shell_builtins = new_shell_builtins;
|
||||
}
|
||||
|
||||
/* Tenon's MachTen has a dlclose that doesn't return a value, so we
|
||||
finesse it with a local wrapper. */
|
||||
static int
|
||||
local_dlclose (handle)
|
||||
void *handle;
|
||||
{
|
||||
#if !defined (__MACHTEN__)
|
||||
return (dlclose (handle));
|
||||
#else /* __MACHTEN__ */
|
||||
dlclose (handle);
|
||||
return ((dlerror () != NULL) ? -1 : 0);
|
||||
#endif /* __MACHTEN__ */
|
||||
}
|
||||
|
||||
static int
|
||||
dyn_unload_builtin (name)
|
||||
char *name;
|
||||
{
|
||||
struct builtin *b;
|
||||
void *handle;
|
||||
char *funcname;
|
||||
sh_unload_func_t *unloadfunc;
|
||||
int ref, i, size;
|
||||
|
||||
b = builtin_address_internal (name, 1);
|
||||
if (b == 0)
|
||||
{
|
||||
sh_notbuiltin (name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
if (b->flags & STATIC_BUILTIN)
|
||||
{
|
||||
builtin_error (_("%s: not dynamically loaded"), name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
handle = (void *)b->handle;
|
||||
for (ref = i = 0; i < num_shell_builtins; i++)
|
||||
{
|
||||
if (shell_builtins[i].handle == b->handle)
|
||||
ref++;
|
||||
}
|
||||
|
||||
/* Call any unload function */
|
||||
size = strlen (name);
|
||||
funcname = xmalloc (size + sizeof (UNLOAD_SUFFIX) + 1);
|
||||
strcpy (funcname, name);
|
||||
strcpy (funcname + size, UNLOAD_SUFFIX);
|
||||
|
||||
unloadfunc = (sh_unload_func_t *)dlsym (handle, funcname);
|
||||
if (unloadfunc)
|
||||
(*unloadfunc) (name); /* void function */
|
||||
free (funcname);
|
||||
|
||||
/* Don't remove the shared object unless the reference count of builtins
|
||||
using it drops to zero. */
|
||||
if (ref == 1 && local_dlclose (handle) != 0)
|
||||
{
|
||||
builtin_error (_("%s: cannot delete: %s"), name, dlerror ());
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* Now remove this entry from the builtin table and reinitialize. */
|
||||
delete_builtin (b);
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
#endif
|
28
third_party/bash/builtins_eval.c
vendored
Normal file
28
third_party/bash/builtins_eval.c
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
/* eval.c, created from eval.def. */
|
||||
#line 22 "./eval.def"
|
||||
|
||||
#line 34 "./eval.def"
|
||||
|
||||
#include "config.h"
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "shell.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
/* Parse the string that these words make, and execute the command found. */
|
||||
int
|
||||
eval_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
if (no_options (list))
|
||||
return (EX_USAGE);
|
||||
list = loptend; /* skip over possible `--' */
|
||||
|
||||
return (list ? evalstring (string_list (list), "eval", SEVAL_NOHIST) : EXECUTION_SUCCESS);
|
||||
}
|
238
third_party/bash/builtins_exec.c
vendored
Normal file
238
third_party/bash/builtins_exec.c
vendored
Normal file
|
@ -0,0 +1,238 @@
|
|||
/* exec.c, created from exec.def. */
|
||||
#line 22 "./exec.def"
|
||||
|
||||
#line 43 "./exec.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "bashtypes.h"
|
||||
#include "posixstat.h"
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "execute_cmd.h"
|
||||
#include "findcmd.h"
|
||||
#if defined (JOB_CONTROL)
|
||||
# include "jobs.h"
|
||||
#endif
|
||||
#include "flags.h"
|
||||
#include "trap.h"
|
||||
#if defined (HISTORY)
|
||||
# include "bashhist.h"
|
||||
#endif
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "input.h"
|
||||
|
||||
/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
extern REDIRECT *redirection_undo_list;
|
||||
extern char *exec_argv0;
|
||||
|
||||
int no_exit_on_failed_exec;
|
||||
|
||||
/* If the user wants this to look like a login shell, then
|
||||
prepend a `-' onto NAME and return the new name. */
|
||||
static char *
|
||||
mkdashname (name)
|
||||
char *name;
|
||||
{
|
||||
char *ret;
|
||||
|
||||
ret = (char *)xmalloc (2 + strlen (name));
|
||||
ret[0] = '-';
|
||||
strcpy (ret + 1, name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
exec_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int exit_value = EXECUTION_FAILURE;
|
||||
int cleanenv, login, opt, orig_job_control;
|
||||
char *argv0, *command, **args, **env, *newname, *com2;
|
||||
|
||||
cleanenv = login = orig_job_control = 0;
|
||||
exec_argv0 = argv0 = (char *)NULL;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "cla:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'c':
|
||||
cleanenv = 1;
|
||||
break;
|
||||
case 'l':
|
||||
login = 1;
|
||||
break;
|
||||
case 'a':
|
||||
argv0 = list_optarg;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
/* First, let the redirections remain. */
|
||||
dispose_redirects (redirection_undo_list);
|
||||
redirection_undo_list = (REDIRECT *)NULL;
|
||||
|
||||
if (list == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
if (restricted)
|
||||
{
|
||||
sh_restricted ((char *)NULL);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif /* RESTRICTED_SHELL */
|
||||
|
||||
args = strvec_from_word_list (list, 1, 0, (int *)NULL);
|
||||
env = (char **)0;
|
||||
|
||||
/* A command with a slash anywhere in its name is not looked up in $PATH. */
|
||||
command = absolute_program (args[0]) ? args[0] : search_for_command (args[0], 1);
|
||||
|
||||
if (command == 0)
|
||||
{
|
||||
if (file_isdir (args[0]))
|
||||
{
|
||||
#if defined (EISDIR)
|
||||
builtin_error (_("%s: cannot execute: %s"), args[0], strerror (EISDIR));
|
||||
#else
|
||||
builtin_error (_("%s: cannot execute: %s"), args[0], strerror (errno));
|
||||
#endif
|
||||
exit_value = EX_NOEXEC;
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_notfound (args[0]);
|
||||
exit_value = EX_NOTFOUND; /* As per Posix.2, 3.14.6 */
|
||||
}
|
||||
goto failed_exec;
|
||||
}
|
||||
|
||||
com2 = full_pathname (command);
|
||||
if (com2)
|
||||
{
|
||||
if (command != args[0])
|
||||
free (command);
|
||||
command = com2;
|
||||
}
|
||||
|
||||
if (argv0)
|
||||
{
|
||||
free (args[0]);
|
||||
args[0] = login ? mkdashname (argv0) : savestring (argv0);
|
||||
exec_argv0 = savestring (args[0]);
|
||||
}
|
||||
else if (login)
|
||||
{
|
||||
newname = mkdashname (args[0]);
|
||||
free (args[0]);
|
||||
args[0] = newname;
|
||||
}
|
||||
|
||||
/* Decrement SHLVL by 1 so a new shell started here has the same value,
|
||||
preserving the appearance. After we do that, we need to change the
|
||||
exported environment to include the new value. If we've already forked
|
||||
and are in a subshell, we don't want to decrement the shell level,
|
||||
since we are `increasing' the level */
|
||||
|
||||
if (cleanenv == 0 && (subshell_environment & SUBSHELL_PAREN) == 0)
|
||||
adjust_shell_level (-1);
|
||||
|
||||
if (cleanenv)
|
||||
{
|
||||
env = strvec_create (1);
|
||||
env[0] = (char *)0;
|
||||
}
|
||||
else
|
||||
{
|
||||
maybe_make_export_env ();
|
||||
env = export_env;
|
||||
}
|
||||
|
||||
#if defined (HISTORY)
|
||||
if (interactive_shell && subshell_environment == 0)
|
||||
maybe_save_shell_history ();
|
||||
#endif /* HISTORY */
|
||||
|
||||
reset_signal_handlers (); /* leave trap strings in place */
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
orig_job_control = job_control; /* XXX - was also interactive_shell */
|
||||
if (subshell_environment == 0)
|
||||
end_job_control ();
|
||||
if (interactive || job_control)
|
||||
default_tty_job_signals (); /* undo initialize_job_signals */
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
if (default_buffered_input >= 0)
|
||||
sync_buffered_stream (default_buffered_input);
|
||||
#endif
|
||||
|
||||
exit_value = shell_execve (command, args, env);
|
||||
|
||||
/* We have to set this to NULL because shell_execve has called realloc()
|
||||
to stuff more items at the front of the array, which may have caused
|
||||
the memory to be freed by realloc(). We don't want to free it twice. */
|
||||
args = (char **)NULL;
|
||||
if (cleanenv == 0)
|
||||
adjust_shell_level (1);
|
||||
|
||||
if (exit_value == EX_NOTFOUND) /* no duplicate error message */
|
||||
goto failed_exec;
|
||||
else if (executable_file (command) == 0)
|
||||
{
|
||||
builtin_error (_("%s: cannot execute: %s"), command, strerror (errno));
|
||||
exit_value = EX_NOEXEC; /* As per Posix.2, 3.14.6 */
|
||||
}
|
||||
else
|
||||
file_error (command);
|
||||
|
||||
failed_exec:
|
||||
FREE (command);
|
||||
|
||||
if (subshell_environment || (interactive == 0 && no_exit_on_failed_exec == 0))
|
||||
exit_shell (last_command_exit_value = exit_value);
|
||||
|
||||
if (args)
|
||||
strvec_dispose (args);
|
||||
|
||||
if (env && env != export_env)
|
||||
strvec_dispose (env);
|
||||
|
||||
/* If we're not exiting after the exec fails, we restore the shell signal
|
||||
handlers and then modify the signal dispositions based on the trap strings
|
||||
before the failed exec. */
|
||||
initialize_signals (1);
|
||||
restore_traps ();
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
if (orig_job_control)
|
||||
restart_job_control ();
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
return (exit_value);
|
||||
}
|
136
third_party/bash/builtins_exit.c
vendored
Normal file
136
third_party/bash/builtins_exit.c
vendored
Normal file
|
@ -0,0 +1,136 @@
|
|||
/* exit.c, created from exit.def. */
|
||||
#line 22 "./exit.def"
|
||||
|
||||
#line 31 "./exit.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "bashtypes.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "execute_cmd.h"
|
||||
#include "jobs.h"
|
||||
#include "trap.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "builtext.h" /* for jobs_builtin */
|
||||
|
||||
extern int check_jobs_at_exit;
|
||||
|
||||
static int exit_or_logout PARAMS((WORD_LIST *));
|
||||
static int sourced_logout;
|
||||
|
||||
int
|
||||
exit_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
CHECK_HELPOPT (list);
|
||||
|
||||
if (interactive)
|
||||
{
|
||||
fprintf (stderr, login_shell ? _("logout\n") : "exit\n");
|
||||
fflush (stderr);
|
||||
}
|
||||
|
||||
return (exit_or_logout (list));
|
||||
}
|
||||
|
||||
#line 79 "./exit.def"
|
||||
|
||||
/* How to logout. */
|
||||
int
|
||||
logout_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
CHECK_HELPOPT (list);
|
||||
|
||||
if (login_shell == 0 /* && interactive */)
|
||||
{
|
||||
builtin_error (_("not login shell: use `exit'"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
return (exit_or_logout (list));
|
||||
}
|
||||
|
||||
static int
|
||||
exit_or_logout (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int exit_value;
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
int exit_immediate_okay, stopmsg;
|
||||
|
||||
exit_immediate_okay = (interactive == 0 ||
|
||||
last_shell_builtin == exit_builtin ||
|
||||
last_shell_builtin == logout_builtin ||
|
||||
last_shell_builtin == jobs_builtin);
|
||||
|
||||
/* Check for stopped jobs if the user wants to. */
|
||||
if (exit_immediate_okay == 0)
|
||||
{
|
||||
register int i;
|
||||
for (i = stopmsg = 0; i < js.j_jobslots; i++)
|
||||
if (jobs[i] && STOPPED (i))
|
||||
stopmsg = JSTOPPED;
|
||||
else if (check_jobs_at_exit && stopmsg == 0 && jobs[i] && RUNNING (i))
|
||||
stopmsg = JRUNNING;
|
||||
|
||||
if (stopmsg == JSTOPPED)
|
||||
fprintf (stderr, _("There are stopped jobs.\n"));
|
||||
else if (stopmsg == JRUNNING)
|
||||
fprintf (stderr, _("There are running jobs.\n"));
|
||||
|
||||
if (stopmsg && check_jobs_at_exit)
|
||||
list_all_jobs (JLIST_STANDARD);
|
||||
|
||||
if (stopmsg)
|
||||
{
|
||||
/* This is NOT superfluous because EOF can get here without
|
||||
going through the command parser. Set both last and this
|
||||
so that either `exit', `logout', or ^D will work to exit
|
||||
immediately if nothing intervenes. */
|
||||
this_shell_builtin = last_shell_builtin = exit_builtin;
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
/* Get return value if present. This means that you can type
|
||||
`logout 5' to a shell, and it returns 5. */
|
||||
|
||||
/* If we're running the exit trap (running_trap == 1, since running_trap
|
||||
gets set to SIG+1), and we don't have a argument given to `exit'
|
||||
(list == 0), use the exit status we saved before running the trap
|
||||
commands (trap_saved_exit_value). */
|
||||
exit_value = (running_trap == 1 && list == 0) ? trap_saved_exit_value : get_exitstat (list);
|
||||
|
||||
bash_logout ();
|
||||
|
||||
last_command_exit_value = exit_value;
|
||||
|
||||
/* Exit the program. */
|
||||
jump_to_top_level (EXITBLTIN);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
void
|
||||
bash_logout ()
|
||||
{
|
||||
/* Run our `~/.bash_logout' file if it exists, and this is a login shell. */
|
||||
if (login_shell && sourced_logout++ == 0 && subshell_environment == 0)
|
||||
{
|
||||
maybe_execute_file ("~/.bash_logout", 1);
|
||||
#ifdef SYS_BASH_LOGOUT
|
||||
maybe_execute_file (SYS_BASH_LOGOUT, 1);
|
||||
#endif
|
||||
}
|
||||
}
|
739
third_party/bash/builtins_fc.c
vendored
Normal file
739
third_party/bash/builtins_fc.c
vendored
Normal file
|
@ -0,0 +1,739 @@
|
|||
/* fc.c, created from fc.def. */
|
||||
#line 22 "./fc.def"
|
||||
|
||||
#line 51 "./fc.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HISTORY)
|
||||
#if defined (HAVE_SYS_PARAM_H)
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
#include "bashtypes.h"
|
||||
#include "posixstat.h"
|
||||
#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
|
||||
# include <sys/file.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "chartypes.h"
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
#include <errno.h>
|
||||
|
||||
#include "shell.h"
|
||||
#include "builtins.h"
|
||||
#include "flags.h"
|
||||
#include "parser.h"
|
||||
#include "bashhist.h"
|
||||
#include "maxpath.h"
|
||||
#include "third_party/readline/history.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
#define HIST_INVALID INT_MIN
|
||||
#define HIST_ERANGE INT_MIN+1
|
||||
#define HIST_NOTFOUND INT_MIN+2
|
||||
|
||||
/* Values for the flags argument to fc_gethnum */
|
||||
#define HN_LISTING 0x01
|
||||
#define HN_FIRST 0x02
|
||||
|
||||
extern int unlink PARAMS((const char *));
|
||||
|
||||
extern FILE *sh_mktmpfp PARAMS((char *, int, char **));
|
||||
|
||||
extern int suppress_debug_trap_verbose;
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* The K*rn shell style fc command (Fix Command) */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* fc builtin command (fix command) for Bash for those who
|
||||
like K*rn-style history better than csh-style.
|
||||
|
||||
fc [-e ename] [-nlr] [first] [last]
|
||||
|
||||
FIRST and LAST can be numbers specifying the range, or FIRST can be
|
||||
a string, which means the most recent command beginning with that
|
||||
string.
|
||||
|
||||
-e ENAME selects which editor to use. Default is FCEDIT, then EDITOR,
|
||||
then the editor which corresponds to the current readline editing
|
||||
mode, then vi.
|
||||
|
||||
-l means list lines instead of editing.
|
||||
-n means no line numbers listed.
|
||||
-r means reverse the order of the lines (making it newest listed first).
|
||||
|
||||
fc -e - [pat=rep ...] [command]
|
||||
fc -s [pat=rep ...] [command]
|
||||
|
||||
Equivalent to !command:sg/pat/rep execpt there can be multiple PAT=REP's.
|
||||
*/
|
||||
|
||||
/* Data structure describing a list of global replacements to perform. */
|
||||
typedef struct repl {
|
||||
struct repl *next;
|
||||
char *pat;
|
||||
char *rep;
|
||||
} REPL;
|
||||
|
||||
/* Accessors for HIST_ENTRY lists that are called HLIST. */
|
||||
#define histline(i) (hlist[(i)]->line)
|
||||
#define histdata(i) (hlist[(i)]->data)
|
||||
|
||||
#define FREE_RLIST() \
|
||||
do { \
|
||||
for (rl = rlist; rl; ) { \
|
||||
REPL *r; \
|
||||
r = rl->next; \
|
||||
if (rl->pat) \
|
||||
free (rl->pat); \
|
||||
if (rl->rep) \
|
||||
free (rl->rep); \
|
||||
free (rl); \
|
||||
rl = r; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static char *fc_dosubs PARAMS((char *, REPL *));
|
||||
static char *fc_gethist PARAMS((char *, HIST_ENTRY **, int));
|
||||
static int fc_gethnum PARAMS((char *, HIST_ENTRY **, int));
|
||||
static int fc_number PARAMS((WORD_LIST *));
|
||||
static void fc_replhist PARAMS((char *));
|
||||
#ifdef INCLUDE_UNUSED
|
||||
static char *fc_readline PARAMS((FILE *));
|
||||
static void fc_addhist PARAMS((char *));
|
||||
#endif
|
||||
|
||||
static void
|
||||
set_verbose_flag ()
|
||||
{
|
||||
echo_input_at_read = verbose_flag;
|
||||
}
|
||||
|
||||
/* String to execute on a file that we want to edit. */
|
||||
#define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}"
|
||||
#if defined (STRICT_POSIX)
|
||||
# define POSIX_FC_EDIT_COMMAND "${FCEDIT:-ed}"
|
||||
#else
|
||||
# define POSIX_FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-ed}}"
|
||||
#endif
|
||||
|
||||
int
|
||||
fc_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register int i;
|
||||
register char *sep;
|
||||
int numbering, reverse, listing, execute;
|
||||
int histbeg, histend, last_hist, retval, opt, rh, real_last;
|
||||
FILE *stream;
|
||||
REPL *rlist, *rl;
|
||||
char *ename, *command, *newcom, *fcedit;
|
||||
HIST_ENTRY **hlist;
|
||||
char *fn;
|
||||
|
||||
numbering = 1;
|
||||
reverse = listing = execute = 0;
|
||||
ename = (char *)NULL;
|
||||
|
||||
/* Parse out the options and set which of the two forms we're in. */
|
||||
reset_internal_getopt ();
|
||||
lcurrent = list; /* XXX */
|
||||
while (fc_number (loptend = lcurrent) == 0 &&
|
||||
(opt = internal_getopt (list, ":e:lnrs")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'n':
|
||||
numbering = 0;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
listing = HN_LISTING; /* for fc_gethnum */
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
reverse = 1;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
execute = 1;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
ename = list_optarg;
|
||||
break;
|
||||
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
if (ename && (*ename == '-') && (ename[1] == '\0'))
|
||||
execute = 1;
|
||||
|
||||
/* The "execute" form of the command (re-run, with possible string
|
||||
substitutions). */
|
||||
if (execute)
|
||||
{
|
||||
rlist = (REPL *)NULL;
|
||||
while (list && ((sep = (char *)strchr (list->word->word, '=')) != NULL))
|
||||
{
|
||||
*sep++ = '\0';
|
||||
rl = (REPL *)xmalloc (sizeof (REPL));
|
||||
rl->next = (REPL *)NULL;
|
||||
rl->pat = savestring (list->word->word);
|
||||
rl->rep = savestring (sep);
|
||||
|
||||
if (rlist == NULL)
|
||||
rlist = rl;
|
||||
else
|
||||
{
|
||||
rl->next = rlist;
|
||||
rlist = rl;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
/* If we have a list of substitutions to do, then reverse it
|
||||
to get the replacements in the proper order. */
|
||||
|
||||
rlist = REVERSE_LIST (rlist, REPL *);
|
||||
|
||||
hlist = history_list ();
|
||||
|
||||
/* If we still have something in list, it is a command spec.
|
||||
Otherwise, we use the most recent command in time. */
|
||||
command = fc_gethist (list ? list->word->word : (char *)NULL, hlist, 0);
|
||||
|
||||
if (command == NULL)
|
||||
{
|
||||
builtin_error (_("no command found"));
|
||||
if (rlist)
|
||||
FREE_RLIST ();
|
||||
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (rlist)
|
||||
{
|
||||
newcom = fc_dosubs (command, rlist);
|
||||
free (command);
|
||||
FREE_RLIST ();
|
||||
command = newcom;
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s\n", command);
|
||||
fc_replhist (command); /* replace `fc -s' with command */
|
||||
/* Posix says that the re-executed commands should be entered into the
|
||||
history. */
|
||||
return (parse_and_execute (command, "fc", SEVAL_NOHIST));
|
||||
}
|
||||
|
||||
/* This is the second form of the command (the list-or-edit-and-rerun
|
||||
form). */
|
||||
hlist = history_list ();
|
||||
if (hlist == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
for (i = 0; hlist[i]; i++);
|
||||
|
||||
/* With the Bash implementation of history, the current command line
|
||||
("fc blah..." and so on) is already part of the history list by
|
||||
the time we get to this point. This just skips over that command
|
||||
and makes the last command that this deals with be the last command
|
||||
the user entered before the fc. We need to check whether the
|
||||
line was actually added (HISTIGNORE may have caused it to not be),
|
||||
so we check hist_last_line_added. */
|
||||
|
||||
/* Even though command substitution through parse_and_execute turns off
|
||||
remember_on_history, command substitution in a shell when set -o history
|
||||
has been enabled (interactive or not) should use it in the last_hist
|
||||
calculation as if it were on. */
|
||||
rh = remember_on_history || ((subshell_environment & SUBSHELL_COMSUB) && enable_history_list);
|
||||
last_hist = i - rh - hist_last_line_added;
|
||||
|
||||
/* Make sure that real_last is calculated the same way here and in
|
||||
fc_gethnum. The return value from fc_gethnum is treated specially if
|
||||
it is == real_last and we are listing commands. */
|
||||
real_last = i;
|
||||
/* back up from the end to the last non-null history entry */
|
||||
while (hlist[real_last] == 0 && real_last > 0)
|
||||
real_last--;
|
||||
|
||||
/* XXX */
|
||||
if (i == last_hist && hlist[last_hist] == 0)
|
||||
while (last_hist >= 0 && hlist[last_hist] == 0)
|
||||
last_hist--;
|
||||
if (last_hist < 0)
|
||||
last_hist = 0; /* per POSIX */
|
||||
|
||||
if (list)
|
||||
{
|
||||
histbeg = fc_gethnum (list->word->word, hlist, listing|HN_FIRST);
|
||||
list = list->next;
|
||||
|
||||
if (list)
|
||||
histend = fc_gethnum (list->word->word, hlist, listing);
|
||||
else if (histbeg == real_last)
|
||||
histend = listing ? real_last : histbeg;
|
||||
else
|
||||
histend = listing ? last_hist : histbeg;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The default for listing is the last 16 history items. */
|
||||
if (listing)
|
||||
{
|
||||
histend = last_hist;
|
||||
histbeg = histend - 16 + 1; /* +1 because loop below uses >= */
|
||||
if (histbeg < 0)
|
||||
histbeg = 0;
|
||||
}
|
||||
else
|
||||
/* For editing, it is the last history command. */
|
||||
histbeg = histend = last_hist;
|
||||
}
|
||||
|
||||
if (histbeg == HIST_INVALID || histend == HIST_INVALID)
|
||||
{
|
||||
sh_erange ((char *)NULL, _("history specification"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else if (histbeg == HIST_ERANGE || histend == HIST_ERANGE)
|
||||
{
|
||||
sh_erange ((char *)NULL, _("history specification"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else if (histbeg == HIST_NOTFOUND || histend == HIST_NOTFOUND)
|
||||
{
|
||||
builtin_error (_("no command found"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* We don't throw an error for line specifications out of range, per POSIX */
|
||||
if (histbeg < 0)
|
||||
histbeg = 0;
|
||||
if (histend < 0)
|
||||
histend = 0;
|
||||
|
||||
/* "When not listing, the fc command that caused the editing shall not be
|
||||
entered into the history list." */
|
||||
if (listing == 0 && hist_last_line_added)
|
||||
{
|
||||
bash_delete_last_history ();
|
||||
/* If we're editing a single command -- the last command in the
|
||||
history -- and we just removed the dummy command added by
|
||||
edit_and_execute_command (), we need to check whether or not we
|
||||
just removed the last command in the history and need to back
|
||||
the pointer up. remember_on_history is off because we're running
|
||||
in parse_and_execute(). */
|
||||
if (histbeg == histend && histend == last_hist && hlist[last_hist] == 0)
|
||||
last_hist = histbeg = --histend;
|
||||
|
||||
if (hlist[last_hist] == 0)
|
||||
last_hist--;
|
||||
if (histend >= last_hist)
|
||||
histend = last_hist;
|
||||
else if (histbeg >= last_hist)
|
||||
histbeg = last_hist;
|
||||
}
|
||||
|
||||
if (histbeg == HIST_INVALID || histend == HIST_INVALID)
|
||||
{
|
||||
sh_erange ((char *)NULL, _("history specification"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else if (histbeg == HIST_ERANGE || histend == HIST_ERANGE)
|
||||
{
|
||||
sh_erange ((char *)NULL, _("history specification"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else if (histbeg == HIST_NOTFOUND || histend == HIST_NOTFOUND)
|
||||
{
|
||||
builtin_error (_("no command found"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* We don't throw an error for line specifications out of range, per POSIX */
|
||||
if (histbeg < 0)
|
||||
histbeg = 0;
|
||||
if (histend < 0)
|
||||
histend = 0;
|
||||
|
||||
if (histend < histbeg)
|
||||
{
|
||||
i = histend;
|
||||
histend = histbeg;
|
||||
histbeg = i;
|
||||
|
||||
reverse = 1;
|
||||
}
|
||||
|
||||
if (listing)
|
||||
stream = stdout;
|
||||
else
|
||||
{
|
||||
numbering = 0;
|
||||
stream = sh_mktmpfp ("bash-fc", MT_USERANDOM|MT_USETMPDIR, &fn);
|
||||
if (stream == 0)
|
||||
{
|
||||
builtin_error (_("%s: cannot open temp file: %s"), fn ? fn : "", strerror (errno));
|
||||
FREE (fn);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = reverse ? histend : histbeg; reverse ? i >= histbeg : i <= histend; reverse ? i-- : i++)
|
||||
{
|
||||
QUIT;
|
||||
if (hlist[i] == 0)
|
||||
continue;
|
||||
if (numbering)
|
||||
fprintf (stream, "%d", i + history_base);
|
||||
if (listing)
|
||||
{
|
||||
if (posixly_correct)
|
||||
fputs ("\t", stream);
|
||||
else
|
||||
fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
|
||||
}
|
||||
if (histline (i))
|
||||
fprintf (stream, "%s\n", histline (i));
|
||||
}
|
||||
|
||||
if (listing)
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
|
||||
fflush (stream);
|
||||
if (ferror (stream))
|
||||
{
|
||||
sh_wrerror ();
|
||||
fclose (stream);
|
||||
FREE (fn);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
fclose (stream);
|
||||
|
||||
/* Now edit the file of commands. */
|
||||
if (ename)
|
||||
{
|
||||
command = (char *)xmalloc (strlen (ename) + strlen (fn) + 2);
|
||||
sprintf (command, "%s %s", ename, fn);
|
||||
}
|
||||
else
|
||||
{
|
||||
fcedit = posixly_correct ? POSIX_FC_EDIT_COMMAND : FC_EDIT_COMMAND;
|
||||
command = (char *)xmalloc (3 + strlen (fcedit) + strlen (fn));
|
||||
sprintf (command, "%s %s", fcedit, fn);
|
||||
}
|
||||
retval = parse_and_execute (command, "fc", SEVAL_NOHIST);
|
||||
if (retval != EXECUTION_SUCCESS)
|
||||
{
|
||||
unlink (fn);
|
||||
free (fn);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
#if defined (READLINE)
|
||||
/* If we're executing as part of a dispatched readline command like
|
||||
{emacs,vi}_edit_and_execute_command, the readline state will indicate it.
|
||||
We could remove the partial command from the history, but ksh93 doesn't
|
||||
so we stay compatible. */
|
||||
#endif
|
||||
|
||||
/* Make sure parse_and_execute doesn't turn this off, even though a
|
||||
call to parse_and_execute farther up the function call stack (e.g.,
|
||||
if this is called by vi_edit_and_execute_command) may have already
|
||||
called bash_history_disable. */
|
||||
remember_on_history = 1;
|
||||
|
||||
/* Turn on the `v' flag while fc_execute_file runs so the commands
|
||||
will be echoed as they are read by the parser. */
|
||||
begin_unwind_frame ("fc builtin");
|
||||
add_unwind_protect (xfree, fn);
|
||||
add_unwind_protect (unlink, fn);
|
||||
add_unwind_protect (set_verbose_flag, (char *)NULL);
|
||||
unwind_protect_int (suppress_debug_trap_verbose);
|
||||
echo_input_at_read = 1;
|
||||
suppress_debug_trap_verbose = 1;
|
||||
|
||||
retval = fc_execute_file (fn);
|
||||
run_unwind_frame ("fc builtin");
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/* Return 1 if LIST->word->word is a legal number for fc's use. */
|
||||
static int
|
||||
fc_number (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *s;
|
||||
|
||||
if (list == 0)
|
||||
return 0;
|
||||
s = list->word->word;
|
||||
if (*s == '-')
|
||||
s++;
|
||||
return (legal_number (s, (intmax_t *)NULL));
|
||||
}
|
||||
|
||||
/* Return an absolute index into HLIST which corresponds to COMMAND. If
|
||||
COMMAND is a number, then it was specified in relative terms. If it
|
||||
is a string, then it is the start of a command line present in HLIST.
|
||||
MODE includes HN_LISTING if we are listing commands, and does not if we
|
||||
are executing them. If MODE includes HN_FIRST we are looking for the
|
||||
first history number specification. */
|
||||
static int
|
||||
fc_gethnum (command, hlist, mode)
|
||||
char *command;
|
||||
HIST_ENTRY **hlist;
|
||||
int mode;
|
||||
{
|
||||
int sign, n, clen, rh;
|
||||
register int i, j, last_hist, real_last, listing;
|
||||
register char *s;
|
||||
|
||||
listing = mode & HN_LISTING;
|
||||
sign = 1;
|
||||
/* Count history elements. */
|
||||
for (i = 0; hlist[i]; i++);
|
||||
|
||||
/* With the Bash implementation of history, the current command line
|
||||
("fc blah..." and so on) is already part of the history list by
|
||||
the time we get to this point. This just skips over that command
|
||||
and makes the last command that this deals with be the last command
|
||||
the user entered before the fc. We need to check whether the
|
||||
line was actually added (HISTIGNORE may have caused it to not be),
|
||||
so we check hist_last_line_added. This needs to agree with the
|
||||
calculation of last_hist in fc_builtin above. */
|
||||
/* Even though command substitution through parse_and_execute turns off
|
||||
remember_on_history, command substitution in a shell when set -o history
|
||||
has been enabled (interactive or not) should use it in the last_hist
|
||||
calculation as if it were on. */
|
||||
rh = remember_on_history || ((subshell_environment & SUBSHELL_COMSUB) && enable_history_list);
|
||||
last_hist = i - rh - hist_last_line_added;
|
||||
|
||||
if (i == last_hist && hlist[last_hist] == 0)
|
||||
while (last_hist >= 0 && hlist[last_hist] == 0)
|
||||
last_hist--;
|
||||
if (last_hist < 0)
|
||||
return (-1);
|
||||
|
||||
real_last = i;
|
||||
i = last_hist;
|
||||
|
||||
/* No specification defaults to most recent command. */
|
||||
if (command == NULL)
|
||||
return (i);
|
||||
|
||||
/* back up from the end to the last non-null history entry */
|
||||
while (hlist[real_last] == 0 && real_last > 0)
|
||||
real_last--;
|
||||
|
||||
/* Otherwise, there is a specification. It can be a number relative to
|
||||
the current position, or an absolute history number. */
|
||||
s = command;
|
||||
|
||||
/* Handle possible leading minus sign. */
|
||||
if (s && (*s == '-'))
|
||||
{
|
||||
sign = -1;
|
||||
s++;
|
||||
}
|
||||
|
||||
if (s && DIGIT(*s))
|
||||
{
|
||||
n = atoi (s);
|
||||
n *= sign;
|
||||
|
||||
/* We want to return something that is an offset to HISTORY_BASE. */
|
||||
|
||||
/* If the value is negative or zero, then it is an offset from
|
||||
the current history item. */
|
||||
/* We don't use HN_FIRST here, so we don't return different values
|
||||
depending on whether we're looking for the first or last in a
|
||||
pair of range arguments, but nobody else does, either. */
|
||||
if (n < 0)
|
||||
{
|
||||
n += i + 1;
|
||||
return (n < 0 ? 0 : n);
|
||||
}
|
||||
else if (n == 0)
|
||||
return ((sign == -1) ? (listing ? real_last : HIST_INVALID) : i);
|
||||
else
|
||||
{
|
||||
/* If we're out of range (greater than I (last history entry) or
|
||||
less than HISTORY_BASE, we want to return different values
|
||||
based on whether or not we are looking for the first or last
|
||||
value in a desired range of history entries. */
|
||||
n -= history_base;
|
||||
if (n < 0)
|
||||
return (mode & HN_FIRST ? 0 : i);
|
||||
else if (n >= i)
|
||||
return (mode & HN_FIRST ? 0 : i);
|
||||
else
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
clen = strlen (command);
|
||||
for (j = i; j >= 0; j--)
|
||||
{
|
||||
if (STREQN (command, histline (j), clen))
|
||||
return (j);
|
||||
}
|
||||
return (HIST_NOTFOUND);
|
||||
}
|
||||
|
||||
/* Locate the most recent history line which begins with
|
||||
COMMAND in HLIST, and return a malloc()'ed copy of it.
|
||||
MODE is 1 if we are listing commands, 0 if we are executing them. */
|
||||
static char *
|
||||
fc_gethist (command, hlist, mode)
|
||||
char *command;
|
||||
HIST_ENTRY **hlist;
|
||||
int mode;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (hlist == 0)
|
||||
return ((char *)NULL);
|
||||
|
||||
i = fc_gethnum (command, hlist, mode);
|
||||
|
||||
if (i >= 0)
|
||||
return (savestring (histline (i)));
|
||||
else
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_UNUSED
|
||||
/* Read the edited history lines from STREAM and return them
|
||||
one at a time. This can read unlimited length lines. The
|
||||
caller should free the storage. */
|
||||
static char *
|
||||
fc_readline (stream)
|
||||
FILE *stream;
|
||||
{
|
||||
register int c;
|
||||
int line_len = 0, lindex = 0;
|
||||
char *line = (char *)NULL;
|
||||
|
||||
while ((c = getc (stream)) != EOF)
|
||||
{
|
||||
if ((lindex + 2) >= line_len)
|
||||
line = (char *)xrealloc (line, (line_len += 128));
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
line[lindex++] = '\n';
|
||||
line[lindex++] = '\0';
|
||||
return (line);
|
||||
}
|
||||
else
|
||||
line[lindex++] = c;
|
||||
}
|
||||
|
||||
if (!lindex)
|
||||
{
|
||||
if (line)
|
||||
free (line);
|
||||
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
if (lindex + 2 >= line_len)
|
||||
line = (char *)xrealloc (line, lindex + 3);
|
||||
|
||||
line[lindex++] = '\n'; /* Finish with newline if none in file */
|
||||
line[lindex++] = '\0';
|
||||
return (line);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Perform the SUBS on COMMAND.
|
||||
SUBS is a list of substitutions, and COMMAND is a simple string.
|
||||
Return a pointer to a malloc'ed string which contains the substituted
|
||||
command. */
|
||||
static char *
|
||||
fc_dosubs (command, subs)
|
||||
char *command;
|
||||
REPL *subs;
|
||||
{
|
||||
register char *new, *t;
|
||||
register REPL *r;
|
||||
|
||||
for (new = savestring (command), r = subs; r; r = r->next)
|
||||
{
|
||||
t = strsub (new, r->pat, r->rep, 1);
|
||||
free (new);
|
||||
new = t;
|
||||
}
|
||||
return (new);
|
||||
}
|
||||
|
||||
/* Use `command' to replace the last entry in the history list, which,
|
||||
by this time, is `fc blah...'. The intent is that the new command
|
||||
become the history entry, and that `fc' should never appear in the
|
||||
history list. This way you can do `r' to your heart's content. */
|
||||
static void
|
||||
fc_replhist (command)
|
||||
char *command;
|
||||
{
|
||||
int n;
|
||||
|
||||
if (command == 0 || *command == '\0')
|
||||
return;
|
||||
|
||||
n = strlen (command);
|
||||
if (command[n - 1] == '\n')
|
||||
command[n - 1] = '\0';
|
||||
|
||||
if (command && *command)
|
||||
{
|
||||
bash_delete_last_history ();
|
||||
maybe_add_history (command); /* Obeys HISTCONTROL setting. */
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_UNUSED
|
||||
/* Add LINE to the history, after removing a single trailing newline. */
|
||||
static void
|
||||
fc_addhist (line)
|
||||
char *line;
|
||||
{
|
||||
register int n;
|
||||
|
||||
if (line == 0 || *line == 0)
|
||||
return;
|
||||
|
||||
n = strlen (line);
|
||||
|
||||
if (line[n - 1] == '\n')
|
||||
line[n - 1] = '\0';
|
||||
|
||||
if (line && *line)
|
||||
maybe_add_history (line); /* Obeys HISTCONTROL setting. */
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HISTORY */
|
146
third_party/bash/builtins_fg_bg.c
vendored
Normal file
146
third_party/bash/builtins_fg_bg.c
vendored
Normal file
|
@ -0,0 +1,146 @@
|
|||
/* fg_bg.c, created from fg_bg.def. */
|
||||
#line 22 "./fg_bg.def"
|
||||
|
||||
#line 36 "./fg_bg.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "bashtypes.h"
|
||||
#include <signal.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "execute_cmd.h"
|
||||
#include "jobs.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
static int fg_bg PARAMS((WORD_LIST *, int));
|
||||
|
||||
/* How to bring a job into the foreground. */
|
||||
int
|
||||
fg_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int fg_bit;
|
||||
register WORD_LIST *t;
|
||||
|
||||
CHECK_HELPOPT (list);
|
||||
|
||||
if (job_control == 0)
|
||||
{
|
||||
sh_nojobs ((char *)NULL);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (no_options (list))
|
||||
return (EX_USAGE);
|
||||
list = loptend;
|
||||
|
||||
/* If the last arg on the line is '&', then start this job in the
|
||||
background. Else, fg the job. */
|
||||
for (t = list; t && t->next; t = t->next)
|
||||
;
|
||||
fg_bit = (t && t->word->word[0] == '&' && t->word->word[1] == '\0') == 0;
|
||||
|
||||
return (fg_bg (list, fg_bit));
|
||||
}
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
#line 100 "./fg_bg.def"
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
/* How to put a job into the background. */
|
||||
int
|
||||
bg_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int r;
|
||||
|
||||
CHECK_HELPOPT (list);
|
||||
|
||||
if (job_control == 0)
|
||||
{
|
||||
sh_nojobs ((char *)NULL);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (no_options (list))
|
||||
return (EX_USAGE);
|
||||
list = loptend;
|
||||
|
||||
/* This relies on the fact that fg_bg() takes a WORD_LIST *, but only acts
|
||||
on the first member (if any) of that list. */
|
||||
r = EXECUTION_SUCCESS;
|
||||
do
|
||||
{
|
||||
if (fg_bg (list, 0) == EXECUTION_FAILURE)
|
||||
r = EXECUTION_FAILURE;
|
||||
if (list)
|
||||
list = list->next;
|
||||
}
|
||||
while (list);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* How to put a job into the foreground/background. */
|
||||
static int
|
||||
fg_bg (list, foreground)
|
||||
WORD_LIST *list;
|
||||
int foreground;
|
||||
{
|
||||
sigset_t set, oset;
|
||||
int job, status, old_async_pid;
|
||||
JOB *j;
|
||||
|
||||
BLOCK_CHILD (set, oset);
|
||||
job = get_job_spec (list);
|
||||
|
||||
if (INVALID_JOB (job))
|
||||
{
|
||||
if (job != DUP_JOB)
|
||||
sh_badjob (list ? list->word->word : _("current"));
|
||||
|
||||
goto failure;
|
||||
}
|
||||
|
||||
j = get_job_by_jid (job);
|
||||
/* Or if j->pgrp == shell_pgrp. */
|
||||
if (IS_JOBCONTROL (job) == 0)
|
||||
{
|
||||
builtin_error (_("job %d started without job control"), job + 1);
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if (foreground == 0)
|
||||
{
|
||||
old_async_pid = last_asynchronous_pid;
|
||||
last_asynchronous_pid = j->pgrp; /* As per Posix.2 5.4.2 */
|
||||
}
|
||||
|
||||
status = start_job (job, foreground);
|
||||
|
||||
if (status >= 0)
|
||||
{
|
||||
/* win: */
|
||||
UNBLOCK_CHILD (oset);
|
||||
return (foreground ? status : EXECUTION_SUCCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (foreground == 0)
|
||||
last_asynchronous_pid = old_async_pid;
|
||||
|
||||
failure:
|
||||
UNBLOCK_CHILD (oset);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
#endif /* JOB_CONTROL */
|
284
third_party/bash/builtins_getopts.c
vendored
Normal file
284
third_party/bash/builtins_getopts.c
vendored
Normal file
|
@ -0,0 +1,284 @@
|
|||
/* getopts.c, created from getopts.def. */
|
||||
#line 22 "./getopts.def"
|
||||
|
||||
#line 64 "./getopts.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "execute_cmd.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "getopt.h"
|
||||
|
||||
#define G_EOF -1
|
||||
#define G_INVALID_OPT -2
|
||||
#define G_ARG_MISSING -3
|
||||
|
||||
static int getopts_unbind_variable PARAMS((char *));
|
||||
static int getopts_bind_variable PARAMS((char *, char *));
|
||||
static int dogetopts PARAMS((int, char **));
|
||||
|
||||
/* getopts_reset is magic code for when OPTIND is reset. N is the
|
||||
value that has just been assigned to OPTIND. */
|
||||
void
|
||||
getopts_reset (newind)
|
||||
int newind;
|
||||
{
|
||||
sh_optind = newind;
|
||||
sh_badopt = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
getopts_unbind_variable (name)
|
||||
char *name;
|
||||
{
|
||||
#if 0
|
||||
return (unbind_variable (name));
|
||||
#else
|
||||
return (unbind_variable_noref (name));
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
getopts_bind_variable (name, value)
|
||||
char *name, *value;
|
||||
{
|
||||
SHELL_VAR *v;
|
||||
|
||||
if (legal_identifier (name))
|
||||
{
|
||||
v = bind_variable (name, value, 0);
|
||||
if (v && (readonly_p (v) || noassign_p (v)))
|
||||
return (EX_MISCERROR);
|
||||
return (v ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_invalidid (name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Error handling is now performed as specified by Posix.2, draft 11
|
||||
(identical to that of ksh-88). The special handling is enabled if
|
||||
the first character of the option string is a colon; this handling
|
||||
disables diagnostic messages concerning missing option arguments
|
||||
and invalid option characters. The handling is as follows.
|
||||
|
||||
INVALID OPTIONS:
|
||||
name -> "?"
|
||||
if (special_error) then
|
||||
OPTARG = option character found
|
||||
no error output
|
||||
else
|
||||
OPTARG unset
|
||||
diagnostic message
|
||||
fi
|
||||
|
||||
MISSING OPTION ARGUMENT;
|
||||
if (special_error) then
|
||||
name -> ":"
|
||||
OPTARG = option character found
|
||||
else
|
||||
name -> "?"
|
||||
OPTARG unset
|
||||
diagnostic message
|
||||
fi
|
||||
*/
|
||||
|
||||
static int
|
||||
dogetopts (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int ret, special_error, old_opterr, i, n;
|
||||
char strval[2], numval[16];
|
||||
char *optstr; /* list of options */
|
||||
char *name; /* variable to get flag val */
|
||||
char *t;
|
||||
|
||||
if (argc < 3)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
/* argv[0] is "getopts". */
|
||||
|
||||
optstr = argv[1];
|
||||
name = argv[2];
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
|
||||
special_error = optstr[0] == ':';
|
||||
|
||||
if (special_error)
|
||||
{
|
||||
old_opterr = sh_opterr;
|
||||
optstr++;
|
||||
sh_opterr = 0; /* suppress diagnostic messages */
|
||||
}
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
sh_getopt_restore_state (argv);
|
||||
t = argv[0];
|
||||
argv[0] = dollar_vars[0];
|
||||
ret = sh_getopt (argc, argv, optstr);
|
||||
argv[0] = t;
|
||||
}
|
||||
else if (rest_of_args == (WORD_LIST *)NULL)
|
||||
{
|
||||
for (i = 0; i < 10 && dollar_vars[i]; i++)
|
||||
;
|
||||
|
||||
sh_getopt_restore_state (dollar_vars);
|
||||
ret = sh_getopt (i, dollar_vars, optstr);
|
||||
}
|
||||
else
|
||||
{
|
||||
register WORD_LIST *words;
|
||||
char **v;
|
||||
|
||||
i = number_of_args () + 1; /* +1 for $0 */
|
||||
v = strvec_create (i + 1);
|
||||
for (i = 0; i < 10 && dollar_vars[i]; i++)
|
||||
v[i] = dollar_vars[i];
|
||||
for (words = rest_of_args; words; words = words->next, i++)
|
||||
v[i] = words->word->word;
|
||||
v[i] = (char *)NULL;
|
||||
sh_getopt_restore_state (v);
|
||||
ret = sh_getopt (i, v, optstr);
|
||||
free (v);
|
||||
}
|
||||
|
||||
if (special_error)
|
||||
sh_opterr = old_opterr;
|
||||
|
||||
/* Set the OPTIND variable in any case, to handle "--" skipping. It's
|
||||
highly unlikely that 14 digits will be too few. */
|
||||
if (sh_optind < 10)
|
||||
{
|
||||
numval[14] = sh_optind + '0';
|
||||
numval[15] = '\0';
|
||||
i = 14;
|
||||
}
|
||||
else
|
||||
{
|
||||
numval[i = 15] = '\0';
|
||||
n = sh_optind;
|
||||
do
|
||||
{
|
||||
numval[--i] = (n % 10) + '0';
|
||||
}
|
||||
while (n /= 10);
|
||||
}
|
||||
bind_variable ("OPTIND", numval + i, 0);
|
||||
|
||||
/* If an error occurred, decide which one it is and set the return
|
||||
code appropriately. In all cases, the option character in error
|
||||
is in OPTOPT. If an invalid option was encountered, OPTARG is
|
||||
NULL. If a required option argument was missing, OPTARG points
|
||||
to a NULL string (that is, sh_optarg[0] == 0). */
|
||||
if (ret == '?')
|
||||
{
|
||||
if (sh_optarg == NULL)
|
||||
ret = G_INVALID_OPT;
|
||||
else if (sh_optarg[0] == '\0')
|
||||
ret = G_ARG_MISSING;
|
||||
}
|
||||
|
||||
if (ret == G_EOF)
|
||||
{
|
||||
getopts_unbind_variable ("OPTARG");
|
||||
getopts_bind_variable (name, "?");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (ret == G_INVALID_OPT)
|
||||
{
|
||||
/* Invalid option encountered. */
|
||||
ret = getopts_bind_variable (name, "?");
|
||||
|
||||
if (special_error)
|
||||
{
|
||||
strval[0] = (char)sh_optopt;
|
||||
strval[1] = '\0';
|
||||
bind_variable ("OPTARG", strval, 0);
|
||||
}
|
||||
else
|
||||
getopts_unbind_variable ("OPTARG");
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
if (ret == G_ARG_MISSING)
|
||||
{
|
||||
/* Required argument missing. */
|
||||
if (special_error)
|
||||
{
|
||||
ret = getopts_bind_variable (name, ":");
|
||||
|
||||
strval[0] = (char)sh_optopt;
|
||||
strval[1] = '\0';
|
||||
bind_variable ("OPTARG", strval, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = getopts_bind_variable (name, "?");
|
||||
getopts_unbind_variable ("OPTARG");
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
bind_variable ("OPTARG", sh_optarg, 0);
|
||||
|
||||
strval[0] = (char) ret;
|
||||
strval[1] = '\0';
|
||||
return (getopts_bind_variable (name, strval));
|
||||
}
|
||||
|
||||
/* The getopts builtin. Build an argv, and call dogetopts with it. */
|
||||
int
|
||||
getopts_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char **av;
|
||||
int ac, ret;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return EX_USAGE;
|
||||
}
|
||||
|
||||
reset_internal_getopt ();
|
||||
if ((ret = internal_getopt (list, "")) != -1)
|
||||
{
|
||||
if (ret == GETOPT_HELP)
|
||||
builtin_help ();
|
||||
else
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
av = make_builtin_argv (list, &ac);
|
||||
ret = dogetopts (ac, av);
|
||||
free ((char *)av);
|
||||
|
||||
return (ret);
|
||||
}
|
264
third_party/bash/builtins_hash.c
vendored
Normal file
264
third_party/bash/builtins_hash.c
vendored
Normal file
|
@ -0,0 +1,264 @@
|
|||
/* hash.c, created from hash.def. */
|
||||
#line 22 "./hash.def"
|
||||
|
||||
#line 46 "./hash.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bashtypes.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "builtins.h"
|
||||
#include "execute_cmd.h"
|
||||
#include "flags.h"
|
||||
#include "findcmd.h"
|
||||
#include "hashcmd.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
extern int dot_found_in_search;
|
||||
|
||||
static int add_hashed_command PARAMS((char *, int));
|
||||
static int print_hash_info PARAMS((BUCKET_CONTENTS *));
|
||||
static int print_portable_hash_info PARAMS((BUCKET_CONTENTS *));
|
||||
static int print_hashed_commands PARAMS((int));
|
||||
static int list_hashed_filename_targets PARAMS((WORD_LIST *, int));
|
||||
|
||||
/* Print statistics on the current state of hashed commands. If LIST is
|
||||
not empty, then rehash (or hash in the first place) the specified
|
||||
commands. */
|
||||
int
|
||||
hash_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int expunge_hash_table, list_targets, list_portably, delete, opt;
|
||||
char *w, *pathname;
|
||||
|
||||
if (hashing_enabled == 0)
|
||||
{
|
||||
builtin_error (_("hashing disabled"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
expunge_hash_table = list_targets = list_portably = delete = 0;
|
||||
pathname = (char *)NULL;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "dlp:rt")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'd':
|
||||
delete = 1;
|
||||
break;
|
||||
case 'l':
|
||||
list_portably = 1;
|
||||
break;
|
||||
case 'p':
|
||||
pathname = list_optarg;
|
||||
break;
|
||||
case 'r':
|
||||
expunge_hash_table = 1;
|
||||
break;
|
||||
case 't':
|
||||
list_targets = 1;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
/* hash -t requires at least one argument. */
|
||||
if (list == 0 && (delete || list_targets))
|
||||
{
|
||||
sh_needarg (delete ? "-d" : "-t");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* We want hash -r to be silent, but hash -- to print hashing info, so
|
||||
we test expunge_hash_table. */
|
||||
if (list == 0 && expunge_hash_table == 0)
|
||||
{
|
||||
opt = print_hashed_commands (list_portably);
|
||||
if (opt == 0 && posixly_correct == 0 &&
|
||||
(list_portably == 0 || shell_compatibility_level <= 50))
|
||||
printf (_("%s: hash table empty\n"), this_command_name);
|
||||
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
if (expunge_hash_table)
|
||||
phash_flush ();
|
||||
|
||||
/* If someone runs `hash -r -t xyz' he will be disappointed. */
|
||||
if (list_targets)
|
||||
return (list_hashed_filename_targets (list, list_portably));
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
if (restricted && pathname)
|
||||
{
|
||||
if (strchr (pathname, '/'))
|
||||
{
|
||||
sh_restricted (pathname);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
/* If we are changing the hash table in a restricted shell, make sure the
|
||||
target pathname can be found using a $PATH search. */
|
||||
w = find_user_command (pathname);
|
||||
if (w == 0 || *w == 0 || executable_file (w) == 0)
|
||||
{
|
||||
sh_notfound (pathname);
|
||||
free (w);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
free (w);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (opt = EXECUTION_SUCCESS; list; list = list->next)
|
||||
{
|
||||
/* Add, remove or rehash the specified commands. */
|
||||
w = list->word->word;
|
||||
if (absolute_program (w))
|
||||
continue;
|
||||
else if (pathname)
|
||||
{
|
||||
if (file_isdir (pathname))
|
||||
{
|
||||
#ifdef EISDIR
|
||||
builtin_error ("%s: %s", pathname, strerror (EISDIR));
|
||||
#else
|
||||
builtin_error (_("%s: is a directory"), pathname);
|
||||
#endif
|
||||
opt = EXECUTION_FAILURE;
|
||||
}
|
||||
else
|
||||
phash_insert (w, pathname, 0, 0);
|
||||
}
|
||||
else if (delete)
|
||||
{
|
||||
if (phash_remove (w))
|
||||
{
|
||||
sh_notfound (w);
|
||||
opt = EXECUTION_FAILURE;
|
||||
}
|
||||
}
|
||||
else if (add_hashed_command (w, 0))
|
||||
opt = EXECUTION_FAILURE;
|
||||
}
|
||||
|
||||
fflush (stdout);
|
||||
return (opt);
|
||||
}
|
||||
|
||||
static int
|
||||
add_hashed_command (w, quiet)
|
||||
char *w;
|
||||
int quiet;
|
||||
{
|
||||
int rv;
|
||||
char *full_path;
|
||||
|
||||
rv = 0;
|
||||
if (find_function (w) == 0 && find_shell_builtin (w) == 0)
|
||||
{
|
||||
phash_remove (w);
|
||||
full_path = find_user_command (w);
|
||||
if (full_path && executable_file (full_path))
|
||||
phash_insert (w, full_path, dot_found_in_search, 0);
|
||||
else
|
||||
{
|
||||
if (quiet == 0)
|
||||
sh_notfound (w);
|
||||
rv++;
|
||||
}
|
||||
FREE (full_path);
|
||||
}
|
||||
return (rv);
|
||||
}
|
||||
|
||||
/* Print information about current hashed info. */
|
||||
static int
|
||||
print_hash_info (item)
|
||||
BUCKET_CONTENTS *item;
|
||||
{
|
||||
printf ("%4d\t%s\n", item->times_found, pathdata(item)->path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
print_portable_hash_info (item)
|
||||
BUCKET_CONTENTS *item;
|
||||
{
|
||||
char *fp, *fn;
|
||||
|
||||
fp = printable_filename (pathdata(item)->path, 1);
|
||||
fn = printable_filename (item->key, 1);
|
||||
printf ("builtin hash -p %s %s\n", fp, fn);
|
||||
if (fp != pathdata(item)->path)
|
||||
free (fp);
|
||||
if (fn != item->key)
|
||||
free (fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
print_hashed_commands (fmt)
|
||||
int fmt;
|
||||
{
|
||||
if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0)
|
||||
return (0);
|
||||
|
||||
if (fmt == 0)
|
||||
printf (_("hits\tcommand\n"));
|
||||
hash_walk (hashed_filenames, fmt ? print_portable_hash_info : print_hash_info);
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
list_hashed_filename_targets (list, fmt)
|
||||
WORD_LIST *list;
|
||||
int fmt;
|
||||
{
|
||||
int all_found, multiple;
|
||||
char *target;
|
||||
WORD_LIST *l;
|
||||
|
||||
all_found = 1;
|
||||
multiple = list->next != 0;
|
||||
|
||||
for (l = list; l; l = l->next)
|
||||
{
|
||||
target = phash_search (l->word->word);
|
||||
if (target == 0)
|
||||
{
|
||||
all_found = 0;
|
||||
sh_notfound (l->word->word);
|
||||
continue;
|
||||
}
|
||||
if (fmt)
|
||||
printf ("builtin hash -p %s %s\n", target, l->word->word);
|
||||
else
|
||||
{
|
||||
if (multiple)
|
||||
printf ("%s\t", l->word->word);
|
||||
printf ("%s\n", target);
|
||||
}
|
||||
free (target);
|
||||
}
|
||||
|
||||
return (all_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
512
third_party/bash/builtins_help.c
vendored
Normal file
512
third_party/bash/builtins_help.c
vendored
Normal file
|
@ -0,0 +1,512 @@
|
|||
/* help.c, created from help.def. */
|
||||
#line 22 "./help.def"
|
||||
|
||||
#line 45 "./help.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HELP_BUILTIN)
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "filecntl.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "builtins.h"
|
||||
#include "execute_cmd.h"
|
||||
#include "pathexp.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#include "strmatch.h"
|
||||
#include "glob.h"
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
extern const char * const bash_copyright;
|
||||
extern const char * const bash_license;
|
||||
|
||||
static void show_builtin_command_help PARAMS((void));
|
||||
static int open_helpfile PARAMS((char *));
|
||||
static void show_desc PARAMS((char *, int));
|
||||
static void show_manpage PARAMS((char *, int));
|
||||
static void show_longdoc PARAMS((int));
|
||||
|
||||
/* Print out a list of the known functions in the shell, and what they do.
|
||||
If LIST is supplied, print out the list which matches for each pattern
|
||||
specified. */
|
||||
int
|
||||
help_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register int i;
|
||||
char *pattern, *name;
|
||||
int plen, match_found, sflag, dflag, mflag, m, pass, this_found;
|
||||
|
||||
dflag = sflag = mflag = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((i = internal_getopt (list, "dms")) != -1)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 'd':
|
||||
dflag = 1;
|
||||
break;
|
||||
case 'm':
|
||||
mflag = 1;
|
||||
break;
|
||||
case 's':
|
||||
sflag = 1;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
show_shell_version (0);
|
||||
show_builtin_command_help ();
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* We should consider making `help bash' do something. */
|
||||
|
||||
if (glob_pattern_p (list->word->word) == 1)
|
||||
{
|
||||
printf ("%s", ngettext ("Shell commands matching keyword `", "Shell commands matching keywords `", (list->next ? 2 : 1)));
|
||||
print_word_list (list, ", ");
|
||||
printf ("%s", _("'\n\n"));
|
||||
}
|
||||
|
||||
for (match_found = 0, pattern = ""; list; list = list->next)
|
||||
{
|
||||
pattern = list->word->word;
|
||||
plen = strlen (pattern);
|
||||
|
||||
for (pass = 1, this_found = 0; pass < 3; pass++)
|
||||
{
|
||||
for (i = 0; name = shell_builtins[i].name; i++)
|
||||
{
|
||||
QUIT;
|
||||
|
||||
/* First pass: look for exact string or pattern matches.
|
||||
Second pass: look for prefix matches like bash-4.2 */
|
||||
if (pass == 1)
|
||||
m = (strcmp (pattern, name) == 0) ||
|
||||
(strmatch (pattern, name, FNMATCH_EXTFLAG) != FNM_NOMATCH);
|
||||
else
|
||||
m = strncmp (pattern, name, plen) == 0;
|
||||
|
||||
if (m)
|
||||
{
|
||||
this_found = 1;
|
||||
match_found++;
|
||||
if (dflag)
|
||||
{
|
||||
show_desc (name, i);
|
||||
continue;
|
||||
}
|
||||
else if (mflag)
|
||||
{
|
||||
show_manpage (name, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
printf ("%s: %s\n", name, _(shell_builtins[i].short_doc));
|
||||
|
||||
if (sflag == 0)
|
||||
show_longdoc (i);
|
||||
}
|
||||
}
|
||||
if (pass == 1 && this_found == 1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match_found == 0)
|
||||
{
|
||||
builtin_error (_("no help topics match `%s'. Try `help help' or `man -k %s' or `info %s'."), pattern, pattern, pattern);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
void
|
||||
builtin_help ()
|
||||
{
|
||||
int ind;
|
||||
ptrdiff_t d;
|
||||
|
||||
current_builtin = builtin_address_internal (this_command_name, 0);
|
||||
if (current_builtin == 0)
|
||||
return;
|
||||
|
||||
d = current_builtin - shell_builtins;
|
||||
|
||||
#if defined (__STDC__)
|
||||
ind = (int)d;
|
||||
#else
|
||||
ind = (int)d / sizeof (struct builtin);
|
||||
#endif
|
||||
|
||||
printf ("%s: %s\n", this_command_name, _(shell_builtins[ind].short_doc));
|
||||
show_longdoc (ind);
|
||||
}
|
||||
|
||||
static int
|
||||
open_helpfile (name)
|
||||
char *name;
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open (name, O_RDONLY);
|
||||
if (fd == -1)
|
||||
{
|
||||
builtin_error (_("%s: cannot open: %s"), name, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* By convention, enforced by mkbuiltins.c, if separate help files are being
|
||||
used, the long_doc array contains one string -- the full pathname of the
|
||||
help file for this builtin. */
|
||||
static void
|
||||
show_longdoc (i)
|
||||
int i;
|
||||
{
|
||||
register int j;
|
||||
char * const *doc;
|
||||
int fd;
|
||||
|
||||
doc = shell_builtins[i].long_doc;
|
||||
|
||||
if (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL)
|
||||
{
|
||||
fd = open_helpfile (doc[0]);
|
||||
if (fd < 0)
|
||||
return;
|
||||
zcatfd (fd, 1, doc[0]);
|
||||
close (fd);
|
||||
}
|
||||
else if (doc)
|
||||
for (j = 0; doc[j]; j++)
|
||||
printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j]));
|
||||
}
|
||||
|
||||
static void
|
||||
show_desc (name, i)
|
||||
char *name;
|
||||
int i;
|
||||
{
|
||||
register int j, r;
|
||||
char **doc, *line;
|
||||
int fd, usefile;
|
||||
|
||||
doc = (char **)shell_builtins[i].long_doc;
|
||||
|
||||
usefile = (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL);
|
||||
if (usefile)
|
||||
{
|
||||
fd = open_helpfile (doc[0]);
|
||||
if (fd < 0)
|
||||
return;
|
||||
r = zmapfd (fd, &line, doc[0]);
|
||||
close (fd);
|
||||
/* XXX - handle errors if zmapfd returns < 0 */
|
||||
}
|
||||
else
|
||||
line = doc ? doc[0] : (char *)NULL;
|
||||
|
||||
printf ("%s - ", name);
|
||||
for (j = 0; line && line[j]; j++)
|
||||
{
|
||||
putchar (line[j]);
|
||||
if (line[j] == '\n')
|
||||
break;
|
||||
}
|
||||
|
||||
fflush (stdout);
|
||||
|
||||
if (usefile)
|
||||
free (line);
|
||||
}
|
||||
|
||||
/* Print builtin help in pseudo-manpage format. */
|
||||
static void
|
||||
show_manpage (name, i)
|
||||
char *name;
|
||||
int i;
|
||||
{
|
||||
register int j;
|
||||
char **doc, *line;
|
||||
int fd, usefile;
|
||||
|
||||
doc = (char **)shell_builtins[i].long_doc;
|
||||
|
||||
usefile = (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL);
|
||||
if (usefile)
|
||||
{
|
||||
fd = open_helpfile (doc[0]);
|
||||
if (fd < 0)
|
||||
return;
|
||||
zmapfd (fd, &line, doc[0]);
|
||||
close (fd);
|
||||
}
|
||||
else
|
||||
line = doc ? _(doc[0]) : (char *)NULL;
|
||||
|
||||
/* NAME */
|
||||
printf ("NAME\n");
|
||||
printf ("%*s%s - ", BASE_INDENT, " ", name);
|
||||
for (j = 0; line && line[j]; j++)
|
||||
{
|
||||
putchar (line[j]);
|
||||
if (line[j] == '\n')
|
||||
break;
|
||||
}
|
||||
printf ("\n");
|
||||
|
||||
/* SYNOPSIS */
|
||||
printf ("SYNOPSIS\n");
|
||||
printf ("%*s%s\n\n", BASE_INDENT, " ", _(shell_builtins[i].short_doc));
|
||||
|
||||
/* DESCRIPTION */
|
||||
printf ("DESCRIPTION\n");
|
||||
if (usefile == 0)
|
||||
{
|
||||
for (j = 0; doc[j]; j++)
|
||||
printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j]));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (j = 0; line && line[j]; j++)
|
||||
{
|
||||
putchar (line[j]);
|
||||
if (line[j] == '\n')
|
||||
printf ("%*s", BASE_INDENT, " ");
|
||||
}
|
||||
}
|
||||
putchar ('\n');
|
||||
|
||||
/* SEE ALSO */
|
||||
printf ("SEE ALSO\n");
|
||||
printf ("%*sbash(1)\n\n", BASE_INDENT, " ");
|
||||
|
||||
/* IMPLEMENTATION */
|
||||
printf ("IMPLEMENTATION\n");
|
||||
printf ("%*s", BASE_INDENT, " ");
|
||||
show_shell_version (0);
|
||||
printf ("%*s", BASE_INDENT, " ");
|
||||
printf ("%s\n", _(bash_copyright));
|
||||
printf ("%*s", BASE_INDENT, " ");
|
||||
printf ("%s\n", _(bash_license));
|
||||
|
||||
fflush (stdout);
|
||||
if (usefile)
|
||||
free (line);
|
||||
}
|
||||
|
||||
static void
|
||||
dispcolumn (i, buf, bufsize, width, height)
|
||||
int i;
|
||||
char *buf;
|
||||
size_t bufsize;
|
||||
int width, height;
|
||||
{
|
||||
int j;
|
||||
int dispcols;
|
||||
char *helpdoc;
|
||||
|
||||
/* first column */
|
||||
helpdoc = _(shell_builtins[i].short_doc);
|
||||
|
||||
buf[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? ' ' : '*';
|
||||
strncpy (buf + 1, helpdoc, width - 2);
|
||||
buf[width - 2] = '>'; /* indicate truncation */
|
||||
buf[width - 1] = '\0';
|
||||
printf ("%s", buf);
|
||||
if (((i << 1) >= num_shell_builtins) || (i+height >= num_shell_builtins))
|
||||
{
|
||||
printf ("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dispcols = strlen (buf);
|
||||
/* two spaces */
|
||||
for (j = dispcols; j < width; j++)
|
||||
putc (' ', stdout);
|
||||
|
||||
/* second column */
|
||||
helpdoc = _(shell_builtins[i+height].short_doc);
|
||||
|
||||
buf[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*';
|
||||
strncpy (buf + 1, helpdoc, width - 3);
|
||||
buf[width - 3] = '>'; /* indicate truncation */
|
||||
buf[width - 2] = '\0';
|
||||
|
||||
printf ("%s\n", buf);
|
||||
}
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
static void
|
||||
wdispcolumn (i, buf, bufsize, width, height)
|
||||
int i;
|
||||
char *buf;
|
||||
size_t bufsize;
|
||||
int width, height;
|
||||
{
|
||||
int j;
|
||||
int dispcols, dispchars;
|
||||
char *helpdoc;
|
||||
wchar_t *wcstr;
|
||||
size_t slen, n;
|
||||
|
||||
/* first column */
|
||||
helpdoc = _(shell_builtins[i].short_doc);
|
||||
|
||||
wcstr = 0;
|
||||
slen = mbstowcs ((wchar_t *)0, helpdoc, 0);
|
||||
if (slen == -1)
|
||||
{
|
||||
dispcolumn (i, buf, bufsize, width, height);
|
||||
return;
|
||||
}
|
||||
|
||||
/* No bigger than the passed max width */
|
||||
if (slen >= width)
|
||||
slen = width - 2;
|
||||
wcstr = (wchar_t *)xmalloc (sizeof (wchar_t) * (width + 2));
|
||||
n = mbstowcs (wcstr+1, helpdoc, slen + 1);
|
||||
wcstr[n+1] = L'\0';
|
||||
|
||||
/* Turn tabs and newlines into spaces for column display, since wcwidth
|
||||
returns -1 for them */
|
||||
for (j = 1; j < n; j++)
|
||||
if (wcstr[j] == L'\n' || wcstr[j] == L'\t')
|
||||
wcstr[j] = L' ';
|
||||
|
||||
/* dispchars == number of characters that will be displayed */
|
||||
dispchars = wcsnwidth (wcstr+1, slen, width - 2);
|
||||
/* dispcols == number of columns required to display DISPCHARS */
|
||||
dispcols = wcswidth (wcstr+1, dispchars) + 1; /* +1 for ' ' or '*' */
|
||||
|
||||
wcstr[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? L' ' : L'*';
|
||||
|
||||
if (dispcols >= width-2)
|
||||
{
|
||||
wcstr[dispchars] = L'>'; /* indicate truncation */
|
||||
wcstr[dispchars+1] = L'\0';
|
||||
}
|
||||
|
||||
printf ("%ls", wcstr);
|
||||
if (((i << 1) >= num_shell_builtins) || (i+height >= num_shell_builtins))
|
||||
{
|
||||
printf ("\n");
|
||||
free (wcstr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* at least one space */
|
||||
for (j = dispcols; j < width; j++)
|
||||
putc (' ', stdout);
|
||||
|
||||
/* second column */
|
||||
helpdoc = _(shell_builtins[i+height].short_doc);
|
||||
slen = mbstowcs ((wchar_t *)0, helpdoc, 0);
|
||||
if (slen == -1)
|
||||
{
|
||||
/* for now */
|
||||
printf ("%c%s\n", (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*', helpdoc);
|
||||
free (wcstr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reuse wcstr since it is already width wide chars long */
|
||||
if (slen >= width)
|
||||
slen = width - 2;
|
||||
n = mbstowcs (wcstr+1, helpdoc, slen + 1);
|
||||
wcstr[n+1] = L'\0'; /* make sure null-terminated */
|
||||
|
||||
/* Turn tabs and newlines into spaces for column display */
|
||||
for (j = 1; j < n; j++)
|
||||
if (wcstr[j] == L'\n' || wcstr[j] == L'\t')
|
||||
wcstr[j] = L' ';
|
||||
|
||||
/* dispchars == number of characters that will be displayed */
|
||||
dispchars = wcsnwidth (wcstr+1, slen, width - 2);
|
||||
dispcols = wcswidth (wcstr+1, dispchars) + 1; /* +1 for ' ' or '*' */
|
||||
|
||||
wcstr[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? L' ' : L'*';
|
||||
|
||||
/* The dispchars-1 is there for terminals that behave strangely when you
|
||||
have \n in the nth column for terminal width n; this is what bash-4.3
|
||||
did. */
|
||||
if (dispcols >= width - 2)
|
||||
{
|
||||
wcstr[dispchars-1] = L'>'; /* indicate truncation */
|
||||
wcstr[dispchars] = L'\0';
|
||||
}
|
||||
|
||||
printf ("%ls\n", wcstr);
|
||||
|
||||
free (wcstr);
|
||||
}
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
|
||||
static void
|
||||
show_builtin_command_help ()
|
||||
{
|
||||
int i, j;
|
||||
int height, width;
|
||||
char *t, blurb[128];
|
||||
|
||||
printf (
|
||||
_("These shell commands are defined internally. Type `help' to see this list.\n\
|
||||
Type `help name' to find out more about the function `name'.\n\
|
||||
Use `info bash' to find out more about the shell in general.\n\
|
||||
Use `man -k' or `info' to find out more about commands not in this list.\n\
|
||||
\n\
|
||||
A star (*) next to a name means that the command is disabled.\n\
|
||||
\n"));
|
||||
|
||||
width = default_columns ();
|
||||
|
||||
width /= 2;
|
||||
if (width > sizeof (blurb))
|
||||
width = sizeof (blurb);
|
||||
if (width <= 3)
|
||||
width = 40;
|
||||
height = (num_shell_builtins + 1) / 2; /* number of rows */
|
||||
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
QUIT;
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1)
|
||||
wdispcolumn (i, blurb, sizeof (blurb), width, height);
|
||||
else
|
||||
#endif
|
||||
dispcolumn (i, blurb, sizeof (blurb), width, height);
|
||||
}
|
||||
}
|
||||
#endif /* HELP_BUILTIN */
|
411
third_party/bash/builtins_history.c
vendored
Normal file
411
third_party/bash/builtins_history.c
vendored
Normal file
|
@ -0,0 +1,411 @@
|
|||
/* history.c, created from history.def. */
|
||||
#line 22 "./history.def"
|
||||
|
||||
#line 58 "./history.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HISTORY)
|
||||
#include "bashtypes.h"
|
||||
#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
|
||||
# include <sys/file.h>
|
||||
#endif
|
||||
#include "posixstat.h"
|
||||
#include "filecntl.h"
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "flags.h"
|
||||
#include "parser.h"
|
||||
#include "bashhist.h"
|
||||
#include "third_party/readline/history.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
static char *histtime PARAMS((HIST_ENTRY *, const char *));
|
||||
static int display_history PARAMS((WORD_LIST *));
|
||||
static void push_history PARAMS((WORD_LIST *));
|
||||
static int expand_and_print_history PARAMS((WORD_LIST *));
|
||||
|
||||
#define AFLAG 0x01
|
||||
#define RFLAG 0x02
|
||||
#define WFLAG 0x04
|
||||
#define NFLAG 0x08
|
||||
#define SFLAG 0x10
|
||||
#define PFLAG 0x20
|
||||
#define CFLAG 0x40
|
||||
#define DFLAG 0x80
|
||||
|
||||
#ifndef TIMELEN_MAX
|
||||
# define TIMELEN_MAX 128
|
||||
#endif
|
||||
|
||||
int
|
||||
history_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int flags, opt, result, old_history_lines, obase, ind;
|
||||
char *filename, *delete_arg, *range;
|
||||
intmax_t delete_offset;
|
||||
|
||||
flags = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "acd:npsrw")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'a':
|
||||
flags |= AFLAG;
|
||||
break;
|
||||
case 'c':
|
||||
flags |= CFLAG;
|
||||
break;
|
||||
case 'n':
|
||||
flags |= NFLAG;
|
||||
break;
|
||||
case 'r':
|
||||
flags |= RFLAG;
|
||||
break;
|
||||
case 'w':
|
||||
flags |= WFLAG;
|
||||
break;
|
||||
case 's':
|
||||
flags |= SFLAG;
|
||||
break;
|
||||
case 'd':
|
||||
flags |= DFLAG;
|
||||
delete_arg = list_optarg;
|
||||
break;
|
||||
case 'p':
|
||||
#if defined (BANG_HISTORY)
|
||||
flags |= PFLAG;
|
||||
#endif
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
opt = flags & (AFLAG|RFLAG|WFLAG|NFLAG);
|
||||
if (opt && opt != AFLAG && opt != RFLAG && opt != WFLAG && opt != NFLAG)
|
||||
{
|
||||
builtin_error (_("cannot use more than one of -anrw"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* clear the history, but allow other arguments to add to it again. */
|
||||
if (flags & CFLAG)
|
||||
{
|
||||
bash_clear_history ();
|
||||
if (list == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
if (flags & SFLAG)
|
||||
{
|
||||
if (list)
|
||||
push_history (list);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
#if defined (BANG_HISTORY)
|
||||
else if (flags & PFLAG)
|
||||
{
|
||||
if (list)
|
||||
return (expand_and_print_history (list));
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
#endif
|
||||
else if ((flags & DFLAG) && (range = strchr ((delete_arg[0] == '-') ? delete_arg + 1 : delete_arg, '-')))
|
||||
{
|
||||
intmax_t delete_start, delete_end;
|
||||
*range++ = '\0';
|
||||
if (legal_number (delete_arg, &delete_start) == 0 || legal_number (range, &delete_end) == 0)
|
||||
{
|
||||
range[-1] = '-';
|
||||
sh_erange (delete_arg, _("history position"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
if (delete_arg[0] == '-' && delete_start < 0)
|
||||
/* the_history[history_length] == 0x0, so this is correct */
|
||||
delete_start += history_length;
|
||||
/* numbers as displayed by display_history are offset by history_base */
|
||||
else if (delete_start > 0)
|
||||
delete_start -= history_base;
|
||||
|
||||
if (delete_start < 0 || delete_start >= history_length)
|
||||
{
|
||||
sh_erange (delete_arg, _("history position"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (range[0] == '-' && delete_end < 0)
|
||||
delete_end += history_length;
|
||||
else if (delete_end > 0)
|
||||
delete_end -= history_base;
|
||||
|
||||
if (delete_end < 0 || delete_end >= history_length)
|
||||
{
|
||||
sh_erange (range, _("history position"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
/* XXX - print error if end < start? */
|
||||
result = bash_delete_history_range (delete_start, delete_end);
|
||||
if (where_history () > history_length)
|
||||
history_set_pos (history_length);
|
||||
return (result ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
else if (flags & DFLAG)
|
||||
{
|
||||
if (legal_number (delete_arg, &delete_offset) == 0)
|
||||
{
|
||||
sh_erange (delete_arg, _("history position"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
/* check for negative offsets, count back from end of list */
|
||||
if (delete_arg[0] == '-' && delete_offset < 0)
|
||||
{
|
||||
/* since the_history[history_length] == 0x0, this calculation means
|
||||
that history -d -1 will delete the last history entry, which at
|
||||
this point is the history -d -1 we just added. */
|
||||
ind = history_length + delete_offset;
|
||||
if (ind < 0) /* offset by history_base below */
|
||||
{
|
||||
sh_erange (delete_arg, _("history position"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
opt = ind + history_base; /* compensate for opt - history_base below */
|
||||
}
|
||||
else if ((delete_offset < history_base) || (delete_offset >= (history_base + history_length)))
|
||||
{
|
||||
sh_erange (delete_arg, _("history position"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
opt = delete_offset;
|
||||
|
||||
/* Positive arguments from numbers as displayed by display_history need
|
||||
to be offset by history_base */
|
||||
result = bash_delete_histent (opt - history_base);
|
||||
/* Since remove_history changes history_length, this can happen if
|
||||
we delete the last history entry. */
|
||||
if (where_history () > history_length)
|
||||
history_set_pos (history_length);
|
||||
return (result ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
else if ((flags & (AFLAG|RFLAG|NFLAG|WFLAG|CFLAG)) == 0)
|
||||
{
|
||||
result = display_history (list);
|
||||
return (sh_chkwrite (result));
|
||||
}
|
||||
|
||||
filename = list ? list->word->word : get_string_value ("HISTFILE");
|
||||
result = EXECUTION_SUCCESS;
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
if (restricted && strchr (filename, '/'))
|
||||
{
|
||||
sh_restricted (filename);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (flags & AFLAG) /* Append session's history to file. */
|
||||
result = maybe_append_history (filename);
|
||||
else if (flags & WFLAG) /* Write entire history. */
|
||||
result = write_history (filename);
|
||||
else if (flags & RFLAG) /* Read entire file. */
|
||||
{
|
||||
result = read_history (filename);
|
||||
history_lines_in_file = history_lines_read_from_file;
|
||||
/* history_lines_in_file = where_history () + history_base - 1; */
|
||||
}
|
||||
else if (flags & NFLAG) /* Read `new' history from file. */
|
||||
{
|
||||
/* Read all of the lines in the file that we haven't already read. */
|
||||
old_history_lines = history_lines_in_file;
|
||||
obase = history_base;
|
||||
|
||||
using_history ();
|
||||
result = read_history_range (filename, history_lines_in_file, -1);
|
||||
using_history ();
|
||||
|
||||
history_lines_in_file = history_lines_read_from_file;
|
||||
/* history_lines_in_file = where_history () + history_base - 1; */
|
||||
|
||||
/* If we're rewriting the history file at shell exit rather than just
|
||||
appending the lines from this session to it, the question is whether
|
||||
we reset history_lines_this_session to 0, losing any history entries
|
||||
we had before we read the new entries from the history file, or
|
||||
whether we count the new entries we just read from the file as
|
||||
history lines added during this session.
|
||||
Right now, we do the latter. This will cause these history entries
|
||||
to be written to the history file along with any intermediate entries
|
||||
we add when we do a `history -a', but the alternative is losing
|
||||
them altogether. */
|
||||
if (force_append_history == 0)
|
||||
history_lines_this_session += history_lines_in_file - old_history_lines +
|
||||
history_base - obase;
|
||||
}
|
||||
|
||||
return (result ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Accessors for HIST_ENTRY lists that are called HLIST. */
|
||||
#define histline(i) (hlist[(i)]->line)
|
||||
#define histdata(i) (hlist[(i)]->data)
|
||||
|
||||
static char *
|
||||
histtime (hlist, histtimefmt)
|
||||
HIST_ENTRY *hlist;
|
||||
const char *histtimefmt;
|
||||
{
|
||||
static char timestr[TIMELEN_MAX];
|
||||
time_t t;
|
||||
struct tm *tm;
|
||||
|
||||
t = history_get_time (hlist);
|
||||
tm = t ? localtime (&t) : 0;
|
||||
if (t && tm)
|
||||
strftime (timestr, sizeof (timestr), histtimefmt, tm);
|
||||
else if (hlist->timestamp && hlist->timestamp[0])
|
||||
snprintf (timestr, sizeof (timestr), _("%s: invalid timestamp"),
|
||||
(hlist->timestamp[0] == '#') ? hlist->timestamp + 1: hlist->timestamp);
|
||||
else
|
||||
strcpy (timestr, "??");
|
||||
return timestr;
|
||||
}
|
||||
|
||||
static int
|
||||
display_history (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register int i;
|
||||
intmax_t limit;
|
||||
HIST_ENTRY **hlist;
|
||||
char *histtimefmt, *timestr;
|
||||
|
||||
if (list)
|
||||
{
|
||||
if (get_numeric_arg (list, 0, &limit) == 0)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
if (limit < 0)
|
||||
limit = -limit;
|
||||
}
|
||||
else
|
||||
limit = -1;
|
||||
|
||||
hlist = history_list ();
|
||||
|
||||
if (hlist)
|
||||
{
|
||||
for (i = 0; hlist[i]; i++)
|
||||
;
|
||||
|
||||
if (0 <= limit && limit < i)
|
||||
i -= limit;
|
||||
else
|
||||
i = 0;
|
||||
|
||||
histtimefmt = get_string_value ("HISTTIMEFORMAT");
|
||||
|
||||
while (hlist[i])
|
||||
{
|
||||
QUIT;
|
||||
|
||||
timestr = (histtimefmt && *histtimefmt) ? histtime (hlist[i], histtimefmt) : (char *)NULL;
|
||||
printf ("%5d%c %s%s\n", i + history_base,
|
||||
histdata(i) ? '*' : ' ',
|
||||
((timestr && *timestr) ? timestr : ""),
|
||||
histline(i));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Remove the last entry in the history list and add each argument in
|
||||
LIST to the history. */
|
||||
static void
|
||||
push_history (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *s;
|
||||
|
||||
/* Delete the last history entry if it was a single entry added to the
|
||||
history list (generally the `history -s' itself), or if `history -s'
|
||||
is being used in a compound command and the compound command was
|
||||
added to the history as a single element (command-oriented history).
|
||||
If you don't want history -s to remove the compound command from the
|
||||
history, change #if 0 to #if 1 below. */
|
||||
#if 0
|
||||
if (remember_on_history && hist_last_line_pushed == 0 &&
|
||||
hist_last_line_added && bash_delete_last_history () == 0)
|
||||
#else
|
||||
if (remember_on_history && hist_last_line_pushed == 0 &&
|
||||
(hist_last_line_added ||
|
||||
(current_command_line_count > 0 && current_command_first_line_saved && command_oriented_history))
|
||||
&& bash_delete_last_history () == 0)
|
||||
#endif
|
||||
return;
|
||||
|
||||
s = string_list (list);
|
||||
/* Call check_add_history with FORCE set to 1 to skip the check against
|
||||
current_command_line_count. If history -s is used in a compound
|
||||
command, the above code will delete the compound command's history
|
||||
entry and this call will add the line to the history as a separate
|
||||
entry. Without FORCE=1, if current_command_line_count were > 1, the
|
||||
line would be appended to the entry before the just-deleted entry. */
|
||||
check_add_history (s, 1); /* obeys HISTCONTROL, HISTIGNORE */
|
||||
|
||||
hist_last_line_pushed = 1; /* XXX */
|
||||
free (s);
|
||||
}
|
||||
|
||||
#if defined (BANG_HISTORY)
|
||||
static int
|
||||
expand_and_print_history (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *s;
|
||||
int r, result;
|
||||
|
||||
if (hist_last_line_pushed == 0 && hist_last_line_added && bash_delete_last_history () == 0)
|
||||
return EXECUTION_FAILURE;
|
||||
result = EXECUTION_SUCCESS;
|
||||
while (list)
|
||||
{
|
||||
r = history_expand (list->word->word, &s);
|
||||
if (r < 0)
|
||||
{
|
||||
builtin_error (_("%s: history expansion failed"), list->word->word);
|
||||
result = EXECUTION_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
fputs (s, stdout);
|
||||
putchar ('\n');
|
||||
}
|
||||
FREE (s);
|
||||
list = list->next;
|
||||
}
|
||||
fflush (stdout);
|
||||
return result;
|
||||
}
|
||||
#endif /* BANG_HISTORY */
|
||||
#endif /* HISTORY */
|
240
third_party/bash/builtins_jobs.c
vendored
Normal file
240
third_party/bash/builtins_jobs.c
vendored
Normal file
|
@ -0,0 +1,240 @@
|
|||
/* jobs.c, created from jobs.def. */
|
||||
#line 22 "./jobs.def"
|
||||
|
||||
#line 48 "./jobs.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
#include "bashtypes.h"
|
||||
#include <signal.h>
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "jobs.h"
|
||||
#include "execute_cmd.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#define JSTATE_ANY 0x0
|
||||
#define JSTATE_RUNNING 0x1
|
||||
#define JSTATE_STOPPED 0x2
|
||||
|
||||
static int execute_list_with_replacements PARAMS((WORD_LIST *));
|
||||
|
||||
/* The `jobs' command. Prints outs a list of active jobs. If the
|
||||
argument `-l' is given, then the process id's are printed also.
|
||||
If the argument `-p' is given, print the process group leader's
|
||||
pid only. If `-n' is given, only processes that have changed
|
||||
status since the last notification are printed. If -x is given,
|
||||
replace all job specs with the pid of the appropriate process
|
||||
group leader and execute the command. The -r and -s options mean
|
||||
to print info about running and stopped jobs only, respectively. */
|
||||
int
|
||||
jobs_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int form, execute, state, opt, any_failed, job;
|
||||
sigset_t set, oset;
|
||||
|
||||
execute = any_failed = 0;
|
||||
form = JLIST_STANDARD;
|
||||
state = JSTATE_ANY;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "lpnxrs")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'l':
|
||||
form = JLIST_LONG;
|
||||
break;
|
||||
case 'p':
|
||||
form = JLIST_PID_ONLY;
|
||||
break;
|
||||
case 'n':
|
||||
form = JLIST_CHANGED_ONLY;
|
||||
break;
|
||||
case 'x':
|
||||
if (form != JLIST_STANDARD)
|
||||
{
|
||||
builtin_error (_("no other options allowed with `-x'"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
execute++;
|
||||
break;
|
||||
case 'r':
|
||||
state = JSTATE_RUNNING;
|
||||
break;
|
||||
case 's':
|
||||
state = JSTATE_STOPPED;
|
||||
break;
|
||||
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
if (execute)
|
||||
return (execute_list_with_replacements (list));
|
||||
|
||||
if (!list)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case JSTATE_ANY:
|
||||
list_all_jobs (form);
|
||||
break;
|
||||
case JSTATE_RUNNING:
|
||||
list_running_jobs (form);
|
||||
break;
|
||||
case JSTATE_STOPPED:
|
||||
list_stopped_jobs (form);
|
||||
break;
|
||||
}
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
while (list)
|
||||
{
|
||||
BLOCK_CHILD (set, oset);
|
||||
job = get_job_spec (list);
|
||||
|
||||
if ((job == NO_JOB) || jobs == 0 || get_job_by_jid (job) == 0)
|
||||
{
|
||||
sh_badjob (list->word->word);
|
||||
any_failed++;
|
||||
}
|
||||
else if (job != DUP_JOB)
|
||||
list_one_job ((JOB *)NULL, form, 0, job);
|
||||
|
||||
UNBLOCK_CHILD (oset);
|
||||
list = list->next;
|
||||
}
|
||||
return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
static int
|
||||
execute_list_with_replacements (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register WORD_LIST *l;
|
||||
int job, result;
|
||||
COMMAND *command;
|
||||
JOB *j;
|
||||
|
||||
/* First do the replacement of job specifications with pids. */
|
||||
for (l = list; l; l = l->next)
|
||||
{
|
||||
if (l->word->word[0] == '%') /* we have a winner */
|
||||
{
|
||||
job = get_job_spec (l);
|
||||
|
||||
/* A bad job spec is not really a job spec! Pass it through. */
|
||||
if (INVALID_JOB (job))
|
||||
continue;
|
||||
|
||||
j = get_job_by_jid (job);
|
||||
free (l->word->word);
|
||||
l->word->word = itos (j->pgrp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Next make a new simple command and execute it. */
|
||||
begin_unwind_frame ("jobs_builtin");
|
||||
|
||||
command = make_bare_simple_command ();
|
||||
command->value.Simple->words = copy_word_list (list);
|
||||
command->value.Simple->redirects = (REDIRECT *)NULL;
|
||||
command->flags |= CMD_INHIBIT_EXPANSION;
|
||||
command->value.Simple->flags |= CMD_INHIBIT_EXPANSION;
|
||||
|
||||
add_unwind_protect (dispose_command, command);
|
||||
result = execute_command (command);
|
||||
dispose_command (command);
|
||||
|
||||
discard_unwind_frame ("jobs_builtin");
|
||||
return (result);
|
||||
}
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
#line 231 "./jobs.def"
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
int
|
||||
disown_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt, job, retval, nohup_only, running_jobs, all_jobs;
|
||||
sigset_t set, oset;
|
||||
intmax_t pid_value;
|
||||
|
||||
nohup_only = running_jobs = all_jobs = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "ahr")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'a':
|
||||
all_jobs = 1;
|
||||
break;
|
||||
case 'h':
|
||||
nohup_only = 1;
|
||||
break;
|
||||
case 'r':
|
||||
running_jobs = 1;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
retval = EXECUTION_SUCCESS;
|
||||
|
||||
/* `disown -a' or `disown -r' */
|
||||
if (list == 0 && (all_jobs || running_jobs))
|
||||
{
|
||||
if (nohup_only)
|
||||
nohup_all_jobs (running_jobs);
|
||||
else
|
||||
delete_all_jobs (running_jobs);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
BLOCK_CHILD (set, oset);
|
||||
job = (list && legal_number (list->word->word, &pid_value) && pid_value == (pid_t) pid_value)
|
||||
? get_job_by_pid ((pid_t) pid_value, 0, 0)
|
||||
: get_job_spec (list);
|
||||
|
||||
if (job == NO_JOB || jobs == 0 || INVALID_JOB (job))
|
||||
{
|
||||
sh_badjob (list ? list->word->word : _("current"));
|
||||
retval = EXECUTION_FAILURE;
|
||||
}
|
||||
else if (nohup_only)
|
||||
nohup_job (job);
|
||||
else
|
||||
delete_job (job, 1);
|
||||
UNBLOCK_CHILD (oset);
|
||||
|
||||
if (list)
|
||||
list = list->next;
|
||||
}
|
||||
while (list);
|
||||
|
||||
return (retval);
|
||||
}
|
||||
#endif /* JOB_CONTROL */
|
235
third_party/bash/builtins_kill.c
vendored
Normal file
235
third_party/bash/builtins_kill.c
vendored
Normal file
|
@ -0,0 +1,235 @@
|
|||
/* kill.c, created from kill.def. */
|
||||
#line 22 "./kill.def"
|
||||
|
||||
#line 46 "./kill.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include "shell.h"
|
||||
#include "trap.h"
|
||||
#include "jobs.h"
|
||||
#include "common.h"
|
||||
|
||||
/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
static void kill_error PARAMS((pid_t, int));
|
||||
|
||||
#if !defined (CONTINUE_AFTER_KILL_ERROR)
|
||||
# define CONTINUE_OR_FAIL return (EXECUTION_FAILURE)
|
||||
#else
|
||||
# define CONTINUE_OR_FAIL goto continue_killing
|
||||
#endif /* CONTINUE_AFTER_KILL_ERROR */
|
||||
|
||||
/* Here is the kill builtin. We only have it so that people can type
|
||||
kill -KILL %1? No, if you fill up the process table this way you
|
||||
can still kill some. */
|
||||
int
|
||||
kill_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int sig, any_succeeded, listing, saw_signal, dflags;
|
||||
char *sigspec, *word;
|
||||
pid_t pid;
|
||||
intmax_t pid_value;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
CHECK_HELPOPT (list);
|
||||
|
||||
any_succeeded = listing = saw_signal = 0;
|
||||
sig = SIGTERM;
|
||||
sigspec = "TERM";
|
||||
|
||||
dflags = DSIG_NOCASE | ((posixly_correct == 0) ? DSIG_SIGPREFIX : 0);
|
||||
/* Process options. */
|
||||
while (list)
|
||||
{
|
||||
word = list->word->word;
|
||||
|
||||
if (ISOPTION (word, 'l') || ISOPTION (word, 'L'))
|
||||
{
|
||||
listing++;
|
||||
list = list->next;
|
||||
}
|
||||
else if (ISOPTION (word, 's') || ISOPTION (word, 'n'))
|
||||
{
|
||||
list = list->next;
|
||||
if (list)
|
||||
{
|
||||
sigspec = list->word->word;
|
||||
use_sigspec:
|
||||
if (sigspec[0] == '0' && sigspec[1] == '\0')
|
||||
sig = 0;
|
||||
else
|
||||
sig = decode_signal (sigspec, dflags);
|
||||
list = list->next;
|
||||
saw_signal++;
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_needarg (word);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
else if (word[0] == '-' && word[1] == 's' && ISALPHA (word[2]))
|
||||
{
|
||||
sigspec = word + 2;
|
||||
goto use_sigspec;
|
||||
}
|
||||
else if (word[0] == '-' && word[1] == 'n' && ISDIGIT (word[2]))
|
||||
{
|
||||
sigspec = word + 2;
|
||||
goto use_sigspec;
|
||||
}
|
||||
else if (ISOPTION (word, '-'))
|
||||
{
|
||||
list = list->next;
|
||||
break;
|
||||
}
|
||||
else if (ISOPTION (word, '?'))
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
/* If this is a signal specification then process it. We only process
|
||||
the first one seen; other arguments may signify process groups (e.g,
|
||||
-num == process group num). */
|
||||
else if (*word == '-' && saw_signal == 0)
|
||||
{
|
||||
sigspec = word + 1;
|
||||
sig = decode_signal (sigspec, dflags);
|
||||
saw_signal++;
|
||||
list = list->next;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (listing)
|
||||
return (display_signal_list (list, 0));
|
||||
|
||||
/* OK, we are killing processes. */
|
||||
if (sig == NO_SIG)
|
||||
{
|
||||
sh_invalidsig (sigspec);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
while (list)
|
||||
{
|
||||
word = list->word->word;
|
||||
|
||||
if (*word == '-')
|
||||
word++;
|
||||
|
||||
/* Use the entire argument in case of minus sign presence. */
|
||||
if (*word && legal_number (list->word->word, &pid_value) && (pid_value == (pid_t)pid_value))
|
||||
{
|
||||
pid = (pid_t) pid_value;
|
||||
|
||||
if (kill_pid (pid, sig, pid < -1) < 0)
|
||||
{
|
||||
if (errno == EINVAL)
|
||||
sh_invalidsig (sigspec);
|
||||
else
|
||||
kill_error (pid, errno);
|
||||
CONTINUE_OR_FAIL;
|
||||
}
|
||||
else
|
||||
any_succeeded++;
|
||||
}
|
||||
#if defined (JOB_CONTROL)
|
||||
else if (*list->word->word && *list->word->word != '%')
|
||||
{
|
||||
builtin_error (_("%s: arguments must be process or job IDs"), list->word->word);
|
||||
CONTINUE_OR_FAIL;
|
||||
}
|
||||
else if (*word)
|
||||
/* Posix.2 says you can kill without job control active (4.32.4) */
|
||||
{ /* Must be a job spec. Check it out. */
|
||||
int job;
|
||||
sigset_t set, oset;
|
||||
JOB *j;
|
||||
|
||||
BLOCK_CHILD (set, oset);
|
||||
job = get_job_spec (list);
|
||||
|
||||
if (INVALID_JOB (job))
|
||||
{
|
||||
if (job != DUP_JOB)
|
||||
sh_badjob (list->word->word);
|
||||
UNBLOCK_CHILD (oset);
|
||||
CONTINUE_OR_FAIL;
|
||||
}
|
||||
|
||||
j = get_job_by_jid (job);
|
||||
/* Job spec used. Kill the process group. If the job was started
|
||||
without job control, then its pgrp == shell_pgrp, so we have
|
||||
to be careful. We take the pid of the first job in the pipeline
|
||||
in that case. */
|
||||
pid = IS_JOBCONTROL (job) ? j->pgrp : j->pipe->pid;
|
||||
|
||||
UNBLOCK_CHILD (oset);
|
||||
|
||||
if (kill_pid (pid, sig, 1) < 0)
|
||||
{
|
||||
if (errno == EINVAL)
|
||||
sh_invalidsig (sigspec);
|
||||
else
|
||||
kill_error (pid, errno);
|
||||
CONTINUE_OR_FAIL;
|
||||
}
|
||||
else
|
||||
any_succeeded++;
|
||||
}
|
||||
#endif /* !JOB_CONTROL */
|
||||
else
|
||||
{
|
||||
sh_badpid (list->word->word);
|
||||
CONTINUE_OR_FAIL;
|
||||
}
|
||||
continue_killing:
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
return (any_succeeded ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
static void
|
||||
kill_error (pid, e)
|
||||
pid_t pid;
|
||||
int e;
|
||||
{
|
||||
char *x;
|
||||
|
||||
x = strerror (e);
|
||||
if (x == 0)
|
||||
x = _("Unknown error");
|
||||
builtin_error ("(%ld) - %s", (long)pid, x);
|
||||
}
|
68
third_party/bash/builtins_let.c
vendored
Normal file
68
third_party/bash/builtins_let.c
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
/* let.c, created from let.def. */
|
||||
#line 66 "./let.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
|
||||
/* Arithmetic LET function. */
|
||||
int
|
||||
let_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
intmax_t ret;
|
||||
int expok;
|
||||
|
||||
CHECK_HELPOPT (list);
|
||||
|
||||
/* Skip over leading `--' argument. */
|
||||
if (list && list->word && ISOPTION (list->word->word, '-'))
|
||||
list = list->next;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_error (_("expression expected"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
for (; list; list = list->next)
|
||||
{
|
||||
ret = evalexp (list->word->word, EXP_EXPANDED, &expok);
|
||||
if (expok == 0)
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
return ((ret == 0) ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_UNUSED
|
||||
int
|
||||
exp_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *exp;
|
||||
intmax_t ret;
|
||||
int expok;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_error (_("expression expected"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
exp = string_list (list);
|
||||
ret = evalexp (exp, EXP_EXPANDED, &expok);
|
||||
(void)free (exp);
|
||||
return (((ret == 0) || (expok == 0)) ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
|
||||
}
|
||||
#endif
|
304
third_party/bash/builtins_mapfile.c
vendored
Normal file
304
third_party/bash/builtins_mapfile.c
vendored
Normal file
|
@ -0,0 +1,304 @@
|
|||
/* mapfile.c, created from mapfile.def. */
|
||||
#line 23 "./mapfile.def"
|
||||
|
||||
#line 59 "./mapfile.def"
|
||||
|
||||
#line 67 "./mapfile.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "builtins.h"
|
||||
#include "bashtypes.h"
|
||||
#include "posixstat.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "bashintl.h"
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
|
||||
static int run_callback PARAMS((const char *, unsigned int, const char *));
|
||||
|
||||
#define DEFAULT_ARRAY_NAME "MAPFILE"
|
||||
#define DEFAULT_VARIABLE_NAME "MAPLINE" /* not used right now */
|
||||
|
||||
/* The value specifying how frequently `mapfile' calls the callback. */
|
||||
#define DEFAULT_QUANTUM 5000
|
||||
|
||||
/* Values for FLAGS */
|
||||
#define MAPF_CLEARARRAY 0x01
|
||||
#define MAPF_CHOP 0x02
|
||||
|
||||
static int delim;
|
||||
|
||||
static int
|
||||
run_callback (callback, curindex, curline)
|
||||
const char *callback;
|
||||
unsigned int curindex;
|
||||
const char *curline;
|
||||
{
|
||||
unsigned int execlen;
|
||||
char *execstr, *qline;
|
||||
int flags;
|
||||
|
||||
qline = sh_single_quote (curline);
|
||||
execlen = strlen (callback) + strlen (qline) + 10;
|
||||
/* 1 for each space between %s and %d,
|
||||
another 1 for the last nul char for C string. */
|
||||
execlen += 3;
|
||||
execstr = xmalloc (execlen);
|
||||
|
||||
flags = SEVAL_NOHIST;
|
||||
#if 0
|
||||
if (interactive)
|
||||
flags |= SEVAL_INTERACT;
|
||||
#endif
|
||||
snprintf (execstr, execlen, "%s %d %s", callback, curindex, qline);
|
||||
free (qline);
|
||||
return evalstring (execstr, NULL, flags);
|
||||
}
|
||||
|
||||
static void
|
||||
do_chop(line, delim)
|
||||
char *line;
|
||||
unsigned char delim;
|
||||
{
|
||||
int length;
|
||||
|
||||
length = strlen (line);
|
||||
if (length && (unsigned char)line[length-1] == delim)
|
||||
line[length-1] = '\0';
|
||||
}
|
||||
|
||||
static int
|
||||
mapfile (fd, line_count_goal, origin, nskip, callback_quantum, callback, array_name, delim, flags)
|
||||
int fd;
|
||||
long line_count_goal, origin, nskip, callback_quantum;
|
||||
char *callback, *array_name;
|
||||
int delim;
|
||||
int flags;
|
||||
{
|
||||
char *line;
|
||||
size_t line_length;
|
||||
unsigned int array_index, line_count;
|
||||
SHELL_VAR *entry;
|
||||
struct stat sb;
|
||||
int unbuffered_read;
|
||||
|
||||
line = NULL;
|
||||
line_length = 0;
|
||||
unbuffered_read = 0;
|
||||
|
||||
/* The following check should be done before reading any lines. Doing it
|
||||
here allows us to call bind_array_element instead of bind_array_variable
|
||||
and skip the variable lookup on every call. */
|
||||
entry = builtin_find_indexed_array (array_name, flags & MAPF_CLEARARRAY);
|
||||
if (entry == 0)
|
||||
return EXECUTION_FAILURE;
|
||||
|
||||
#ifndef __CYGWIN__
|
||||
/* If the delimiter is a newline, turn on unbuffered reads for pipes
|
||||
(terminals are ok). If the delimiter is not a newline, unbuffered reads
|
||||
for every file descriptor that's not a regular file. */
|
||||
if (delim == '\n')
|
||||
unbuffered_read = (lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE);
|
||||
else
|
||||
unbuffered_read = (fstat (fd, &sb) != 0) || (S_ISREG (sb.st_mode) == 0);
|
||||
#else
|
||||
unbuffered_read = 1;
|
||||
#endif
|
||||
|
||||
zreset ();
|
||||
|
||||
/* Skip any lines at beginning of file? */
|
||||
for (line_count = 0; line_count < nskip; line_count++)
|
||||
if (zgetline (fd, &line, &line_length, delim, unbuffered_read) < 0)
|
||||
break;
|
||||
|
||||
line = 0;
|
||||
line_length = 0;
|
||||
|
||||
/* Reset the buffer for bash own stream */
|
||||
for (array_index = origin, line_count = 1;
|
||||
zgetline (fd, &line, &line_length, delim, unbuffered_read) != -1;
|
||||
array_index++)
|
||||
{
|
||||
/* Remove trailing newlines? */
|
||||
if (flags & MAPF_CHOP)
|
||||
do_chop (line, delim);
|
||||
|
||||
/* Has a callback been registered and if so is it time to call it? */
|
||||
if (callback && line_count && (line_count % callback_quantum) == 0)
|
||||
{
|
||||
/* Reset the buffer for bash own stream. */
|
||||
if (unbuffered_read == 0)
|
||||
zsyncfd (fd);
|
||||
|
||||
run_callback (callback, array_index, line);
|
||||
}
|
||||
|
||||
/* XXX - bad things can happen if the callback modifies ENTRY, e.g.,
|
||||
unsetting it or changing it to a non-indexed-array type. */
|
||||
bind_array_element (entry, array_index, line, 0);
|
||||
|
||||
/* Have we exceeded # of lines to store? */
|
||||
line_count++;
|
||||
if (line_count_goal != 0 && line_count > line_count_goal)
|
||||
break;
|
||||
}
|
||||
|
||||
free (line);
|
||||
|
||||
if (unbuffered_read == 0)
|
||||
zsyncfd (fd);
|
||||
|
||||
return EXECUTION_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
mapfile_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt, code, fd, flags;
|
||||
intmax_t intval;
|
||||
long lines, origin, nskip, callback_quantum;
|
||||
char *array_name, *callback;
|
||||
|
||||
fd = 0;
|
||||
lines = origin = nskip = 0;
|
||||
flags = MAPF_CLEARARRAY;
|
||||
callback_quantum = DEFAULT_QUANTUM;
|
||||
callback = 0;
|
||||
delim = '\n';
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "d:u:n:O:tC:c:s:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'd':
|
||||
delim = *list_optarg;
|
||||
break;
|
||||
case 'u':
|
||||
code = legal_number (list_optarg, &intval);
|
||||
if (code == 0 || intval < 0 || intval != (int)intval)
|
||||
{
|
||||
builtin_error (_("%s: invalid file descriptor specification"), list_optarg);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
fd = intval;
|
||||
|
||||
if (sh_validfd (fd) == 0)
|
||||
{
|
||||
builtin_error (_("%d: invalid file descriptor: %s"), fd, strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
code = legal_number (list_optarg, &intval);
|
||||
if (code == 0 || intval < 0 || intval != (unsigned)intval)
|
||||
{
|
||||
builtin_error (_("%s: invalid line count"), list_optarg);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
lines = intval;
|
||||
break;
|
||||
|
||||
case 'O':
|
||||
code = legal_number (list_optarg, &intval);
|
||||
if (code == 0 || intval < 0 || intval != (unsigned)intval)
|
||||
{
|
||||
builtin_error (_("%s: invalid array origin"), list_optarg);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
origin = intval;
|
||||
flags &= ~MAPF_CLEARARRAY;
|
||||
break;
|
||||
case 't':
|
||||
flags |= MAPF_CHOP;
|
||||
break;
|
||||
case 'C':
|
||||
callback = list_optarg;
|
||||
break;
|
||||
case 'c':
|
||||
code = legal_number (list_optarg, &intval);
|
||||
if (code == 0 || intval <= 0 || intval != (unsigned)intval)
|
||||
{
|
||||
builtin_error (_("%s: invalid callback quantum"), list_optarg);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
callback_quantum = intval;
|
||||
break;
|
||||
case 's':
|
||||
code = legal_number (list_optarg, &intval);
|
||||
if (code == 0 || intval < 0 || intval != (unsigned)intval)
|
||||
{
|
||||
builtin_error (_("%s: invalid line count"), list_optarg);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
nskip = intval;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list == 0)
|
||||
array_name = DEFAULT_ARRAY_NAME;
|
||||
else if (list->word == 0 || list->word->word == 0)
|
||||
{
|
||||
builtin_error ("internal error: getting variable name");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else if (list->word->word[0] == '\0')
|
||||
{
|
||||
builtin_error (_("empty array variable name"));
|
||||
return (EX_USAGE);
|
||||
}
|
||||
else
|
||||
array_name = list->word->word;
|
||||
|
||||
if (legal_identifier (array_name) == 0)
|
||||
{
|
||||
sh_invalidid (array_name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
return mapfile (fd, lines, origin, nskip, callback_quantum, callback, array_name, delim, flags);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int
|
||||
mapfile_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
builtin_error (_("array variable support required"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
#endif /* ARRAY_VARS */
|
1303
third_party/bash/builtins_printf.c
vendored
Normal file
1303
third_party/bash/builtins_printf.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
690
third_party/bash/builtins_pushd.c
vendored
Normal file
690
third_party/bash/builtins_pushd.c
vendored
Normal file
|
@ -0,0 +1,690 @@
|
|||
/* pushd.c, created from pushd.def. */
|
||||
#line 22 "./pushd.def"
|
||||
|
||||
#line 55 "./pushd.def"
|
||||
|
||||
#line 84 "./pushd.def"
|
||||
|
||||
#line 115 "./pushd.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (PUSHD_AND_POPD)
|
||||
#include <stdio.h>
|
||||
#if defined (HAVE_SYS_PARAM_H)
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "tilde.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "maxpath.h"
|
||||
#include "common.h"
|
||||
#include "builtext.h"
|
||||
|
||||
#ifdef LOADABLE_BUILTIN
|
||||
# include "builtins.h"
|
||||
#endif
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
/* The list of remembered directories. */
|
||||
static char **pushd_directory_list = (char **)NULL;
|
||||
|
||||
/* Number of existing slots in this list. */
|
||||
static int directory_list_size;
|
||||
|
||||
/* Offset to the end of the list. */
|
||||
static int directory_list_offset;
|
||||
|
||||
static void pushd_error PARAMS((int, char *));
|
||||
static void clear_directory_stack PARAMS((void));
|
||||
static int cd_to_string PARAMS((char *));
|
||||
static int change_to_temp PARAMS((char *));
|
||||
static void add_dirstack_element PARAMS((char *));
|
||||
static int get_dirstack_index PARAMS((intmax_t, int, int *));
|
||||
|
||||
#define NOCD 0x01
|
||||
#define ROTATE 0x02
|
||||
#define LONGFORM 0x04
|
||||
#define CLEARSTAK 0x08
|
||||
|
||||
int
|
||||
pushd_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
WORD_LIST *orig_list;
|
||||
char *temp, *current_directory, *top;
|
||||
int j, flags, skipopt;
|
||||
intmax_t num;
|
||||
char direction;
|
||||
|
||||
orig_list = list;
|
||||
|
||||
CHECK_HELPOPT (list);
|
||||
if (list && list->word && ISOPTION (list->word->word, '-'))
|
||||
{
|
||||
list = list->next;
|
||||
skipopt = 1;
|
||||
}
|
||||
else
|
||||
skipopt = 0;
|
||||
|
||||
/* If there is no argument list then switch current and
|
||||
top of list. */
|
||||
if (list == 0)
|
||||
{
|
||||
if (directory_list_offset == 0)
|
||||
{
|
||||
builtin_error (_("no other directory"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
current_directory = get_working_directory ("pushd");
|
||||
if (current_directory == 0)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
j = directory_list_offset - 1;
|
||||
temp = pushd_directory_list[j];
|
||||
pushd_directory_list[j] = current_directory;
|
||||
j = change_to_temp (temp);
|
||||
free (temp);
|
||||
return j;
|
||||
}
|
||||
|
||||
for (flags = 0; skipopt == 0 && list; list = list->next)
|
||||
{
|
||||
if (ISOPTION (list->word->word, 'n'))
|
||||
{
|
||||
flags |= NOCD;
|
||||
}
|
||||
else if (ISOPTION (list->word->word, '-'))
|
||||
{
|
||||
list = list->next;
|
||||
break;
|
||||
}
|
||||
else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
|
||||
/* Let `pushd -' work like it used to. */
|
||||
break;
|
||||
else if (((direction = list->word->word[0]) == '+') || direction == '-')
|
||||
{
|
||||
if (legal_number (list->word->word + 1, &num) == 0)
|
||||
{
|
||||
sh_invalidnum (list->word->word);
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
if (direction == '-')
|
||||
num = directory_list_offset - num;
|
||||
|
||||
if (num > directory_list_offset || num < 0)
|
||||
{
|
||||
pushd_error (directory_list_offset, list->word->word);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
flags |= ROTATE;
|
||||
}
|
||||
else if (*list->word->word == '-')
|
||||
{
|
||||
sh_invalidopt (list->word->word);
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (flags & ROTATE)
|
||||
{
|
||||
/* Rotate the stack num times. Remember, the current
|
||||
directory acts like it is part of the stack. */
|
||||
temp = get_working_directory ("pushd");
|
||||
|
||||
if (num == 0)
|
||||
{
|
||||
j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS;
|
||||
free (temp);
|
||||
return j;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
top = pushd_directory_list[directory_list_offset - 1];
|
||||
|
||||
for (j = directory_list_offset - 2; j > -1; j--)
|
||||
pushd_directory_list[j + 1] = pushd_directory_list[j];
|
||||
|
||||
pushd_directory_list[j + 1] = temp;
|
||||
|
||||
temp = top;
|
||||
num--;
|
||||
}
|
||||
while (num);
|
||||
|
||||
j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS;
|
||||
free (temp);
|
||||
return j;
|
||||
}
|
||||
|
||||
if (list == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
/* Change to the directory in list->word->word. Save the current
|
||||
directory on the top of the stack. */
|
||||
current_directory = get_working_directory ("pushd");
|
||||
if (current_directory == 0)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
j = ((flags & NOCD) == 0) ? cd_builtin (skipopt ? orig_list : list) : EXECUTION_SUCCESS;
|
||||
if (j == EXECUTION_SUCCESS)
|
||||
{
|
||||
add_dirstack_element ((flags & NOCD) ? savestring (list->word->word) : current_directory);
|
||||
dirs_builtin ((WORD_LIST *)NULL);
|
||||
if (flags & NOCD)
|
||||
free (current_directory);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
free (current_directory);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Pop the directory stack, and then change to the new top of the stack.
|
||||
If LIST is non-null it should consist of a word +N or -N, which says
|
||||
what element to delete from the stack. The default is the top one. */
|
||||
int
|
||||
popd_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register int i;
|
||||
intmax_t which;
|
||||
int flags;
|
||||
char direction;
|
||||
char *which_word;
|
||||
|
||||
CHECK_HELPOPT (list);
|
||||
|
||||
which_word = (char *)NULL;
|
||||
for (flags = 0, which = 0, direction = '+'; list; list = list->next)
|
||||
{
|
||||
if (ISOPTION (list->word->word, 'n'))
|
||||
{
|
||||
flags |= NOCD;
|
||||
}
|
||||
else if (ISOPTION (list->word->word, '-'))
|
||||
{
|
||||
list = list->next;
|
||||
break;
|
||||
}
|
||||
else if (((direction = list->word->word[0]) == '+') || direction == '-')
|
||||
{
|
||||
if (legal_number (list->word->word + 1, &which) == 0)
|
||||
{
|
||||
sh_invalidnum (list->word->word);
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
which_word = list->word->word;
|
||||
}
|
||||
else if (*list->word->word == '-')
|
||||
{
|
||||
sh_invalidopt (list->word->word);
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
else if (*list->word->word)
|
||||
{
|
||||
builtin_error (_("%s: invalid argument"), list->word->word);
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (which > directory_list_offset || (which < -directory_list_offset) || (directory_list_offset == 0 && which == 0))
|
||||
{
|
||||
pushd_error (directory_list_offset, which_word ? which_word : "");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* Handle case of no specification, or top of stack specification. */
|
||||
if ((direction == '+' && which == 0) ||
|
||||
(direction == '-' && which == directory_list_offset))
|
||||
{
|
||||
i = ((flags & NOCD) == 0) ? cd_to_string (pushd_directory_list[directory_list_offset - 1])
|
||||
: EXECUTION_SUCCESS;
|
||||
if (i != EXECUTION_SUCCESS)
|
||||
return (i);
|
||||
free (pushd_directory_list[--directory_list_offset]);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Since an offset other than the top directory was specified,
|
||||
remove that directory from the list and shift the remainder
|
||||
of the list into place. */
|
||||
i = (direction == '+') ? directory_list_offset - which : which;
|
||||
if (i < 0 || i > directory_list_offset)
|
||||
{
|
||||
pushd_error (directory_list_offset, which_word ? which_word : "");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
free (pushd_directory_list[i]);
|
||||
directory_list_offset--;
|
||||
|
||||
/* Shift the remainder of the list into place. */
|
||||
for (; i < directory_list_offset; i++)
|
||||
pushd_directory_list[i] = pushd_directory_list[i + 1];
|
||||
}
|
||||
|
||||
dirs_builtin ((WORD_LIST *)NULL);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Print the current list of directories on the directory stack. */
|
||||
int
|
||||
dirs_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int flags, desired_index, index_flag, vflag;
|
||||
intmax_t i;
|
||||
char *temp, *w;
|
||||
|
||||
CHECK_HELPOPT (list);
|
||||
for (flags = vflag = index_flag = 0, desired_index = -1, w = ""; list; list = list->next)
|
||||
{
|
||||
if (ISOPTION (list->word->word, 'l'))
|
||||
{
|
||||
flags |= LONGFORM;
|
||||
}
|
||||
else if (ISOPTION (list->word->word, 'c'))
|
||||
{
|
||||
flags |= CLEARSTAK;
|
||||
}
|
||||
else if (ISOPTION (list->word->word, 'v'))
|
||||
{
|
||||
vflag |= 2;
|
||||
}
|
||||
else if (ISOPTION (list->word->word, 'p'))
|
||||
{
|
||||
vflag |= 1;
|
||||
}
|
||||
else if (ISOPTION (list->word->word, '-'))
|
||||
{
|
||||
list = list->next;
|
||||
break;
|
||||
}
|
||||
else if (*list->word->word == '+' || *list->word->word == '-')
|
||||
{
|
||||
int sign;
|
||||
if (legal_number (w = list->word->word + 1, &i) == 0)
|
||||
{
|
||||
sh_invalidnum (list->word->word);
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
sign = (*list->word->word == '+') ? 1 : -1;
|
||||
desired_index = get_dirstack_index (i, sign, &index_flag);
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_invalidopt (list->word->word);
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & CLEARSTAK)
|
||||
{
|
||||
clear_directory_stack ();
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
if (index_flag && (desired_index < 0 || desired_index > directory_list_offset))
|
||||
{
|
||||
pushd_error (directory_list_offset, w);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
#define DIRSTACK_FORMAT(temp) \
|
||||
(flags & LONGFORM) ? temp : polite_directory_format (temp)
|
||||
|
||||
/* The first directory printed is always the current working directory. */
|
||||
if (index_flag == 0 || (index_flag == 1 && desired_index == 0))
|
||||
{
|
||||
temp = get_working_directory ("dirs");
|
||||
if (temp == 0)
|
||||
temp = savestring (_("<no current directory>"));
|
||||
if (vflag & 2)
|
||||
printf ("%2d %s", 0, DIRSTACK_FORMAT (temp));
|
||||
else
|
||||
printf ("%s", DIRSTACK_FORMAT (temp));
|
||||
free (temp);
|
||||
if (index_flag)
|
||||
{
|
||||
putchar ('\n');
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
}
|
||||
|
||||
#define DIRSTACK_ENTRY(i) \
|
||||
(flags & LONGFORM) ? pushd_directory_list[i] \
|
||||
: polite_directory_format (pushd_directory_list[i])
|
||||
|
||||
/* Now print the requested directory stack entries. */
|
||||
if (index_flag)
|
||||
{
|
||||
if (vflag & 2)
|
||||
printf ("%2d %s", directory_list_offset - desired_index,
|
||||
DIRSTACK_ENTRY (desired_index));
|
||||
else
|
||||
printf ("%s", DIRSTACK_ENTRY (desired_index));
|
||||
}
|
||||
else
|
||||
for (i = directory_list_offset - 1; i >= 0; i--)
|
||||
if (vflag >= 2)
|
||||
printf ("\n%2d %s", directory_list_offset - (int)i, DIRSTACK_ENTRY (i));
|
||||
else
|
||||
printf ("%s%s", (vflag & 1) ? "\n" : " ", DIRSTACK_ENTRY (i));
|
||||
|
||||
putchar ('\n');
|
||||
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
static void
|
||||
pushd_error (offset, arg)
|
||||
int offset;
|
||||
char *arg;
|
||||
{
|
||||
if (offset == 0)
|
||||
builtin_error (_("directory stack empty"));
|
||||
else
|
||||
sh_erange (arg, _("directory stack index"));
|
||||
}
|
||||
|
||||
static void
|
||||
clear_directory_stack ()
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; i < directory_list_offset; i++)
|
||||
free (pushd_directory_list[i]);
|
||||
directory_list_offset = 0;
|
||||
}
|
||||
|
||||
/* Switch to the directory in NAME. This uses the cd_builtin to do the work,
|
||||
so if the result is EXECUTION_FAILURE then an error message has already
|
||||
been printed. */
|
||||
static int
|
||||
cd_to_string (name)
|
||||
char *name;
|
||||
{
|
||||
WORD_LIST *tlist;
|
||||
WORD_LIST *dir;
|
||||
int result;
|
||||
|
||||
dir = make_word_list (make_word (name), NULL);
|
||||
tlist = make_word_list (make_word ("--"), dir);
|
||||
result = cd_builtin (tlist);
|
||||
dispose_words (tlist);
|
||||
return (result);
|
||||
}
|
||||
|
||||
static int
|
||||
change_to_temp (temp)
|
||||
char *temp;
|
||||
{
|
||||
int tt;
|
||||
|
||||
tt = temp ? cd_to_string (temp) : EXECUTION_FAILURE;
|
||||
|
||||
if (tt == EXECUTION_SUCCESS)
|
||||
dirs_builtin ((WORD_LIST *)NULL);
|
||||
|
||||
return (tt);
|
||||
}
|
||||
|
||||
static void
|
||||
add_dirstack_element (dir)
|
||||
char *dir;
|
||||
{
|
||||
if (directory_list_offset == directory_list_size)
|
||||
pushd_directory_list = strvec_resize (pushd_directory_list, directory_list_size += 10);
|
||||
pushd_directory_list[directory_list_offset++] = dir;
|
||||
}
|
||||
|
||||
static int
|
||||
get_dirstack_index (ind, sign, indexp)
|
||||
intmax_t ind;
|
||||
int sign, *indexp;
|
||||
{
|
||||
if (indexp)
|
||||
*indexp = sign > 0 ? 1 : 2;
|
||||
|
||||
/* dirs +0 prints the current working directory. */
|
||||
/* dirs -0 prints last element in directory stack */
|
||||
if (ind == 0 && sign > 0)
|
||||
return 0;
|
||||
else if (ind == directory_list_offset)
|
||||
{
|
||||
if (indexp)
|
||||
*indexp = sign > 0 ? 2 : 1;
|
||||
return 0;
|
||||
}
|
||||
else if (ind >= 0 && ind <= directory_list_offset)
|
||||
return (sign > 0 ? directory_list_offset - ind : ind);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Used by the tilde expansion code. */
|
||||
char *
|
||||
get_dirstack_from_string (string)
|
||||
char *string;
|
||||
{
|
||||
int ind, sign, index_flag;
|
||||
intmax_t i;
|
||||
|
||||
sign = 1;
|
||||
if (*string == '-' || *string == '+')
|
||||
{
|
||||
sign = (*string == '-') ? -1 : 1;
|
||||
string++;
|
||||
}
|
||||
if (legal_number (string, &i) == 0)
|
||||
return ((char *)NULL);
|
||||
|
||||
index_flag = 0;
|
||||
ind = get_dirstack_index (i, sign, &index_flag);
|
||||
if (index_flag && (ind < 0 || ind > directory_list_offset))
|
||||
return ((char *)NULL);
|
||||
if (index_flag == 0 || (index_flag == 1 && ind == 0))
|
||||
return (get_string_value ("PWD"));
|
||||
else
|
||||
return (pushd_directory_list[ind]);
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_UNUSED
|
||||
char *
|
||||
get_dirstack_element (ind, sign)
|
||||
intmax_t ind;
|
||||
int sign;
|
||||
{
|
||||
int i;
|
||||
|
||||
i = get_dirstack_index (ind, sign, (int *)NULL);
|
||||
return (i < 0 || i > directory_list_offset) ? (char *)NULL
|
||||
: pushd_directory_list[i];
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
set_dirstack_element (ind, sign, value)
|
||||
intmax_t ind;
|
||||
int sign;
|
||||
char *value;
|
||||
{
|
||||
int i;
|
||||
|
||||
i = get_dirstack_index (ind, sign, (int *)NULL);
|
||||
if (ind == 0 || i < 0 || i > directory_list_offset)
|
||||
return;
|
||||
free (pushd_directory_list[i]);
|
||||
pushd_directory_list[i] = savestring (value);
|
||||
}
|
||||
|
||||
WORD_LIST *
|
||||
get_directory_stack (flags)
|
||||
int flags;
|
||||
{
|
||||
register int i;
|
||||
WORD_LIST *ret;
|
||||
char *d, *t;
|
||||
|
||||
for (ret = (WORD_LIST *)NULL, i = 0; i < directory_list_offset; i++)
|
||||
{
|
||||
d = (flags&1) ? polite_directory_format (pushd_directory_list[i])
|
||||
: pushd_directory_list[i];
|
||||
ret = make_word_list (make_word (d), ret);
|
||||
}
|
||||
/* Now the current directory. */
|
||||
d = get_working_directory ("dirstack");
|
||||
i = 0; /* sentinel to decide whether or not to free d */
|
||||
if (d == 0)
|
||||
d = ".";
|
||||
else
|
||||
{
|
||||
t = (flags&1) ? polite_directory_format (d) : d;
|
||||
/* polite_directory_format sometimes returns its argument unchanged.
|
||||
If it does not, we can free d right away. If it does, we need to
|
||||
mark d to be deleted later. */
|
||||
if (t != d)
|
||||
{
|
||||
free (d);
|
||||
d = t;
|
||||
}
|
||||
else /* t == d, so d is what we want */
|
||||
i = 1;
|
||||
}
|
||||
ret = make_word_list (make_word (d), ret);
|
||||
if (i)
|
||||
free (d);
|
||||
return ret; /* was (REVERSE_LIST (ret, (WORD_LIST *)); */
|
||||
}
|
||||
|
||||
#ifdef LOADABLE_BUILTIN
|
||||
char * const dirs_doc[] = {
|
||||
N_("Display the list of currently remembered directories. Directories\n\
|
||||
find their way onto the list with the `pushd' command; you can get\n\
|
||||
back up through the list with the `popd' command.\n\
|
||||
\n\
|
||||
Options:\n\
|
||||
-c clear the directory stack by deleting all of the elements\n\
|
||||
-l do not print tilde-prefixed versions of directories relative\n\
|
||||
to your home directory\n\
|
||||
-p print the directory stack with one entry per line\n\
|
||||
-v print the directory stack with one entry per line prefixed\n\
|
||||
with its position in the stack\n\
|
||||
\n\
|
||||
Arguments:\n\
|
||||
+N Displays the Nth entry counting from the left of the list shown by\n\
|
||||
dirs when invoked without options, starting with zero.\n\
|
||||
\n\
|
||||
-N Displays the Nth entry counting from the right of the list shown by\n\
|
||||
dirs when invoked without options, starting with zero."),
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
char * const pushd_doc[] = {
|
||||
N_("Adds a directory to the top of the directory stack, or rotates\n\
|
||||
the stack, making the new top of the stack the current working\n\
|
||||
directory. With no arguments, exchanges the top two directories.\n\
|
||||
\n\
|
||||
Options:\n\
|
||||
-n Suppresses the normal change of directory when adding\n\
|
||||
directories to the stack, so only the stack is manipulated.\n\
|
||||
\n\
|
||||
Arguments:\n\
|
||||
+N Rotates the stack so that the Nth directory (counting\n\
|
||||
from the left of the list shown by `dirs', starting with\n\
|
||||
zero) is at the top.\n\
|
||||
\n\
|
||||
-N Rotates the stack so that the Nth directory (counting\n\
|
||||
from the right of the list shown by `dirs', starting with\n\
|
||||
zero) is at the top.\n\
|
||||
\n\
|
||||
dir Adds DIR to the directory stack at the top, making it the\n\
|
||||
new current working directory.\n\
|
||||
\n\
|
||||
The `dirs' builtin displays the directory stack."),
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
char * const popd_doc[] = {
|
||||
N_("Removes entries from the directory stack. With no arguments, removes\n\
|
||||
the top directory from the stack, and changes to the new top directory.\n\
|
||||
\n\
|
||||
Options:\n\
|
||||
-n Suppresses the normal change of directory when removing\n\
|
||||
directories from the stack, so only the stack is manipulated.\n\
|
||||
\n\
|
||||
Arguments:\n\
|
||||
+N Removes the Nth entry counting from the left of the list\n\
|
||||
shown by `dirs', starting with zero. For example: `popd +0'\n\
|
||||
removes the first directory, `popd +1' the second.\n\
|
||||
\n\
|
||||
-N Removes the Nth entry counting from the right of the list\n\
|
||||
shown by `dirs', starting with zero. For example: `popd -0'\n\
|
||||
removes the last directory, `popd -1' the next to last.\n\
|
||||
\n\
|
||||
The `dirs' builtin displays the directory stack."),
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin pushd_struct = {
|
||||
"pushd",
|
||||
pushd_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
pushd_doc,
|
||||
"pushd [+N | -N] [-n] [dir]",
|
||||
0
|
||||
};
|
||||
|
||||
struct builtin popd_struct = {
|
||||
"popd",
|
||||
popd_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
popd_doc,
|
||||
"popd [+N | -N] [-n]",
|
||||
0
|
||||
};
|
||||
|
||||
struct builtin dirs_struct = {
|
||||
"dirs",
|
||||
dirs_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
dirs_doc,
|
||||
"dirs [-clpv] [+N] [-N]",
|
||||
0
|
||||
};
|
||||
#endif /* LOADABLE_BUILTIN */
|
||||
|
||||
#endif /* PUSHD_AND_POPD */
|
1205
third_party/bash/builtins_read.c
vendored
Normal file
1205
third_party/bash/builtins_read.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
40
third_party/bash/builtins_return.c
vendored
Normal file
40
third_party/bash/builtins_return.c
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
/* return.c, created from return.def. */
|
||||
#line 22 "./return.def"
|
||||
|
||||
#line 36 "./return.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "execute_cmd.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
/* If we are executing a user-defined function then exit with the value
|
||||
specified as an argument. if no argument is given, then the last
|
||||
exit status is used. */
|
||||
int
|
||||
return_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
CHECK_HELPOPT (list);
|
||||
|
||||
return_catch_value = get_exitstat (list);
|
||||
|
||||
if (return_catch_flag)
|
||||
sh_longjmp (return_catch, 1);
|
||||
else
|
||||
{
|
||||
builtin_error (_("can only `return' from a function or sourced script"));
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
890
third_party/bash/builtins_set.c
vendored
Normal file
890
third_party/bash/builtins_set.c
vendored
Normal file
|
@ -0,0 +1,890 @@
|
|||
/* set.c, created from set.def. */
|
||||
#line 22 "./set.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "parser.h"
|
||||
#include "flags.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#if defined (READLINE)
|
||||
# include "input.h"
|
||||
# include "bashline.h"
|
||||
# include "third_party/readline/readline.h"
|
||||
#endif
|
||||
|
||||
#if defined (HISTORY)
|
||||
# include "bashhist.h"
|
||||
#endif
|
||||
|
||||
#line 153 "./set.def"
|
||||
|
||||
typedef int setopt_set_func_t PARAMS((int, char *));
|
||||
typedef int setopt_get_func_t PARAMS((char *));
|
||||
|
||||
static int find_minus_o_option PARAMS((char *));
|
||||
|
||||
static void print_minus_o_option PARAMS((char *, int, int));
|
||||
static void print_all_shell_variables PARAMS((void));
|
||||
|
||||
static int set_ignoreeof PARAMS((int, char *));
|
||||
static int set_posix_mode PARAMS((int, char *));
|
||||
|
||||
#if defined (READLINE)
|
||||
static int set_edit_mode PARAMS((int, char *));
|
||||
static int get_edit_mode PARAMS((char *));
|
||||
#endif
|
||||
|
||||
#if defined (HISTORY)
|
||||
static int bash_set_history PARAMS((int, char *));
|
||||
#endif
|
||||
|
||||
static const char * const on = "on";
|
||||
static const char * const off = "off";
|
||||
|
||||
static int previous_option_value;
|
||||
|
||||
/* A struct used to match long options for set -o to the corresponding
|
||||
option letter or internal variable. The functions can be called to
|
||||
dynamically generate values. If you add a new variable name here
|
||||
that doesn't have a corresponding single-character option letter, make
|
||||
sure to set the value appropriately in reset_shell_options. */
|
||||
const struct {
|
||||
char *name;
|
||||
int letter;
|
||||
int *variable;
|
||||
setopt_set_func_t *set_func;
|
||||
setopt_get_func_t *get_func;
|
||||
} o_options[] = {
|
||||
{ "allexport", 'a', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#if defined (BRACE_EXPANSION)
|
||||
{ "braceexpand",'B', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#endif
|
||||
#if defined (READLINE)
|
||||
{ "emacs", '\0', (int *)NULL, set_edit_mode, get_edit_mode },
|
||||
#endif
|
||||
{ "errexit", 'e', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "errtrace", 'E', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "functrace", 'T', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "hashall", 'h', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#if defined (BANG_HISTORY)
|
||||
{ "histexpand", 'H', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#endif /* BANG_HISTORY */
|
||||
#if defined (HISTORY)
|
||||
{ "history", '\0', &enable_history_list, bash_set_history, (setopt_get_func_t *)NULL },
|
||||
#endif
|
||||
{ "ignoreeof", '\0', &ignoreeof, set_ignoreeof, (setopt_get_func_t *)NULL },
|
||||
{ "interactive-comments", '\0', &interactive_comments, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "keyword", 'k', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#if defined (JOB_CONTROL)
|
||||
{ "monitor", 'm', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#endif
|
||||
{ "noclobber", 'C', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "noexec", 'n', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "noglob", 'f', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#if defined (HISTORY)
|
||||
{ "nolog", '\0', &dont_save_function_defs, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#endif
|
||||
#if defined (JOB_CONTROL)
|
||||
{ "notify", 'b', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#endif /* JOB_CONTROL */
|
||||
{ "nounset", 'u', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "onecmd", 't', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "physical", 'P', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "pipefail", '\0', &pipefail_opt, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "posix", '\0', &posixly_correct, set_posix_mode, (setopt_get_func_t *)NULL },
|
||||
{ "privileged", 'p', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "verbose", 'v', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#if defined (READLINE)
|
||||
{ "vi", '\0', (int *)NULL, set_edit_mode, get_edit_mode },
|
||||
#endif
|
||||
{ "xtrace", 'x', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{(char *)NULL, 0 , (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
};
|
||||
|
||||
#define N_O_OPTIONS (sizeof (o_options) / sizeof (o_options[0]))
|
||||
|
||||
#define GET_BINARY_O_OPTION_VALUE(i, name) \
|
||||
((o_options[i].get_func) ? (*o_options[i].get_func) (name) \
|
||||
: (*o_options[i].variable))
|
||||
|
||||
#define SET_BINARY_O_OPTION_VALUE(i, onoff, name) \
|
||||
((o_options[i].set_func) ? (*o_options[i].set_func) (onoff, name) \
|
||||
: (*o_options[i].variable = (onoff == FLAG_ON)))
|
||||
|
||||
static int
|
||||
find_minus_o_option (name)
|
||||
char *name;
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; o_options[i].name; i++)
|
||||
if (STREQ (name, o_options[i].name))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
minus_o_option_value (name)
|
||||
char *name;
|
||||
{
|
||||
register int i;
|
||||
int *on_or_off;
|
||||
|
||||
i = find_minus_o_option (name);
|
||||
if (i < 0)
|
||||
return (-1);
|
||||
|
||||
if (o_options[i].letter)
|
||||
{
|
||||
on_or_off = find_flag (o_options[i].letter);
|
||||
return ((on_or_off == FLAG_UNKNOWN) ? -1 : *on_or_off);
|
||||
}
|
||||
else
|
||||
return (GET_BINARY_O_OPTION_VALUE (i, name));
|
||||
}
|
||||
|
||||
#define MINUS_O_FORMAT "%-15s\t%s\n"
|
||||
|
||||
static void
|
||||
print_minus_o_option (name, value, pflag)
|
||||
char *name;
|
||||
int value, pflag;
|
||||
{
|
||||
if (pflag == 0)
|
||||
printf (MINUS_O_FORMAT, name, value ? on : off);
|
||||
else
|
||||
printf ("set %co %s\n", value ? '-' : '+', name);
|
||||
}
|
||||
|
||||
void
|
||||
list_minus_o_opts (mode, reusable)
|
||||
int mode, reusable;
|
||||
{
|
||||
register int i;
|
||||
int *on_or_off, value;
|
||||
|
||||
for (i = 0; o_options[i].name; i++)
|
||||
{
|
||||
if (o_options[i].letter)
|
||||
{
|
||||
value = 0;
|
||||
on_or_off = find_flag (o_options[i].letter);
|
||||
if (on_or_off == FLAG_UNKNOWN)
|
||||
on_or_off = &value;
|
||||
if (mode == -1 || mode == *on_or_off)
|
||||
print_minus_o_option (o_options[i].name, *on_or_off, reusable);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
|
||||
if (mode == -1 || mode == value)
|
||||
print_minus_o_option (o_options[i].name, value, reusable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char **
|
||||
get_minus_o_opts ()
|
||||
{
|
||||
char **ret;
|
||||
int i;
|
||||
|
||||
ret = strvec_create (N_O_OPTIONS + 1);
|
||||
for (i = 0; o_options[i].name; i++)
|
||||
ret[i] = o_options[i].name;
|
||||
ret[i] = (char *)NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *
|
||||
get_current_options ()
|
||||
{
|
||||
char *temp;
|
||||
int i, posixopts;
|
||||
|
||||
posixopts = num_posix_options (); /* shopts modified by posix mode */
|
||||
/* Make the buffer big enough to hold the set -o options and the shopt
|
||||
options modified by posix mode. */
|
||||
temp = (char *)xmalloc (1 + N_O_OPTIONS + posixopts);
|
||||
for (i = 0; o_options[i].name; i++)
|
||||
{
|
||||
if (o_options[i].letter)
|
||||
temp[i] = *(find_flag (o_options[i].letter));
|
||||
else
|
||||
temp[i] = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
|
||||
}
|
||||
|
||||
/* Add the shell options that are modified by posix mode to the end of the
|
||||
bitmap. They will be handled in set_current_options() */
|
||||
get_posix_options (temp+i);
|
||||
temp[i+posixopts] = '\0';
|
||||
return (temp);
|
||||
}
|
||||
|
||||
void
|
||||
set_current_options (bitmap)
|
||||
const char *bitmap;
|
||||
{
|
||||
int i, v, cv, *on_or_off;
|
||||
|
||||
if (bitmap == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; o_options[i].name; i++)
|
||||
{
|
||||
v = bitmap[i] ? FLAG_ON : FLAG_OFF;
|
||||
if (o_options[i].letter)
|
||||
{
|
||||
/* We should not get FLAG_UNKNOWN here */
|
||||
on_or_off = find_flag (o_options[i].letter);
|
||||
cv = *on_or_off ? FLAG_ON : FLAG_OFF;
|
||||
if (v != cv)
|
||||
change_flag (o_options[i].letter, v);
|
||||
}
|
||||
else
|
||||
{
|
||||
cv = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
|
||||
cv = cv ? FLAG_ON : FLAG_OFF;
|
||||
if (v != cv)
|
||||
SET_BINARY_O_OPTION_VALUE (i, v, o_options[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now reset the variables changed by posix mode */
|
||||
set_posix_options (bitmap+i);
|
||||
}
|
||||
|
||||
static int
|
||||
set_ignoreeof (on_or_off, option_name)
|
||||
int on_or_off;
|
||||
char *option_name;
|
||||
{
|
||||
ignoreeof = on_or_off == FLAG_ON;
|
||||
unbind_variable_noref ("ignoreeof");
|
||||
if (ignoreeof)
|
||||
bind_variable ("IGNOREEOF", "10", 0);
|
||||
else
|
||||
unbind_variable_noref ("IGNOREEOF");
|
||||
sv_ignoreeof ("IGNOREEOF");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
set_posix_mode (on_or_off, option_name)
|
||||
int on_or_off;
|
||||
char *option_name;
|
||||
{
|
||||
/* short-circuit on no-op */
|
||||
if ((on_or_off == FLAG_ON && posixly_correct) ||
|
||||
(on_or_off == FLAG_OFF && posixly_correct == 0))
|
||||
return 0;
|
||||
|
||||
posixly_correct = on_or_off == FLAG_ON;
|
||||
if (posixly_correct == 0)
|
||||
unbind_variable_noref ("POSIXLY_CORRECT");
|
||||
else
|
||||
bind_variable ("POSIXLY_CORRECT", "y", 0);
|
||||
sv_strict_posix ("POSIXLY_CORRECT");
|
||||
return (0);
|
||||
}
|
||||
|
||||
#if defined (READLINE)
|
||||
/* Magic. This code `knows' how readline handles rl_editing_mode. */
|
||||
static int
|
||||
set_edit_mode (on_or_off, option_name)
|
||||
int on_or_off;
|
||||
char *option_name;
|
||||
{
|
||||
int isemacs;
|
||||
|
||||
if (on_or_off == FLAG_ON)
|
||||
{
|
||||
rl_variable_bind ("editing-mode", option_name);
|
||||
|
||||
if (interactive)
|
||||
with_input_from_stdin ();
|
||||
no_line_editing = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
isemacs = rl_editing_mode == 1;
|
||||
if ((isemacs && *option_name == 'e') || (!isemacs && *option_name == 'v'))
|
||||
{
|
||||
if (interactive)
|
||||
with_input_from_stream (stdin, "stdin");
|
||||
no_line_editing = 1;
|
||||
}
|
||||
}
|
||||
return 1-no_line_editing;
|
||||
}
|
||||
|
||||
static int
|
||||
get_edit_mode (name)
|
||||
char *name;
|
||||
{
|
||||
return (*name == 'e' ? no_line_editing == 0 && rl_editing_mode == 1
|
||||
: no_line_editing == 0 && rl_editing_mode == 0);
|
||||
}
|
||||
#endif /* READLINE */
|
||||
|
||||
#if defined (HISTORY)
|
||||
static int
|
||||
bash_set_history (on_or_off, option_name)
|
||||
int on_or_off;
|
||||
char *option_name;
|
||||
{
|
||||
if (on_or_off == FLAG_ON)
|
||||
{
|
||||
enable_history_list = 1;
|
||||
bash_history_enable ();
|
||||
if (history_lines_this_session == 0)
|
||||
load_history ();
|
||||
}
|
||||
else
|
||||
{
|
||||
enable_history_list = 0;
|
||||
bash_history_disable ();
|
||||
}
|
||||
return (1 - enable_history_list);
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
set_minus_o_option (on_or_off, option_name)
|
||||
int on_or_off;
|
||||
char *option_name;
|
||||
{
|
||||
register int i;
|
||||
|
||||
i = find_minus_o_option (option_name);
|
||||
if (i < 0)
|
||||
{
|
||||
sh_invalidoptname (option_name);
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
if (o_options[i].letter == 0)
|
||||
{
|
||||
previous_option_value = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
|
||||
SET_BINARY_O_OPTION_VALUE (i, on_or_off, option_name);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((previous_option_value = change_flag (o_options[i].letter, on_or_off)) == FLAG_ERROR)
|
||||
{
|
||||
sh_invalidoptname (option_name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_all_shell_variables ()
|
||||
{
|
||||
SHELL_VAR **vars;
|
||||
|
||||
vars = all_shell_variables ();
|
||||
if (vars)
|
||||
{
|
||||
print_var_list (vars);
|
||||
free (vars);
|
||||
}
|
||||
|
||||
/* POSIX.2 does not allow function names and definitions to be output when
|
||||
`set' is invoked without options (PASC Interp #202). */
|
||||
if (posixly_correct == 0)
|
||||
{
|
||||
vars = all_shell_functions ();
|
||||
if (vars)
|
||||
{
|
||||
print_func_list (vars);
|
||||
free (vars);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
set_shellopts ()
|
||||
{
|
||||
char *value;
|
||||
char tflag[N_O_OPTIONS];
|
||||
int vsize, i, vptr, *ip, exported;
|
||||
SHELL_VAR *v;
|
||||
|
||||
for (vsize = i = 0; o_options[i].name; i++)
|
||||
{
|
||||
tflag[i] = 0;
|
||||
if (o_options[i].letter)
|
||||
{
|
||||
ip = find_flag (o_options[i].letter);
|
||||
if (ip && *ip)
|
||||
{
|
||||
vsize += strlen (o_options[i].name) + 1;
|
||||
tflag[i] = 1;
|
||||
}
|
||||
}
|
||||
else if (GET_BINARY_O_OPTION_VALUE (i, o_options[i].name))
|
||||
{
|
||||
vsize += strlen (o_options[i].name) + 1;
|
||||
tflag[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
value = (char *)xmalloc (vsize + 1);
|
||||
|
||||
for (i = vptr = 0; o_options[i].name; i++)
|
||||
{
|
||||
if (tflag[i])
|
||||
{
|
||||
strcpy (value + vptr, o_options[i].name);
|
||||
vptr += strlen (o_options[i].name);
|
||||
value[vptr++] = ':';
|
||||
}
|
||||
}
|
||||
|
||||
if (vptr)
|
||||
vptr--; /* cut off trailing colon */
|
||||
value[vptr] = '\0';
|
||||
|
||||
v = find_variable ("SHELLOPTS");
|
||||
|
||||
/* Turn off the read-only attribute so we can bind the new value, and
|
||||
note whether or not the variable was exported. */
|
||||
if (v)
|
||||
{
|
||||
VUNSETATTR (v, att_readonly);
|
||||
exported = exported_p (v);
|
||||
}
|
||||
else
|
||||
exported = 0;
|
||||
|
||||
v = bind_variable ("SHELLOPTS", value, 0);
|
||||
|
||||
/* Turn the read-only attribute back on, and turn off the export attribute
|
||||
if it was set implicitly by mark_modified_vars and SHELLOPTS was not
|
||||
exported before we bound the new value. */
|
||||
VSETATTR (v, att_readonly);
|
||||
if (mark_modified_vars && exported == 0 && exported_p (v))
|
||||
VUNSETATTR (v, att_exported);
|
||||
|
||||
free (value);
|
||||
}
|
||||
|
||||
void
|
||||
parse_shellopts (value)
|
||||
char *value;
|
||||
{
|
||||
char *vname;
|
||||
int vptr;
|
||||
|
||||
vptr = 0;
|
||||
while (vname = extract_colon_unit (value, &vptr))
|
||||
{
|
||||
set_minus_o_option (FLAG_ON, vname);
|
||||
free (vname);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
initialize_shell_options (no_shellopts)
|
||||
int no_shellopts;
|
||||
{
|
||||
char *temp;
|
||||
SHELL_VAR *var;
|
||||
|
||||
if (no_shellopts == 0)
|
||||
{
|
||||
var = find_variable ("SHELLOPTS");
|
||||
/* set up any shell options we may have inherited. */
|
||||
if (var && imported_p (var))
|
||||
{
|
||||
temp = (array_p (var) || assoc_p (var)) ? (char *)NULL : savestring (value_cell (var));
|
||||
if (temp)
|
||||
{
|
||||
parse_shellopts (temp);
|
||||
free (temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set up the $SHELLOPTS variable. */
|
||||
set_shellopts ();
|
||||
}
|
||||
|
||||
/* Reset the values of the -o options that are not also shell flags. This is
|
||||
called from execute_cmd.c:initialize_subshell() when setting up a subshell
|
||||
to run an executable shell script without a leading `#!'. */
|
||||
void
|
||||
reset_shell_options ()
|
||||
{
|
||||
pipefail_opt = 0;
|
||||
ignoreeof = 0;
|
||||
|
||||
#if defined (STRICT_POSIX)
|
||||
posixly_correct = 1;
|
||||
#else
|
||||
posixly_correct = 0;
|
||||
#endif
|
||||
#if defined (HISTORY)
|
||||
dont_save_function_defs = 0;
|
||||
remember_on_history = enable_history_list = 1; /* XXX */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Set some flags from the word values in the input list. If LIST is empty,
|
||||
then print out the values of the variables instead. If LIST contains
|
||||
non-flags, then set $1 - $9 to the successive words of LIST. */
|
||||
int
|
||||
set_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int on_or_off, flag_name, force_assignment, opts_changed, rv, r;
|
||||
register char *arg;
|
||||
char s[3];
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
print_all_shell_variables ();
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
/* Check validity of flag arguments. */
|
||||
rv = EXECUTION_SUCCESS;
|
||||
reset_internal_getopt ();
|
||||
while ((flag_name = internal_getopt (list, optflags)) != -1)
|
||||
{
|
||||
switch (flag_name)
|
||||
{
|
||||
case 'i': /* don't allow set -i */
|
||||
s[0] = list_opttype;
|
||||
s[1] = 'i';
|
||||
s[2] = '\0';
|
||||
sh_invalidopt (s);
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
CASE_HELPOPT;
|
||||
case '?':
|
||||
builtin_usage ();
|
||||
return (list_optopt == '?' ? EXECUTION_SUCCESS : EX_USAGE);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do the set command. While the list consists of words starting with
|
||||
'-' or '+' treat them as flags, otherwise, start assigning them to
|
||||
$1 ... $n. */
|
||||
for (force_assignment = opts_changed = 0; list; )
|
||||
{
|
||||
arg = list->word->word;
|
||||
|
||||
/* If the argument is `--' or `-' then signal the end of the list
|
||||
and remember the remaining arguments. */
|
||||
if (arg[0] == '-' && (!arg[1] || (arg[1] == '-' && !arg[2])))
|
||||
{
|
||||
list = list->next;
|
||||
|
||||
/* `set --' unsets the positional parameters. */
|
||||
if (arg[1] == '-')
|
||||
force_assignment = 1;
|
||||
|
||||
/* Until told differently, the old shell behaviour of
|
||||
`set - [arg ...]' being equivalent to `set +xv [arg ...]'
|
||||
stands. Posix.2 says the behaviour is marked as obsolescent. */
|
||||
else
|
||||
{
|
||||
change_flag ('x', '+');
|
||||
change_flag ('v', '+');
|
||||
opts_changed = 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ((on_or_off = *arg) && (on_or_off == '-' || on_or_off == '+'))
|
||||
{
|
||||
while (flag_name = *++arg)
|
||||
{
|
||||
if (flag_name == '?')
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
else if (flag_name == 'o') /* -+o option-name */
|
||||
{
|
||||
char *option_name;
|
||||
WORD_LIST *opt;
|
||||
|
||||
opt = list->next;
|
||||
|
||||
if (opt == 0)
|
||||
{
|
||||
list_minus_o_opts (-1, (on_or_off == '+'));
|
||||
rv = sh_chkwrite (rv);
|
||||
continue;
|
||||
}
|
||||
|
||||
option_name = opt->word->word;
|
||||
|
||||
if (option_name == 0 || *option_name == '\0' ||
|
||||
*option_name == '-' || *option_name == '+')
|
||||
{
|
||||
list_minus_o_opts (-1, (on_or_off == '+'));
|
||||
continue;
|
||||
}
|
||||
list = list->next; /* Skip over option name. */
|
||||
|
||||
opts_changed = 1;
|
||||
if ((r = set_minus_o_option (on_or_off, option_name)) != EXECUTION_SUCCESS)
|
||||
{
|
||||
set_shellopts ();
|
||||
return (r);
|
||||
}
|
||||
}
|
||||
else if (change_flag (flag_name, on_or_off) == FLAG_ERROR)
|
||||
{
|
||||
s[0] = on_or_off;
|
||||
s[1] = flag_name;
|
||||
s[2] = '\0';
|
||||
sh_invalidopt (s);
|
||||
builtin_usage ();
|
||||
set_shellopts ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
opts_changed = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
/* Assigning $1 ... $n */
|
||||
if (list || force_assignment)
|
||||
remember_args (list, 1);
|
||||
/* Set up new value of $SHELLOPTS */
|
||||
if (opts_changed)
|
||||
set_shellopts ();
|
||||
return (rv);
|
||||
}
|
||||
|
||||
#line 830 "./set.def"
|
||||
|
||||
#define NEXT_VARIABLE() any_failed++; list = list->next; continue;
|
||||
|
||||
int
|
||||
unset_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int unset_function, unset_variable, unset_array, opt, nameref, any_failed;
|
||||
int global_unset_func, global_unset_var, vflags, base_vflags, valid_id;
|
||||
char *name, *tname;
|
||||
|
||||
unset_function = unset_variable = unset_array = nameref = any_failed = 0;
|
||||
global_unset_func = global_unset_var = 0;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "fnv")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'f':
|
||||
global_unset_func = 1;
|
||||
break;
|
||||
case 'v':
|
||||
global_unset_var = 1;
|
||||
break;
|
||||
case 'n':
|
||||
nameref = 1;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
if (global_unset_func && global_unset_var)
|
||||
{
|
||||
builtin_error (_("cannot simultaneously unset a function and a variable"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else if (unset_function && nameref)
|
||||
nameref = 0;
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
base_vflags = assoc_expand_once ? VA_NOEXPAND : 0;
|
||||
#endif
|
||||
|
||||
while (list)
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
int tem;
|
||||
#if defined (ARRAY_VARS)
|
||||
char *t;
|
||||
#endif
|
||||
|
||||
name = list->word->word;
|
||||
|
||||
unset_function = global_unset_func;
|
||||
unset_variable = global_unset_var;
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
vflags = builtin_arrayref_flags (list->word, base_vflags);
|
||||
#endif
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
unset_array = 0;
|
||||
/* XXX valid array reference second arg was 0 */
|
||||
if (!unset_function && nameref == 0 && tokenize_array_reference (name, vflags, &t))
|
||||
unset_array = 1;
|
||||
#endif
|
||||
/* Get error checking out of the way first. The low-level functions
|
||||
just perform the unset, relying on the caller to verify. */
|
||||
valid_id = legal_identifier (name);
|
||||
|
||||
/* Whether or not we are in posix mode, if neither -f nor -v appears,
|
||||
skip over trying to unset variables with invalid names and just
|
||||
treat them as potential shell function names. */
|
||||
if (global_unset_func == 0 && global_unset_var == 0 && valid_id == 0)
|
||||
{
|
||||
unset_variable = unset_array = 0;
|
||||
unset_function = 1;
|
||||
}
|
||||
|
||||
/* Bash allows functions with names which are not valid identifiers
|
||||
to be created when not in posix mode, so check only when in posix
|
||||
mode when unsetting a function. */
|
||||
if (unset_function == 0 && valid_id == 0)
|
||||
{
|
||||
sh_invalidid (name);
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* Search for functions here if -f supplied or if NAME cannot be a
|
||||
variable name. */
|
||||
var = unset_function ? find_function (name)
|
||||
: (nameref ? find_variable_last_nameref (name, 0) : find_variable (name));
|
||||
|
||||
/* Some variables (but not functions yet) cannot be unset, period. */
|
||||
if (var && unset_function == 0 && non_unsettable_p (var))
|
||||
{
|
||||
builtin_error (_("%s: cannot unset"), name);
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* if we have a nameref we want to use it */
|
||||
if (var && unset_function == 0 && nameref == 0 && STREQ (name, name_cell(var)) == 0)
|
||||
name = name_cell (var);
|
||||
|
||||
/* Posix.2 says try variables first, then functions. If we would
|
||||
find a function after unsuccessfully searching for a variable,
|
||||
note that we're acting on a function now as if -f were
|
||||
supplied. The readonly check below takes care of it. */
|
||||
if (var == 0 && nameref == 0 && unset_variable == 0 && unset_function == 0)
|
||||
{
|
||||
if (var = find_function (name))
|
||||
unset_function = 1;
|
||||
}
|
||||
|
||||
/* Posix.2 says that unsetting readonly variables is an error. */
|
||||
if (var && readonly_p (var))
|
||||
{
|
||||
builtin_error (_("%s: cannot unset: readonly %s"),
|
||||
var->name, unset_function ? "function" : "variable");
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* Unless the -f option is supplied, the name refers to a variable. */
|
||||
#if defined (ARRAY_VARS)
|
||||
if (var && unset_array)
|
||||
{
|
||||
if (shell_compatibility_level <= 51)
|
||||
vflags |= VA_ALLOWALL;
|
||||
|
||||
/* Let unbind_array_element decide what to do with non-array vars */
|
||||
tem = unbind_array_element (var, t, vflags); /* XXX new third arg */
|
||||
if (tem == -2 && array_p (var) == 0 && assoc_p (var) == 0)
|
||||
{
|
||||
builtin_error (_("%s: not an array variable"), var->name);
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
else if (tem < 0)
|
||||
any_failed++;
|
||||
}
|
||||
else
|
||||
#endif /* ARRAY_VARS */
|
||||
/* If we're trying to unset a nameref variable whose value isn't a set
|
||||
variable, make sure we still try to unset the nameref's value */
|
||||
if (var == 0 && nameref == 0 && unset_function == 0)
|
||||
{
|
||||
var = find_variable_last_nameref (name, 0);
|
||||
if (var && nameref_p (var))
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
if (valid_array_reference (nameref_cell (var), 0))
|
||||
{
|
||||
int len;
|
||||
|
||||
tname = savestring (nameref_cell (var));
|
||||
if (var = array_variable_part (tname, 0, &t, &len))
|
||||
{
|
||||
/* change to what unbind_array_element now expects */
|
||||
if (t[len - 1] == ']')
|
||||
t[len - 1] = 0;
|
||||
tem = unbind_array_element (var, t, vflags); /* XXX new third arg */
|
||||
}
|
||||
free (tname);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
tem = unbind_variable (nameref_cell (var));
|
||||
}
|
||||
else
|
||||
tem = unbind_variable (name);
|
||||
}
|
||||
else
|
||||
tem = unset_function ? unbind_func (name) : (nameref ? unbind_nameref (name) : unbind_variable (name));
|
||||
|
||||
/* This is what Posix.2 says: ``If neither -f nor -v
|
||||
is specified, the name refers to a variable; if a variable by
|
||||
that name does not exist, a function by that name, if any,
|
||||
shall be unset.'' */
|
||||
if (tem == -1 && nameref == 0 && unset_function == 0 && unset_variable == 0)
|
||||
tem = unbind_func (name);
|
||||
|
||||
name = list->word->word; /* reset above for namerefs */
|
||||
|
||||
/* SUSv3, POSIX.1-2001 say: ``Unsetting a variable or function that
|
||||
was not previously set shall not be considered an error.'' */
|
||||
|
||||
if (unset_function == 0)
|
||||
stupidly_hack_special_variables (name);
|
||||
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
|
||||
}
|
616
third_party/bash/builtins_setattr.c
vendored
Normal file
616
third_party/bash/builtins_setattr.c
vendored
Normal file
|
@ -0,0 +1,616 @@
|
|||
/* setattr.c, created from setattr.def. */
|
||||
#line 22 "./setattr.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "execute_cmd.h"
|
||||
#include "flags.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
extern sh_builtin_func_t *this_shell_builtin;
|
||||
|
||||
#ifdef ARRAY_VARS
|
||||
extern int declare_builtin PARAMS((WORD_LIST *));
|
||||
#endif
|
||||
|
||||
#define READONLY_OR_EXPORT \
|
||||
(this_shell_builtin == readonly_builtin || this_shell_builtin == export_builtin)
|
||||
|
||||
#line 69 "./setattr.def"
|
||||
|
||||
/* For each variable name in LIST, make that variable appear in the
|
||||
environment passed to simple commands. If there is no LIST, then
|
||||
print all such variables. An argument of `-n' says to remove the
|
||||
exported attribute from variables named in LIST. An argument of
|
||||
-f indicates that the names present in LIST refer to functions. */
|
||||
int
|
||||
export_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
return (set_or_show_attributes (list, att_exported, 0));
|
||||
}
|
||||
|
||||
#line 103 "./setattr.def"
|
||||
|
||||
/* For each variable name in LIST, make that variable readonly. Given an
|
||||
empty LIST, print out all existing readonly variables. */
|
||||
int
|
||||
readonly_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
return (set_or_show_attributes (list, att_readonly, 0));
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
# define ATTROPTS "aAfnp"
|
||||
#else
|
||||
# define ATTROPTS "fnp"
|
||||
#endif
|
||||
|
||||
/* For each variable name in LIST, make that variable have the specified
|
||||
ATTRIBUTE. An arg of `-n' says to remove the attribute from the the
|
||||
remaining names in LIST (doesn't work for readonly). */
|
||||
int
|
||||
set_or_show_attributes (list, attribute, nodefs)
|
||||
register WORD_LIST *list;
|
||||
int attribute, nodefs;
|
||||
{
|
||||
register SHELL_VAR *var;
|
||||
int assign, undo, any_failed, assign_error, opt;
|
||||
int functions_only, arrays_only, assoc_only;
|
||||
int aflags;
|
||||
char *name;
|
||||
#if defined (ARRAY_VARS)
|
||||
WORD_LIST *nlist, *tlist;
|
||||
WORD_DESC *w;
|
||||
char optw[8];
|
||||
int opti;
|
||||
#endif
|
||||
|
||||
functions_only = arrays_only = assoc_only = 0;
|
||||
undo = any_failed = assign_error = 0;
|
||||
/* Read arguments from the front of the list. */
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, ATTROPTS)) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'n':
|
||||
undo = 1;
|
||||
break;
|
||||
case 'f':
|
||||
functions_only = 1;
|
||||
break;
|
||||
#if defined (ARRAY_VARS)
|
||||
case 'a':
|
||||
arrays_only = 1;
|
||||
break;
|
||||
case 'A':
|
||||
assoc_only = 1;
|
||||
break;
|
||||
#endif
|
||||
case 'p':
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list)
|
||||
{
|
||||
if (attribute & att_exported)
|
||||
array_needs_making = 1;
|
||||
|
||||
/* Cannot undo readonly status, silently disallowed. */
|
||||
if (undo && (attribute & att_readonly))
|
||||
attribute &= ~att_readonly;
|
||||
|
||||
while (list)
|
||||
{
|
||||
name = list->word->word;
|
||||
|
||||
if (functions_only) /* xxx -f name */
|
||||
{
|
||||
var = find_function (name);
|
||||
if (var == 0)
|
||||
{
|
||||
builtin_error (_("%s: not a function"), name);
|
||||
any_failed++;
|
||||
}
|
||||
else if ((attribute & att_exported) && undo == 0 && exportable_function_name (name) == 0)
|
||||
{
|
||||
builtin_error (_("%s: cannot export"), name);
|
||||
any_failed++;
|
||||
}
|
||||
else
|
||||
SETVARATTR (var, attribute, undo);
|
||||
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* xxx [-np] name[=value] */
|
||||
assign = assignment (name, 0);
|
||||
|
||||
aflags = 0;
|
||||
if (assign)
|
||||
{
|
||||
name[assign] = '\0';
|
||||
if (name[assign - 1] == '+')
|
||||
{
|
||||
aflags |= ASS_APPEND;
|
||||
name[assign - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (legal_identifier (name) == 0)
|
||||
{
|
||||
sh_invalidid (name);
|
||||
if (assign)
|
||||
assign_error++;
|
||||
else
|
||||
any_failed++;
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (assign) /* xxx [-np] name=value */
|
||||
{
|
||||
name[assign] = '=';
|
||||
if (aflags & ASS_APPEND)
|
||||
name[assign - 1] = '+';
|
||||
#if defined (ARRAY_VARS)
|
||||
/* Let's try something here. Turn readonly -a xxx=yyy into
|
||||
declare -ra xxx=yyy and see what that gets us. */
|
||||
if (arrays_only || assoc_only)
|
||||
{
|
||||
tlist = list->next;
|
||||
list->next = (WORD_LIST *)NULL;
|
||||
/* Add -g to avoid readonly/export creating local variables:
|
||||
only local/declare/typeset create local variables */
|
||||
opti = 0;
|
||||
optw[opti++] = '-';
|
||||
optw[opti++] = 'g';
|
||||
if (attribute & att_readonly)
|
||||
optw[opti++] = 'r';
|
||||
if (attribute & att_exported)
|
||||
optw[opti++] = 'x';
|
||||
if (arrays_only)
|
||||
optw[opti++] = 'a';
|
||||
else
|
||||
optw[opti++] = 'A';
|
||||
optw[opti] = '\0';
|
||||
|
||||
w = make_word (optw);
|
||||
nlist = make_word_list (w, list);
|
||||
|
||||
opt = declare_builtin (nlist);
|
||||
if (opt != EXECUTION_SUCCESS)
|
||||
assign_error++;
|
||||
list->next = tlist;
|
||||
dispose_word (w);
|
||||
free (nlist);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
/* This word has already been expanded once with command
|
||||
and parameter expansion. Call do_assignment_no_expand (),
|
||||
which does not do command or parameter substitution. If
|
||||
the assignment is not performed correctly, flag an error. */
|
||||
if (do_assignment_no_expand (name) == 0)
|
||||
assign_error++;
|
||||
name[assign] = '\0';
|
||||
if (aflags & ASS_APPEND)
|
||||
name[assign - 1] = '\0';
|
||||
}
|
||||
|
||||
set_var_attribute (name, attribute, undo);
|
||||
if (assign) /* restore word */
|
||||
{
|
||||
name[assign] = '=';
|
||||
if (aflags & ASS_APPEND)
|
||||
name[assign-1] = '+';
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SHELL_VAR **variable_list;
|
||||
register int i;
|
||||
|
||||
if ((attribute & att_function) || functions_only)
|
||||
{
|
||||
variable_list = all_shell_functions ();
|
||||
if (attribute != att_function)
|
||||
attribute &= ~att_function; /* so declare -xf works, for example */
|
||||
}
|
||||
else
|
||||
variable_list = all_shell_variables ();
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if (attribute & att_array)
|
||||
{
|
||||
arrays_only++;
|
||||
if (attribute != att_array)
|
||||
attribute &= ~att_array;
|
||||
}
|
||||
else if (attribute & att_assoc)
|
||||
{
|
||||
assoc_only++;
|
||||
if (attribute != att_assoc)
|
||||
attribute &= ~att_assoc;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (variable_list)
|
||||
{
|
||||
for (i = 0; var = variable_list[i]; i++)
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
if (arrays_only && array_p (var) == 0)
|
||||
continue;
|
||||
else if (assoc_only && assoc_p (var) == 0)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
/* If we imported a variable that's not a valid identifier, don't
|
||||
show it in any lists. */
|
||||
if ((var->attributes & (att_invisible|att_imported)) == (att_invisible|att_imported))
|
||||
continue;
|
||||
|
||||
if ((var->attributes & attribute))
|
||||
{
|
||||
show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
|
||||
if (any_failed = sh_chkwrite (any_failed))
|
||||
break;
|
||||
}
|
||||
}
|
||||
free (variable_list);
|
||||
}
|
||||
}
|
||||
|
||||
return (assign_error ? EX_BADASSIGN
|
||||
: ((any_failed == 0) ? EXECUTION_SUCCESS
|
||||
: EXECUTION_FAILURE));
|
||||
}
|
||||
|
||||
/* Show all variable variables (v == 1) or functions (v == 0) with
|
||||
attributes. */
|
||||
int
|
||||
show_all_var_attributes (v, nodefs)
|
||||
int v, nodefs;
|
||||
{
|
||||
SHELL_VAR **variable_list, *var;
|
||||
int any_failed;
|
||||
register int i;
|
||||
|
||||
variable_list = v ? all_shell_variables () : all_shell_functions ();
|
||||
if (variable_list == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
for (i = any_failed = 0; var = variable_list[i]; i++)
|
||||
{
|
||||
/* There is no equivalent `declare -'. */
|
||||
if (variable_context && var->context == variable_context && STREQ (var->name, "-"))
|
||||
printf ("local -\n");
|
||||
else
|
||||
show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
|
||||
if (any_failed = sh_chkwrite (any_failed))
|
||||
break;
|
||||
}
|
||||
free (variable_list);
|
||||
return (any_failed == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* Show all local variable variables with their attributes. This shows unset
|
||||
local variables (all_local_variables called with 0 argument). */
|
||||
int
|
||||
show_local_var_attributes (v, nodefs)
|
||||
int v, nodefs;
|
||||
{
|
||||
SHELL_VAR **variable_list, *var;
|
||||
int any_failed;
|
||||
register int i;
|
||||
|
||||
variable_list = all_local_variables (0);
|
||||
if (variable_list == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
for (i = any_failed = 0; var = variable_list[i]; i++)
|
||||
{
|
||||
/* There is no equivalent `declare -'. */
|
||||
if (STREQ (var->name, "-"))
|
||||
printf ("local -\n");
|
||||
else
|
||||
show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
|
||||
if (any_failed = sh_chkwrite (any_failed))
|
||||
break;
|
||||
}
|
||||
free (variable_list);
|
||||
return (any_failed == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
int
|
||||
var_attribute_string (var, pattr, flags)
|
||||
SHELL_VAR *var;
|
||||
int pattr;
|
||||
char *flags; /* filled in with attributes */
|
||||
{
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
|
||||
/* pattr == 0 means we are called from `declare'. */
|
||||
if (pattr == 0 || posixly_correct == 0)
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
if (array_p (var))
|
||||
flags[i++] = 'a';
|
||||
|
||||
if (assoc_p (var))
|
||||
flags[i++] = 'A';
|
||||
#endif
|
||||
|
||||
if (function_p (var))
|
||||
flags[i++] = 'f';
|
||||
|
||||
if (integer_p (var))
|
||||
flags[i++] = 'i';
|
||||
|
||||
if (nameref_p (var))
|
||||
flags[i++] = 'n';
|
||||
|
||||
if (readonly_p (var))
|
||||
flags[i++] = 'r';
|
||||
|
||||
if (trace_p (var))
|
||||
flags[i++] = 't';
|
||||
|
||||
if (exported_p (var))
|
||||
flags[i++] = 'x';
|
||||
|
||||
if (capcase_p (var))
|
||||
flags[i++] = 'c';
|
||||
|
||||
if (lowercase_p (var))
|
||||
flags[i++] = 'l';
|
||||
|
||||
if (uppercase_p (var))
|
||||
flags[i++] = 'u';
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
if (array_p (var))
|
||||
flags[i++] = 'a';
|
||||
|
||||
if (assoc_p (var))
|
||||
flags[i++] = 'A';
|
||||
#endif
|
||||
|
||||
if (function_p (var))
|
||||
flags[i++] = 'f';
|
||||
}
|
||||
|
||||
flags[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Show the attributes for shell variable VAR. If NODEFS is non-zero,
|
||||
don't show function definitions along with the name. If PATTR is
|
||||
non-zero, it indicates we're being called from `export' or `readonly'.
|
||||
In POSIX mode, this prints the name of the calling builtin (`export'
|
||||
or `readonly') instead of `declare', and doesn't print function defs
|
||||
when called by `export' or `readonly'. */
|
||||
int
|
||||
show_var_attributes (var, pattr, nodefs)
|
||||
SHELL_VAR *var;
|
||||
int pattr, nodefs;
|
||||
{
|
||||
char flags[MAX_ATTRIBUTES], *x;
|
||||
int i;
|
||||
|
||||
i = var_attribute_string (var, pattr, flags);
|
||||
|
||||
/* If we're printing functions with definitions, print the function def
|
||||
first, then the attributes, instead of printing output that can't be
|
||||
reused as input to recreate the current state. */
|
||||
if (function_p (var) && nodefs == 0 && (pattr == 0 || posixly_correct == 0))
|
||||
{
|
||||
printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL));
|
||||
nodefs++;
|
||||
if (pattr == 0 && i == 1 && flags[0] == 'f')
|
||||
return 0; /* don't print `declare -f name' */
|
||||
}
|
||||
|
||||
if (pattr == 0 || posixly_correct == 0)
|
||||
printf ("declare -%s ", i ? flags : "-");
|
||||
else if (i)
|
||||
printf ("%s -%s ", this_command_name, flags);
|
||||
else
|
||||
printf ("%s ", this_command_name);
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if (invisible_p (var) && (array_p (var) || assoc_p (var)))
|
||||
printf ("%s\n", var->name);
|
||||
else if (array_p (var))
|
||||
print_array_assignment (var, 0);
|
||||
else if (assoc_p (var))
|
||||
print_assoc_assignment (var, 0);
|
||||
else
|
||||
#endif
|
||||
/* force `readonly' and `export' to not print out function definitions
|
||||
when in POSIX mode. */
|
||||
if (nodefs || (function_p (var) && pattr != 0 && posixly_correct))
|
||||
printf ("%s\n", var->name);
|
||||
else if (function_p (var))
|
||||
printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL));
|
||||
else if (invisible_p (var) || var_isset (var) == 0)
|
||||
printf ("%s\n", var->name);
|
||||
else
|
||||
{
|
||||
if (ansic_shouldquote (value_cell (var)))
|
||||
x = ansic_quote (value_cell (var), 0, (int *)0);
|
||||
else
|
||||
x = sh_double_quote (value_cell (var));
|
||||
printf ("%s=%s\n", var->name, x);
|
||||
free (x);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
show_name_attributes (name, nodefs)
|
||||
char *name;
|
||||
int nodefs;
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
|
||||
var = find_variable_noref (name);
|
||||
|
||||
if (var) /* show every variable with attributes, even unset ones */
|
||||
{
|
||||
show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
|
||||
return (0);
|
||||
}
|
||||
else
|
||||
return (1);
|
||||
}
|
||||
|
||||
int
|
||||
show_localname_attributes (name, nodefs)
|
||||
char *name;
|
||||
int nodefs;
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
|
||||
var = find_variable_noref (name);
|
||||
|
||||
if (var && local_p (var) && var->context == variable_context) /* show every variable with attributes, even unset ones */
|
||||
{
|
||||
show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
|
||||
return (0);
|
||||
}
|
||||
else
|
||||
return (1);
|
||||
}
|
||||
|
||||
int
|
||||
show_func_attributes (name, nodefs)
|
||||
char *name;
|
||||
int nodefs;
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
|
||||
var = find_function (name);
|
||||
|
||||
if (var)
|
||||
{
|
||||
show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
|
||||
return (0);
|
||||
}
|
||||
else
|
||||
return (1);
|
||||
}
|
||||
|
||||
void
|
||||
set_var_attribute (name, attribute, undo)
|
||||
char *name;
|
||||
int attribute, undo;
|
||||
{
|
||||
SHELL_VAR *var, *tv, *v, *refvar;
|
||||
char *tvalue;
|
||||
|
||||
if (undo)
|
||||
var = find_variable (name);
|
||||
else
|
||||
{
|
||||
tv = find_tempenv_variable (name);
|
||||
/* XXX -- need to handle case where tv is a temp variable in a
|
||||
function-scope context, since function_env has been merged into
|
||||
the local variables table. */
|
||||
if (tv && tempvar_p (tv))
|
||||
{
|
||||
tvalue = var_isset (tv) ? savestring (value_cell (tv)) : savestring ("");
|
||||
|
||||
var = bind_variable (tv->name, tvalue, 0);
|
||||
if (var == 0)
|
||||
{
|
||||
free (tvalue);
|
||||
return; /* XXX - no error message here */
|
||||
}
|
||||
var->attributes |= tv->attributes & ~att_tempvar;
|
||||
/* This avoids an error message when propagating a read-only var
|
||||
later on. */
|
||||
if (posixly_correct || shell_compatibility_level <= 44)
|
||||
{
|
||||
if (var->context == 0 && (attribute & att_readonly))
|
||||
{
|
||||
/* Don't bother to set the `propagate to the global variables
|
||||
table' flag if we've just bound the variable in that
|
||||
table */
|
||||
v = find_global_variable (tv->name);
|
||||
if (v != var)
|
||||
VSETATTR (tv, att_propagate);
|
||||
}
|
||||
else
|
||||
VSETATTR (tv, att_propagate);
|
||||
if (var->context != 0)
|
||||
VSETATTR (var, att_propagate);
|
||||
}
|
||||
|
||||
SETVARATTR (tv, attribute, undo); /* XXX */
|
||||
|
||||
stupidly_hack_special_variables (tv->name);
|
||||
|
||||
free (tvalue);
|
||||
}
|
||||
else
|
||||
{
|
||||
var = find_variable_notempenv (name);
|
||||
if (var == 0)
|
||||
{
|
||||
/* We might have a nameref pointing to something that we can't
|
||||
resolve to a shell variable. If we do, skip it. We do a little
|
||||
checking just so we can print an error message. */
|
||||
refvar = find_variable_nameref_for_create (name, 0);
|
||||
if (refvar == INVALID_NAMEREF_VALUE)
|
||||
return;
|
||||
/* Otherwise we probably have a nameref pointing to a variable
|
||||
that hasn't been created yet. bind_variable will take care
|
||||
of that. */
|
||||
}
|
||||
if (var == 0)
|
||||
{
|
||||
var = bind_variable (name, (char *)NULL, 0);
|
||||
if (var)
|
||||
VSETATTR (var, att_invisible);
|
||||
}
|
||||
else if (var->context != 0)
|
||||
VSETATTR (var, att_propagate);
|
||||
}
|
||||
}
|
||||
|
||||
if (var)
|
||||
SETVARATTR (var, attribute, undo);
|
||||
|
||||
if (var && (exported_p (var) || (attribute & att_exported)))
|
||||
array_needs_making++; /* XXX */
|
||||
}
|
61
third_party/bash/builtins_shift.c
vendored
Normal file
61
third_party/bash/builtins_shift.c
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
/* shift.c, created from shift.def. */
|
||||
#line 22 "./shift.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
|
||||
#line 49 "./shift.def"
|
||||
|
||||
int print_shift_error;
|
||||
|
||||
/* Shift the arguments ``left''. Shift DOLLAR_VARS down then take one
|
||||
off of REST_OF_ARGS and place it into DOLLAR_VARS[9]. If LIST has
|
||||
anything in it, it is a number which says where to start the
|
||||
shifting. Return > 0 if `times' > $#, otherwise 0. */
|
||||
int
|
||||
shift_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
intmax_t times;
|
||||
int itimes, nargs;
|
||||
|
||||
CHECK_HELPOPT (list);
|
||||
|
||||
if (get_numeric_arg (list, 0, ×) == 0)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
if (times == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
else if (times < 0)
|
||||
{
|
||||
sh_erange (list ? list->word->word : NULL, _("shift count"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
nargs = number_of_args ();
|
||||
if (times > nargs)
|
||||
{
|
||||
if (print_shift_error)
|
||||
sh_erange (list ? list->word->word : NULL, _("shift count"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else if (times == nargs)
|
||||
clear_dollar_vars ();
|
||||
else
|
||||
shift_args (itimes = times);
|
||||
|
||||
invalidate_cached_quoted_dollar_at ();
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
900
third_party/bash/builtins_shopt.c
vendored
Normal file
900
third_party/bash/builtins_shopt.c
vendored
Normal file
|
@ -0,0 +1,900 @@
|
|||
/* shopt.c, created from shopt.def. */
|
||||
#line 22 "./shopt.def"
|
||||
|
||||
#line 43 "./shopt.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "version.h"
|
||||
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "flags.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#if defined (READLINE)
|
||||
# include "bashline.h"
|
||||
#endif
|
||||
|
||||
#if defined (HISTORY)
|
||||
# include "bashhist.h"
|
||||
#endif
|
||||
|
||||
#define UNSETOPT 0
|
||||
#define SETOPT 1
|
||||
|
||||
#define OPTFMT "%-15s\t%s\n"
|
||||
|
||||
extern int allow_null_glob_expansion, fail_glob_expansion, glob_dot_filenames;
|
||||
extern int cdable_vars, mail_warning, source_uses_path;
|
||||
extern int no_exit_on_failed_exec, print_shift_error;
|
||||
extern int check_hashed_filenames, promptvars;
|
||||
extern int cdspelling, expand_aliases;
|
||||
extern int extended_quote;
|
||||
extern int check_window_size;
|
||||
extern int glob_ignore_case, match_ignore_case;
|
||||
extern int hup_on_exit;
|
||||
extern int xpg_echo;
|
||||
extern int gnu_error_format;
|
||||
extern int check_jobs_at_exit;
|
||||
extern int autocd;
|
||||
extern int glob_star;
|
||||
extern int glob_asciirange;
|
||||
extern int glob_always_skip_dot_and_dotdot;
|
||||
extern int lastpipe_opt;
|
||||
extern int inherit_errexit;
|
||||
extern int localvar_inherit;
|
||||
extern int localvar_unset;
|
||||
extern int varassign_redir_autoclose;
|
||||
extern int singlequote_translations;
|
||||
extern int patsub_replacement;
|
||||
|
||||
#if defined (EXTENDED_GLOB)
|
||||
extern int extended_glob;
|
||||
#endif
|
||||
|
||||
#if defined (READLINE)
|
||||
extern int hist_verify, history_reediting, perform_hostname_completion;
|
||||
extern int no_empty_command_completion;
|
||||
extern int force_fignore;
|
||||
extern int dircomplete_spelling, dircomplete_expand;
|
||||
extern int complete_fullquote;
|
||||
|
||||
extern int enable_hostname_completion PARAMS((int));
|
||||
#endif
|
||||
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
extern int prog_completion_enabled;
|
||||
extern int progcomp_alias;
|
||||
#endif
|
||||
|
||||
#if defined (DEBUGGER)
|
||||
extern int debugging_mode;
|
||||
#endif
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
extern int assoc_expand_once;
|
||||
extern int array_expand_once;
|
||||
int expand_once_flag;
|
||||
#endif
|
||||
|
||||
#if defined (SYSLOG_HISTORY)
|
||||
extern int syslog_history;
|
||||
#endif
|
||||
|
||||
static void shopt_error PARAMS((char *));
|
||||
|
||||
static int set_shellopts_after_change PARAMS((char *, int));
|
||||
static int set_compatibility_level PARAMS((char *, int));
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
static int set_restricted_shell PARAMS((char *, int));
|
||||
#endif
|
||||
|
||||
#if defined (READLINE)
|
||||
static int shopt_enable_hostname_completion PARAMS((char *, int));
|
||||
static int shopt_set_complete_direxpand PARAMS((char *, int));
|
||||
#endif
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
static int set_assoc_expand PARAMS((char *, int));
|
||||
#endif
|
||||
|
||||
static int shopt_set_debug_mode PARAMS((char *, int));
|
||||
|
||||
static int shopt_login_shell;
|
||||
static int shopt_compat31;
|
||||
static int shopt_compat32;
|
||||
static int shopt_compat40;
|
||||
static int shopt_compat41;
|
||||
static int shopt_compat42;
|
||||
static int shopt_compat43;
|
||||
static int shopt_compat44;
|
||||
|
||||
typedef int shopt_set_func_t PARAMS((char *, int));
|
||||
|
||||
/* If you add a new variable name here, make sure to set the default value
|
||||
appropriately in reset_shopt_options. */
|
||||
|
||||
static struct {
|
||||
char *name;
|
||||
int *value;
|
||||
shopt_set_func_t *set_func;
|
||||
} shopt_vars[] = {
|
||||
{ "autocd", &autocd, (shopt_set_func_t *)NULL },
|
||||
#if defined (ARRAY_VARS)
|
||||
{ "assoc_expand_once", &expand_once_flag, set_assoc_expand },
|
||||
#endif
|
||||
{ "cdable_vars", &cdable_vars, (shopt_set_func_t *)NULL },
|
||||
{ "cdspell", &cdspelling, (shopt_set_func_t *)NULL },
|
||||
{ "checkhash", &check_hashed_filenames, (shopt_set_func_t *)NULL },
|
||||
#if defined (JOB_CONTROL)
|
||||
{ "checkjobs", &check_jobs_at_exit, (shopt_set_func_t *)NULL },
|
||||
#endif
|
||||
{ "checkwinsize", &check_window_size, (shopt_set_func_t *)NULL },
|
||||
#if defined (HISTORY)
|
||||
{ "cmdhist", &command_oriented_history, (shopt_set_func_t *)NULL },
|
||||
#endif
|
||||
{ "compat31", &shopt_compat31, set_compatibility_level },
|
||||
{ "compat32", &shopt_compat32, set_compatibility_level },
|
||||
{ "compat40", &shopt_compat40, set_compatibility_level },
|
||||
{ "compat41", &shopt_compat41, set_compatibility_level },
|
||||
{ "compat42", &shopt_compat42, set_compatibility_level },
|
||||
{ "compat43", &shopt_compat43, set_compatibility_level },
|
||||
{ "compat44", &shopt_compat44, set_compatibility_level },
|
||||
#if defined (READLINE)
|
||||
{ "complete_fullquote", &complete_fullquote, (shopt_set_func_t *)NULL},
|
||||
{ "direxpand", &dircomplete_expand, shopt_set_complete_direxpand },
|
||||
{ "dirspell", &dircomplete_spelling, (shopt_set_func_t *)NULL },
|
||||
#endif
|
||||
{ "dotglob", &glob_dot_filenames, (shopt_set_func_t *)NULL },
|
||||
{ "execfail", &no_exit_on_failed_exec, (shopt_set_func_t *)NULL },
|
||||
{ "expand_aliases", &expand_aliases, (shopt_set_func_t *)NULL },
|
||||
#if defined (DEBUGGER)
|
||||
{ "extdebug", &debugging_mode, shopt_set_debug_mode },
|
||||
#endif
|
||||
#if defined (EXTENDED_GLOB)
|
||||
{ "extglob", &extended_glob, (shopt_set_func_t *)NULL },
|
||||
#endif
|
||||
{ "extquote", &extended_quote, (shopt_set_func_t *)NULL },
|
||||
{ "failglob", &fail_glob_expansion, (shopt_set_func_t *)NULL },
|
||||
#if defined (READLINE)
|
||||
{ "force_fignore", &force_fignore, (shopt_set_func_t *)NULL },
|
||||
#endif
|
||||
{ "globasciiranges", &glob_asciirange, (shopt_set_func_t *)NULL },
|
||||
{ "globskipdots", &glob_always_skip_dot_and_dotdot, (shopt_set_func_t *)NULL },
|
||||
{ "globstar", &glob_star, (shopt_set_func_t *)NULL },
|
||||
{ "gnu_errfmt", &gnu_error_format, (shopt_set_func_t *)NULL },
|
||||
#if defined (HISTORY)
|
||||
{ "histappend", &force_append_history, (shopt_set_func_t *)NULL },
|
||||
#endif
|
||||
#if defined (READLINE)
|
||||
{ "histreedit", &history_reediting, (shopt_set_func_t *)NULL },
|
||||
{ "histverify", &hist_verify, (shopt_set_func_t *)NULL },
|
||||
{ "hostcomplete", &perform_hostname_completion, shopt_enable_hostname_completion },
|
||||
#endif
|
||||
{ "huponexit", &hup_on_exit, (shopt_set_func_t *)NULL },
|
||||
{ "inherit_errexit", &inherit_errexit, (shopt_set_func_t *)NULL },
|
||||
{ "interactive_comments", &interactive_comments, set_shellopts_after_change },
|
||||
{ "lastpipe", &lastpipe_opt, (shopt_set_func_t *)NULL },
|
||||
#if defined (HISTORY)
|
||||
{ "lithist", &literal_history, (shopt_set_func_t *)NULL },
|
||||
#endif
|
||||
{ "localvar_inherit", &localvar_inherit, (shopt_set_func_t *)NULL },
|
||||
{ "localvar_unset", &localvar_unset, (shopt_set_func_t *)NULL },
|
||||
{ "login_shell", &shopt_login_shell, set_login_shell },
|
||||
{ "mailwarn", &mail_warning, (shopt_set_func_t *)NULL },
|
||||
#if defined (READLINE)
|
||||
{ "no_empty_cmd_completion", &no_empty_command_completion, (shopt_set_func_t *)NULL },
|
||||
#endif
|
||||
{ "nocaseglob", &glob_ignore_case, (shopt_set_func_t *)NULL },
|
||||
{ "nocasematch", &match_ignore_case, (shopt_set_func_t *)NULL },
|
||||
{ "noexpand_translation", &singlequote_translations, (shopt_set_func_t *)NULL },
|
||||
{ "nullglob", &allow_null_glob_expansion, (shopt_set_func_t *)NULL },
|
||||
{ "patsub_replacement", &patsub_replacement, (shopt_set_func_t *)NULL },
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
{ "progcomp", &prog_completion_enabled, (shopt_set_func_t *)NULL },
|
||||
# if defined (ALIAS)
|
||||
{ "progcomp_alias", &progcomp_alias, (shopt_set_func_t *)NULL },
|
||||
# endif
|
||||
#endif
|
||||
{ "promptvars", &promptvars, (shopt_set_func_t *)NULL },
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
{ "restricted_shell", &restricted_shell, set_restricted_shell },
|
||||
#endif
|
||||
{ "shift_verbose", &print_shift_error, (shopt_set_func_t *)NULL },
|
||||
{ "sourcepath", &source_uses_path, (shopt_set_func_t *)NULL },
|
||||
#if defined (SYSLOG_HISTORY) && defined (SYSLOG_SHOPT)
|
||||
{ "syslog_history", &syslog_history, (shopt_set_func_t *)NULL },
|
||||
#endif
|
||||
{ "varredir_close", &varassign_redir_autoclose, (shopt_set_func_t *)NULL },
|
||||
{ "xpg_echo", &xpg_echo, (shopt_set_func_t *)NULL },
|
||||
{ (char *)0, (int *)0, (shopt_set_func_t *)NULL }
|
||||
};
|
||||
|
||||
#define N_SHOPT_OPTIONS (sizeof (shopt_vars) / sizeof (shopt_vars[0]))
|
||||
|
||||
#define GET_SHOPT_OPTION_VALUE(i) (*shopt_vars[i].value)
|
||||
|
||||
static const char * const on = "on";
|
||||
static const char * const off = "off";
|
||||
|
||||
static int find_shopt PARAMS((char *));
|
||||
static int toggle_shopts PARAMS((int, WORD_LIST *, int));
|
||||
static void print_shopt PARAMS((char *, int, int));
|
||||
static int list_shopts PARAMS((WORD_LIST *, int));
|
||||
static int list_some_shopts PARAMS((int, int));
|
||||
static int list_shopt_o_options PARAMS((WORD_LIST *, int));
|
||||
static int list_some_o_options PARAMS((int, int));
|
||||
static int set_shopt_o_options PARAMS((int, WORD_LIST *, int));
|
||||
|
||||
#define SFLAG 0x01
|
||||
#define UFLAG 0x02
|
||||
#define QFLAG 0x04
|
||||
#define OFLAG 0x08
|
||||
#define PFLAG 0x10
|
||||
|
||||
int
|
||||
shopt_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt, flags, rval;
|
||||
|
||||
flags = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "psuoq")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 's':
|
||||
flags |= SFLAG;
|
||||
break;
|
||||
case 'u':
|
||||
flags |= UFLAG;
|
||||
break;
|
||||
case 'q':
|
||||
flags |= QFLAG;
|
||||
break;
|
||||
case 'o':
|
||||
flags |= OFLAG;
|
||||
break;
|
||||
case 'p':
|
||||
flags |= PFLAG;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if ((flags & (SFLAG|UFLAG)) == (SFLAG|UFLAG))
|
||||
{
|
||||
builtin_error (_("cannot set and unset shell options simultaneously"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
rval = EXECUTION_SUCCESS;
|
||||
if ((flags & OFLAG) && ((flags & (SFLAG|UFLAG)) == 0)) /* shopt -o */
|
||||
rval = list_shopt_o_options (list, flags);
|
||||
else if (list && (flags & OFLAG)) /* shopt -so args */
|
||||
rval = set_shopt_o_options ((flags & SFLAG) ? FLAG_ON : FLAG_OFF, list, flags & QFLAG);
|
||||
else if (flags & OFLAG) /* shopt -so */
|
||||
rval = list_some_o_options ((flags & SFLAG) ? 1 : 0, flags);
|
||||
else if (list && (flags & (SFLAG|UFLAG))) /* shopt -su args */
|
||||
rval = toggle_shopts ((flags & SFLAG) ? SETOPT : UNSETOPT, list, flags & QFLAG);
|
||||
else if ((flags & (SFLAG|UFLAG)) == 0) /* shopt [args] */
|
||||
rval = list_shopts (list, flags);
|
||||
else /* shopt -su */
|
||||
rval = list_some_shopts ((flags & SFLAG) ? SETOPT : UNSETOPT, flags);
|
||||
return (rval);
|
||||
}
|
||||
|
||||
/* Reset the options managed by `shopt' to the values they would have at
|
||||
shell startup. Variables from shopt_vars. */
|
||||
void
|
||||
reset_shopt_options ()
|
||||
{
|
||||
autocd = cdable_vars = cdspelling = 0;
|
||||
check_hashed_filenames = CHECKHASH_DEFAULT;
|
||||
check_window_size = CHECKWINSIZE_DEFAULT;
|
||||
allow_null_glob_expansion = glob_dot_filenames = 0;
|
||||
no_exit_on_failed_exec = 0;
|
||||
expand_aliases = 0;
|
||||
extended_quote = 1;
|
||||
fail_glob_expansion = 0;
|
||||
glob_asciirange = GLOBASCII_DEFAULT;
|
||||
glob_star = 0;
|
||||
gnu_error_format = 0;
|
||||
hup_on_exit = 0;
|
||||
inherit_errexit = 0;
|
||||
interactive_comments = 1;
|
||||
lastpipe_opt = 0;
|
||||
localvar_inherit = localvar_unset = 0;
|
||||
mail_warning = 0;
|
||||
glob_ignore_case = match_ignore_case = 0;
|
||||
print_shift_error = 0;
|
||||
source_uses_path = promptvars = 1;
|
||||
varassign_redir_autoclose = 0;
|
||||
singlequote_translations = 0;
|
||||
patsub_replacement = 1;
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
check_jobs_at_exit = 0;
|
||||
#endif
|
||||
|
||||
#if defined (EXTENDED_GLOB)
|
||||
extended_glob = EXTGLOB_DEFAULT;
|
||||
#endif
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
expand_once_flag = assoc_expand_once = 0;
|
||||
#endif
|
||||
|
||||
#if defined (HISTORY)
|
||||
literal_history = 0;
|
||||
force_append_history = 0;
|
||||
command_oriented_history = 1;
|
||||
#endif
|
||||
|
||||
#if defined (SYSLOG_HISTORY)
|
||||
# if defined (SYSLOG_SHOPT)
|
||||
syslog_history = SYSLOG_SHOPT;
|
||||
# else
|
||||
syslog_history = 1;
|
||||
# endif /* SYSLOG_SHOPT */
|
||||
#endif
|
||||
|
||||
#if defined (READLINE)
|
||||
complete_fullquote = 1;
|
||||
force_fignore = 1;
|
||||
hist_verify = history_reediting = 0;
|
||||
perform_hostname_completion = 1;
|
||||
# if DIRCOMPLETE_EXPAND_DEFAULT
|
||||
dircomplete_expand = 1;
|
||||
# else
|
||||
dircomplete_expand = 0;
|
||||
#endif
|
||||
dircomplete_spelling = 0;
|
||||
no_empty_command_completion = 0;
|
||||
#endif
|
||||
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
prog_completion_enabled = 1;
|
||||
# if defined (ALIAS)
|
||||
progcomp_alias = 0;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined (DEFAULT_ECHO_TO_XPG) || defined (STRICT_POSIX)
|
||||
xpg_echo = 1;
|
||||
#else
|
||||
xpg_echo = 0;
|
||||
#endif /* DEFAULT_ECHO_TO_XPG */
|
||||
|
||||
shopt_login_shell = login_shell;
|
||||
}
|
||||
|
||||
static int
|
||||
find_shopt (name)
|
||||
char *name;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; shopt_vars[i].name; i++)
|
||||
if (STREQ (name, shopt_vars[i].name))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
shopt_error (s)
|
||||
char *s;
|
||||
{
|
||||
builtin_error (_("%s: invalid shell option name"), s);
|
||||
}
|
||||
|
||||
static int
|
||||
toggle_shopts (mode, list, quiet)
|
||||
int mode;
|
||||
WORD_LIST *list;
|
||||
int quiet;
|
||||
{
|
||||
WORD_LIST *l;
|
||||
int ind, rval;
|
||||
SHELL_VAR *v;
|
||||
|
||||
for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next)
|
||||
{
|
||||
ind = find_shopt (l->word->word);
|
||||
if (ind < 0)
|
||||
{
|
||||
shopt_error (l->word->word);
|
||||
rval = EXECUTION_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*shopt_vars[ind].value = mode; /* 1 for set, 0 for unset */
|
||||
if (shopt_vars[ind].set_func)
|
||||
(*shopt_vars[ind].set_func) (shopt_vars[ind].name, mode);
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't set $BASHOPTS here if it hasn't already been initialized */
|
||||
if (v = find_variable ("BASHOPTS"))
|
||||
set_bashopts ();
|
||||
return (rval);
|
||||
}
|
||||
|
||||
static void
|
||||
print_shopt (name, val, flags)
|
||||
char *name;
|
||||
int val, flags;
|
||||
{
|
||||
if (flags & PFLAG)
|
||||
printf ("shopt %s %s\n", val ? "-s" : "-u", name);
|
||||
else
|
||||
printf (OPTFMT, name, val ? on : off);
|
||||
}
|
||||
|
||||
/* List the values of all or any of the `shopt' options. Returns 0 if
|
||||
all were listed or all variables queried were on; 1 otherwise. */
|
||||
static int
|
||||
list_shopts (list, flags)
|
||||
WORD_LIST *list;
|
||||
int flags;
|
||||
{
|
||||
WORD_LIST *l;
|
||||
int i, val, rval;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
for (i = 0; shopt_vars[i].name; i++)
|
||||
{
|
||||
val = *shopt_vars[i].value;
|
||||
if ((flags & QFLAG) == 0)
|
||||
print_shopt (shopt_vars[i].name, val, flags);
|
||||
}
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next)
|
||||
{
|
||||
i = find_shopt (l->word->word);
|
||||
if (i < 0)
|
||||
{
|
||||
shopt_error (l->word->word);
|
||||
rval = EXECUTION_FAILURE;
|
||||
continue;
|
||||
}
|
||||
val = *shopt_vars[i].value;
|
||||
if (val == 0)
|
||||
rval = EXECUTION_FAILURE;
|
||||
if ((flags & QFLAG) == 0)
|
||||
print_shopt (l->word->word, val, flags);
|
||||
}
|
||||
|
||||
return (sh_chkwrite (rval));
|
||||
}
|
||||
|
||||
static int
|
||||
list_some_shopts (mode, flags)
|
||||
int mode, flags;
|
||||
{
|
||||
int val, i;
|
||||
|
||||
for (i = 0; shopt_vars[i].name; i++)
|
||||
{
|
||||
val = *shopt_vars[i].value;
|
||||
if (((flags & QFLAG) == 0) && mode == val)
|
||||
print_shopt (shopt_vars[i].name, val, flags);
|
||||
}
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
static int
|
||||
list_shopt_o_options (list, flags)
|
||||
WORD_LIST *list;
|
||||
int flags;
|
||||
{
|
||||
WORD_LIST *l;
|
||||
int val, rval;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
if ((flags & QFLAG) == 0)
|
||||
list_minus_o_opts (-1, (flags & PFLAG));
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next)
|
||||
{
|
||||
val = minus_o_option_value (l->word->word);
|
||||
if (val == -1)
|
||||
{
|
||||
sh_invalidoptname (l->word->word);
|
||||
rval = EXECUTION_FAILURE;
|
||||
continue;
|
||||
}
|
||||
if (val == 0)
|
||||
rval = EXECUTION_FAILURE;
|
||||
if ((flags & QFLAG) == 0)
|
||||
{
|
||||
if (flags & PFLAG)
|
||||
printf ("set %co %s\n", val ? '-' : '+', l->word->word);
|
||||
else
|
||||
printf (OPTFMT, l->word->word, val ? on : off);
|
||||
}
|
||||
}
|
||||
return (sh_chkwrite (rval));
|
||||
}
|
||||
|
||||
static int
|
||||
list_some_o_options (mode, flags)
|
||||
int mode, flags;
|
||||
{
|
||||
if ((flags & QFLAG) == 0)
|
||||
list_minus_o_opts (mode, (flags & PFLAG));
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
static int
|
||||
set_shopt_o_options (mode, list, quiet)
|
||||
int mode;
|
||||
WORD_LIST *list;
|
||||
int quiet;
|
||||
{
|
||||
WORD_LIST *l;
|
||||
int rval;
|
||||
|
||||
for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next)
|
||||
{
|
||||
if (set_minus_o_option (mode, l->word->word) == EXECUTION_FAILURE)
|
||||
rval = EXECUTION_FAILURE;
|
||||
}
|
||||
set_shellopts ();
|
||||
return rval;
|
||||
}
|
||||
|
||||
/* If we set or unset interactive_comments with shopt, make sure the
|
||||
change is reflected in $SHELLOPTS. */
|
||||
static int
|
||||
set_shellopts_after_change (option_name, mode)
|
||||
char *option_name;
|
||||
int mode;
|
||||
{
|
||||
set_shellopts ();
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
shopt_set_debug_mode (option_name, mode)
|
||||
char *option_name;
|
||||
int mode;
|
||||
{
|
||||
#if defined (DEBUGGER)
|
||||
error_trace_mode = function_trace_mode = debugging_mode;
|
||||
set_shellopts ();
|
||||
if (debugging_mode)
|
||||
init_bash_argv ();
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
#if defined (READLINE)
|
||||
static int
|
||||
shopt_enable_hostname_completion (option_name, mode)
|
||||
char *option_name;
|
||||
int mode;
|
||||
{
|
||||
return (enable_hostname_completion (mode));
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
set_compatibility_level (option_name, mode)
|
||||
char *option_name;
|
||||
int mode;
|
||||
{
|
||||
int ind, oldval;
|
||||
char *rhs;
|
||||
|
||||
/* If we're unsetting one of the compatibility options, make sure the
|
||||
current value is in the range of the compatNN space. */
|
||||
if (mode == 0)
|
||||
oldval = shell_compatibility_level;
|
||||
|
||||
/* If we're setting something, redo some of the work we did above in
|
||||
toggle_shopt(). Unset everything and reset the appropriate option
|
||||
based on OPTION_NAME. */
|
||||
if (mode)
|
||||
{
|
||||
shopt_compat31 = shopt_compat32 = 0;
|
||||
shopt_compat40 = shopt_compat41 = shopt_compat42 = shopt_compat43 = 0;
|
||||
shopt_compat44 = 0;
|
||||
ind = find_shopt (option_name);
|
||||
*shopt_vars[ind].value = mode;
|
||||
}
|
||||
|
||||
/* Then set shell_compatibility_level based on what remains */
|
||||
if (shopt_compat31)
|
||||
shell_compatibility_level = 31;
|
||||
else if (shopt_compat32)
|
||||
shell_compatibility_level = 32;
|
||||
else if (shopt_compat40)
|
||||
shell_compatibility_level = 40;
|
||||
else if (shopt_compat41)
|
||||
shell_compatibility_level = 41;
|
||||
else if (shopt_compat42)
|
||||
shell_compatibility_level = 42;
|
||||
else if (shopt_compat43)
|
||||
shell_compatibility_level = 43;
|
||||
else if (shopt_compat44)
|
||||
shell_compatibility_level = 44;
|
||||
else if (oldval > 44 && shell_compatibility_level < DEFAULT_COMPAT_LEVEL)
|
||||
;
|
||||
else
|
||||
shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
|
||||
|
||||
/* Make sure the current compatibility level is reflected in BASH_COMPAT */
|
||||
rhs = itos (shell_compatibility_level);
|
||||
bind_variable ("BASH_COMPAT", rhs, 0);
|
||||
free (rhs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set and unset the various compatibility options from the value of
|
||||
shell_compatibility_level; used by sv_shcompat */
|
||||
void
|
||||
set_compatibility_opts ()
|
||||
{
|
||||
shopt_compat31 = shopt_compat32 = 0;
|
||||
shopt_compat40 = shopt_compat41 = shopt_compat42 = shopt_compat43 = 0;
|
||||
shopt_compat44 = 0;
|
||||
switch (shell_compatibility_level)
|
||||
{
|
||||
case DEFAULT_COMPAT_LEVEL:
|
||||
case 51: /* completeness */
|
||||
case 50:
|
||||
break;
|
||||
case 44:
|
||||
shopt_compat44 = 1; break;
|
||||
case 43:
|
||||
shopt_compat43 = 1; break;
|
||||
case 42:
|
||||
shopt_compat42 = 1; break;
|
||||
case 41:
|
||||
shopt_compat41 = 1; break;
|
||||
case 40:
|
||||
shopt_compat40 = 1; break;
|
||||
case 32:
|
||||
shopt_compat32 = 1; break;
|
||||
case 31:
|
||||
shopt_compat31 = 1; break;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined (READLINE)
|
||||
static int
|
||||
shopt_set_complete_direxpand (option_name, mode)
|
||||
char *option_name;
|
||||
int mode;
|
||||
{
|
||||
set_directory_hook ();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
/* Don't allow the value of restricted_shell to be modified. */
|
||||
|
||||
static int
|
||||
set_restricted_shell (option_name, mode)
|
||||
char *option_name;
|
||||
int mode;
|
||||
{
|
||||
static int save_restricted = -1;
|
||||
|
||||
if (save_restricted == -1)
|
||||
save_restricted = shell_is_restricted (shell_name);
|
||||
|
||||
restricted_shell = save_restricted;
|
||||
return (0);
|
||||
}
|
||||
#endif /* RESTRICTED_SHELL */
|
||||
|
||||
/* Not static so shell.c can call it to initialize shopt_login_shell */
|
||||
int
|
||||
set_login_shell (option_name, mode)
|
||||
char *option_name;
|
||||
int mode;
|
||||
{
|
||||
shopt_login_shell = login_shell != 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
char **
|
||||
get_shopt_options ()
|
||||
{
|
||||
char **ret;
|
||||
int n, i;
|
||||
|
||||
n = sizeof (shopt_vars) / sizeof (shopt_vars[0]);
|
||||
ret = strvec_create (n + 1);
|
||||
for (i = 0; shopt_vars[i].name; i++)
|
||||
ret[i] = savestring (shopt_vars[i].name);
|
||||
ret[i] = (char *)NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* External interface for other parts of the shell. NAME is a string option;
|
||||
* MODE is 0 if we want to unset an option; 1 if we want to set an option.
|
||||
* REUSABLE is 1 if we want to print output in a form that may be reused.
|
||||
*/
|
||||
int
|
||||
shopt_setopt (name, mode)
|
||||
char *name;
|
||||
int mode;
|
||||
{
|
||||
WORD_LIST *wl;
|
||||
int r;
|
||||
|
||||
wl = add_string_to_list (name, (WORD_LIST *)NULL);
|
||||
r = toggle_shopts (mode, wl, 0);
|
||||
dispose_words (wl);
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
shopt_listopt (name, reusable)
|
||||
char *name;
|
||||
int reusable;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (name == 0)
|
||||
return (list_shopts ((WORD_LIST *)NULL, reusable ? PFLAG : 0));
|
||||
|
||||
i = find_shopt (name);
|
||||
if (i < 0)
|
||||
{
|
||||
shopt_error (name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
print_shopt (name, *shopt_vars[i].value, reusable ? PFLAG : 0);
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
void
|
||||
set_bashopts ()
|
||||
{
|
||||
char *value;
|
||||
char tflag[N_SHOPT_OPTIONS];
|
||||
int vsize, i, vptr, *ip, exported;
|
||||
SHELL_VAR *v;
|
||||
|
||||
for (vsize = i = 0; shopt_vars[i].name; i++)
|
||||
{
|
||||
tflag[i] = 0;
|
||||
if (GET_SHOPT_OPTION_VALUE (i))
|
||||
{
|
||||
vsize += strlen (shopt_vars[i].name) + 1;
|
||||
tflag[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
value = (char *)xmalloc (vsize + 1);
|
||||
|
||||
for (i = vptr = 0; shopt_vars[i].name; i++)
|
||||
{
|
||||
if (tflag[i])
|
||||
{
|
||||
strcpy (value + vptr, shopt_vars[i].name);
|
||||
vptr += strlen (shopt_vars[i].name);
|
||||
value[vptr++] = ':';
|
||||
}
|
||||
}
|
||||
|
||||
if (vptr)
|
||||
vptr--; /* cut off trailing colon */
|
||||
value[vptr] = '\0';
|
||||
|
||||
v = find_variable ("BASHOPTS");
|
||||
|
||||
/* Turn off the read-only attribute so we can bind the new value, and
|
||||
note whether or not the variable was exported. */
|
||||
if (v)
|
||||
{
|
||||
VUNSETATTR (v, att_readonly);
|
||||
exported = exported_p (v);
|
||||
}
|
||||
else
|
||||
exported = 0;
|
||||
|
||||
v = bind_variable ("BASHOPTS", value, 0);
|
||||
|
||||
/* Turn the read-only attribute back on, and turn off the export attribute
|
||||
if it was set implicitly by mark_modified_vars and SHELLOPTS was not
|
||||
exported before we bound the new value. */
|
||||
VSETATTR (v, att_readonly);
|
||||
if (mark_modified_vars && exported == 0 && exported_p (v))
|
||||
VUNSETATTR (v, att_exported);
|
||||
|
||||
free (value);
|
||||
}
|
||||
|
||||
void
|
||||
parse_bashopts (value)
|
||||
char *value;
|
||||
{
|
||||
char *vname;
|
||||
int vptr, ind;
|
||||
|
||||
vptr = 0;
|
||||
while (vname = extract_colon_unit (value, &vptr))
|
||||
{
|
||||
ind = find_shopt (vname);
|
||||
if (ind >= 0)
|
||||
{
|
||||
*shopt_vars[ind].value = 1;
|
||||
if (shopt_vars[ind].set_func)
|
||||
(*shopt_vars[ind].set_func) (shopt_vars[ind].name, 1);
|
||||
}
|
||||
free (vname);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
initialize_bashopts (no_bashopts)
|
||||
int no_bashopts;
|
||||
{
|
||||
char *temp;
|
||||
SHELL_VAR *var;
|
||||
|
||||
if (no_bashopts == 0)
|
||||
{
|
||||
var = find_variable ("BASHOPTS");
|
||||
/* set up any shell options we may have inherited. */
|
||||
if (var && imported_p (var))
|
||||
{
|
||||
temp = (array_p (var) || assoc_p (var)) ? (char *)NULL : savestring (value_cell (var));
|
||||
if (temp)
|
||||
{
|
||||
parse_bashopts (temp);
|
||||
free (temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set up the $BASHOPTS variable. */
|
||||
set_bashopts ();
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
static int
|
||||
set_assoc_expand (option_name, mode)
|
||||
char *option_name;
|
||||
int mode;
|
||||
{
|
||||
#if 0 /* leave this disabled */
|
||||
if (shell_compatibility_level <= 51)
|
||||
#endif
|
||||
assoc_expand_once = expand_once_flag;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
154
third_party/bash/builtins_source.c
vendored
Normal file
154
third_party/bash/builtins_source.c
vendored
Normal file
|
@ -0,0 +1,154 @@
|
|||
/* source.c, created from source.def. */
|
||||
#line 22 "./source.def"
|
||||
|
||||
#line 37 "./source.def"
|
||||
|
||||
#line 53 "./source.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "bashtypes.h"
|
||||
#include "posixstat.h"
|
||||
#include "filecntl.h"
|
||||
#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
|
||||
# include <sys/file.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "execute_cmd.h"
|
||||
#include "flags.h"
|
||||
#include "findcmd.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "trap.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
static void maybe_pop_dollar_vars PARAMS((void));
|
||||
|
||||
/* If non-zero, `.' uses $PATH to look up the script to be sourced. */
|
||||
int source_uses_path = 1;
|
||||
|
||||
/* If non-zero, `.' looks in the current directory if the filename argument
|
||||
is not found in the $PATH. */
|
||||
int source_searches_cwd = 1;
|
||||
|
||||
/* If this . script is supplied arguments, we save the dollar vars and
|
||||
replace them with the script arguments for the duration of the script's
|
||||
execution. If the script does not change the dollar vars, we restore
|
||||
what we saved. If the dollar vars are changed in the script, and we are
|
||||
not executing a shell function, we leave the new values alone and free
|
||||
the saved values. */
|
||||
static void
|
||||
maybe_pop_dollar_vars ()
|
||||
{
|
||||
if (variable_context == 0 && (dollar_vars_changed () & ARGS_SETBLTIN))
|
||||
dispose_saved_dollar_vars ();
|
||||
else
|
||||
pop_dollar_vars ();
|
||||
if (debugging_mode)
|
||||
pop_args (); /* restore BASH_ARGC and BASH_ARGV */
|
||||
set_dollar_vars_unchanged ();
|
||||
invalidate_cached_quoted_dollar_at (); /* just invalidate to be safe */
|
||||
}
|
||||
|
||||
/* Read and execute commands from the file passed as argument. Guess what.
|
||||
This cannot be done in a subshell, since things like variable assignments
|
||||
take place in there. So, I open the file, place it into a large string,
|
||||
close the file, and then execute the string. */
|
||||
int
|
||||
source_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int result;
|
||||
char *filename, *debug_trap, *x;
|
||||
|
||||
if (no_options (list))
|
||||
return (EX_USAGE);
|
||||
list = loptend;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_error (_("filename argument required"));
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
if (restricted && strchr (list->word->word, '/'))
|
||||
{
|
||||
sh_restricted (list->word->word);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
filename = (char *)NULL;
|
||||
/* XXX -- should this be absolute_pathname? */
|
||||
if (posixly_correct && strchr (list->word->word, '/'))
|
||||
filename = savestring (list->word->word);
|
||||
else if (absolute_pathname (list->word->word))
|
||||
filename = savestring (list->word->word);
|
||||
else if (source_uses_path)
|
||||
filename = find_path_file (list->word->word);
|
||||
if (filename == 0)
|
||||
{
|
||||
if (source_searches_cwd == 0)
|
||||
{
|
||||
x = printable_filename (list->word->word, 0);
|
||||
builtin_error (_("%s: file not found"), x);
|
||||
if (x != list->word->word)
|
||||
free (x);
|
||||
if (posixly_correct && interactive_shell == 0 && executing_command_builtin == 0)
|
||||
{
|
||||
last_command_exit_value = EXECUTION_FAILURE;
|
||||
jump_to_top_level (EXITPROG);
|
||||
}
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
filename = savestring (list->word->word);
|
||||
}
|
||||
|
||||
begin_unwind_frame ("source");
|
||||
add_unwind_protect (xfree, filename);
|
||||
|
||||
if (list->next)
|
||||
{
|
||||
push_dollar_vars ();
|
||||
add_unwind_protect ((Function *)maybe_pop_dollar_vars, (char *)NULL);
|
||||
if (debugging_mode || shell_compatibility_level <= 44)
|
||||
init_bash_argv (); /* Initialize BASH_ARGV and BASH_ARGC */
|
||||
remember_args (list->next, 1);
|
||||
if (debugging_mode)
|
||||
push_args (list->next); /* Update BASH_ARGV and BASH_ARGC */
|
||||
}
|
||||
set_dollar_vars_unchanged ();
|
||||
|
||||
/* Don't inherit the DEBUG trap unless function_trace_mode (overloaded)
|
||||
is set. XXX - should sourced files inherit the RETURN trap? Functions
|
||||
don't. */
|
||||
debug_trap = TRAP_STRING (DEBUG_TRAP);
|
||||
if (debug_trap && function_trace_mode == 0)
|
||||
{
|
||||
debug_trap = savestring (debug_trap);
|
||||
add_unwind_protect (xfree, debug_trap);
|
||||
add_unwind_protect (maybe_set_debug_trap, debug_trap);
|
||||
restore_default_signal (DEBUG_TRAP);
|
||||
}
|
||||
|
||||
result = source_file (filename, (list && list->next));
|
||||
|
||||
run_unwind_frame ("source");
|
||||
|
||||
return (result);
|
||||
}
|
94
third_party/bash/builtins_suspend.c
vendored
Normal file
94
third_party/bash/builtins_suspend.c
vendored
Normal file
|
@ -0,0 +1,94 @@
|
|||
/* suspend.c, created from suspend.def. */
|
||||
#line 22 "./suspend.def"
|
||||
|
||||
#line 40 "./suspend.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashtypes.h"
|
||||
#include <signal.h>
|
||||
#include "bashintl.h"
|
||||
#include "shell.h"
|
||||
#include "jobs.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
static sighandler suspend_continue PARAMS((int));
|
||||
|
||||
static SigHandler *old_cont;
|
||||
#if 0
|
||||
static SigHandler *old_stop;
|
||||
#endif
|
||||
|
||||
/* Continue handler. */
|
||||
static sighandler
|
||||
suspend_continue (sig)
|
||||
int sig;
|
||||
{
|
||||
set_signal_handler (SIGCONT, old_cont);
|
||||
#if 0
|
||||
set_signal_handler (SIGSTOP, old_stop);
|
||||
#endif
|
||||
SIGRETURN (0);
|
||||
}
|
||||
|
||||
/* Suspending the shell. If -f is the arg, then do the suspend
|
||||
no matter what. Otherwise, complain if a login shell. */
|
||||
int
|
||||
suspend_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt, force;
|
||||
|
||||
reset_internal_getopt ();
|
||||
force = 0;
|
||||
while ((opt = internal_getopt (list, "f")) != -1)
|
||||
switch (opt)
|
||||
{
|
||||
case 'f':
|
||||
force++;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
no_args (list);
|
||||
|
||||
if (force == 0)
|
||||
{
|
||||
if (job_control == 0)
|
||||
{
|
||||
sh_nojobs (_("cannot suspend"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (login_shell)
|
||||
{
|
||||
builtin_error (_("cannot suspend a login shell"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX - should we put ourselves back into the original pgrp now? If so,
|
||||
call end_job_control() here and do the right thing in suspend_continue
|
||||
(that is, call restart_job_control()). */
|
||||
old_cont = (SigHandler *)set_signal_handler (SIGCONT, suspend_continue);
|
||||
#if 0
|
||||
old_stop = (SigHandler *)set_signal_handler (SIGSTOP, SIG_DFL);
|
||||
#endif
|
||||
killpg (shell_pgrp, SIGSTOP);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
#endif /* JOB_CONTROL */
|
52
third_party/bash/builtins_test.c
vendored
Normal file
52
third_party/bash/builtins_test.c
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
/* test.c, created from test.def. */
|
||||
#line 22 "./test.def"
|
||||
|
||||
#line 104 "./test.def"
|
||||
|
||||
#line 114 "./test.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "execute_cmd.h"
|
||||
#include "test.h"
|
||||
#include "common.h"
|
||||
|
||||
/* TEST/[ builtin. */
|
||||
int
|
||||
test_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char **argv;
|
||||
int argc, result;
|
||||
|
||||
/* We let Matthew Bradburn and Kevin Braunsdorf's code do the
|
||||
actual test command. So turn the list of args into an array
|
||||
of strings, since that is what their code wants. */
|
||||
if (list == 0)
|
||||
{
|
||||
if (this_command_name[0] == '[' && !this_command_name[1])
|
||||
{
|
||||
builtin_error (_("missing `]'"));
|
||||
return (EX_BADUSAGE);
|
||||
}
|
||||
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
argv = make_builtin_argv (list, &argc);
|
||||
result = test_command (argc, argv);
|
||||
free ((char *)argv);
|
||||
|
||||
return (result);
|
||||
}
|
90
third_party/bash/builtins_times.c
vendored
Normal file
90
third_party/bash/builtins_times.c
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
/* times.c, created from times.def. */
|
||||
#line 22 "./times.def"
|
||||
|
||||
#line 34 "./times.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "bashtypes.h"
|
||||
#include "shell.h"
|
||||
|
||||
#include "posixtime.h"
|
||||
|
||||
#if defined (HAVE_SYS_TIMES_H)
|
||||
# include <sys/times.h>
|
||||
#endif /* HAVE_SYS_TIMES_H */
|
||||
|
||||
#if defined (HAVE_SYS_RESOURCE_H) && !defined (RLIMTYPE)
|
||||
# include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/* Print the totals for system and user time used. */
|
||||
int
|
||||
times_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
#if defined (HAVE_GETRUSAGE) && defined (HAVE_TIMEVAL) && defined (RUSAGE_SELF)
|
||||
struct rusage self, kids;
|
||||
|
||||
USE_VAR(list);
|
||||
|
||||
if (no_options (list))
|
||||
return (EX_USAGE);
|
||||
|
||||
getrusage (RUSAGE_SELF, &self);
|
||||
getrusage (RUSAGE_CHILDREN, &kids); /* terminated child processes */
|
||||
|
||||
print_timeval (stdout, &self.ru_utime);
|
||||
putchar (' ');
|
||||
print_timeval (stdout, &self.ru_stime);
|
||||
putchar ('\n');
|
||||
print_timeval (stdout, &kids.ru_utime);
|
||||
putchar (' ');
|
||||
print_timeval (stdout, &kids.ru_stime);
|
||||
putchar ('\n');
|
||||
|
||||
#else
|
||||
# if defined (HAVE_TIMES)
|
||||
/* This uses the POSIX.1/XPG5 times(2) interface, which fills in a
|
||||
`struct tms' with values of type clock_t. */
|
||||
struct tms t;
|
||||
|
||||
USE_VAR(list);
|
||||
|
||||
if (no_options (list))
|
||||
return (EX_USAGE);
|
||||
|
||||
times (&t);
|
||||
|
||||
print_clock_t (stdout, t.tms_utime);
|
||||
putchar (' ');
|
||||
print_clock_t (stdout, t.tms_stime);
|
||||
putchar ('\n');
|
||||
print_clock_t (stdout, t.tms_cutime);
|
||||
putchar (' ');
|
||||
print_clock_t (stdout, t.tms_cstime);
|
||||
putchar ('\n');
|
||||
|
||||
# else /* !HAVE_TIMES */
|
||||
|
||||
USE_VAR(list);
|
||||
|
||||
if (no_options (list))
|
||||
return (EX_USAGE);
|
||||
printf ("0.00 0.00\n0.00 0.00\n");
|
||||
|
||||
# endif /* HAVE_TIMES */
|
||||
#endif /* !HAVE_TIMES */
|
||||
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
263
third_party/bash/builtins_trap.c
vendored
Normal file
263
third_party/bash/builtins_trap.c
vendored
Normal file
|
@ -0,0 +1,263 @@
|
|||
/* trap.c, created from trap.def. */
|
||||
#line 22 "./trap.def"
|
||||
|
||||
#line 58 "./trap.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashtypes.h"
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include "bashansi.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "trap.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
static void showtrap PARAMS((int, int));
|
||||
static int display_traps PARAMS((WORD_LIST *, int));
|
||||
|
||||
/* The trap command:
|
||||
|
||||
trap <arg> <signal ...>
|
||||
trap <signal ...>
|
||||
trap -l
|
||||
trap -p [sigspec ...]
|
||||
trap [--]
|
||||
|
||||
Set things up so that ARG is executed when SIGNAL(s) N is received.
|
||||
If ARG is the empty string, then ignore the SIGNAL(s). If there is
|
||||
no ARG, then set the trap for SIGNAL(s) to its original value. Just
|
||||
plain "trap" means to print out the list of commands associated with
|
||||
each signal number. Single arg of "-l" means list the signal names. */
|
||||
|
||||
/* Possible operations to perform on the list of signals.*/
|
||||
#define SET 0 /* Set this signal to first_arg. */
|
||||
#define REVERT 1 /* Revert to this signals original value. */
|
||||
#define IGNORE 2 /* Ignore this signal. */
|
||||
|
||||
int
|
||||
trap_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int list_signal_names, display, result, opt;
|
||||
|
||||
list_signal_names = display = 0;
|
||||
result = EXECUTION_SUCCESS;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "lp")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'l':
|
||||
list_signal_names++;
|
||||
break;
|
||||
case 'p':
|
||||
display++;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
opt = DSIG_NOCASE|DSIG_SIGPREFIX; /* flags for decode_signal */
|
||||
|
||||
if (list_signal_names)
|
||||
return (sh_chkwrite (display_signal_list ((WORD_LIST *)NULL, 1)));
|
||||
else if (display || list == 0)
|
||||
{
|
||||
initialize_terminating_signals ();
|
||||
get_all_original_signals ();
|
||||
return (sh_chkwrite (display_traps (list, display && posixly_correct)));
|
||||
}
|
||||
else
|
||||
{
|
||||
char *first_arg;
|
||||
int operation, sig, first_signal;
|
||||
|
||||
operation = SET;
|
||||
first_arg = list->word->word;
|
||||
first_signal = first_arg && *first_arg && all_digits (first_arg) && signal_object_p (first_arg, opt);
|
||||
|
||||
/* Backwards compatibility. XXX - question about whether or not we
|
||||
should throw an error if an all-digit argument doesn't correspond
|
||||
to a valid signal number (e.g., if it's `50' on a system with only
|
||||
32 signals). */
|
||||
if (first_signal)
|
||||
operation = REVERT;
|
||||
/* When in posix mode, the historical behavior of looking for a
|
||||
missing first argument is disabled. To revert to the original
|
||||
signal handling disposition, use `-' as the first argument. */
|
||||
else if (posixly_correct == 0 && first_arg && *first_arg &&
|
||||
(*first_arg != '-' || first_arg[1]) &&
|
||||
signal_object_p (first_arg, opt) && list->next == 0)
|
||||
operation = REVERT;
|
||||
else
|
||||
{
|
||||
list = list->next;
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
else if (*first_arg == '\0')
|
||||
operation = IGNORE;
|
||||
else if (first_arg[0] == '-' && !first_arg[1])
|
||||
operation = REVERT;
|
||||
}
|
||||
|
||||
/* If we're in a command substitution, we haven't freed the trap strings
|
||||
(though we reset the signal handlers). If we're setting a trap to
|
||||
handle a signal here, free the rest of the trap strings since they
|
||||
don't apply any more. */
|
||||
if (subshell_environment & SUBSHELL_RESETTRAP)
|
||||
{
|
||||
free_trap_strings ();
|
||||
subshell_environment &= ~SUBSHELL_RESETTRAP;
|
||||
}
|
||||
|
||||
while (list)
|
||||
{
|
||||
sig = decode_signal (list->word->word, opt);
|
||||
|
||||
if (sig == NO_SIG)
|
||||
{
|
||||
sh_invalidsig (list->word->word);
|
||||
result = EXECUTION_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (operation)
|
||||
{
|
||||
case SET:
|
||||
set_signal (sig, first_arg);
|
||||
break;
|
||||
|
||||
case REVERT:
|
||||
restore_default_signal (sig);
|
||||
|
||||
/* Signals that the shell treats specially need special
|
||||
handling. */
|
||||
switch (sig)
|
||||
{
|
||||
case SIGINT:
|
||||
/* XXX - should we do this if original disposition
|
||||
was SIG_IGN? */
|
||||
if (interactive)
|
||||
set_signal_handler (SIGINT, sigint_sighandler);
|
||||
/* special cases for interactive == 0 */
|
||||
else if (interactive_shell && (sourcelevel||running_trap||parse_and_execute_level))
|
||||
set_signal_handler (SIGINT, sigint_sighandler);
|
||||
else
|
||||
set_signal_handler (SIGINT, termsig_sighandler);
|
||||
break;
|
||||
|
||||
case SIGQUIT:
|
||||
/* Always ignore SIGQUIT. */
|
||||
set_signal_handler (SIGQUIT, SIG_IGN);
|
||||
break;
|
||||
case SIGTERM:
|
||||
#if defined (JOB_CONTROL)
|
||||
case SIGTTIN:
|
||||
case SIGTTOU:
|
||||
case SIGTSTP:
|
||||
#endif /* JOB_CONTROL */
|
||||
if (interactive)
|
||||
set_signal_handler (sig, SIG_IGN);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case IGNORE:
|
||||
ignore_signal (sig);
|
||||
break;
|
||||
}
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static void
|
||||
showtrap (i, show_default)
|
||||
int i, show_default;
|
||||
{
|
||||
char *t, *p, *sn;
|
||||
int free_t;
|
||||
|
||||
free_t = 1;
|
||||
p = trap_list[i];
|
||||
if (p == (char *)DEFAULT_SIG && signal_is_hard_ignored (i) == 0)
|
||||
{
|
||||
if (show_default)
|
||||
t = "-";
|
||||
else
|
||||
return;
|
||||
free_t = 0;
|
||||
}
|
||||
else if (signal_is_hard_ignored (i))
|
||||
t = (char *)NULL;
|
||||
else
|
||||
t = (p == (char *)IGNORE_SIG) ? (char *)NULL : sh_single_quote (p);
|
||||
|
||||
sn = signal_name (i);
|
||||
/* Make sure that signals whose names are unknown (for whatever reason)
|
||||
are printed as signal numbers. */
|
||||
if (STREQN (sn, "SIGJUNK", 7) || STREQN (sn, "unknown", 7))
|
||||
printf ("trap -- %s %d\n", t ? t : "''", i);
|
||||
else if (posixly_correct)
|
||||
{
|
||||
if (STREQN (sn, "SIG", 3))
|
||||
printf ("trap -- %s %s\n", t ? t : "''", sn+3);
|
||||
else
|
||||
printf ("trap -- %s %s\n", t ? t : "''", sn);
|
||||
}
|
||||
else
|
||||
printf ("trap -- %s %s\n", t ? t : "''", sn);
|
||||
|
||||
if (free_t)
|
||||
FREE (t);
|
||||
}
|
||||
|
||||
static int
|
||||
display_traps (list, show_all)
|
||||
WORD_LIST *list;
|
||||
int show_all;
|
||||
{
|
||||
int result, i;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
for (i = 0; i < BASH_NSIG; i++)
|
||||
showtrap (i, show_all);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
for (result = EXECUTION_SUCCESS; list; list = list->next)
|
||||
{
|
||||
i = decode_signal (list->word->word, DSIG_NOCASE|DSIG_SIGPREFIX);
|
||||
if (i == NO_SIG)
|
||||
{
|
||||
sh_invalidsig (list->word->word);
|
||||
result = EXECUTION_FAILURE;
|
||||
}
|
||||
else
|
||||
showtrap (i, show_all);
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
373
third_party/bash/builtins_type.c
vendored
Normal file
373
third_party/bash/builtins_type.c
vendored
Normal file
|
@ -0,0 +1,373 @@
|
|||
/* type.c, created from type.def. */
|
||||
#line 22 "./type.def"
|
||||
|
||||
#line 52 "./type.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "bashtypes.h"
|
||||
#include "posixstat.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "parser.h"
|
||||
#include "execute_cmd.h"
|
||||
#include "findcmd.h"
|
||||
#include "hashcmd.h"
|
||||
|
||||
#if defined (ALIAS)
|
||||
#include "alias.h"
|
||||
#endif /* ALIAS */
|
||||
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
extern int find_reserved_word PARAMS((char *));
|
||||
|
||||
/* For each word in LIST, find out what the shell is going to do with
|
||||
it as a simple command. i.e., which file would this shell use to
|
||||
execve, or if it is a builtin command, or an alias. Possible flag
|
||||
arguments:
|
||||
-t Returns the "type" of the object, one of
|
||||
`alias', `keyword', `function', `builtin',
|
||||
or `file'.
|
||||
|
||||
-p Returns the pathname of the file if -type is
|
||||
a file.
|
||||
|
||||
-a Returns all occurrences of words, whether they
|
||||
be a filename in the path, alias, function,
|
||||
or builtin.
|
||||
|
||||
-f Suppress shell function lookup, like `command'.
|
||||
|
||||
-P Force a path search even in the presence of other
|
||||
definitions.
|
||||
|
||||
Order of evaluation:
|
||||
alias
|
||||
keyword
|
||||
function
|
||||
builtin
|
||||
file
|
||||
*/
|
||||
|
||||
int
|
||||
type_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int dflags, any_failed, opt;
|
||||
WORD_LIST *this;
|
||||
|
||||
if (list == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
dflags = CDESC_SHORTDESC; /* default */
|
||||
any_failed = 0;
|
||||
|
||||
/* Handle the obsolescent `-type', `-path', and `-all' by prescanning
|
||||
the arguments and converting those options to the form that
|
||||
internal_getopt recognizes. Converts `--type', `--path', and `--all'
|
||||
also. THIS SHOULD REALLY GO AWAY. */
|
||||
for (this = list; this && this->word->word[0] == '-'; this = this->next)
|
||||
{
|
||||
char *flag = &(this->word->word[1]);
|
||||
|
||||
if (STREQ (flag, "type") || STREQ (flag, "-type"))
|
||||
{
|
||||
this->word->word[1] = 't';
|
||||
this->word->word[2] = '\0';
|
||||
}
|
||||
else if (STREQ (flag, "path") || STREQ (flag, "-path"))
|
||||
{
|
||||
this->word->word[1] = 'p';
|
||||
this->word->word[2] = '\0';
|
||||
}
|
||||
else if (STREQ (flag, "all") || STREQ (flag, "-all"))
|
||||
{
|
||||
this->word->word[1] = 'a';
|
||||
this->word->word[2] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "afptP")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'a':
|
||||
dflags |= CDESC_ALL;
|
||||
break;
|
||||
case 'f':
|
||||
dflags |= CDESC_NOFUNCS;
|
||||
break;
|
||||
case 'p':
|
||||
dflags |= CDESC_PATH_ONLY;
|
||||
dflags &= ~(CDESC_TYPE|CDESC_SHORTDESC);
|
||||
break;
|
||||
case 't':
|
||||
dflags |= CDESC_TYPE;
|
||||
dflags &= ~(CDESC_PATH_ONLY|CDESC_SHORTDESC);
|
||||
break;
|
||||
case 'P': /* shorthand for type -ap */
|
||||
dflags |= (CDESC_PATH_ONLY|CDESC_FORCE_PATH);
|
||||
dflags &= ~(CDESC_TYPE|CDESC_SHORTDESC);
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
while (list)
|
||||
{
|
||||
int found;
|
||||
|
||||
found = describe_command (list->word->word, dflags);
|
||||
|
||||
if (!found && (dflags & (CDESC_PATH_ONLY|CDESC_TYPE)) == 0)
|
||||
sh_notfound (list->word->word);
|
||||
|
||||
any_failed += found == 0;
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
opt = (any_failed == 0) ? EXECUTION_SUCCESS : EXECUTION_FAILURE;
|
||||
return (sh_chkwrite (opt));
|
||||
}
|
||||
|
||||
/*
|
||||
* Describe COMMAND as required by the type and command builtins.
|
||||
*
|
||||
* Behavior is controlled by DFLAGS. Flag values are
|
||||
* CDESC_ALL print all descriptions of a command
|
||||
* CDESC_SHORTDESC print the description for type and command -V
|
||||
* CDESC_REUSABLE print in a format that may be reused as input
|
||||
* CDESC_TYPE print the type for type -t
|
||||
* CDESC_PATH_ONLY print the path for type -p
|
||||
* CDESC_FORCE_PATH force a path search for type -P
|
||||
* CDESC_NOFUNCS skip function lookup for type -f
|
||||
* CDESC_ABSPATH convert to absolute path, no ./ prefix
|
||||
* CDESC_STDPATH command -p standard path list
|
||||
*
|
||||
* CDESC_ALL says whether or not to look for all occurrences of COMMAND, or
|
||||
* return after finding it once.
|
||||
*/
|
||||
int
|
||||
describe_command (command, dflags)
|
||||
char *command;
|
||||
int dflags;
|
||||
{
|
||||
int found, i, found_file, f, all;
|
||||
char *full_path, *x, *pathlist;
|
||||
SHELL_VAR *func;
|
||||
#if defined (ALIAS)
|
||||
alias_t *alias;
|
||||
#endif
|
||||
|
||||
all = (dflags & CDESC_ALL) != 0;
|
||||
found = found_file = 0;
|
||||
full_path = (char *)NULL;
|
||||
|
||||
#if defined (ALIAS)
|
||||
/* Command is an alias? */
|
||||
if (((dflags & CDESC_FORCE_PATH) == 0) && expand_aliases && (alias = find_alias (command)))
|
||||
{
|
||||
if (dflags & CDESC_TYPE)
|
||||
puts ("alias");
|
||||
else if (dflags & CDESC_SHORTDESC)
|
||||
printf (_("%s is aliased to `%s'\n"), command, alias->value);
|
||||
else if (dflags & CDESC_REUSABLE)
|
||||
{
|
||||
x = sh_single_quote (alias->value);
|
||||
printf ("alias %s=%s\n", command, x);
|
||||
free (x);
|
||||
}
|
||||
|
||||
found = 1;
|
||||
|
||||
if (all == 0)
|
||||
return (1);
|
||||
}
|
||||
#endif /* ALIAS */
|
||||
|
||||
/* Command is a shell reserved word? */
|
||||
if (((dflags & CDESC_FORCE_PATH) == 0) && (i = find_reserved_word (command)) >= 0)
|
||||
{
|
||||
if (dflags & CDESC_TYPE)
|
||||
puts ("keyword");
|
||||
else if (dflags & CDESC_SHORTDESC)
|
||||
printf (_("%s is a shell keyword\n"), command);
|
||||
else if (dflags & CDESC_REUSABLE)
|
||||
printf ("%s\n", command);
|
||||
|
||||
found = 1;
|
||||
|
||||
if (all == 0)
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Command is a function? */
|
||||
if (((dflags & (CDESC_FORCE_PATH|CDESC_NOFUNCS)) == 0) && (func = find_function (command)))
|
||||
{
|
||||
if (dflags & CDESC_TYPE)
|
||||
puts ("function");
|
||||
else if (dflags & CDESC_SHORTDESC)
|
||||
{
|
||||
char *result;
|
||||
|
||||
printf (_("%s is a function\n"), command);
|
||||
|
||||
/* We're blowing away THE_PRINTED_COMMAND here... */
|
||||
|
||||
result = named_function_string (command, function_cell (func), FUNC_MULTILINE|FUNC_EXTERNAL);
|
||||
printf ("%s\n", result);
|
||||
}
|
||||
else if (dflags & CDESC_REUSABLE)
|
||||
printf ("%s\n", command);
|
||||
|
||||
found = 1;
|
||||
|
||||
if (all == 0)
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Command is a builtin? */
|
||||
if (((dflags & CDESC_FORCE_PATH) == 0) && find_shell_builtin (command))
|
||||
{
|
||||
if (dflags & CDESC_TYPE)
|
||||
puts ("builtin");
|
||||
else if (dflags & CDESC_SHORTDESC)
|
||||
{
|
||||
if (posixly_correct && find_special_builtin (command) != 0)
|
||||
printf (_("%s is a special shell builtin\n"), command);
|
||||
else
|
||||
printf (_("%s is a shell builtin\n"), command);
|
||||
}
|
||||
else if (dflags & CDESC_REUSABLE)
|
||||
printf ("%s\n", command);
|
||||
|
||||
found = 1;
|
||||
|
||||
if (all == 0)
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Command is a disk file? */
|
||||
/* If the command name given is already an absolute command, just
|
||||
check to see if it is executable. */
|
||||
if (absolute_program (command))
|
||||
{
|
||||
f = file_status (command);
|
||||
if (f & FS_EXECABLE)
|
||||
{
|
||||
if (dflags & CDESC_TYPE)
|
||||
puts ("file");
|
||||
else if (dflags & CDESC_SHORTDESC)
|
||||
printf (_("%s is %s\n"), command, command);
|
||||
else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
|
||||
printf ("%s\n", command);
|
||||
|
||||
/* There's no use looking in the hash table or in $PATH,
|
||||
because they're not consulted when an absolute program
|
||||
name is supplied. */
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the user isn't doing "-a", then we might care about
|
||||
whether the file is present in our hash table. */
|
||||
if (all == 0 || (dflags & CDESC_FORCE_PATH))
|
||||
{
|
||||
if (full_path = phash_search (command))
|
||||
{
|
||||
if (dflags & CDESC_TYPE)
|
||||
puts ("file");
|
||||
else if (dflags & CDESC_SHORTDESC)
|
||||
printf (_("%s is hashed (%s)\n"), command, full_path);
|
||||
else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
|
||||
printf ("%s\n", full_path);
|
||||
|
||||
free (full_path);
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now search through $PATH. */
|
||||
while (1)
|
||||
{
|
||||
if (dflags & CDESC_STDPATH) /* command -p, all cannot be non-zero */
|
||||
{
|
||||
pathlist = conf_standard_path ();
|
||||
full_path = find_in_path (command, pathlist, FS_EXEC_PREFERRED|FS_NODIRS);
|
||||
free (pathlist);
|
||||
/* Will only go through this once, since all == 0 if STDPATH set */
|
||||
}
|
||||
else if (all == 0)
|
||||
full_path = find_user_command (command);
|
||||
else
|
||||
full_path = user_command_matches (command, FS_EXEC_ONLY, found_file); /* XXX - should that be FS_EXEC_PREFERRED? */
|
||||
|
||||
if (full_path == 0)
|
||||
break;
|
||||
|
||||
/* If we found the command as itself by looking through $PATH, it
|
||||
probably doesn't exist. Check whether or not the command is an
|
||||
executable file. If it's not, don't report a match. This is
|
||||
the default posix mode behavior */
|
||||
if (STREQ (full_path, command) || posixly_correct)
|
||||
{
|
||||
f = file_status (full_path);
|
||||
if ((f & FS_EXECABLE) == 0)
|
||||
{
|
||||
free (full_path);
|
||||
full_path = (char *)NULL;
|
||||
if (all == 0)
|
||||
break;
|
||||
}
|
||||
else if (ABSPATH (full_path))
|
||||
; /* placeholder; don't need to do anything yet */
|
||||
else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY|CDESC_SHORTDESC))
|
||||
{
|
||||
f = MP_DOCWD | ((dflags & CDESC_ABSPATH) ? MP_RMDOT : 0);
|
||||
x = sh_makepath ((char *)NULL, full_path, f);
|
||||
free (full_path);
|
||||
full_path = x;
|
||||
}
|
||||
}
|
||||
/* If we require a full path and don't have one, make one */
|
||||
else if ((dflags & CDESC_ABSPATH) && ABSPATH (full_path) == 0)
|
||||
{
|
||||
x = sh_makepath ((char *)NULL, full_path, MP_DOCWD|MP_RMDOT);
|
||||
free (full_path);
|
||||
full_path = x;
|
||||
}
|
||||
|
||||
found_file++;
|
||||
found = 1;
|
||||
|
||||
if (dflags & CDESC_TYPE)
|
||||
puts ("file");
|
||||
else if (dflags & CDESC_SHORTDESC)
|
||||
printf (_("%s is %s\n"), command, full_path);
|
||||
else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
|
||||
printf ("%s\n", full_path);
|
||||
|
||||
free (full_path);
|
||||
full_path = (char *)NULL;
|
||||
|
||||
if (all == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return (found);
|
||||
}
|
741
third_party/bash/builtins_ulimit.c
vendored
Normal file
741
third_party/bash/builtins_ulimit.c
vendored
Normal file
|
@ -0,0 +1,741 @@
|
|||
/* ulimit.c, created from ulimit.def. */
|
||||
#line 22 "./ulimit.def"
|
||||
|
||||
#line 73 "./ulimit.def"
|
||||
|
||||
#if !defined (_MINIX)
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "bashtypes.h"
|
||||
#if defined (HAVE_SYS_PARAM_H)
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "pipesize.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
/* For some reason, HPUX chose to make these definitions visible only if
|
||||
_KERNEL is defined, so we define _KERNEL before including <sys/resource.h>
|
||||
and #undef it afterward. */
|
||||
#if defined (HAVE_RESOURCE)
|
||||
# include <sys/time.h>
|
||||
# if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL)
|
||||
# define _KERNEL
|
||||
# endif
|
||||
# include <sys/resource.h>
|
||||
# if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL)
|
||||
# undef _KERNEL
|
||||
# endif
|
||||
#elif defined (HAVE_SYS_TIMES_H)
|
||||
# include <sys/times.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_LIMITS_H)
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
/* Check for the most basic symbols. If they aren't present, this
|
||||
system's <sys/resource.h> isn't very useful to us. */
|
||||
#if !defined (RLIMIT_FSIZE) || !defined (HAVE_GETRLIMIT)
|
||||
# undef HAVE_RESOURCE
|
||||
#endif
|
||||
|
||||
#if !defined (HAVE_RESOURCE) && defined (HAVE_ULIMIT_H)
|
||||
# include <ulimit.h>
|
||||
#endif
|
||||
|
||||
#if !defined (RLIMTYPE)
|
||||
# define RLIMTYPE long
|
||||
# define string_to_rlimtype(s) strtol(s, (char **)NULL, 10)
|
||||
# define print_rlimtype(num, nl) printf ("%ld%s", num, nl ? "\n" : "")
|
||||
#endif
|
||||
|
||||
/* Alternate names */
|
||||
|
||||
/* Some systems use RLIMIT_NOFILE, others use RLIMIT_OFILE */
|
||||
#if defined (HAVE_RESOURCE) && defined (RLIMIT_OFILE) && !defined (RLIMIT_NOFILE)
|
||||
# define RLIMIT_NOFILE RLIMIT_OFILE
|
||||
#endif /* HAVE_RESOURCE && RLIMIT_OFILE && !RLIMIT_NOFILE */
|
||||
|
||||
#if defined (HAVE_RESOURCE) && defined (RLIMIT_POSIXLOCKS) && !defined (RLIMIT_LOCKS)
|
||||
# define RLIMIT_LOCKS RLIMIT_POSIXLOCKS
|
||||
#endif /* HAVE_RESOURCE && RLIMIT_POSIXLOCKS && !RLIMIT_LOCKS */
|
||||
|
||||
/* Some systems have these, some do not. */
|
||||
#ifdef RLIMIT_FSIZE
|
||||
# define RLIMIT_FILESIZE RLIMIT_FSIZE
|
||||
#else
|
||||
# define RLIMIT_FILESIZE 256
|
||||
#endif
|
||||
|
||||
#define RLIMIT_PIPESIZE 257
|
||||
|
||||
#ifdef RLIMIT_NOFILE
|
||||
# define RLIMIT_OPENFILES RLIMIT_NOFILE
|
||||
#else
|
||||
# define RLIMIT_OPENFILES 258
|
||||
#endif
|
||||
|
||||
#ifdef RLIMIT_VMEM
|
||||
# define RLIMIT_VIRTMEM RLIMIT_VMEM
|
||||
# define RLIMIT_VMBLKSZ 1024
|
||||
#else
|
||||
# ifdef RLIMIT_AS
|
||||
# define RLIMIT_VIRTMEM RLIMIT_AS
|
||||
# define RLIMIT_VMBLKSZ 1024
|
||||
# else
|
||||
# define RLIMIT_VIRTMEM 259
|
||||
# define RLIMIT_VMBLKSZ 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef RLIMIT_NPROC
|
||||
# define RLIMIT_MAXUPROC RLIMIT_NPROC
|
||||
#else
|
||||
# define RLIMIT_MAXUPROC 260
|
||||
#endif
|
||||
|
||||
#if !defined (RLIMIT_PTHREAD) && defined (RLIMIT_NTHR)
|
||||
# define RLIMIT_PTHREAD RLIMIT_NTHR
|
||||
#endif
|
||||
|
||||
#if !defined (RLIM_INFINITY)
|
||||
# define RLIM_INFINITY 0x7fffffff
|
||||
#endif
|
||||
|
||||
#if !defined (RLIM_SAVED_CUR)
|
||||
# define RLIM_SAVED_CUR RLIM_INFINITY
|
||||
#endif
|
||||
|
||||
#if !defined (RLIM_SAVED_MAX)
|
||||
# define RLIM_SAVED_MAX RLIM_INFINITY
|
||||
#endif
|
||||
|
||||
#define LIMIT_HARD 0x01
|
||||
#define LIMIT_SOFT 0x02
|
||||
|
||||
/* "Blocks" are defined as 512 bytes when in Posix mode and 1024 bytes
|
||||
otherwise. */
|
||||
#define POSIXBLK -2
|
||||
|
||||
#define BLOCKSIZE(x) (((x) == POSIXBLK) ? (posixly_correct ? 512 : 1024) : (x))
|
||||
|
||||
static int _findlim PARAMS((int));
|
||||
|
||||
static int ulimit_internal PARAMS((int, char *, int, int));
|
||||
|
||||
static int get_limit PARAMS((int, RLIMTYPE *, RLIMTYPE *));
|
||||
static int set_limit PARAMS((int, RLIMTYPE, int));
|
||||
|
||||
static void printone PARAMS((int, RLIMTYPE, int));
|
||||
static void print_all_limits PARAMS((int));
|
||||
|
||||
static int set_all_limits PARAMS((int, RLIMTYPE));
|
||||
|
||||
static int filesize PARAMS((RLIMTYPE *));
|
||||
static int pipesize PARAMS((RLIMTYPE *));
|
||||
static int getmaxuprc PARAMS((RLIMTYPE *));
|
||||
static int getmaxvm PARAMS((RLIMTYPE *, RLIMTYPE *));
|
||||
|
||||
typedef struct {
|
||||
int option; /* The ulimit option for this limit. */
|
||||
int parameter; /* Parameter to pass to get_limit (). */
|
||||
int block_factor; /* Blocking factor for specific limit. */
|
||||
const char * const description; /* Descriptive string to output. */
|
||||
const char * const units; /* scale */
|
||||
} RESOURCE_LIMITS;
|
||||
|
||||
static RESOURCE_LIMITS limits[] = {
|
||||
#ifdef RLIMIT_NPTS
|
||||
{ 'P', RLIMIT_NPTS, 1, "number of pseudoterminals", (char *)NULL },
|
||||
#endif
|
||||
#ifdef RLIMIT_RTTIME
|
||||
{ 'R', RLIMIT_RTTIME, 1, "real-time non-blocking time", "microseconds" },
|
||||
#endif
|
||||
#ifdef RLIMIT_PTHREAD
|
||||
{ 'T', RLIMIT_PTHREAD, 1, "number of threads", (char *)NULL },
|
||||
#endif
|
||||
#ifdef RLIMIT_SBSIZE
|
||||
{ 'b', RLIMIT_SBSIZE, 1, "socket buffer size", "bytes" },
|
||||
#endif
|
||||
#ifdef RLIMIT_CORE
|
||||
{ 'c', RLIMIT_CORE, POSIXBLK, "core file size", "blocks" },
|
||||
#endif
|
||||
#ifdef RLIMIT_DATA
|
||||
{ 'd', RLIMIT_DATA, 1024, "data seg size", "kbytes" },
|
||||
#endif
|
||||
#ifdef RLIMIT_NICE
|
||||
{ 'e', RLIMIT_NICE, 1, "scheduling priority", (char *)NULL },
|
||||
#endif
|
||||
{ 'f', RLIMIT_FILESIZE, POSIXBLK, "file size", "blocks" },
|
||||
#ifdef RLIMIT_SIGPENDING
|
||||
{ 'i', RLIMIT_SIGPENDING, 1, "pending signals", (char *)NULL },
|
||||
#endif
|
||||
#ifdef RLIMIT_KQUEUES
|
||||
{ 'k', RLIMIT_KQUEUES, 1, "max kqueues", (char *)NULL },
|
||||
#endif
|
||||
#ifdef RLIMIT_MEMLOCK
|
||||
{ 'l', RLIMIT_MEMLOCK, 1024, "max locked memory", "kbytes" },
|
||||
#endif
|
||||
#ifdef RLIMIT_RSS
|
||||
{ 'm', RLIMIT_RSS, 1024, "max memory size", "kbytes" },
|
||||
#endif /* RLIMIT_RSS */
|
||||
{ 'n', RLIMIT_OPENFILES, 1, "open files", (char *)NULL},
|
||||
{ 'p', RLIMIT_PIPESIZE, 512, "pipe size", "512 bytes" },
|
||||
#ifdef RLIMIT_MSGQUEUE
|
||||
{ 'q', RLIMIT_MSGQUEUE, 1, "POSIX message queues", "bytes" },
|
||||
#endif
|
||||
#ifdef RLIMIT_RTPRIO
|
||||
{ 'r', RLIMIT_RTPRIO, 1, "real-time priority", (char *)NULL },
|
||||
#endif
|
||||
#ifdef RLIMIT_STACK
|
||||
{ 's', RLIMIT_STACK, 1024, "stack size", "kbytes" },
|
||||
#endif
|
||||
#ifdef RLIMIT_CPU
|
||||
{ 't', RLIMIT_CPU, 1, "cpu time", "seconds" },
|
||||
#endif /* RLIMIT_CPU */
|
||||
{ 'u', RLIMIT_MAXUPROC, 1, "max user processes", (char *)NULL },
|
||||
#if defined (HAVE_RESOURCE)
|
||||
{ 'v', RLIMIT_VIRTMEM, RLIMIT_VMBLKSZ, "virtual memory", "kbytes" },
|
||||
#endif
|
||||
#ifdef RLIMIT_SWAP
|
||||
{ 'w', RLIMIT_SWAP, 1024, "swap size", "kbytes" },
|
||||
#endif
|
||||
#ifdef RLIMIT_LOCKS
|
||||
{ 'x', RLIMIT_LOCKS, 1, "file locks", (char *)NULL },
|
||||
#endif
|
||||
{ -1, -1, -1, (char *)NULL, (char *)NULL }
|
||||
};
|
||||
#define NCMDS (sizeof(limits) / sizeof(limits[0]))
|
||||
|
||||
typedef struct _cmd {
|
||||
int cmd;
|
||||
char *arg;
|
||||
} ULCMD;
|
||||
|
||||
static ULCMD *cmdlist;
|
||||
static int ncmd;
|
||||
static int cmdlistsz;
|
||||
|
||||
#if !defined (HAVE_RESOURCE) && !defined (HAVE_ULIMIT)
|
||||
long
|
||||
ulimit (cmd, newlim)
|
||||
int cmd;
|
||||
long newlim;
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#endif /* !HAVE_RESOURCE && !HAVE_ULIMIT */
|
||||
|
||||
static int
|
||||
_findlim (opt)
|
||||
int opt;
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; limits[i].option > 0; i++)
|
||||
if (limits[i].option == opt)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char optstring[4 + 2 * NCMDS];
|
||||
|
||||
/* Report or set limits associated with certain per-process resources.
|
||||
See the help documentation in builtins.c for a full description. */
|
||||
int
|
||||
ulimit_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
register char *s;
|
||||
int c, limind, mode, opt, all_limits;
|
||||
|
||||
mode = 0;
|
||||
|
||||
all_limits = 0;
|
||||
|
||||
/* Idea stolen from pdksh -- build option string the first time called. */
|
||||
if (optstring[0] == 0)
|
||||
{
|
||||
s = optstring;
|
||||
*s++ = 'a'; *s++ = 'S'; *s++ = 'H';
|
||||
for (c = 0; limits[c].option > 0; c++)
|
||||
{
|
||||
*s++ = limits[c].option;
|
||||
*s++ = ';';
|
||||
}
|
||||
*s = '\0';
|
||||
}
|
||||
|
||||
/* Initialize the command list. */
|
||||
if (cmdlistsz == 0)
|
||||
cmdlist = (ULCMD *)xmalloc ((cmdlistsz = 16) * sizeof (ULCMD));
|
||||
ncmd = 0;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, optstring)) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'a':
|
||||
all_limits++;
|
||||
break;
|
||||
|
||||
/* -S and -H are modifiers, not real options. */
|
||||
case 'S':
|
||||
mode |= LIMIT_SOFT;
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
mode |= LIMIT_HARD;
|
||||
break;
|
||||
|
||||
CASE_HELPOPT;
|
||||
case '?':
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
|
||||
default:
|
||||
if (ncmd >= cmdlistsz)
|
||||
cmdlist = (ULCMD *)xrealloc (cmdlist, (cmdlistsz *= 2) * sizeof (ULCMD));
|
||||
cmdlist[ncmd].cmd = opt;
|
||||
cmdlist[ncmd++].arg = list_optarg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (all_limits)
|
||||
{
|
||||
#ifdef NOTYET
|
||||
if (list) /* setting */
|
||||
{
|
||||
if (STREQ (list->word->word, "unlimited") == 0)
|
||||
{
|
||||
builtin_error (_("%s: invalid limit argument"), list->word->word);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
return (set_all_limits (mode == 0 ? LIMIT_SOFT|LIMIT_HARD : mode, RLIM_INFINITY));
|
||||
}
|
||||
#endif
|
||||
print_all_limits (mode == 0 ? LIMIT_SOFT : mode);
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
/* default is `ulimit -f' */
|
||||
if (ncmd == 0)
|
||||
{
|
||||
cmdlist[ncmd].cmd = 'f';
|
||||
/* `ulimit something' is same as `ulimit -f something' */
|
||||
cmdlist[ncmd++].arg = list ? list->word->word : (char *)NULL;
|
||||
if (list)
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
/* verify each command in the list. */
|
||||
for (c = 0; c < ncmd; c++)
|
||||
{
|
||||
limind = _findlim (cmdlist[c].cmd);
|
||||
if (limind == -1)
|
||||
{
|
||||
builtin_error (_("`%c': bad command"), cmdlist[c].cmd);
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
/* POSIX compatibility. If the last item in cmdlist does not have an option
|
||||
argument, but there is an operand (list != 0), treat the operand as if
|
||||
it were an option argument for that last command. */
|
||||
if (list && list->word && cmdlist[ncmd - 1].arg == 0)
|
||||
{
|
||||
cmdlist[ncmd - 1].arg = list->word->word;
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
for (c = 0; c < ncmd; c++)
|
||||
if (ulimit_internal (cmdlist[c].cmd, cmdlist[c].arg, mode, ncmd > 1) == EXECUTION_FAILURE)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
static int
|
||||
ulimit_internal (cmd, cmdarg, mode, multiple)
|
||||
int cmd;
|
||||
char *cmdarg;
|
||||
int mode, multiple;
|
||||
{
|
||||
int opt, limind, setting;
|
||||
int block_factor;
|
||||
RLIMTYPE soft_limit, hard_limit, real_limit, limit;
|
||||
|
||||
setting = cmdarg != 0;
|
||||
limind = _findlim (cmd);
|
||||
if (mode == 0)
|
||||
mode = setting ? (LIMIT_HARD|LIMIT_SOFT) : LIMIT_SOFT;
|
||||
opt = get_limit (limind, &soft_limit, &hard_limit);
|
||||
if (opt < 0)
|
||||
{
|
||||
builtin_error (_("%s: cannot get limit: %s"), limits[limind].description,
|
||||
strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (setting == 0) /* print the value of the specified limit */
|
||||
{
|
||||
printone (limind, (mode & LIMIT_SOFT) ? soft_limit : hard_limit, multiple);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Setting the limit. */
|
||||
if (STREQ (cmdarg, "hard"))
|
||||
real_limit = hard_limit;
|
||||
else if (STREQ (cmdarg, "soft"))
|
||||
real_limit = soft_limit;
|
||||
else if (STREQ (cmdarg, "unlimited"))
|
||||
real_limit = RLIM_INFINITY;
|
||||
else if (all_digits (cmdarg))
|
||||
{
|
||||
limit = string_to_rlimtype (cmdarg);
|
||||
block_factor = BLOCKSIZE(limits[limind].block_factor);
|
||||
real_limit = limit * block_factor;
|
||||
|
||||
if ((real_limit / block_factor) != limit)
|
||||
{
|
||||
sh_erange (cmdarg, _("limit"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_invalidnum (cmdarg);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (set_limit (limind, real_limit, mode) < 0)
|
||||
{
|
||||
builtin_error (_("%s: cannot modify limit: %s"), limits[limind].description,
|
||||
strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
static int
|
||||
get_limit (ind, softlim, hardlim)
|
||||
int ind;
|
||||
RLIMTYPE *softlim, *hardlim;
|
||||
{
|
||||
RLIMTYPE value;
|
||||
#if defined (HAVE_RESOURCE)
|
||||
struct rlimit limit;
|
||||
#endif
|
||||
|
||||
if (limits[ind].parameter >= 256)
|
||||
{
|
||||
switch (limits[ind].parameter)
|
||||
{
|
||||
case RLIMIT_FILESIZE:
|
||||
if (filesize (&value) < 0)
|
||||
return -1;
|
||||
break;
|
||||
case RLIMIT_PIPESIZE:
|
||||
if (pipesize (&value) < 0)
|
||||
return -1;
|
||||
break;
|
||||
case RLIMIT_OPENFILES:
|
||||
value = (RLIMTYPE)getdtablesize ();
|
||||
break;
|
||||
case RLIMIT_VIRTMEM:
|
||||
return (getmaxvm (softlim, hardlim));
|
||||
case RLIMIT_MAXUPROC:
|
||||
if (getmaxuprc (&value) < 0)
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
*softlim = *hardlim = value;
|
||||
return (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined (HAVE_RESOURCE)
|
||||
if (getrlimit (limits[ind].parameter, &limit) < 0)
|
||||
return -1;
|
||||
*softlim = limit.rlim_cur;
|
||||
*hardlim = limit.rlim_max;
|
||||
# if defined (HPUX9)
|
||||
if (limits[ind].parameter == RLIMIT_FILESIZE)
|
||||
{
|
||||
*softlim *= 512;
|
||||
*hardlim *= 512; /* Ugh. */
|
||||
}
|
||||
else
|
||||
# endif /* HPUX9 */
|
||||
return 0;
|
||||
#else
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
set_limit (ind, newlim, mode)
|
||||
int ind;
|
||||
RLIMTYPE newlim;
|
||||
int mode;
|
||||
{
|
||||
#if defined (HAVE_RESOURCE)
|
||||
struct rlimit limit;
|
||||
RLIMTYPE val;
|
||||
#endif
|
||||
|
||||
if (limits[ind].parameter >= 256)
|
||||
switch (limits[ind].parameter)
|
||||
{
|
||||
case RLIMIT_FILESIZE:
|
||||
#if !defined (HAVE_RESOURCE)
|
||||
return (ulimit (2, newlim / 512L));
|
||||
#else
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
case RLIMIT_OPENFILES:
|
||||
#if defined (HAVE_SETDTABLESIZE)
|
||||
# if defined (__CYGWIN__)
|
||||
/* Grrr... Cygwin declares setdtablesize as void. */
|
||||
setdtablesize (newlim);
|
||||
return 0;
|
||||
# else
|
||||
return (setdtablesize (newlim));
|
||||
# endif
|
||||
#endif
|
||||
case RLIMIT_PIPESIZE:
|
||||
case RLIMIT_VIRTMEM:
|
||||
case RLIMIT_MAXUPROC:
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined (HAVE_RESOURCE)
|
||||
if (getrlimit (limits[ind].parameter, &limit) < 0)
|
||||
return -1;
|
||||
# if defined (HPUX9)
|
||||
if (limits[ind].parameter == RLIMIT_FILESIZE)
|
||||
newlim /= 512; /* Ugh. */
|
||||
# endif /* HPUX9 */
|
||||
val = (current_user.euid != 0 && newlim == RLIM_INFINITY &&
|
||||
(mode & LIMIT_HARD) == 0 && /* XXX -- test */
|
||||
(limit.rlim_cur <= limit.rlim_max))
|
||||
? limit.rlim_max : newlim;
|
||||
if (mode & LIMIT_SOFT)
|
||||
limit.rlim_cur = val;
|
||||
if (mode & LIMIT_HARD)
|
||||
limit.rlim_max = val;
|
||||
|
||||
return (setrlimit (limits[ind].parameter, &limit));
|
||||
#else
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
getmaxvm (softlim, hardlim)
|
||||
RLIMTYPE *softlim, *hardlim;
|
||||
{
|
||||
#if defined (HAVE_RESOURCE)
|
||||
struct rlimit datalim, stacklim;
|
||||
|
||||
if (getrlimit (RLIMIT_DATA, &datalim) < 0)
|
||||
return -1;
|
||||
|
||||
if (getrlimit (RLIMIT_STACK, &stacklim) < 0)
|
||||
return -1;
|
||||
|
||||
/* Protect against overflow. */
|
||||
*softlim = (datalim.rlim_cur / 1024L) + (stacklim.rlim_cur / 1024L);
|
||||
*hardlim = (datalim.rlim_max / 1024L) + (stacklim.rlim_max / 1024L);
|
||||
return 0;
|
||||
#else
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
#endif /* HAVE_RESOURCE */
|
||||
}
|
||||
|
||||
static int
|
||||
filesize(valuep)
|
||||
RLIMTYPE *valuep;
|
||||
{
|
||||
#if !defined (HAVE_RESOURCE)
|
||||
long result;
|
||||
if ((result = ulimit (1, 0L)) < 0)
|
||||
return -1;
|
||||
else
|
||||
*valuep = (RLIMTYPE) result * 512;
|
||||
return 0;
|
||||
#else
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
pipesize (valuep)
|
||||
RLIMTYPE *valuep;
|
||||
{
|
||||
#if defined (PIPE_BUF)
|
||||
/* This is defined on Posix systems. */
|
||||
*valuep = (RLIMTYPE) PIPE_BUF;
|
||||
return 0;
|
||||
#else
|
||||
# if defined (_POSIX_PIPE_BUF)
|
||||
*valuep = (RLIMTYPE) _POSIX_PIPE_BUF;
|
||||
return 0;
|
||||
# else
|
||||
# if defined (PIPESIZE)
|
||||
/* This is defined by running a program from the Makefile. */
|
||||
*valuep = (RLIMTYPE) PIPESIZE;
|
||||
return 0;
|
||||
# else
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
# endif /* PIPESIZE */
|
||||
# endif /* _POSIX_PIPE_BUF */
|
||||
#endif /* PIPE_BUF */
|
||||
}
|
||||
|
||||
static int
|
||||
getmaxuprc (valuep)
|
||||
RLIMTYPE *valuep;
|
||||
{
|
||||
long maxchild;
|
||||
|
||||
maxchild = getmaxchild ();
|
||||
if (maxchild < 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*valuep = (RLIMTYPE) maxchild;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_all_limits (mode)
|
||||
int mode;
|
||||
{
|
||||
register int i;
|
||||
RLIMTYPE softlim, hardlim;
|
||||
|
||||
if (mode == 0)
|
||||
mode |= LIMIT_SOFT;
|
||||
|
||||
for (i = 0; limits[i].option > 0; i++)
|
||||
{
|
||||
if (get_limit (i, &softlim, &hardlim) == 0)
|
||||
printone (i, (mode & LIMIT_SOFT) ? softlim : hardlim, 1);
|
||||
else if (errno != EINVAL)
|
||||
builtin_error ("%s: cannot get limit: %s", limits[i].description,
|
||||
strerror (errno));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
printone (limind, curlim, pdesc)
|
||||
int limind;
|
||||
RLIMTYPE curlim;
|
||||
int pdesc;
|
||||
{
|
||||
char unitstr[64];
|
||||
int factor;
|
||||
|
||||
factor = BLOCKSIZE(limits[limind].block_factor);
|
||||
if (pdesc)
|
||||
{
|
||||
if (limits[limind].units)
|
||||
sprintf (unitstr, "(%s, -%c) ", limits[limind].units, limits[limind].option);
|
||||
else
|
||||
sprintf (unitstr, "(-%c) ", limits[limind].option);
|
||||
|
||||
printf ("%-20s %20s", limits[limind].description, unitstr);
|
||||
}
|
||||
if (curlim == RLIM_INFINITY)
|
||||
puts ("unlimited");
|
||||
else if (curlim == RLIM_SAVED_MAX)
|
||||
puts ("hard");
|
||||
else if (curlim == RLIM_SAVED_CUR)
|
||||
puts ("soft");
|
||||
else
|
||||
print_rlimtype ((curlim / factor), 1);
|
||||
}
|
||||
|
||||
/* Set all limits to NEWLIM. NEWLIM currently must be RLIM_INFINITY, which
|
||||
causes all limits to be set as high as possible depending on mode (like
|
||||
csh `unlimit'). Returns -1 if NEWLIM is invalid, 0 if all limits
|
||||
were set successfully, and 1 if at least one limit could not be set.
|
||||
|
||||
To raise all soft limits to their corresponding hard limits, use
|
||||
ulimit -S -a unlimited
|
||||
To attempt to raise all hard limits to infinity (superuser-only), use
|
||||
ulimit -H -a unlimited
|
||||
To attempt to raise all soft and hard limits to infinity, use
|
||||
ulimit -a unlimited
|
||||
*/
|
||||
|
||||
static int
|
||||
set_all_limits (mode, newlim)
|
||||
int mode;
|
||||
RLIMTYPE newlim;
|
||||
{
|
||||
register int i;
|
||||
int retval = 0;
|
||||
|
||||
if (newlim != RLIM_INFINITY)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mode == 0)
|
||||
mode = LIMIT_SOFT|LIMIT_HARD;
|
||||
|
||||
for (retval = i = 0; limits[i].option > 0; i++)
|
||||
if (set_limit (i, newlim, mode) < 0)
|
||||
{
|
||||
builtin_error (_("%s: cannot modify limit: %s"), limits[i].description,
|
||||
strerror (errno));
|
||||
retval = 1;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif /* !_MINIX */
|
281
third_party/bash/builtins_umask.c
vendored
Normal file
281
third_party/bash/builtins_umask.c
vendored
Normal file
|
@ -0,0 +1,281 @@
|
|||
/* umask.c, created from umask.def. */
|
||||
#line 22 "./umask.def"
|
||||
|
||||
#line 41 "./umask.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "bashtypes.h"
|
||||
#include "filecntl.h"
|
||||
#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
|
||||
# include <sys/file.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "chartypes.h"
|
||||
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "posixstat.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* UMASK Builtin and Helpers */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
static void print_symbolic_umask PARAMS((mode_t));
|
||||
static int symbolic_umask PARAMS((WORD_LIST *));
|
||||
|
||||
/* Set or display the mask used by the system when creating files. Flag
|
||||
of -S means display the umask in a symbolic mode. */
|
||||
int
|
||||
umask_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int print_symbolically, opt, umask_value, pflag;
|
||||
mode_t umask_arg;
|
||||
|
||||
print_symbolically = pflag = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "Sp")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'S':
|
||||
print_symbolically++;
|
||||
break;
|
||||
case 'p':
|
||||
pflag++;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
if (list)
|
||||
{
|
||||
if (DIGIT (*list->word->word))
|
||||
{
|
||||
umask_value = read_octal (list->word->word);
|
||||
|
||||
/* Note that other shells just let you set the umask to zero
|
||||
by specifying a number out of range. This is a problem
|
||||
with those shells. We don't change the umask if the input
|
||||
is lousy. */
|
||||
if (umask_value == -1)
|
||||
{
|
||||
sh_erange (list->word->word, _("octal number"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
umask_value = symbolic_umask (list);
|
||||
if (umask_value == -1)
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
umask_arg = (mode_t)umask_value;
|
||||
umask (umask_arg);
|
||||
if (print_symbolically)
|
||||
print_symbolic_umask (umask_arg);
|
||||
}
|
||||
else /* Display the UMASK for this user. */
|
||||
{
|
||||
umask_arg = umask (022);
|
||||
umask (umask_arg);
|
||||
|
||||
if (pflag)
|
||||
printf ("umask%s ", (print_symbolically ? " -S" : ""));
|
||||
if (print_symbolically)
|
||||
print_symbolic_umask (umask_arg);
|
||||
else
|
||||
printf ("%04lo\n", (unsigned long)umask_arg);
|
||||
}
|
||||
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
/* Print the umask in a symbolic form. In the output, a letter is
|
||||
printed if the corresponding bit is clear in the umask. */
|
||||
static void
|
||||
#if defined (__STDC__)
|
||||
print_symbolic_umask (mode_t um)
|
||||
#else
|
||||
print_symbolic_umask (um)
|
||||
mode_t um;
|
||||
#endif
|
||||
{
|
||||
char ubits[4], gbits[4], obits[4]; /* u=rwx,g=rwx,o=rwx */
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
if ((um & S_IRUSR) == 0)
|
||||
ubits[i++] = 'r';
|
||||
if ((um & S_IWUSR) == 0)
|
||||
ubits[i++] = 'w';
|
||||
if ((um & S_IXUSR) == 0)
|
||||
ubits[i++] = 'x';
|
||||
ubits[i] = '\0';
|
||||
|
||||
i = 0;
|
||||
if ((um & S_IRGRP) == 0)
|
||||
gbits[i++] = 'r';
|
||||
if ((um & S_IWGRP) == 0)
|
||||
gbits[i++] = 'w';
|
||||
if ((um & S_IXGRP) == 0)
|
||||
gbits[i++] = 'x';
|
||||
gbits[i] = '\0';
|
||||
|
||||
i = 0;
|
||||
if ((um & S_IROTH) == 0)
|
||||
obits[i++] = 'r';
|
||||
if ((um & S_IWOTH) == 0)
|
||||
obits[i++] = 'w';
|
||||
if ((um & S_IXOTH) == 0)
|
||||
obits[i++] = 'x';
|
||||
obits[i] = '\0';
|
||||
|
||||
printf ("u=%s,g=%s,o=%s\n", ubits, gbits, obits);
|
||||
}
|
||||
|
||||
int
|
||||
parse_symbolic_mode (mode, initial_bits)
|
||||
char *mode;
|
||||
int initial_bits;
|
||||
{
|
||||
int who, op, perm, bits, c;
|
||||
char *s;
|
||||
|
||||
for (s = mode, bits = initial_bits;;)
|
||||
{
|
||||
who = op = perm = 0;
|
||||
|
||||
/* Parse the `who' portion of the symbolic mode clause. */
|
||||
while (member (*s, "agou"))
|
||||
{
|
||||
switch (c = *s++)
|
||||
{
|
||||
case 'u':
|
||||
who |= S_IRWXU;
|
||||
continue;
|
||||
case 'g':
|
||||
who |= S_IRWXG;
|
||||
continue;
|
||||
case 'o':
|
||||
who |= S_IRWXO;
|
||||
continue;
|
||||
case 'a':
|
||||
who |= S_IRWXU | S_IRWXG | S_IRWXO;
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* The operation is now sitting in *s. */
|
||||
op = *s++;
|
||||
switch (op)
|
||||
{
|
||||
case '+':
|
||||
case '-':
|
||||
case '=':
|
||||
break;
|
||||
default:
|
||||
builtin_error (_("`%c': invalid symbolic mode operator"), op);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Parse out the `perm' section of the symbolic mode clause. */
|
||||
while (member (*s, "rwx"))
|
||||
{
|
||||
c = *s++;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 'r':
|
||||
perm |= S_IRUGO;
|
||||
break;
|
||||
case 'w':
|
||||
perm |= S_IWUGO;
|
||||
break;
|
||||
case 'x':
|
||||
perm |= S_IXUGO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now perform the operation or return an error for a
|
||||
bad permission string. */
|
||||
if (!*s || *s == ',')
|
||||
{
|
||||
if (who)
|
||||
perm &= who;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case '+':
|
||||
bits |= perm;
|
||||
break;
|
||||
case '-':
|
||||
bits &= ~perm;
|
||||
break;
|
||||
case '=':
|
||||
if (who == 0)
|
||||
who = S_IRWXU | S_IRWXG | S_IRWXO;
|
||||
bits &= ~who;
|
||||
bits |= perm;
|
||||
break;
|
||||
|
||||
/* No other values are possible. */
|
||||
}
|
||||
|
||||
if (*s == '\0')
|
||||
break;
|
||||
else
|
||||
s++; /* skip past ',' */
|
||||
}
|
||||
else
|
||||
{
|
||||
builtin_error (_("`%c': invalid symbolic mode character"), *s);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
return (bits);
|
||||
}
|
||||
|
||||
/* Set the umask from a symbolic mode string similar to that accepted
|
||||
by chmod. If the -S argument is given, then print the umask in a
|
||||
symbolic form. */
|
||||
static int
|
||||
symbolic_umask (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int um, bits;
|
||||
|
||||
/* Get the initial umask. Don't change it yet. */
|
||||
um = umask (022);
|
||||
umask (um);
|
||||
|
||||
/* All work is done with the complement of the umask -- it's
|
||||
more intuitive and easier to deal with. It is complemented
|
||||
again before being returned. */
|
||||
bits = parse_symbolic_mode (list->word->word, ~um & 0777);
|
||||
if (bits == -1)
|
||||
return (-1);
|
||||
|
||||
um = ~bits & 0777;
|
||||
return (um);
|
||||
}
|
320
third_party/bash/builtins_wait.c
vendored
Normal file
320
third_party/bash/builtins_wait.c
vendored
Normal file
|
@ -0,0 +1,320 @@
|
|||
/* wait.c, created from wait.def. */
|
||||
#line 51 "./wait.def"
|
||||
|
||||
#line 66 "./wait.def"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "bashtypes.h"
|
||||
#include <signal.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "chartypes.h"
|
||||
|
||||
#include "bashansi.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "execute_cmd.h"
|
||||
#include "jobs.h"
|
||||
#include "trap.h"
|
||||
#include "sig.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
extern int wait_signal_received;
|
||||
|
||||
procenv_t wait_intr_buf;
|
||||
int wait_intr_flag;
|
||||
|
||||
static int set_waitlist PARAMS((WORD_LIST *));
|
||||
static void unset_waitlist PARAMS((void));
|
||||
|
||||
/* Wait for the pid in LIST to stop or die. If no arguments are given, then
|
||||
wait for all of the active background processes of the shell and return
|
||||
0. If a list of pids or job specs are given, return the exit status of
|
||||
the last one waited for. */
|
||||
|
||||
#define WAIT_RETURN(s) \
|
||||
do \
|
||||
{ \
|
||||
wait_signal_received = 0; \
|
||||
wait_intr_flag = 0; \
|
||||
return (s);\
|
||||
} \
|
||||
while (0)
|
||||
|
||||
int
|
||||
wait_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int status, code, opt, nflag, vflags, bindflags;
|
||||
volatile int wflags;
|
||||
char *vname;
|
||||
SHELL_VAR *pidvar;
|
||||
struct procstat pstat;
|
||||
|
||||
USE_VAR(list);
|
||||
|
||||
nflag = wflags = vflags = 0;
|
||||
vname = NULL;
|
||||
pidvar = (SHELL_VAR *)NULL;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "fnp:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
#if defined (JOB_CONTROL)
|
||||
case 'n':
|
||||
nflag = 1;
|
||||
break;
|
||||
case 'f':
|
||||
wflags |= JWAIT_FORCE;
|
||||
break;
|
||||
case 'p':
|
||||
vname = list_optarg;
|
||||
vflags = list_optflags;
|
||||
break;
|
||||
#endif
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
/* Sanity-check variable name if -p supplied. */
|
||||
if (vname)
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
int arrayflags;
|
||||
|
||||
SET_VFLAGS (vflags, arrayflags, bindflags);
|
||||
if (legal_identifier (vname) == 0 && valid_array_reference (vname, arrayflags) == 0)
|
||||
#else
|
||||
bindflags = 0;
|
||||
if (legal_identifier (vname) == 0)
|
||||
#endif
|
||||
{
|
||||
sh_invalidid (vname);
|
||||
WAIT_RETURN (EXECUTION_FAILURE);
|
||||
}
|
||||
if (builtin_unbind_variable (vname) == -2)
|
||||
WAIT_RETURN (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* POSIX.2 says: When the shell is waiting (by means of the wait utility)
|
||||
for asynchronous commands to complete, the reception of a signal for
|
||||
which a trap has been set shall cause the wait utility to return
|
||||
immediately with an exit status greater than 128, after which the trap
|
||||
associated with the signal shall be taken.
|
||||
|
||||
We handle SIGINT here; it's the only one that needs to be treated
|
||||
specially (I think), since it's handled specially in {no,}jobs.c. */
|
||||
wait_intr_flag = 1;
|
||||
code = setjmp_sigs (wait_intr_buf);
|
||||
|
||||
if (code)
|
||||
{
|
||||
last_command_exit_signal = wait_signal_received;
|
||||
status = 128 + wait_signal_received;
|
||||
wait_sigint_cleanup ();
|
||||
#if defined (JOB_CONTROL)
|
||||
if (wflags & JWAIT_WAITING)
|
||||
unset_waitlist ();
|
||||
#endif
|
||||
WAIT_RETURN (status);
|
||||
}
|
||||
|
||||
opt = first_pending_trap ();
|
||||
#if defined (SIGCHLD)
|
||||
/* We special case SIGCHLD when not in posix mode because we don't break
|
||||
out of the wait even when the signal is trapped; we run the trap after
|
||||
the wait completes. See how it's handled in jobs.c:waitchld(). */
|
||||
if (opt == SIGCHLD && posixly_correct == 0)
|
||||
opt = next_pending_trap (opt+1);
|
||||
#endif
|
||||
if (opt != -1)
|
||||
{
|
||||
last_command_exit_signal = wait_signal_received = opt;
|
||||
status = opt + 128;
|
||||
WAIT_RETURN (status);
|
||||
}
|
||||
|
||||
/* We support jobs or pids.
|
||||
wait <pid-or-job> [pid-or-job ...] */
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
if (nflag)
|
||||
{
|
||||
if (list)
|
||||
{
|
||||
opt = set_waitlist (list);
|
||||
if (opt == 0)
|
||||
WAIT_RETURN (127);
|
||||
wflags |= JWAIT_WAITING;
|
||||
}
|
||||
|
||||
status = wait_for_any_job (wflags, &pstat);
|
||||
if (vname && status >= 0)
|
||||
builtin_bind_var_to_int (vname, pstat.pid, bindflags);
|
||||
|
||||
if (status < 0)
|
||||
status = 127;
|
||||
if (list)
|
||||
unset_waitlist ();
|
||||
WAIT_RETURN (status);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* But wait without any arguments means to wait for all of the shell's
|
||||
currently active background processes. */
|
||||
if (list == 0)
|
||||
{
|
||||
opt = wait_for_background_pids (&pstat);
|
||||
#if 0
|
||||
/* Compatibility with NetBSD sh: don't set VNAME since it doesn't
|
||||
correspond to the return status. */
|
||||
if (vname && opt)
|
||||
builtin_bind_var_to_int (vname, pstat.pid, bindflags);
|
||||
#endif
|
||||
WAIT_RETURN (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
status = EXECUTION_SUCCESS;
|
||||
while (list)
|
||||
{
|
||||
pid_t pid;
|
||||
char *w;
|
||||
intmax_t pid_value;
|
||||
|
||||
w = list->word->word;
|
||||
if (DIGIT (*w))
|
||||
{
|
||||
if (legal_number (w, &pid_value) && pid_value == (pid_t)pid_value)
|
||||
{
|
||||
pid = (pid_t)pid_value;
|
||||
status = wait_for_single_pid (pid, wflags|JWAIT_PERROR);
|
||||
/* status > 256 means pid error */
|
||||
pstat.pid = (status > 256) ? NO_PID : pid;
|
||||
pstat.status = (status > 256) ? 127 : status;
|
||||
if (status > 256)
|
||||
status = 127;
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_badpid (w);
|
||||
pstat.pid = NO_PID;
|
||||
pstat.status = 127;
|
||||
WAIT_RETURN (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
#if defined (JOB_CONTROL)
|
||||
else if (*w && *w == '%')
|
||||
/* Must be a job spec. Check it out. */
|
||||
{
|
||||
int job;
|
||||
sigset_t set, oset;
|
||||
|
||||
BLOCK_CHILD (set, oset);
|
||||
job = get_job_spec (list);
|
||||
|
||||
if (INVALID_JOB (job))
|
||||
{
|
||||
if (job != DUP_JOB)
|
||||
sh_badjob (list->word->word);
|
||||
UNBLOCK_CHILD (oset);
|
||||
status = 127; /* As per Posix.2, section 4.70.2 */
|
||||
pstat.pid = NO_PID;
|
||||
pstat.status = status;
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Job spec used. Wait for the last pid in the pipeline. */
|
||||
UNBLOCK_CHILD (oset);
|
||||
status = wait_for_job (job, wflags, &pstat);
|
||||
}
|
||||
#endif /* JOB_CONTROL */
|
||||
else
|
||||
{
|
||||
sh_badpid (w);
|
||||
pstat.pid = NO_PID;
|
||||
pstat.status = 127;
|
||||
status = EXECUTION_FAILURE;
|
||||
}
|
||||
|
||||
/* Don't waste time with a longjmp. */
|
||||
if (wait_signal_received)
|
||||
{
|
||||
last_command_exit_signal = wait_signal_received;
|
||||
status = 128 + wait_signal_received;
|
||||
wait_sigint_cleanup ();
|
||||
WAIT_RETURN (status);
|
||||
}
|
||||
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
if (vname && pstat.pid != NO_PID)
|
||||
builtin_bind_var_to_int (vname, pstat.pid, bindflags);
|
||||
|
||||
WAIT_RETURN (status);
|
||||
}
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
/* Take each valid pid or jobspec in LIST and mark the corresponding job as
|
||||
J_WAITING, so wait -n knows which jobs to wait for. Return the number of
|
||||
jobs we found. */
|
||||
static int
|
||||
set_waitlist (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
sigset_t set, oset;
|
||||
int job, r, njob;
|
||||
intmax_t pid;
|
||||
WORD_LIST *l;
|
||||
|
||||
BLOCK_CHILD (set, oset);
|
||||
njob = 0;
|
||||
for (l = list; l; l = l->next)
|
||||
{
|
||||
job = NO_JOB;
|
||||
job = (l && legal_number (l->word->word, &pid) && pid == (pid_t) pid)
|
||||
? get_job_by_pid ((pid_t) pid, 0, 0)
|
||||
: get_job_spec (l);
|
||||
if (job == NO_JOB || jobs == 0 || INVALID_JOB (job))
|
||||
{
|
||||
sh_badjob (l->word->word);
|
||||
continue;
|
||||
}
|
||||
/* We don't check yet to see if one of the desired jobs has already
|
||||
terminated, but we could. We wait until wait_for_any_job(). This
|
||||
has the advantage of validating all the arguments. */
|
||||
if ((jobs[job]->flags & J_WAITING) == 0)
|
||||
{
|
||||
njob++;
|
||||
jobs[job]->flags |= J_WAITING;
|
||||
}
|
||||
}
|
||||
UNBLOCK_CHILD (oset);
|
||||
return (njob);
|
||||
}
|
||||
|
||||
/* Clean up after a call to wait -n jobs */
|
||||
static void
|
||||
unset_waitlist ()
|
||||
{
|
||||
int i;
|
||||
sigset_t set, oset;
|
||||
|
||||
BLOCK_CHILD (set, oset);
|
||||
for (i = 0; i < js.j_jobslots; i++)
|
||||
if (jobs[i] && (jobs[i]->flags & J_WAITING))
|
||||
jobs[i]->flags &= ~J_WAITING;
|
||||
UNBLOCK_CHILD (oset);
|
||||
}
|
||||
#endif
|
271
third_party/bash/casemod.c
vendored
Normal file
271
third_party/bash/casemod.c
vendored
Normal file
|
@ -0,0 +1,271 @@
|
|||
/* casemod.c -- functions to change case of strings */
|
||||
|
||||
/* Copyright (C) 2008-2020 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined (HAVE_CONFIG_H)
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
#include "bashtypes.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include "xmalloc.h"
|
||||
|
||||
#include "shmbchar.h"
|
||||
#include "shmbutil.h"
|
||||
#include "chartypes.h"
|
||||
#include "typemax.h"
|
||||
|
||||
#include "strmatch.h"
|
||||
|
||||
#define _to_wupper(wc) (iswlower (wc) ? towupper (wc) : (wc))
|
||||
#define _to_wlower(wc) (iswupper (wc) ? towlower (wc) : (wc))
|
||||
|
||||
#if !defined (HANDLE_MULTIBYTE)
|
||||
# define cval(s, i, l) ((s)[(i)])
|
||||
# define iswalnum(c) (isalnum(c))
|
||||
# define TOGGLE(x) (ISUPPER (x) ? tolower ((unsigned char)x) : (TOUPPER (x)))
|
||||
#else
|
||||
# define TOGGLE(x) (iswupper (x) ? towlower (x) : (_to_wupper(x)))
|
||||
#endif
|
||||
|
||||
/* These must agree with the defines in externs.h */
|
||||
#define CASE_NOOP 0x0000
|
||||
#define CASE_LOWER 0x0001
|
||||
#define CASE_UPPER 0x0002
|
||||
#define CASE_CAPITALIZE 0x0004
|
||||
#define CASE_UNCAP 0x0008
|
||||
#define CASE_TOGGLE 0x0010
|
||||
#define CASE_TOGGLEALL 0x0020
|
||||
#define CASE_UPFIRST 0x0040
|
||||
#define CASE_LOWFIRST 0x0080
|
||||
|
||||
#define CASE_USEWORDS 0x1000 /* modify behavior to act on words in passed string */
|
||||
|
||||
extern char *substring PARAMS((char *, int, int));
|
||||
|
||||
#ifndef UCHAR_MAX
|
||||
# define UCHAR_MAX TYPE_MAXIMUM(unsigned char)
|
||||
#endif
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
static wchar_t
|
||||
cval (s, i, l)
|
||||
char *s;
|
||||
int i, l;
|
||||
{
|
||||
size_t tmp;
|
||||
wchar_t wc;
|
||||
mbstate_t mps;
|
||||
|
||||
if (MB_CUR_MAX == 1 || is_basic (s[i]))
|
||||
return ((wchar_t)s[i]);
|
||||
if (i >= (l - 1))
|
||||
return ((wchar_t)s[i]);
|
||||
memset (&mps, 0, sizeof (mbstate_t));
|
||||
tmp = mbrtowc (&wc, s + i, l - i, &mps);
|
||||
if (MB_INVALIDCH (tmp) || MB_NULLWCH (tmp))
|
||||
return ((wchar_t)s[i]);
|
||||
return wc;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Modify the case of characters in STRING matching PAT based on the value of
|
||||
FLAGS. If PAT is null, modify the case of each character */
|
||||
char *
|
||||
sh_modcase (string, pat, flags)
|
||||
const char *string;
|
||||
char *pat;
|
||||
int flags;
|
||||
{
|
||||
int start, next, end, retind;
|
||||
int inword, c, nc, nop, match, usewords;
|
||||
char *ret, *s;
|
||||
wchar_t wc;
|
||||
int mb_cur_max;
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
wchar_t nwc;
|
||||
char mb[MB_LEN_MAX+1];
|
||||
int mlen;
|
||||
size_t m;
|
||||
mbstate_t state;
|
||||
#endif
|
||||
|
||||
if (string == 0 || *string == 0)
|
||||
{
|
||||
ret = (char *)xmalloc (1);
|
||||
ret[0] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
memset (&state, 0, sizeof (mbstate_t));
|
||||
#endif
|
||||
|
||||
start = 0;
|
||||
end = strlen (string);
|
||||
mb_cur_max = MB_CUR_MAX;
|
||||
|
||||
ret = (char *)xmalloc (2*end + 1);
|
||||
retind = 0;
|
||||
|
||||
/* See if we are supposed to split on alphanumerics and operate on each word */
|
||||
usewords = (flags & CASE_USEWORDS);
|
||||
flags &= ~CASE_USEWORDS;
|
||||
|
||||
inword = 0;
|
||||
while (start < end)
|
||||
{
|
||||
wc = cval ((char *)string, start, end);
|
||||
|
||||
if (iswalnum (wc) == 0)
|
||||
inword = 0;
|
||||
|
||||
if (pat)
|
||||
{
|
||||
next = start;
|
||||
ADVANCE_CHAR (string, end, next);
|
||||
s = substring ((char *)string, start, next);
|
||||
match = strmatch (pat, s, FNM_EXTMATCH) != FNM_NOMATCH;
|
||||
free (s);
|
||||
if (match == 0)
|
||||
{
|
||||
/* copy unmatched portion */
|
||||
memcpy (ret + retind, string + start, next - start);
|
||||
retind += next - start;
|
||||
start = next;
|
||||
inword = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX - for now, the toggling operators work on the individual
|
||||
words in the string, breaking on alphanumerics. Should I
|
||||
leave the capitalization operators to do that also? */
|
||||
if (flags == CASE_CAPITALIZE)
|
||||
{
|
||||
if (usewords)
|
||||
nop = inword ? CASE_LOWER : CASE_UPPER;
|
||||
else
|
||||
nop = (start > 0) ? CASE_LOWER : CASE_UPPER;
|
||||
inword = 1;
|
||||
}
|
||||
else if (flags == CASE_UNCAP)
|
||||
{
|
||||
if (usewords)
|
||||
nop = inword ? CASE_UPPER : CASE_LOWER;
|
||||
else
|
||||
nop = (start > 0) ? CASE_UPPER : CASE_LOWER;
|
||||
inword = 1;
|
||||
}
|
||||
else if (flags == CASE_UPFIRST)
|
||||
{
|
||||
if (usewords)
|
||||
nop = inword ? CASE_NOOP : CASE_UPPER;
|
||||
else
|
||||
nop = (start > 0) ? CASE_NOOP : CASE_UPPER;
|
||||
inword = 1;
|
||||
}
|
||||
else if (flags == CASE_LOWFIRST)
|
||||
{
|
||||
if (usewords)
|
||||
nop = inword ? CASE_NOOP : CASE_LOWER;
|
||||
else
|
||||
nop = (start > 0) ? CASE_NOOP : CASE_LOWER;
|
||||
inword = 1;
|
||||
}
|
||||
else if (flags == CASE_TOGGLE)
|
||||
{
|
||||
nop = inword ? CASE_NOOP : CASE_TOGGLE;
|
||||
inword = 1;
|
||||
}
|
||||
else
|
||||
nop = flags;
|
||||
|
||||
/* Can't short-circuit, some locales have multibyte upper and lower
|
||||
case equivalents of single-byte ascii characters (e.g., Turkish) */
|
||||
if (mb_cur_max == 1)
|
||||
{
|
||||
singlebyte:
|
||||
switch (nop)
|
||||
{
|
||||
default:
|
||||
case CASE_NOOP: nc = wc; break;
|
||||
case CASE_UPPER: nc = TOUPPER (wc); break;
|
||||
case CASE_LOWER: nc = TOLOWER (wc); break;
|
||||
case CASE_TOGGLEALL:
|
||||
case CASE_TOGGLE: nc = TOGGLE (wc); break;
|
||||
}
|
||||
ret[retind++] = nc;
|
||||
}
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
else
|
||||
{
|
||||
m = mbrtowc (&wc, string + start, end - start, &state);
|
||||
/* Have to go through wide case conversion even for single-byte
|
||||
chars, to accommodate single-byte characters where the
|
||||
corresponding upper or lower case equivalent is multibyte. */
|
||||
if (MB_INVALIDCH (m))
|
||||
{
|
||||
wc = (unsigned char)string[start];
|
||||
goto singlebyte;
|
||||
}
|
||||
else if (MB_NULLWCH (m))
|
||||
wc = L'\0';
|
||||
switch (nop)
|
||||
{
|
||||
default:
|
||||
case CASE_NOOP: nwc = wc; break;
|
||||
case CASE_UPPER: nwc = _to_wupper (wc); break;
|
||||
case CASE_LOWER: nwc = _to_wlower (wc); break;
|
||||
case CASE_TOGGLEALL:
|
||||
case CASE_TOGGLE: nwc = TOGGLE (wc); break;
|
||||
}
|
||||
|
||||
/* We don't have to convert `wide' characters that are in the
|
||||
unsigned char range back to single-byte `multibyte' characters. */
|
||||
if ((int)nwc <= UCHAR_MAX && is_basic ((int)nwc))
|
||||
ret[retind++] = nwc;
|
||||
else
|
||||
{
|
||||
mlen = wcrtomb (mb, nwc, &state);
|
||||
if (mlen > 0)
|
||||
mb[mlen] = '\0';
|
||||
/* Don't assume the same width */
|
||||
strncpy (ret + retind, mb, mlen);
|
||||
retind += mlen;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ADVANCE_CHAR (string, end, start);
|
||||
}
|
||||
|
||||
ret[retind] = '\0';
|
||||
return ret;
|
||||
}
|
109
third_party/bash/chartypes.h
vendored
Normal file
109
third_party/bash/chartypes.h
vendored
Normal file
|
@ -0,0 +1,109 @@
|
|||
/* chartypes.h -- extend ctype.h */
|
||||
|
||||
/* Copyright (C) 2001-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _SH_CHARTYPES_H
|
||||
#define _SH_CHARTYPES_H
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#ifndef UCHAR_MAX
|
||||
# define UCHAR_MAX 255
|
||||
#endif
|
||||
#ifndef CHAR_MAX
|
||||
# define CHAR_MAX 127
|
||||
#endif
|
||||
|
||||
/* use this as a proxy for C89 */
|
||||
#if defined (HAVE_STDLIB_H) && defined (HAVE_STRING_H)
|
||||
# define IN_CTYPE_DOMAIN(c) 1
|
||||
#else
|
||||
# define IN_CTYPE_DOMAIN(c) ((c) >= 0 && (c) <= CHAR_MAX)
|
||||
#endif
|
||||
|
||||
#if !defined (isspace) && !defined (HAVE_ISSPACE)
|
||||
# define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\f')
|
||||
#endif
|
||||
|
||||
#if !defined (isprint) && !defined (HAVE_ISPRINT)
|
||||
# define isprint(c) (isalpha((unsigned char)c) || isdigit((unsigned char)c) || ispunct((unsigned char)c))
|
||||
#endif
|
||||
|
||||
#if defined (isblank) || defined (HAVE_ISBLANK)
|
||||
# define ISBLANK(c) (IN_CTYPE_DOMAIN (c) && isblank ((unsigned char)c))
|
||||
#else
|
||||
# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
|
||||
#endif
|
||||
|
||||
#if defined (isgraph) || defined (HAVE_ISGRAPH)
|
||||
# define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isgraph (c))
|
||||
#else
|
||||
# define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isprint ((unsigned char)c) && !isspace ((unsigned char)c))
|
||||
#endif
|
||||
|
||||
#if !defined (isxdigit) && !defined (HAVE_ISXDIGIT)
|
||||
# define isxdigit(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
|
||||
#endif
|
||||
|
||||
#undef ISPRINT
|
||||
|
||||
#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint ((unsigned char)c))
|
||||
#define ISDIGIT(c) (IN_CTYPE_DOMAIN (c) && isdigit ((unsigned char)c))
|
||||
#define ISALNUM(c) (IN_CTYPE_DOMAIN (c) && isalnum ((unsigned char)c))
|
||||
#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha ((unsigned char)c))
|
||||
#define ISCNTRL(c) (IN_CTYPE_DOMAIN (c) && iscntrl ((unsigned char)c))
|
||||
#define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower ((unsigned char)c))
|
||||
#define ISPUNCT(c) (IN_CTYPE_DOMAIN (c) && ispunct ((unsigned char)c))
|
||||
#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace ((unsigned char)c))
|
||||
#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper ((unsigned char)c))
|
||||
#define ISXDIGIT(c) (IN_CTYPE_DOMAIN (c) && isxdigit ((unsigned char)c))
|
||||
|
||||
#define ISLETTER(c) (ISALPHA(c))
|
||||
|
||||
#define DIGIT(c) ((c) >= '0' && (c) <= '9')
|
||||
|
||||
#define ISWORD(c) (ISLETTER(c) || DIGIT(c) || ((c) == '_'))
|
||||
|
||||
#define HEXVALUE(c) \
|
||||
(((c) >= 'a' && (c) <= 'f') \
|
||||
? (c)-'a'+10 \
|
||||
: (c) >= 'A' && (c) <= 'F' ? (c)-'A'+10 : (c)-'0')
|
||||
|
||||
#ifndef ISOCTAL
|
||||
# define ISOCTAL(c) ((c) >= '0' && (c) <= '7')
|
||||
#endif
|
||||
#define OCTVALUE(c) ((c) - '0')
|
||||
|
||||
#define TODIGIT(c) ((c) - '0')
|
||||
#define TOCHAR(c) ((c) + '0')
|
||||
|
||||
#define TOLOWER(c) (ISUPPER(c) ? tolower(c) : (c))
|
||||
#define TOUPPER(c) (ISLOWER(c) ? toupper(c) : (c))
|
||||
|
||||
#ifndef TOCTRL
|
||||
/* letter to control char -- ASCII. The TOUPPER is in there so \ce and
|
||||
\cE will map to the same character in $'...' expansions. */
|
||||
# define TOCTRL(x) ((x) == '?' ? 0x7f : (TOUPPER(x) & 0x1f))
|
||||
#endif
|
||||
#ifndef UNCTRL
|
||||
/* control char to letter -- ASCII */
|
||||
# define UNCTRL(x) (TOUPPER(x ^ 0x40))
|
||||
#endif
|
||||
|
||||
#endif /* _SH_CHARTYPES_H */
|
61
third_party/bash/clktck.c
vendored
Normal file
61
third_party/bash/clktck.c
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
/* clktck.c - get the value of CLK_TCK. */
|
||||
|
||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "bashtypes.h"
|
||||
#if defined (HAVE_SYS_PARAM_H)
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_LIMITS_H)
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
#if !defined (HAVE_SYSCONF) || !defined (_SC_CLK_TCK)
|
||||
# if !defined (CLK_TCK)
|
||||
# if defined (HZ)
|
||||
# define CLK_TCK HZ
|
||||
# else
|
||||
# define CLK_TCK 60
|
||||
# endif
|
||||
# endif /* !CLK_TCK */
|
||||
#endif /* !HAVE_SYSCONF && !_SC_CLK_TCK */
|
||||
|
||||
long
|
||||
get_clk_tck ()
|
||||
{
|
||||
static long retval = 0;
|
||||
|
||||
if (retval != 0)
|
||||
return (retval);
|
||||
|
||||
#if defined (HAVE_SYSCONF) && defined (_SC_CLK_TCK)
|
||||
retval = sysconf (_SC_CLK_TCK);
|
||||
#else /* !SYSCONF || !_SC_CLK_TCK */
|
||||
retval = CLK_TCK;
|
||||
#endif /* !SYSCONF || !_SC_CLK_TCK */
|
||||
|
||||
return (retval);
|
||||
}
|
87
third_party/bash/clock.c
vendored
Normal file
87
third_party/bash/clock.c
vendored
Normal file
|
@ -0,0 +1,87 @@
|
|||
/* clock.c - operations on struct tms and clock_t's */
|
||||
|
||||
/* Copyright (C) 1999 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_TIMES)
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "posixtime.h"
|
||||
|
||||
#if defined (HAVE_SYS_TIMES_H)
|
||||
# include <sys/times.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "stdc.h"
|
||||
|
||||
#include "bashintl.h"
|
||||
|
||||
#ifndef locale_decpoint
|
||||
extern int locale_decpoint PARAMS((void));
|
||||
#endif
|
||||
|
||||
extern long get_clk_tck PARAMS((void));
|
||||
|
||||
void
|
||||
clock_t_to_secs (t, sp, sfp)
|
||||
clock_t t;
|
||||
time_t *sp;
|
||||
int *sfp;
|
||||
{
|
||||
static long clk_tck = -1;
|
||||
|
||||
if (clk_tck == -1)
|
||||
clk_tck = get_clk_tck ();
|
||||
|
||||
*sfp = t % clk_tck;
|
||||
*sfp = (*sfp * 1000) / clk_tck;
|
||||
|
||||
*sp = t / clk_tck;
|
||||
|
||||
/* Sanity check */
|
||||
if (*sfp >= 1000)
|
||||
{
|
||||
*sp += 1;
|
||||
*sfp -= 1000;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the time defined by a clock_t (returned by the `times' and `time'
|
||||
system calls) in a standard way to stdio stream FP. This is scaled in
|
||||
terms of the value of CLK_TCK, which is what is returned by the
|
||||
`times' call. */
|
||||
void
|
||||
print_clock_t (fp, t)
|
||||
FILE *fp;
|
||||
clock_t t;
|
||||
{
|
||||
time_t timestamp;
|
||||
long minutes;
|
||||
int seconds, seconds_fraction;
|
||||
|
||||
clock_t_to_secs (t, ×tamp, &seconds_fraction);
|
||||
|
||||
minutes = timestamp / 60;
|
||||
seconds = timestamp % 60;
|
||||
|
||||
fprintf (fp, "%ldm%d%c%03ds", minutes, seconds, locale_decpoint(), seconds_fraction);
|
||||
}
|
||||
#endif /* HAVE_TIMES */
|
140
third_party/bash/collsyms.h
vendored
Normal file
140
third_party/bash/collsyms.h
vendored
Normal file
|
@ -0,0 +1,140 @@
|
|||
/* collsyms.h -- collating symbol names and their corresponding characters
|
||||
(in ascii) as given by POSIX.2 in table 2.8. */
|
||||
|
||||
/* Copyright (C) 1997-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* The upper-case letters, lower-case letters, and digits are omitted from
|
||||
this table. The digits are not included in the table in the POSIX.2
|
||||
spec. The upper and lower case letters are translated by the code
|
||||
in smatch.c:collsym(). */
|
||||
|
||||
typedef struct _COLLSYM {
|
||||
XCHAR *name;
|
||||
CHAR code;
|
||||
} __COLLSYM;
|
||||
|
||||
static __COLLSYM POSIXCOLL [] =
|
||||
{
|
||||
{ L("NUL"), L('\0') },
|
||||
{ L("SOH"), L('\001') },
|
||||
{ L("STX"), L('\002') },
|
||||
{ L("ETX"), L('\003') },
|
||||
{ L("EOT"), L('\004') },
|
||||
{ L("ENQ"), L('\005') },
|
||||
{ L("ACK"), L('\006') },
|
||||
#ifdef __STDC__
|
||||
{ L("alert"), L('\a') },
|
||||
#else
|
||||
{ L("alert"), L('\007') },
|
||||
#endif
|
||||
{ L("BS"), L('\010') },
|
||||
{ L("backspace"), L('\b') },
|
||||
{ L("HT"), L('\011') },
|
||||
{ L("tab"), L('\t') },
|
||||
{ L("LF"), L('\012') },
|
||||
{ L("newline"), L('\n') },
|
||||
{ L("VT"), L('\013') },
|
||||
{ L("vertical-tab"), L('\v') },
|
||||
{ L("FF"), L('\014') },
|
||||
{ L("form-feed"), L('\f') },
|
||||
{ L("CR"), L('\015') },
|
||||
{ L("carriage-return"), L('\r') },
|
||||
{ L("SO"), L('\016') },
|
||||
{ L("SI"), L('\017') },
|
||||
{ L("DLE"), L('\020') },
|
||||
{ L("DC1"), L('\021') },
|
||||
{ L("DC2"), L('\022') },
|
||||
{ L("DC3"), L('\023') },
|
||||
{ L("DC4"), L('\024') },
|
||||
{ L("NAK"), L('\025') },
|
||||
{ L("SYN"), L('\026') },
|
||||
{ L("ETB"), L('\027') },
|
||||
{ L("CAN"), L('\030') },
|
||||
{ L("EM"), L('\031') },
|
||||
{ L("SUB"), L('\032') },
|
||||
{ L("ESC"), L('\033') },
|
||||
{ L("IS4"), L('\034') },
|
||||
{ L("FS"), L('\034') },
|
||||
{ L("IS3"), L('\035') },
|
||||
{ L("GS"), L('\035') },
|
||||
{ L("IS2"), L('\036') },
|
||||
{ L("RS"), L('\036') },
|
||||
{ L("IS1"), L('\037') },
|
||||
{ L("US"), L('\037') },
|
||||
{ L("space"), L(' ') },
|
||||
{ L("exclamation-mark"), L('!') },
|
||||
{ L("quotation-mark"), L('"') },
|
||||
{ L("number-sign"), L('#') },
|
||||
{ L("dollar-sign"), L('$') },
|
||||
{ L("percent-sign"), L('%') },
|
||||
{ L("ampersand"), L('&') },
|
||||
{ L("apostrophe"), L('\'') },
|
||||
{ L("left-parenthesis"), L('(') },
|
||||
{ L("right-parenthesis"), L(')') },
|
||||
{ L("asterisk"), L('*') },
|
||||
{ L("plus-sign"), L('+') },
|
||||
{ L("comma"), L(',') },
|
||||
{ L("hyphen"), L('-') },
|
||||
{ L("hyphen-minus"), L('-') },
|
||||
{ L("minus"), L('-') }, /* extension from POSIX.2 */
|
||||
{ L("dash"), L('-') }, /* extension from POSIX.2 */
|
||||
{ L("period"), L('.') },
|
||||
{ L("full-stop"), L('.') },
|
||||
{ L("slash"), L('/') },
|
||||
{ L("solidus"), L('/') }, /* extension from POSIX.2 */
|
||||
{ L("zero"), L('0') },
|
||||
{ L("one"), L('1') },
|
||||
{ L("two"), L('2') },
|
||||
{ L("three"), L('3') },
|
||||
{ L("four"), L('4') },
|
||||
{ L("five"), L('5') },
|
||||
{ L("six"), L('6') },
|
||||
{ L("seven"), L('7') },
|
||||
{ L("eight"), L('8') },
|
||||
{ L("nine"), L('9') },
|
||||
{ L("colon"), L(':') },
|
||||
{ L("semicolon"), L(';') },
|
||||
{ L("less-than-sign"), L('<') },
|
||||
{ L("equals-sign"), L('=') },
|
||||
{ L("greater-than-sign"), L('>') },
|
||||
{ L("question-mark"), L('?') },
|
||||
{ L("commercial-at"), L('@') },
|
||||
/* upper-case letters omitted */
|
||||
{ L("left-square-bracket"), L('[') },
|
||||
{ L("backslash"), L('\\') },
|
||||
{ L("reverse-solidus"), L('\\') },
|
||||
{ L("right-square-bracket"), L(']') },
|
||||
{ L("circumflex"), L('^') },
|
||||
{ L("circumflex-accent"), L('^') }, /* extension from POSIX.2 */
|
||||
{ L("underscore"), L('_') },
|
||||
{ L("grave-accent"), L('`') },
|
||||
/* lower-case letters omitted */
|
||||
{ L("left-brace"), L('{') }, /* extension from POSIX.2 */
|
||||
{ L("left-curly-bracket"), L('{') },
|
||||
{ L("vertical-line"), L('|') },
|
||||
{ L("right-brace"), L('}') }, /* extension from POSIX.2 */
|
||||
{ L("right-curly-bracket"), L('}') },
|
||||
{ L("tilde"), L('~') },
|
||||
{ L("DEL"), L('\177') },
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
#undef _COLLSYM
|
||||
#undef __COLLSYM
|
||||
#undef POSIXCOLL
|
409
third_party/bash/command.h
vendored
Normal file
409
third_party/bash/command.h
vendored
Normal file
|
@ -0,0 +1,409 @@
|
|||
/* command.h -- The structures used internally to represent commands, and
|
||||
the extern declarations of the functions used to create them. */
|
||||
|
||||
/* Copyright (C) 1993-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (_COMMAND_H_)
|
||||
#define _COMMAND_H_
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
/* Instructions describing what kind of thing to do for a redirection. */
|
||||
enum r_instruction {
|
||||
r_output_direction, r_input_direction, r_inputa_direction,
|
||||
r_appending_to, r_reading_until, r_reading_string,
|
||||
r_duplicating_input, r_duplicating_output, r_deblank_reading_until,
|
||||
r_close_this, r_err_and_out, r_input_output, r_output_force,
|
||||
r_duplicating_input_word, r_duplicating_output_word,
|
||||
r_move_input, r_move_output, r_move_input_word, r_move_output_word,
|
||||
r_append_err_and_out
|
||||
};
|
||||
|
||||
/* Redirection flags; values for rflags */
|
||||
#define REDIR_VARASSIGN 0x01
|
||||
|
||||
/* Redirection errors. */
|
||||
#define AMBIGUOUS_REDIRECT -1
|
||||
#define NOCLOBBER_REDIRECT -2
|
||||
#define RESTRICTED_REDIRECT -3 /* can only happen in restricted shells. */
|
||||
#define HEREDOC_REDIRECT -4 /* here-doc temp file can't be created */
|
||||
#define BADVAR_REDIRECT -5 /* something wrong with {varname}redir */
|
||||
|
||||
#define CLOBBERING_REDIRECT(ri) \
|
||||
(ri == r_output_direction || ri == r_err_and_out)
|
||||
|
||||
#define OUTPUT_REDIRECT(ri) \
|
||||
(ri == r_output_direction || ri == r_input_output || ri == r_err_and_out || ri == r_append_err_and_out)
|
||||
|
||||
#define INPUT_REDIRECT(ri) \
|
||||
(ri == r_input_direction || ri == r_inputa_direction || ri == r_input_output)
|
||||
|
||||
#define WRITE_REDIRECT(ri) \
|
||||
(ri == r_output_direction || \
|
||||
ri == r_input_output || \
|
||||
ri == r_err_and_out || \
|
||||
ri == r_appending_to || \
|
||||
ri == r_append_err_and_out || \
|
||||
ri == r_output_force)
|
||||
|
||||
/* redirection needs translation */
|
||||
#define TRANSLATE_REDIRECT(ri) \
|
||||
(ri == r_duplicating_input_word || ri == r_duplicating_output_word || \
|
||||
ri == r_move_input_word || ri == r_move_output_word)
|
||||
|
||||
/* Command Types: */
|
||||
enum command_type { cm_for, cm_case, cm_while, cm_if, cm_simple, cm_select,
|
||||
cm_connection, cm_function_def, cm_until, cm_group,
|
||||
cm_arith, cm_cond, cm_arith_for, cm_subshell, cm_coproc };
|
||||
|
||||
/* Possible values for the `flags' field of a WORD_DESC. */
|
||||
#define W_HASDOLLAR (1 << 0) /* Dollar sign present. */
|
||||
#define W_QUOTED (1 << 1) /* Some form of quote character is present. */
|
||||
#define W_ASSIGNMENT (1 << 2) /* This word is a variable assignment. */
|
||||
#define W_SPLITSPACE (1 << 3) /* Split this word on " " regardless of IFS */
|
||||
#define W_NOSPLIT (1 << 4) /* Do not perform word splitting on this word because ifs is empty string. */
|
||||
#define W_NOGLOB (1 << 5) /* Do not perform globbing on this word. */
|
||||
#define W_NOSPLIT2 (1 << 6) /* Don't split word except for $@ expansion (using spaces) because context does not allow it. */
|
||||
#define W_TILDEEXP (1 << 7) /* Tilde expand this assignment word */
|
||||
#define W_DOLLARAT (1 << 8) /* UNUSED - $@ and its special handling */
|
||||
#define W_ARRAYREF (1 << 9) /* word is a valid array reference */
|
||||
#define W_NOCOMSUB (1 << 10) /* Don't perform command substitution on this word */
|
||||
#define W_ASSIGNRHS (1 << 11) /* Word is rhs of an assignment statement */
|
||||
#define W_NOTILDE (1 << 12) /* Don't perform tilde expansion on this word */
|
||||
#define W_NOASSNTILDE (1 << 13) /* don't do tilde expansion like an assignment statement */
|
||||
#define W_EXPANDRHS (1 << 14) /* Expanding word in ${paramOPword} */
|
||||
#define W_COMPASSIGN (1 << 15) /* Compound assignment */
|
||||
#define W_ASSNBLTIN (1 << 16) /* word is a builtin command that takes assignments */
|
||||
#define W_ASSIGNARG (1 << 17) /* word is assignment argument to command */
|
||||
#define W_HASQUOTEDNULL (1 << 18) /* word contains a quoted null character */
|
||||
#define W_DQUOTE (1 << 19) /* UNUSED - word should be treated as if double-quoted */
|
||||
#define W_NOPROCSUB (1 << 20) /* don't perform process substitution */
|
||||
#define W_SAWQUOTEDNULL (1 << 21) /* word contained a quoted null that was removed */
|
||||
#define W_ASSIGNASSOC (1 << 22) /* word looks like associative array assignment */
|
||||
#define W_ASSIGNARRAY (1 << 23) /* word looks like a compound indexed array assignment */
|
||||
#define W_ARRAYIND (1 << 24) /* word is an array index being expanded */
|
||||
#define W_ASSNGLOBAL (1 << 25) /* word is a global assignment to declare (declare/typeset -g) */
|
||||
#define W_NOBRACE (1 << 26) /* Don't perform brace expansion */
|
||||
#define W_COMPLETE (1 << 27) /* word is being expanded for completion */
|
||||
#define W_CHKLOCAL (1 << 28) /* check for local vars on assignment */
|
||||
#define W_FORCELOCAL (1 << 29) /* force assignments to be to local variables, non-fatal on assignment errors */
|
||||
/* UNUSED (1 << 30) */
|
||||
|
||||
/* Flags for the `pflags' argument to param_expand() and various
|
||||
parameter_brace_expand_xxx functions; also used for string_list_dollar_at */
|
||||
#define PF_NOCOMSUB 0x01 /* Do not perform command substitution */
|
||||
#define PF_IGNUNBOUND 0x02 /* ignore unbound vars even if -u set */
|
||||
#define PF_NOSPLIT2 0x04 /* same as W_NOSPLIT2 */
|
||||
#define PF_ASSIGNRHS 0x08 /* same as W_ASSIGNRHS */
|
||||
#define PF_COMPLETE 0x10 /* same as W_COMPLETE, sets SX_COMPLETE */
|
||||
#define PF_EXPANDRHS 0x20 /* same as W_EXPANDRHS */
|
||||
#define PF_ALLINDS 0x40 /* array, act as if [@] was supplied */
|
||||
|
||||
/* Possible values for subshell_environment */
|
||||
#define SUBSHELL_ASYNC 0x01 /* subshell caused by `command &' */
|
||||
#define SUBSHELL_PAREN 0x02 /* subshell caused by ( ... ) */
|
||||
#define SUBSHELL_COMSUB 0x04 /* subshell caused by `command` or $(command) */
|
||||
#define SUBSHELL_FORK 0x08 /* subshell caused by executing a disk command */
|
||||
#define SUBSHELL_PIPE 0x10 /* subshell from a pipeline element */
|
||||
#define SUBSHELL_PROCSUB 0x20 /* subshell caused by <(command) or >(command) */
|
||||
#define SUBSHELL_COPROC 0x40 /* subshell from a coproc pipeline */
|
||||
#define SUBSHELL_RESETTRAP 0x80 /* subshell needs to reset trap strings on first call to trap */
|
||||
#define SUBSHELL_IGNTRAP 0x100 /* subshell should reset trapped signals from trap_handler */
|
||||
|
||||
/* A structure which represents a word. */
|
||||
typedef struct word_desc {
|
||||
char *word; /* Zero terminated string. */
|
||||
int flags; /* Flags associated with this word. */
|
||||
} WORD_DESC;
|
||||
|
||||
/* A linked list of words. */
|
||||
typedef struct word_list {
|
||||
struct word_list *next;
|
||||
WORD_DESC *word;
|
||||
} WORD_LIST;
|
||||
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Shell Command Structs */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* What a redirection descriptor looks like. If the redirection instruction
|
||||
is ri_duplicating_input or ri_duplicating_output, use DEST, otherwise
|
||||
use the file in FILENAME. Out-of-range descriptors are identified by a
|
||||
negative DEST. */
|
||||
|
||||
typedef union {
|
||||
int dest; /* Place to redirect REDIRECTOR to, or ... */
|
||||
WORD_DESC *filename; /* filename to redirect to. */
|
||||
} REDIRECTEE;
|
||||
|
||||
/* Structure describing a redirection. If REDIRECTOR is negative, the parser
|
||||
(or translator in redir.c) encountered an out-of-range file descriptor. */
|
||||
typedef struct redirect {
|
||||
struct redirect *next; /* Next element, or NULL. */
|
||||
REDIRECTEE redirector; /* Descriptor or varname to be redirected. */
|
||||
int rflags; /* Private flags for this redirection */
|
||||
int flags; /* Flag value for `open'. */
|
||||
enum r_instruction instruction; /* What to do with the information. */
|
||||
REDIRECTEE redirectee; /* File descriptor or filename */
|
||||
char *here_doc_eof; /* The word that appeared in <<foo. */
|
||||
} REDIRECT;
|
||||
|
||||
/* An element used in parsing. A single word or a single redirection.
|
||||
This is an ephemeral construct. */
|
||||
typedef struct element {
|
||||
WORD_DESC *word;
|
||||
REDIRECT *redirect;
|
||||
} ELEMENT;
|
||||
|
||||
/* Possible values for command->flags. */
|
||||
#define CMD_WANT_SUBSHELL 0x01 /* User wants a subshell: ( command ) */
|
||||
#define CMD_FORCE_SUBSHELL 0x02 /* Shell needs to force a subshell. */
|
||||
#define CMD_INVERT_RETURN 0x04 /* Invert the exit value. */
|
||||
#define CMD_IGNORE_RETURN 0x08 /* Ignore the exit value. For set -e. */
|
||||
#define CMD_NO_FUNCTIONS 0x10 /* Ignore functions during command lookup. */
|
||||
#define CMD_INHIBIT_EXPANSION 0x20 /* Do not expand the command words. */
|
||||
#define CMD_NO_FORK 0x40 /* Don't fork; just call execve */
|
||||
#define CMD_TIME_PIPELINE 0x80 /* Time a pipeline */
|
||||
#define CMD_TIME_POSIX 0x100 /* time -p; use POSIX.2 time output spec. */
|
||||
#define CMD_AMPERSAND 0x200 /* command & */
|
||||
#define CMD_STDIN_REDIR 0x400 /* async command needs implicit </dev/null */
|
||||
#define CMD_COMMAND_BUILTIN 0x0800 /* command executed by `command' builtin */
|
||||
#define CMD_COPROC_SUBSHELL 0x1000
|
||||
#define CMD_LASTPIPE 0x2000
|
||||
#define CMD_STDPATH 0x4000 /* use standard path for command lookup */
|
||||
#define CMD_TRY_OPTIMIZING 0x8000 /* try to optimize this simple command */
|
||||
|
||||
/* What a command looks like. */
|
||||
typedef struct command {
|
||||
enum command_type type; /* FOR CASE WHILE IF CONNECTION or SIMPLE. */
|
||||
int flags; /* Flags controlling execution environment. */
|
||||
int line; /* line number the command starts on */
|
||||
REDIRECT *redirects; /* Special redirects for FOR CASE, etc. */
|
||||
union {
|
||||
struct for_com *For;
|
||||
struct case_com *Case;
|
||||
struct while_com *While;
|
||||
struct if_com *If;
|
||||
struct connection *Connection;
|
||||
struct simple_com *Simple;
|
||||
struct function_def *Function_def;
|
||||
struct group_com *Group;
|
||||
#if defined (SELECT_COMMAND)
|
||||
struct select_com *Select;
|
||||
#endif
|
||||
#if defined (DPAREN_ARITHMETIC)
|
||||
struct arith_com *Arith;
|
||||
#endif
|
||||
#if defined (COND_COMMAND)
|
||||
struct cond_com *Cond;
|
||||
#endif
|
||||
#if defined (ARITH_FOR_COMMAND)
|
||||
struct arith_for_com *ArithFor;
|
||||
#endif
|
||||
struct subshell_com *Subshell;
|
||||
struct coproc_com *Coproc;
|
||||
} value;
|
||||
} COMMAND;
|
||||
|
||||
/* Structure used to represent the CONNECTION type. */
|
||||
typedef struct connection {
|
||||
int ignore; /* Unused; simplifies make_command (). */
|
||||
COMMAND *first; /* Pointer to the first command. */
|
||||
COMMAND *second; /* Pointer to the second command. */
|
||||
int connector; /* What separates this command from others. */
|
||||
} CONNECTION;
|
||||
|
||||
/* Structures used to represent the CASE command. */
|
||||
|
||||
/* Values for FLAGS word in a PATTERN_LIST */
|
||||
#define CASEPAT_FALLTHROUGH 0x01
|
||||
#define CASEPAT_TESTNEXT 0x02
|
||||
|
||||
/* Pattern/action structure for CASE_COM. */
|
||||
typedef struct pattern_list {
|
||||
struct pattern_list *next; /* Clause to try in case this one failed. */
|
||||
WORD_LIST *patterns; /* Linked list of patterns to test. */
|
||||
COMMAND *action; /* Thing to execute if a pattern matches. */
|
||||
int flags;
|
||||
} PATTERN_LIST;
|
||||
|
||||
/* The CASE command. */
|
||||
typedef struct case_com {
|
||||
int flags; /* See description of CMD flags. */
|
||||
int line; /* line number the `case' keyword appears on */
|
||||
WORD_DESC *word; /* The thing to test. */
|
||||
PATTERN_LIST *clauses; /* The clauses to test against, or NULL. */
|
||||
} CASE_COM;
|
||||
|
||||
/* FOR command. */
|
||||
typedef struct for_com {
|
||||
int flags; /* See description of CMD flags. */
|
||||
int line; /* line number the `for' keyword appears on */
|
||||
WORD_DESC *name; /* The variable name to get mapped over. */
|
||||
WORD_LIST *map_list; /* The things to map over. This is never NULL. */
|
||||
COMMAND *action; /* The action to execute.
|
||||
During execution, NAME is bound to successive
|
||||
members of MAP_LIST. */
|
||||
} FOR_COM;
|
||||
|
||||
#if defined (ARITH_FOR_COMMAND)
|
||||
typedef struct arith_for_com {
|
||||
int flags;
|
||||
int line; /* generally used for error messages */
|
||||
WORD_LIST *init;
|
||||
WORD_LIST *test;
|
||||
WORD_LIST *step;
|
||||
COMMAND *action;
|
||||
} ARITH_FOR_COM;
|
||||
#endif
|
||||
|
||||
#if defined (SELECT_COMMAND)
|
||||
/* KSH SELECT command. */
|
||||
typedef struct select_com {
|
||||
int flags; /* See description of CMD flags. */
|
||||
int line; /* line number the `select' keyword appears on */
|
||||
WORD_DESC *name; /* The variable name to get mapped over. */
|
||||
WORD_LIST *map_list; /* The things to map over. This is never NULL. */
|
||||
COMMAND *action; /* The action to execute.
|
||||
During execution, NAME is bound to the member of
|
||||
MAP_LIST chosen by the user. */
|
||||
} SELECT_COM;
|
||||
#endif /* SELECT_COMMAND */
|
||||
|
||||
/* IF command. */
|
||||
typedef struct if_com {
|
||||
int flags; /* See description of CMD flags. */
|
||||
COMMAND *test; /* Thing to test. */
|
||||
COMMAND *true_case; /* What to do if the test returned non-zero. */
|
||||
COMMAND *false_case; /* What to do if the test returned zero. */
|
||||
} IF_COM;
|
||||
|
||||
/* WHILE command. */
|
||||
typedef struct while_com {
|
||||
int flags; /* See description of CMD flags. */
|
||||
COMMAND *test; /* Thing to test. */
|
||||
COMMAND *action; /* Thing to do while test is non-zero. */
|
||||
} WHILE_COM;
|
||||
|
||||
#if defined (DPAREN_ARITHMETIC)
|
||||
/* The arithmetic evaluation command, ((...)). Just a set of flags and
|
||||
a WORD_LIST, of which the first element is the only one used, for the
|
||||
time being. */
|
||||
typedef struct arith_com {
|
||||
int flags;
|
||||
int line;
|
||||
WORD_LIST *exp;
|
||||
} ARITH_COM;
|
||||
#endif /* DPAREN_ARITHMETIC */
|
||||
|
||||
/* The conditional command, [[...]]. This is a binary tree -- we slipped
|
||||
a recursive-descent parser into the YACC grammar to parse it. */
|
||||
#define COND_AND 1
|
||||
#define COND_OR 2
|
||||
#define COND_UNARY 3
|
||||
#define COND_BINARY 4
|
||||
#define COND_TERM 5
|
||||
#define COND_EXPR 6
|
||||
|
||||
typedef struct cond_com {
|
||||
int flags;
|
||||
int line;
|
||||
int type;
|
||||
WORD_DESC *op;
|
||||
struct cond_com *left, *right;
|
||||
} COND_COM;
|
||||
|
||||
/* The "simple" command. Just a collection of words and redirects. */
|
||||
typedef struct simple_com {
|
||||
int flags; /* See description of CMD flags. */
|
||||
int line; /* line number the command starts on */
|
||||
WORD_LIST *words; /* The program name, the arguments,
|
||||
variable assignments, etc. */
|
||||
REDIRECT *redirects; /* Redirections to perform. */
|
||||
} SIMPLE_COM;
|
||||
|
||||
/* The "function definition" command. */
|
||||
typedef struct function_def {
|
||||
int flags; /* See description of CMD flags. */
|
||||
int line; /* Line number the function def starts on. */
|
||||
WORD_DESC *name; /* The name of the function. */
|
||||
COMMAND *command; /* The parsed execution tree. */
|
||||
char *source_file; /* file in which function was defined, if any */
|
||||
} FUNCTION_DEF;
|
||||
|
||||
/* A command that is `grouped' allows pipes and redirections to affect all
|
||||
commands in the group. */
|
||||
typedef struct group_com {
|
||||
int ignore; /* See description of CMD flags. */
|
||||
COMMAND *command;
|
||||
} GROUP_COM;
|
||||
|
||||
typedef struct subshell_com {
|
||||
int flags;
|
||||
int line;
|
||||
COMMAND *command;
|
||||
} SUBSHELL_COM;
|
||||
|
||||
#define COPROC_RUNNING 0x01
|
||||
#define COPROC_DEAD 0x02
|
||||
|
||||
typedef struct coproc {
|
||||
char *c_name;
|
||||
pid_t c_pid;
|
||||
int c_rfd;
|
||||
int c_wfd;
|
||||
int c_rsave;
|
||||
int c_wsave;
|
||||
int c_flags;
|
||||
int c_status;
|
||||
int c_lock;
|
||||
} Coproc;
|
||||
|
||||
typedef struct coproc_com {
|
||||
int flags;
|
||||
char *name;
|
||||
COMMAND *command;
|
||||
} COPROC_COM;
|
||||
|
||||
extern COMMAND *global_command;
|
||||
extern Coproc sh_coproc;
|
||||
|
||||
/* Possible command errors */
|
||||
#define CMDERR_DEFAULT 0
|
||||
#define CMDERR_BADTYPE 1
|
||||
#define CMDERR_BADCONN 2
|
||||
#define CMDERR_BADJUMP 3
|
||||
|
||||
#define CMDERR_LAST 3
|
||||
|
||||
/* Forward declarations of functions declared in copy_cmd.c. */
|
||||
|
||||
extern FUNCTION_DEF *copy_function_def_contents PARAMS((FUNCTION_DEF *, FUNCTION_DEF *));
|
||||
extern FUNCTION_DEF *copy_function_def PARAMS((FUNCTION_DEF *));
|
||||
|
||||
extern WORD_DESC *copy_word PARAMS((WORD_DESC *));
|
||||
extern WORD_LIST *copy_word_list PARAMS((WORD_LIST *));
|
||||
extern REDIRECT *copy_redirect PARAMS((REDIRECT *));
|
||||
extern REDIRECT *copy_redirects PARAMS((REDIRECT *));
|
||||
extern COMMAND *copy_command PARAMS((COMMAND *));
|
||||
|
||||
#endif /* _COMMAND_H_ */
|
1131
third_party/bash/common.c
vendored
Normal file
1131
third_party/bash/common.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
282
third_party/bash/common.h
vendored
Normal file
282
third_party/bash/common.h
vendored
Normal file
|
@ -0,0 +1,282 @@
|
|||
/* common.h -- extern declarations for functions defined in common.c. */
|
||||
|
||||
/* Copyright (C) 1993-2022 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (__COMMON_H)
|
||||
# define __COMMON_H
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
#define ISOPTION(s, c) (s[0] == '-' && s[1] == c && !s[2])
|
||||
#define ISHELP(s) (STREQ ((s), "--help"))
|
||||
|
||||
#define CHECK_HELPOPT(l) \
|
||||
do { \
|
||||
if ((l) && (l)->word && ISHELP((l)->word->word)) \
|
||||
{ \
|
||||
builtin_help (); \
|
||||
return (EX_USAGE); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CASE_HELPOPT \
|
||||
case GETOPT_HELP: \
|
||||
builtin_help (); \
|
||||
return (EX_USAGE)
|
||||
|
||||
/* Flag values for parse_and_execute () and parse_string () */
|
||||
#define SEVAL_NONINT 0x001
|
||||
#define SEVAL_INTERACT 0x002
|
||||
#define SEVAL_NOHIST 0x004
|
||||
#define SEVAL_NOFREE 0x008
|
||||
#define SEVAL_RESETLINE 0x010
|
||||
#define SEVAL_PARSEONLY 0x020
|
||||
#define SEVAL_NOLONGJMP 0x040
|
||||
#define SEVAL_FUNCDEF 0x080 /* only allow function definitions */
|
||||
#define SEVAL_ONECMD 0x100 /* only allow a single command */
|
||||
#define SEVAL_NOHISTEXP 0x200 /* inhibit history expansion */
|
||||
|
||||
/* Flags for describe_command, shared between type.def and command.def */
|
||||
#define CDESC_ALL 0x001 /* type -a */
|
||||
#define CDESC_SHORTDESC 0x002 /* command -V */
|
||||
#define CDESC_REUSABLE 0x004 /* command -v */
|
||||
#define CDESC_TYPE 0x008 /* type -t */
|
||||
#define CDESC_PATH_ONLY 0x010 /* type -p */
|
||||
#define CDESC_FORCE_PATH 0x020 /* type -ap or type -P */
|
||||
#define CDESC_NOFUNCS 0x040 /* type -f */
|
||||
#define CDESC_ABSPATH 0x080 /* convert to absolute path, no ./ */
|
||||
#define CDESC_STDPATH 0x100 /* command -p */
|
||||
|
||||
/* Flags for get_job_by_name */
|
||||
#define JM_PREFIX 0x01 /* prefix of job name */
|
||||
#define JM_SUBSTRING 0x02 /* substring of job name */
|
||||
#define JM_EXACT 0x04 /* match job name exactly */
|
||||
#define JM_STOPPED 0x08 /* match stopped jobs only */
|
||||
#define JM_FIRSTMATCH 0x10 /* return first matching job */
|
||||
|
||||
/* Flags for remember_args and value of changed_dollar_vars */
|
||||
#define ARGS_NONE 0x0
|
||||
#define ARGS_INVOC 0x01
|
||||
#define ARGS_FUNC 0x02
|
||||
#define ARGS_SETBLTIN 0x04
|
||||
|
||||
/* Maximum number of attribute letters */
|
||||
#define MAX_ATTRIBUTES 16
|
||||
|
||||
/* Functions from common.c */
|
||||
extern void builtin_error PARAMS((const char *, ...)) __attribute__((__format__ (printf, 1, 2)));
|
||||
extern void builtin_warning PARAMS((const char *, ...)) __attribute__((__format__ (printf, 1, 2)));
|
||||
extern void builtin_usage PARAMS((void));
|
||||
extern void no_args PARAMS((WORD_LIST *));
|
||||
extern int no_options PARAMS((WORD_LIST *));
|
||||
|
||||
/* common error message functions */
|
||||
extern void sh_needarg PARAMS((char *));
|
||||
extern void sh_neednumarg PARAMS((char *));
|
||||
extern void sh_notfound PARAMS((char *));
|
||||
extern void sh_invalidopt PARAMS((char *));
|
||||
extern void sh_invalidoptname PARAMS((char *));
|
||||
extern void sh_invalidid PARAMS((char *));
|
||||
extern void sh_invalidnum PARAMS((char *));
|
||||
extern void sh_invalidsig PARAMS((char *));
|
||||
extern void sh_readonly PARAMS((const char *));
|
||||
extern void sh_noassign PARAMS((const char *));
|
||||
extern void sh_erange PARAMS((char *, char *));
|
||||
extern void sh_badpid PARAMS((char *));
|
||||
extern void sh_badjob PARAMS((char *));
|
||||
extern void sh_nojobs PARAMS((char *));
|
||||
extern void sh_restricted PARAMS((char *));
|
||||
extern void sh_notbuiltin PARAMS((char *));
|
||||
extern void sh_wrerror PARAMS((void));
|
||||
extern void sh_ttyerror PARAMS((int));
|
||||
extern int sh_chkwrite PARAMS((int));
|
||||
|
||||
extern char **make_builtin_argv PARAMS((WORD_LIST *, int *));
|
||||
extern void remember_args PARAMS((WORD_LIST *, int));
|
||||
extern void shift_args PARAMS((int));
|
||||
extern int number_of_args PARAMS((void));
|
||||
|
||||
extern int dollar_vars_changed PARAMS((void));
|
||||
extern void set_dollar_vars_unchanged PARAMS((void));
|
||||
extern void set_dollar_vars_changed PARAMS((void));
|
||||
|
||||
extern int get_numeric_arg PARAMS((WORD_LIST *, int, intmax_t *));
|
||||
extern int get_exitstat PARAMS((WORD_LIST *));
|
||||
extern int read_octal PARAMS((char *));
|
||||
|
||||
/* Keeps track of the current working directory. */
|
||||
extern char *the_current_working_directory;
|
||||
extern char *get_working_directory PARAMS((char *));
|
||||
extern void set_working_directory PARAMS((char *));
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
extern int get_job_by_name PARAMS((const char *, int));
|
||||
extern int get_job_spec PARAMS((WORD_LIST *));
|
||||
#endif
|
||||
extern int display_signal_list PARAMS((WORD_LIST *, int));
|
||||
|
||||
/* It's OK to declare a function as returning a Function * without
|
||||
providing a definition of what a `Function' is. */
|
||||
extern struct builtin *builtin_address_internal PARAMS((char *, int));
|
||||
extern sh_builtin_func_t *find_shell_builtin PARAMS((char *));
|
||||
extern sh_builtin_func_t *builtin_address PARAMS((char *));
|
||||
extern sh_builtin_func_t *find_special_builtin PARAMS((char *));
|
||||
extern void initialize_shell_builtins PARAMS((void));
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
extern int set_expand_once PARAMS((int, int));
|
||||
#endif
|
||||
|
||||
/* Functions from exit.def */
|
||||
extern void bash_logout PARAMS((void));
|
||||
|
||||
/* Functions from getopts.def */
|
||||
extern void getopts_reset PARAMS((int));
|
||||
|
||||
/* Functions from help.def */
|
||||
extern void builtin_help PARAMS((void));
|
||||
|
||||
/* Functions from read.def */
|
||||
extern void read_tty_cleanup PARAMS((void));
|
||||
extern int read_tty_modified PARAMS((void));
|
||||
|
||||
extern int read_builtin_timeout PARAMS((int));
|
||||
extern void check_read_timeout PARAMS((void));
|
||||
|
||||
/* Functions from set.def */
|
||||
extern int minus_o_option_value PARAMS((char *));
|
||||
extern void list_minus_o_opts PARAMS((int, int));
|
||||
extern char **get_minus_o_opts PARAMS((void));
|
||||
extern int set_minus_o_option PARAMS((int, char *));
|
||||
|
||||
extern void set_shellopts PARAMS((void));
|
||||
extern void parse_shellopts PARAMS((char *));
|
||||
extern void initialize_shell_options PARAMS((int));
|
||||
|
||||
extern void reset_shell_options PARAMS((void));
|
||||
|
||||
extern char *get_current_options PARAMS((void));
|
||||
extern void set_current_options PARAMS((const char *));
|
||||
|
||||
/* Functions from shopt.def */
|
||||
extern void reset_shopt_options PARAMS((void));
|
||||
extern char **get_shopt_options PARAMS((void));
|
||||
|
||||
extern int shopt_setopt PARAMS((char *, int));
|
||||
extern int shopt_listopt PARAMS((char *, int));
|
||||
|
||||
extern int set_login_shell PARAMS((char *, int));
|
||||
|
||||
extern void set_bashopts PARAMS((void));
|
||||
extern void parse_bashopts PARAMS((char *));
|
||||
extern void initialize_bashopts PARAMS((int));
|
||||
|
||||
extern void set_compatibility_opts PARAMS((void));
|
||||
|
||||
/* Functions from type.def */
|
||||
extern int describe_command PARAMS((char *, int));
|
||||
|
||||
/* Functions from setattr.def */
|
||||
extern int set_or_show_attributes PARAMS((WORD_LIST *, int, int));
|
||||
extern int show_all_var_attributes PARAMS((int, int));
|
||||
extern int show_local_var_attributes PARAMS((int, int));
|
||||
extern int show_var_attributes PARAMS((SHELL_VAR *, int, int));
|
||||
extern int show_name_attributes PARAMS((char *, int));
|
||||
extern int show_localname_attributes PARAMS((char *, int));
|
||||
extern int show_func_attributes PARAMS((char *, int));
|
||||
extern void set_var_attribute PARAMS((char *, int, int));
|
||||
extern int var_attribute_string PARAMS((SHELL_VAR *, int, char *));
|
||||
|
||||
/* Functions from pushd.def */
|
||||
extern char *get_dirstack_from_string PARAMS((char *));
|
||||
extern char *get_dirstack_element PARAMS((intmax_t, int));
|
||||
extern void set_dirstack_element PARAMS((intmax_t, int, char *));
|
||||
extern WORD_LIST *get_directory_stack PARAMS((int));
|
||||
|
||||
/* Functions from evalstring.c */
|
||||
extern int parse_and_execute PARAMS((char *, const char *, int));
|
||||
extern int evalstring PARAMS((char *, const char *, int));
|
||||
extern void parse_and_execute_cleanup PARAMS((int));
|
||||
extern int parse_string PARAMS((char *, const char *, int, COMMAND **, char **));
|
||||
extern int should_suppress_fork PARAMS((COMMAND *));
|
||||
extern int can_optimize_connection PARAMS((COMMAND *));
|
||||
extern int can_optimize_cat_file PARAMS((COMMAND *));
|
||||
extern void optimize_connection_fork PARAMS((COMMAND *));
|
||||
extern void optimize_subshell_command PARAMS((COMMAND *));
|
||||
extern void optimize_shell_function PARAMS((COMMAND *));
|
||||
|
||||
/* Functions from evalfile.c */
|
||||
extern int maybe_execute_file PARAMS((const char *, int));
|
||||
extern int force_execute_file PARAMS((const char *, int));
|
||||
extern int source_file PARAMS((const char *, int));
|
||||
extern int fc_execute_file PARAMS((const char *));
|
||||
|
||||
/* variables from common.c */
|
||||
extern sh_builtin_func_t *this_shell_builtin;
|
||||
extern sh_builtin_func_t *last_shell_builtin;
|
||||
|
||||
extern SHELL_VAR *builtin_bind_variable PARAMS((char *, char *, int));
|
||||
extern SHELL_VAR *builtin_bind_var_to_int PARAMS((char *, intmax_t, int));
|
||||
extern int builtin_unbind_variable PARAMS((const char *));
|
||||
|
||||
extern SHELL_VAR *builtin_find_indexed_array PARAMS((char *, int));
|
||||
extern int builtin_arrayref_flags PARAMS((WORD_DESC *, int));
|
||||
|
||||
/* variables from evalfile.c */
|
||||
extern int sourcelevel;
|
||||
|
||||
/* variables from evalstring.c */
|
||||
extern int parse_and_execute_level;
|
||||
|
||||
/* variables from break.def/continue.def */
|
||||
extern int breaking;
|
||||
extern int continuing;
|
||||
extern int loop_level;
|
||||
|
||||
/* variables from shift.def */
|
||||
extern int print_shift_error;
|
||||
|
||||
/* variables from shopt.def */
|
||||
#if defined (ARRAY_VARS)
|
||||
extern int expand_once_flag;
|
||||
#endif
|
||||
|
||||
/* variables from source.def */
|
||||
extern int source_searches_cwd;
|
||||
extern int source_uses_path;
|
||||
|
||||
/* variables from wait.def */
|
||||
extern int wait_intr_flag;
|
||||
|
||||
/* common code to set flags for valid_array_reference and builtin_bind_variable */
|
||||
#if defined (ARRAY_VARS)
|
||||
#define SET_VFLAGS(wordflags, vflags, bindflags) \
|
||||
do { \
|
||||
vflags = assoc_expand_once ? VA_NOEXPAND : 0; \
|
||||
bindflags = assoc_expand_once ? ASS_NOEXPAND : 0; \
|
||||
if (assoc_expand_once && (wordflags & W_ARRAYREF)) \
|
||||
vflags |= VA_ONEWORD|VA_NOEXPAND; \
|
||||
if (vflags & VA_NOEXPAND) \
|
||||
bindflags |= ASS_NOEXPAND; \
|
||||
if (vflags & VA_ONEWORD) \
|
||||
bindflags |= ASS_ONEWORD; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#endif /* !__COMMON_H */
|
207
third_party/bash/config-bot.h
vendored
Normal file
207
third_party/bash/config-bot.h
vendored
Normal file
|
@ -0,0 +1,207 @@
|
|||
/* config-bot.h */
|
||||
/* modify settings or make new ones based on what autoconf tells us. */
|
||||
|
||||
/* Copyright (C) 1989-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*********************************************************/
|
||||
/* Modify or set defines based on the configure results. */
|
||||
/*********************************************************/
|
||||
|
||||
#if !defined (HAVE_VPRINTF) && defined (HAVE_DOPRNT)
|
||||
# define USE_VFPRINTF_EMULATION
|
||||
# define HAVE_VPRINTF
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_SYS_RESOURCE_H) && defined (HAVE_GETRLIMIT)
|
||||
# define HAVE_RESOURCE
|
||||
#endif
|
||||
|
||||
#if !defined (GETPGRP_VOID)
|
||||
# define HAVE_BSD_PGRP
|
||||
#endif
|
||||
|
||||
/* Try this without testing __STDC__ for the time being. */
|
||||
#if defined (HAVE_STDARG_H)
|
||||
# define PREFER_STDARG
|
||||
# define USE_VARARGS
|
||||
#else
|
||||
# if defined (HAVE_VARARGS_H)
|
||||
# define PREFER_VARARGS
|
||||
# define USE_VARARGS
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_SYS_SOCKET_H) && defined (HAVE_GETPEERNAME) && defined (HAVE_NETINET_IN_H)
|
||||
# define HAVE_NETWORK
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_REGEX_H) && defined (HAVE_REGCOMP) && defined (HAVE_REGEXEC)
|
||||
# define HAVE_POSIX_REGEXP
|
||||
#endif
|
||||
|
||||
/* backwards compatibility between different autoconf versions */
|
||||
#if HAVE_DECL_SYS_SIGLIST && !defined (SYS_SIGLIST_DECLARED)
|
||||
# define SYS_SIGLIST_DECLARED
|
||||
#endif
|
||||
|
||||
/***********************************************************************/
|
||||
/* Unset defines based on what configure reports as missing or broken. */
|
||||
/***********************************************************************/
|
||||
|
||||
/* Ultrix botches type-ahead when switching from canonical to
|
||||
non-canonical mode, at least through version 4.3 */
|
||||
#if !defined (HAVE_TERMIOS_H) || !defined (HAVE_TCGETATTR) || defined (ultrix)
|
||||
# define TERMIOS_MISSING
|
||||
#endif
|
||||
|
||||
/* If we have a getcwd(3), but one that does not dynamically allocate memory,
|
||||
#undef HAVE_GETCWD so the replacement in getcwd.c will be built. We do
|
||||
not do this on Solaris, because their implementation of loopback mounts
|
||||
breaks the traditional file system assumptions that getcwd uses. */
|
||||
#if defined (HAVE_GETCWD) && defined (GETCWD_BROKEN) && !defined (SOLARIS)
|
||||
# undef HAVE_GETCWD
|
||||
#endif
|
||||
|
||||
#if !defined (HAVE_DEV_FD) && defined (NAMED_PIPES_MISSING)
|
||||
# undef PROCESS_SUBSTITUTION
|
||||
#endif
|
||||
|
||||
#if defined (JOB_CONTROL_MISSING)
|
||||
# undef JOB_CONTROL
|
||||
#endif
|
||||
|
||||
#if defined (STRCOLL_BROKEN)
|
||||
# undef HAVE_STRCOLL
|
||||
#endif
|
||||
|
||||
#if !defined (HAVE_POSIX_REGEXP)
|
||||
# undef COND_REGEXP
|
||||
#endif
|
||||
|
||||
#if !HAVE_MKSTEMP
|
||||
# undef USE_MKSTEMP
|
||||
#endif
|
||||
|
||||
#if !HAVE_MKDTEMP
|
||||
# undef USE_MKDTEMP
|
||||
#endif
|
||||
|
||||
/* If the shell is called by this name, it will become restricted. */
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
# define RESTRICTED_SHELL_NAME "rbash"
|
||||
#endif
|
||||
|
||||
/***********************************************************/
|
||||
/* Make sure feature defines have necessary prerequisites. */
|
||||
/***********************************************************/
|
||||
|
||||
/* BANG_HISTORY requires HISTORY. */
|
||||
#if defined (BANG_HISTORY) && !defined (HISTORY)
|
||||
# define HISTORY
|
||||
#endif /* BANG_HISTORY && !HISTORY */
|
||||
|
||||
#if defined (READLINE) && !defined (HISTORY)
|
||||
# define HISTORY
|
||||
#endif
|
||||
|
||||
#if defined (PROGRAMMABLE_COMPLETION) && !defined (READLINE)
|
||||
# undef PROGRAMMABLE_COMPLETION
|
||||
#endif
|
||||
|
||||
#if !defined (V9_ECHO)
|
||||
# undef DEFAULT_ECHO_TO_XPG
|
||||
#endif
|
||||
|
||||
#if !defined (PROMPT_STRING_DECODE)
|
||||
# undef PPROMPT
|
||||
# define PPROMPT "$ "
|
||||
#endif
|
||||
|
||||
#if !defined (HAVE_SYSLOG) || !defined (HAVE_SYSLOG_H)
|
||||
# undef SYSLOG_HISTORY
|
||||
#endif
|
||||
|
||||
/************************************************/
|
||||
/* check multibyte capability for I18N code */
|
||||
/************************************************/
|
||||
|
||||
/* For platforms which support the ISO C amendment 1 functionality we
|
||||
support user defined character classes. */
|
||||
/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */
|
||||
#if defined (HAVE_WCTYPE_H) && defined (HAVE_WCHAR_H) && defined (HAVE_LOCALE_H)
|
||||
# include <wchar.h>
|
||||
# include <wctype.h>
|
||||
# if defined (HAVE_ISWCTYPE) && \
|
||||
defined (HAVE_ISWLOWER) && \
|
||||
defined (HAVE_ISWUPPER) && \
|
||||
defined (HAVE_MBSRTOWCS) && \
|
||||
defined (HAVE_MBRTOWC) && \
|
||||
defined (HAVE_MBRLEN) && \
|
||||
defined (HAVE_TOWLOWER) && \
|
||||
defined (HAVE_TOWUPPER) && \
|
||||
defined (HAVE_WCHAR_T) && \
|
||||
defined (HAVE_WCTYPE_T) && \
|
||||
defined (HAVE_WINT_T) && \
|
||||
defined (HAVE_WCWIDTH) && \
|
||||
defined (HAVE_WCTYPE)
|
||||
/* system is supposed to support XPG5 */
|
||||
# define HANDLE_MULTIBYTE 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* If we don't want multibyte chars even on a system that supports them, let
|
||||
the configuring user turn multibyte support off. */
|
||||
#if defined (NO_MULTIBYTE_SUPPORT)
|
||||
# undef HANDLE_MULTIBYTE
|
||||
#endif
|
||||
|
||||
/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */
|
||||
#if HANDLE_MULTIBYTE && !defined (HAVE_MBSTATE_T)
|
||||
# define wcsrtombs(dest, src, len, ps) (wcsrtombs) (dest, src, len, 0)
|
||||
# define mbsrtowcs(dest, src, len, ps) (mbsrtowcs) (dest, src, len, 0)
|
||||
# define wcrtomb(s, wc, ps) (wcrtomb) (s, wc, 0)
|
||||
# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
|
||||
# define mbrlen(s, n, ps) (mbrlen) (s, n, 0)
|
||||
# define mbstate_t int
|
||||
#endif
|
||||
|
||||
/* Make sure MB_LEN_MAX is at least 16 (some systems define
|
||||
MB_LEN_MAX as 1) */
|
||||
#ifdef HANDLE_MULTIBYTE
|
||||
# include <limits.h>
|
||||
# if defined(MB_LEN_MAX) && (MB_LEN_MAX < 16)
|
||||
# undef MB_LEN_MAX
|
||||
# endif
|
||||
# if !defined (MB_LEN_MAX)
|
||||
# define MB_LEN_MAX 16
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/************************************************/
|
||||
/* end of multibyte capability checks for I18N */
|
||||
/************************************************/
|
||||
|
||||
/******************************************************************/
|
||||
/* Placeholder for builders to #undef any unwanted features from */
|
||||
/* config-top.h or created by configure (such as the default mail */
|
||||
/* file for mail checking). */
|
||||
/******************************************************************/
|
||||
|
||||
/* If you don't want bash to provide a default mail file to check. */
|
||||
/* #undef DEFAULT_MAIL_DIRECTORY */
|
201
third_party/bash/config-top.h
vendored
Normal file
201
third_party/bash/config-top.h
vendored
Normal file
|
@ -0,0 +1,201 @@
|
|||
/* config-top.h - various user-settable options not under the control of autoconf. */
|
||||
|
||||
/* Copyright (C) 2002-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Define CONTINUE_AFTER_KILL_ERROR if you want the kill command to
|
||||
continue processing arguments after one of them fails. This is
|
||||
what POSIX.2 specifies. */
|
||||
#define CONTINUE_AFTER_KILL_ERROR
|
||||
|
||||
/* Define BREAK_COMPLAINS if you want the non-standard, but useful
|
||||
error messages about `break' and `continue' out of context. */
|
||||
#define BREAK_COMPLAINS
|
||||
|
||||
/* Define CD_COMPLAINS if you want the non-standard, but sometimes-desired
|
||||
error messages about multiple directory arguments to `cd'. */
|
||||
#define CD_COMPLAINS
|
||||
|
||||
/* Define BUFFERED_INPUT if you want the shell to do its own input
|
||||
buffering, rather than using stdio. Do not undefine this; it's
|
||||
required to preserve semantics required by POSIX. */
|
||||
#define BUFFERED_INPUT
|
||||
|
||||
/* Define ONESHOT if you want sh -c 'command' to avoid forking to execute
|
||||
`command' whenever possible. This is a big efficiency improvement. */
|
||||
#define ONESHOT
|
||||
|
||||
/* Define V9_ECHO if you want to give the echo builtin backslash-escape
|
||||
interpretation using the -e option, in the style of the Bell Labs 9th
|
||||
Edition version of echo. You cannot emulate the System V echo behavior
|
||||
without this option. */
|
||||
#define V9_ECHO
|
||||
|
||||
/* Define DONT_REPORT_SIGPIPE if you don't want to see `Broken pipe' messages
|
||||
when a job like `cat jobs.c | exit 1' terminates due to a SIGPIPE. */
|
||||
#define DONT_REPORT_SIGPIPE
|
||||
|
||||
/* Define DONT_REPORT_SIGTERM if you don't want to see `Terminates' message
|
||||
when a job exits due to SIGTERM, since that's the default signal sent
|
||||
by the kill builtin. */
|
||||
#define DONT_REPORT_SIGTERM
|
||||
|
||||
/* Define DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS if you don't want builtins
|
||||
like `echo' and `printf' to report errors when output does not succeed
|
||||
due to EPIPE. */
|
||||
/* #define DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS */
|
||||
|
||||
/* The default value of the PATH variable. */
|
||||
#ifndef DEFAULT_PATH_VALUE
|
||||
#define DEFAULT_PATH_VALUE \
|
||||
"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:."
|
||||
#endif
|
||||
|
||||
/* If you want to unconditionally set a value for PATH in every restricted
|
||||
shell, set this. */
|
||||
/* #define RBASH_STATIC_PATH_VALUE "/rbin:/usr/rbin" */
|
||||
|
||||
/* The value for PATH when invoking `command -p'. This is only used when
|
||||
the Posix.2 confstr () function, or CS_PATH define are not present. */
|
||||
#ifndef STANDARD_UTILS_PATH
|
||||
#define STANDARD_UTILS_PATH \
|
||||
"/bin:/usr/bin:/sbin:/usr/sbin:/etc:/usr/etc"
|
||||
#endif
|
||||
|
||||
/* The default path for enable -f */
|
||||
#ifndef DEFAULT_LOADABLE_BUILTINS_PATH
|
||||
#define DEFAULT_LOADABLE_BUILTINS_PATH \
|
||||
"/usr/local/lib/bash:/usr/lib/bash:/opt/local/lib/bash:/usr/pkg/lib/bash:/opt/pkg/lib/bash:."
|
||||
#endif
|
||||
|
||||
/* Default primary and secondary prompt strings. */
|
||||
#define PPROMPT "\\s-\\v\\$ "
|
||||
#define SPROMPT "> "
|
||||
|
||||
/* Undefine this if you don't want the ksh-compatible behavior of reprinting
|
||||
the select menu after a valid choice is made only if REPLY is set to NULL
|
||||
in the body of the select command. The menu is always reprinted if the
|
||||
reply to the select query is an empty line. */
|
||||
#define KSH_COMPATIBLE_SELECT
|
||||
|
||||
/* Default interactive shell startup file. */
|
||||
#define DEFAULT_BASHRC "~/.bashrc"
|
||||
|
||||
/* System-wide .bashrc file for interactive shells. */
|
||||
/* #define SYS_BASHRC "/etc/bash.bashrc" */
|
||||
|
||||
/* System-wide .bash_logout for login shells. */
|
||||
/* #define SYS_BASH_LOGOUT "/etc/bash.bash_logout" */
|
||||
|
||||
/* Define this to make non-interactive shells begun with argv[0][0] == '-'
|
||||
run the startup files when not in posix mode. */
|
||||
/* #define NON_INTERACTIVE_LOGIN_SHELLS */
|
||||
|
||||
/* Define this if you want bash to try to check whether it's being run by
|
||||
sshd and source the .bashrc if so (like the rshd behavior). This checks
|
||||
for the presence of SSH_CLIENT or SSH2_CLIENT in the initial environment,
|
||||
which can be fooled under certain not-uncommon circumstances. */
|
||||
/* #define SSH_SOURCE_BASHRC */
|
||||
|
||||
/* Define if you want the case-toggling operators (~[~]) and the
|
||||
`capcase' variable attribute (declare -c). */
|
||||
/* TAG: bash-5.2 disable? */
|
||||
#define CASEMOD_TOGGLECASE
|
||||
#define CASEMOD_CAPCASE
|
||||
|
||||
/* This is used as the name of a shell function to call when a command
|
||||
name is not found. If you want to name it something other than the
|
||||
default ("command_not_found_handle"), change it here. */
|
||||
/* #define NOTFOUND_HOOK "command_not_found_handle" */
|
||||
|
||||
/* Define if you want each line saved to the history list in bashhist.c:
|
||||
bash_add_history() to be sent to syslog(). */
|
||||
/* #define SYSLOG_HISTORY */
|
||||
#if defined (SYSLOG_HISTORY)
|
||||
# define SYSLOG_FACILITY LOG_USER
|
||||
# define SYSLOG_LEVEL LOG_INFO
|
||||
# define OPENLOG_OPTS LOG_PID
|
||||
#endif
|
||||
|
||||
/* Define if you want syslogging history to be controllable at runtime via a
|
||||
shell option; if defined, the value is the default for the syslog_history
|
||||
shopt option */
|
||||
#if defined (SYSLOG_HISTORY)
|
||||
/* #define SYSLOG_SHOPT 1 */
|
||||
#endif
|
||||
|
||||
/* Define if you want to include code in shell.c to support wordexp(3) */
|
||||
/* #define WORDEXP_OPTION */
|
||||
|
||||
/* Define as 1 if you want to enable code that implements multiple coprocs
|
||||
executing simultaneously */
|
||||
#ifndef MULTIPLE_COPROCS
|
||||
# define MULTIPLE_COPROCS 0
|
||||
#endif
|
||||
|
||||
/* Define to 0 if you want the checkwinsize option off by default, 1 if you
|
||||
want it on. */
|
||||
#define CHECKWINSIZE_DEFAULT 1
|
||||
|
||||
/* Define to 1 if you want to optimize for sequential array assignment when
|
||||
using indexed arrays, 0 if you want bash-4.2 behavior, which favors
|
||||
random access but is O(N) for each array assignment. */
|
||||
#define OPTIMIZE_SEQUENTIAL_ARRAY_ASSIGNMENT 1
|
||||
|
||||
/* Define to 1 if you want to be able to export indexed arrays to processes
|
||||
using the foo=([0]=one [1]=two) and so on */
|
||||
/* #define ARRAY_EXPORT 1 */
|
||||
|
||||
/* Define to 1 if you want the shell to exit if it is running setuid and its
|
||||
attempt to drop privilege using setuid(getuid()) fails with errno == EAGAIN */
|
||||
/* #define EXIT_ON_SETUID_FAILURE 1 */
|
||||
|
||||
/* Define to 1 if you want the shell to re-check $PATH if a hashed filename
|
||||
no longer exists. This behavior is the default in Posix mode. */
|
||||
#define CHECKHASH_DEFAULT 0
|
||||
|
||||
/* Define to the maximum level of recursion you want for the eval builtin
|
||||
and trap handlers (since traps are run as if run by eval).
|
||||
0 means the limit is not active. */
|
||||
#define EVALNEST_MAX 0
|
||||
|
||||
/* Define to the maximum level of recursion you want for the source/. builtin.
|
||||
0 means the limit is not active. */
|
||||
#define SOURCENEST_MAX 0
|
||||
|
||||
/* Define to use libc mktemp/mkstemp instead of replacements in lib/sh/tmpfile.c */
|
||||
#define USE_MKTEMP
|
||||
#define USE_MKSTEMP
|
||||
#define USE_MKDTEMP
|
||||
|
||||
/* Define to force the value of OLDPWD inherited from the environment to be a
|
||||
directory */
|
||||
#define OLDPWD_CHECK_DIRECTORY 1
|
||||
|
||||
/* Define to set the initial size of the history list ($HISTSIZE). This must
|
||||
be a string. */
|
||||
/*#define HISTSIZE_DEFAULT "500"*/
|
||||
|
||||
/* Define to 0 if you want history expansion to be disabled by default in
|
||||
interactive shells; define to 1 for the historical behavior of enabling
|
||||
when the shell is interactive. */
|
||||
#define HISTEXPAND_DEFAULT 1
|
||||
|
||||
/* Undefine or define to 0 if you don't want to allow associative array
|
||||
assignment using a compound list of key-value pairs. */
|
||||
#define ASSOC_KVPAIR_ASSIGNMENT 1
|
1235
third_party/bash/config.h
vendored
Normal file
1235
third_party/bash/config.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
58
third_party/bash/conftypes.h
vendored
Normal file
58
third_party/bash/conftypes.h
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
/* conftypes.h -- defines for build and host system. */
|
||||
|
||||
/* Copyright (C) 2001, 2005, 2008,2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (_CONFTYPES_H_)
|
||||
#define _CONFTYPES_H_
|
||||
|
||||
/* Placeholder for future modifications if cross-compiling or building a
|
||||
`fat' binary, e.g. on Apple Rhapsody. These values are used in multiple
|
||||
files, so they appear here. */
|
||||
#if !defined (RHAPSODY) && !defined (MACOSX)
|
||||
# define HOSTTYPE CONF_HOSTTYPE
|
||||
# define OSTYPE CONF_OSTYPE
|
||||
# define MACHTYPE CONF_MACHTYPE
|
||||
#else /* RHAPSODY */
|
||||
# if defined(__powerpc__) || defined(__ppc__)
|
||||
# define HOSTTYPE "powerpc"
|
||||
# elif defined(__i386__)
|
||||
# define HOSTTYPE "i386"
|
||||
# else
|
||||
# define HOSTTYPE CONF_HOSTTYPE
|
||||
# endif
|
||||
|
||||
# define OSTYPE CONF_OSTYPE
|
||||
# define VENDOR CONF_VENDOR
|
||||
|
||||
# define MACHTYPE HOSTTYPE "-" VENDOR "-" OSTYPE
|
||||
#endif /* RHAPSODY */
|
||||
|
||||
#ifndef HOSTTYPE
|
||||
# define HOSTTYPE "unknown"
|
||||
#endif
|
||||
|
||||
#ifndef OSTYPE
|
||||
# define OSTYPE "unknown"
|
||||
#endif
|
||||
|
||||
#ifndef MACHTYPE
|
||||
# define MACHTYPE "unknown"
|
||||
#endif
|
||||
|
||||
#endif /* _CONFTYPES_H_ */
|
459
third_party/bash/copy_cmd.c
vendored
Normal file
459
third_party/bash/copy_cmd.c
vendored
Normal file
|
@ -0,0 +1,459 @@
|
|||
/* copy_command.c -- copy a COMMAND structure. This is needed
|
||||
primarily for making function definitions, but I'm not sure
|
||||
that anyone else will need it. */
|
||||
|
||||
/* Copyright (C) 1987-2020 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "bashtypes.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
static PATTERN_LIST *copy_case_clause PARAMS((PATTERN_LIST *));
|
||||
static PATTERN_LIST *copy_case_clauses PARAMS((PATTERN_LIST *));
|
||||
static FOR_COM *copy_for_command PARAMS((FOR_COM *));
|
||||
#if defined (ARITH_FOR_COMMAND)
|
||||
static ARITH_FOR_COM *copy_arith_for_command PARAMS((ARITH_FOR_COM *));
|
||||
#endif
|
||||
static GROUP_COM *copy_group_command PARAMS((GROUP_COM *));
|
||||
static SUBSHELL_COM *copy_subshell_command PARAMS((SUBSHELL_COM *));
|
||||
static COPROC_COM *copy_coproc_command PARAMS((COPROC_COM *));
|
||||
static CASE_COM *copy_case_command PARAMS((CASE_COM *));
|
||||
static WHILE_COM *copy_while_command PARAMS((WHILE_COM *));
|
||||
static IF_COM *copy_if_command PARAMS((IF_COM *));
|
||||
#if defined (DPAREN_ARITHMETIC)
|
||||
static ARITH_COM *copy_arith_command PARAMS((ARITH_COM *));
|
||||
#endif
|
||||
#if defined (COND_COMMAND)
|
||||
static COND_COM *copy_cond_command PARAMS((COND_COM *));
|
||||
#endif
|
||||
static SIMPLE_COM *copy_simple_command PARAMS((SIMPLE_COM *));
|
||||
|
||||
WORD_DESC *
|
||||
copy_word (w)
|
||||
WORD_DESC *w;
|
||||
{
|
||||
WORD_DESC *new_word;
|
||||
|
||||
new_word = make_bare_word (w->word);
|
||||
new_word->flags = w->flags;
|
||||
return (new_word);
|
||||
}
|
||||
|
||||
/* Copy the chain of words in LIST. Return a pointer to
|
||||
the new chain. */
|
||||
WORD_LIST *
|
||||
copy_word_list (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
WORD_LIST *new_list, *tl;
|
||||
|
||||
for (new_list = tl = (WORD_LIST *)NULL; list; list = list->next)
|
||||
{
|
||||
if (new_list == 0)
|
||||
new_list = tl = make_word_list (copy_word (list->word), new_list);
|
||||
else
|
||||
{
|
||||
tl->next = make_word_list (copy_word (list->word), (WORD_LIST *)NULL);
|
||||
tl = tl->next;
|
||||
}
|
||||
}
|
||||
|
||||
return (new_list);
|
||||
}
|
||||
|
||||
static PATTERN_LIST *
|
||||
copy_case_clause (clause)
|
||||
PATTERN_LIST *clause;
|
||||
{
|
||||
PATTERN_LIST *new_clause;
|
||||
|
||||
new_clause = (PATTERN_LIST *)xmalloc (sizeof (PATTERN_LIST));
|
||||
new_clause->patterns = copy_word_list (clause->patterns);
|
||||
new_clause->action = copy_command (clause->action);
|
||||
new_clause->flags = clause->flags;
|
||||
return (new_clause);
|
||||
}
|
||||
|
||||
static PATTERN_LIST *
|
||||
copy_case_clauses (clauses)
|
||||
PATTERN_LIST *clauses;
|
||||
{
|
||||
PATTERN_LIST *new_list, *new_clause;
|
||||
|
||||
for (new_list = (PATTERN_LIST *)NULL; clauses; clauses = clauses->next)
|
||||
{
|
||||
new_clause = copy_case_clause (clauses);
|
||||
new_clause->next = new_list;
|
||||
new_list = new_clause;
|
||||
}
|
||||
return (REVERSE_LIST (new_list, PATTERN_LIST *));
|
||||
}
|
||||
|
||||
/* Copy a single redirect. */
|
||||
REDIRECT *
|
||||
copy_redirect (redirect)
|
||||
REDIRECT *redirect;
|
||||
{
|
||||
REDIRECT *new_redirect;
|
||||
|
||||
new_redirect = (REDIRECT *)xmalloc (sizeof (REDIRECT));
|
||||
#if 0
|
||||
FASTCOPY ((char *)redirect, (char *)new_redirect, (sizeof (REDIRECT)));
|
||||
#else
|
||||
*new_redirect = *redirect; /* let the compiler do the fast structure copy */
|
||||
#endif
|
||||
|
||||
if (redirect->rflags & REDIR_VARASSIGN)
|
||||
new_redirect->redirector.filename = copy_word (redirect->redirector.filename);
|
||||
|
||||
switch (redirect->instruction)
|
||||
{
|
||||
case r_reading_until:
|
||||
case r_deblank_reading_until:
|
||||
new_redirect->here_doc_eof = redirect->here_doc_eof ? savestring (redirect->here_doc_eof) : 0;
|
||||
/*FALLTHROUGH*/
|
||||
case r_reading_string:
|
||||
case r_appending_to:
|
||||
case r_output_direction:
|
||||
case r_input_direction:
|
||||
case r_inputa_direction:
|
||||
case r_err_and_out:
|
||||
case r_append_err_and_out:
|
||||
case r_input_output:
|
||||
case r_output_force:
|
||||
case r_duplicating_input_word:
|
||||
case r_duplicating_output_word:
|
||||
case r_move_input_word:
|
||||
case r_move_output_word:
|
||||
new_redirect->redirectee.filename = copy_word (redirect->redirectee.filename);
|
||||
break;
|
||||
case r_duplicating_input:
|
||||
case r_duplicating_output:
|
||||
case r_move_input:
|
||||
case r_move_output:
|
||||
case r_close_this:
|
||||
break;
|
||||
}
|
||||
return (new_redirect);
|
||||
}
|
||||
|
||||
REDIRECT *
|
||||
copy_redirects (list)
|
||||
REDIRECT *list;
|
||||
{
|
||||
REDIRECT *new_list, *temp;
|
||||
|
||||
for (new_list = (REDIRECT *)NULL; list; list = list->next)
|
||||
{
|
||||
temp = copy_redirect (list);
|
||||
temp->next = new_list;
|
||||
new_list = temp;
|
||||
}
|
||||
return (REVERSE_LIST (new_list, REDIRECT *));
|
||||
}
|
||||
|
||||
static FOR_COM *
|
||||
copy_for_command (com)
|
||||
FOR_COM *com;
|
||||
{
|
||||
FOR_COM *new_for;
|
||||
|
||||
new_for = (FOR_COM *)xmalloc (sizeof (FOR_COM));
|
||||
new_for->flags = com->flags;
|
||||
new_for->line = com->line;
|
||||
new_for->name = copy_word (com->name);
|
||||
new_for->map_list = copy_word_list (com->map_list);
|
||||
new_for->action = copy_command (com->action);
|
||||
return (new_for);
|
||||
}
|
||||
|
||||
#if defined (ARITH_FOR_COMMAND)
|
||||
static ARITH_FOR_COM *
|
||||
copy_arith_for_command (com)
|
||||
ARITH_FOR_COM *com;
|
||||
{
|
||||
ARITH_FOR_COM *new_arith_for;
|
||||
|
||||
new_arith_for = (ARITH_FOR_COM *)xmalloc (sizeof (ARITH_FOR_COM));
|
||||
new_arith_for->flags = com->flags;
|
||||
new_arith_for->line = com->line;
|
||||
new_arith_for->init = copy_word_list (com->init);
|
||||
new_arith_for->test = copy_word_list (com->test);
|
||||
new_arith_for->step = copy_word_list (com->step);
|
||||
new_arith_for->action = copy_command (com->action);
|
||||
return (new_arith_for);
|
||||
}
|
||||
#endif /* ARITH_FOR_COMMAND */
|
||||
|
||||
static GROUP_COM *
|
||||
copy_group_command (com)
|
||||
GROUP_COM *com;
|
||||
{
|
||||
GROUP_COM *new_group;
|
||||
|
||||
new_group = (GROUP_COM *)xmalloc (sizeof (GROUP_COM));
|
||||
new_group->command = copy_command (com->command);
|
||||
return (new_group);
|
||||
}
|
||||
|
||||
static SUBSHELL_COM *
|
||||
copy_subshell_command (com)
|
||||
SUBSHELL_COM *com;
|
||||
{
|
||||
SUBSHELL_COM *new_subshell;
|
||||
|
||||
new_subshell = (SUBSHELL_COM *)xmalloc (sizeof (SUBSHELL_COM));
|
||||
new_subshell->command = copy_command (com->command);
|
||||
new_subshell->flags = com->flags;
|
||||
new_subshell->line = com->line;
|
||||
return (new_subshell);
|
||||
}
|
||||
|
||||
static COPROC_COM *
|
||||
copy_coproc_command (com)
|
||||
COPROC_COM *com;
|
||||
{
|
||||
COPROC_COM *new_coproc;
|
||||
|
||||
new_coproc = (COPROC_COM *)xmalloc (sizeof (COPROC_COM));
|
||||
new_coproc->name = savestring (com->name);
|
||||
new_coproc->command = copy_command (com->command);
|
||||
new_coproc->flags = com->flags;
|
||||
return (new_coproc);
|
||||
}
|
||||
|
||||
static CASE_COM *
|
||||
copy_case_command (com)
|
||||
CASE_COM *com;
|
||||
{
|
||||
CASE_COM *new_case;
|
||||
|
||||
new_case = (CASE_COM *)xmalloc (sizeof (CASE_COM));
|
||||
new_case->flags = com->flags;
|
||||
new_case->line = com->line;
|
||||
new_case->word = copy_word (com->word);
|
||||
new_case->clauses = copy_case_clauses (com->clauses);
|
||||
return (new_case);
|
||||
}
|
||||
|
||||
static WHILE_COM *
|
||||
copy_while_command (com)
|
||||
WHILE_COM *com;
|
||||
{
|
||||
WHILE_COM *new_while;
|
||||
|
||||
new_while = (WHILE_COM *)xmalloc (sizeof (WHILE_COM));
|
||||
new_while->flags = com->flags;
|
||||
new_while->test = copy_command (com->test);
|
||||
new_while->action = copy_command (com->action);
|
||||
return (new_while);
|
||||
}
|
||||
|
||||
static IF_COM *
|
||||
copy_if_command (com)
|
||||
IF_COM *com;
|
||||
{
|
||||
IF_COM *new_if;
|
||||
|
||||
new_if = (IF_COM *)xmalloc (sizeof (IF_COM));
|
||||
new_if->flags = com->flags;
|
||||
new_if->test = copy_command (com->test);
|
||||
new_if->true_case = copy_command (com->true_case);
|
||||
new_if->false_case = com->false_case ? copy_command (com->false_case) : com->false_case;
|
||||
return (new_if);
|
||||
}
|
||||
|
||||
#if defined (DPAREN_ARITHMETIC)
|
||||
static ARITH_COM *
|
||||
copy_arith_command (com)
|
||||
ARITH_COM *com;
|
||||
{
|
||||
ARITH_COM *new_arith;
|
||||
|
||||
new_arith = (ARITH_COM *)xmalloc (sizeof (ARITH_COM));
|
||||
new_arith->flags = com->flags;
|
||||
new_arith->exp = copy_word_list (com->exp);
|
||||
new_arith->line = com->line;
|
||||
|
||||
return (new_arith);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (COND_COMMAND)
|
||||
static COND_COM *
|
||||
copy_cond_command (com)
|
||||
COND_COM *com;
|
||||
{
|
||||
COND_COM *new_cond;
|
||||
|
||||
new_cond = (COND_COM *)xmalloc (sizeof (COND_COM));
|
||||
new_cond->flags = com->flags;
|
||||
new_cond->line = com->line;
|
||||
new_cond->type = com->type;
|
||||
new_cond->op = com->op ? copy_word (com->op) : com->op;
|
||||
new_cond->left = com->left ? copy_cond_command (com->left) : (COND_COM *)NULL;
|
||||
new_cond->right = com->right ? copy_cond_command (com->right) : (COND_COM *)NULL;
|
||||
|
||||
return (new_cond);
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_COM *
|
||||
copy_simple_command (com)
|
||||
SIMPLE_COM *com;
|
||||
{
|
||||
SIMPLE_COM *new_simple;
|
||||
|
||||
new_simple = (SIMPLE_COM *)xmalloc (sizeof (SIMPLE_COM));
|
||||
new_simple->flags = com->flags;
|
||||
new_simple->words = copy_word_list (com->words);
|
||||
new_simple->redirects = com->redirects ? copy_redirects (com->redirects) : (REDIRECT *)NULL;
|
||||
new_simple->line = com->line;
|
||||
return (new_simple);
|
||||
}
|
||||
|
||||
FUNCTION_DEF *
|
||||
copy_function_def_contents (old, new_def)
|
||||
FUNCTION_DEF *old, *new_def;
|
||||
{
|
||||
new_def->name = copy_word (old->name);
|
||||
new_def->command = old->command ? copy_command (old->command) : old->command;
|
||||
new_def->flags = old->flags;
|
||||
new_def->line = old->line;
|
||||
new_def->source_file = old->source_file ? savestring (old->source_file) : old->source_file;
|
||||
return (new_def);
|
||||
}
|
||||
|
||||
FUNCTION_DEF *
|
||||
copy_function_def (com)
|
||||
FUNCTION_DEF *com;
|
||||
{
|
||||
FUNCTION_DEF *new_def;
|
||||
|
||||
new_def = (FUNCTION_DEF *)xmalloc (sizeof (FUNCTION_DEF));
|
||||
new_def = copy_function_def_contents (com, new_def);
|
||||
return (new_def);
|
||||
}
|
||||
|
||||
/* Copy the command structure in COMMAND. Return a pointer to the
|
||||
copy. Don't you forget to dispose_command () on this pointer
|
||||
later! */
|
||||
COMMAND *
|
||||
copy_command (command)
|
||||
COMMAND *command;
|
||||
{
|
||||
COMMAND *new_command;
|
||||
|
||||
if (command == NULL)
|
||||
return (command);
|
||||
|
||||
new_command = (COMMAND *)xmalloc (sizeof (COMMAND));
|
||||
FASTCOPY ((char *)command, (char *)new_command, sizeof (COMMAND));
|
||||
new_command->flags = command->flags;
|
||||
new_command->line = command->line;
|
||||
|
||||
if (command->redirects)
|
||||
new_command->redirects = copy_redirects (command->redirects);
|
||||
|
||||
switch (command->type)
|
||||
{
|
||||
case cm_for:
|
||||
new_command->value.For = copy_for_command (command->value.For);
|
||||
break;
|
||||
|
||||
#if defined (ARITH_FOR_COMMAND)
|
||||
case cm_arith_for:
|
||||
new_command->value.ArithFor = copy_arith_for_command (command->value.ArithFor);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined (SELECT_COMMAND)
|
||||
case cm_select:
|
||||
new_command->value.Select =
|
||||
(SELECT_COM *)copy_for_command ((FOR_COM *)command->value.Select);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case cm_group:
|
||||
new_command->value.Group = copy_group_command (command->value.Group);
|
||||
break;
|
||||
|
||||
case cm_subshell:
|
||||
new_command->value.Subshell = copy_subshell_command (command->value.Subshell);
|
||||
break;
|
||||
|
||||
case cm_coproc:
|
||||
new_command->value.Coproc = copy_coproc_command (command->value.Coproc);
|
||||
break;
|
||||
|
||||
case cm_case:
|
||||
new_command->value.Case = copy_case_command (command->value.Case);
|
||||
break;
|
||||
|
||||
case cm_until:
|
||||
case cm_while:
|
||||
new_command->value.While = copy_while_command (command->value.While);
|
||||
break;
|
||||
|
||||
case cm_if:
|
||||
new_command->value.If = copy_if_command (command->value.If);
|
||||
break;
|
||||
|
||||
#if defined (DPAREN_ARITHMETIC)
|
||||
case cm_arith:
|
||||
new_command->value.Arith = copy_arith_command (command->value.Arith);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined (COND_COMMAND)
|
||||
case cm_cond:
|
||||
new_command->value.Cond = copy_cond_command (command->value.Cond);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case cm_simple:
|
||||
new_command->value.Simple = copy_simple_command (command->value.Simple);
|
||||
break;
|
||||
|
||||
case cm_connection:
|
||||
{
|
||||
CONNECTION *new_connection;
|
||||
|
||||
new_connection = (CONNECTION *)xmalloc (sizeof (CONNECTION));
|
||||
new_connection->connector = command->value.Connection->connector;
|
||||
new_connection->first = copy_command (command->value.Connection->first);
|
||||
new_connection->second = copy_command (command->value.Connection->second);
|
||||
new_command->value.Connection = new_connection;
|
||||
break;
|
||||
}
|
||||
|
||||
case cm_function_def:
|
||||
new_command->value.Function_def = copy_function_def (command->value.Function_def);
|
||||
break;
|
||||
}
|
||||
return (new_command);
|
||||
}
|
342
third_party/bash/dispose_cmd.c
vendored
Normal file
342
third_party/bash/dispose_cmd.c
vendored
Normal file
|
@ -0,0 +1,342 @@
|
|||
/* dispose_command.c -- dispose of a COMMAND structure. */
|
||||
|
||||
/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "bashtypes.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "shell.h"
|
||||
|
||||
extern sh_obj_cache_t wdcache, wlcache;
|
||||
|
||||
/* Dispose of the command structure passed. */
|
||||
void
|
||||
dispose_command (command)
|
||||
COMMAND *command;
|
||||
{
|
||||
if (command == 0)
|
||||
return;
|
||||
|
||||
if (command->redirects)
|
||||
dispose_redirects (command->redirects);
|
||||
|
||||
switch (command->type)
|
||||
{
|
||||
case cm_for:
|
||||
#if defined (SELECT_COMMAND)
|
||||
case cm_select:
|
||||
#endif
|
||||
{
|
||||
register FOR_COM *c;
|
||||
#if defined (SELECT_COMMAND)
|
||||
if (command->type == cm_select)
|
||||
c = (FOR_COM *)command->value.Select;
|
||||
else
|
||||
#endif
|
||||
c = command->value.For;
|
||||
dispose_word (c->name);
|
||||
dispose_words (c->map_list);
|
||||
dispose_command (c->action);
|
||||
free (c);
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined (ARITH_FOR_COMMAND)
|
||||
case cm_arith_for:
|
||||
{
|
||||
register ARITH_FOR_COM *c;
|
||||
|
||||
c = command->value.ArithFor;
|
||||
dispose_words (c->init);
|
||||
dispose_words (c->test);
|
||||
dispose_words (c->step);
|
||||
dispose_command (c->action);
|
||||
free (c);
|
||||
break;
|
||||
}
|
||||
#endif /* ARITH_FOR_COMMAND */
|
||||
|
||||
case cm_group:
|
||||
{
|
||||
dispose_command (command->value.Group->command);
|
||||
free (command->value.Group);
|
||||
break;
|
||||
}
|
||||
|
||||
case cm_subshell:
|
||||
{
|
||||
dispose_command (command->value.Subshell->command);
|
||||
free (command->value.Subshell);
|
||||
break;
|
||||
}
|
||||
|
||||
case cm_coproc:
|
||||
{
|
||||
free (command->value.Coproc->name);
|
||||
dispose_command (command->value.Coproc->command);
|
||||
free (command->value.Coproc);
|
||||
break;
|
||||
}
|
||||
|
||||
case cm_case:
|
||||
{
|
||||
register CASE_COM *c;
|
||||
PATTERN_LIST *t, *p;
|
||||
|
||||
c = command->value.Case;
|
||||
dispose_word (c->word);
|
||||
|
||||
for (p = c->clauses; p; )
|
||||
{
|
||||
dispose_words (p->patterns);
|
||||
dispose_command (p->action);
|
||||
t = p;
|
||||
p = p->next;
|
||||
free (t);
|
||||
}
|
||||
free (c);
|
||||
break;
|
||||
}
|
||||
|
||||
case cm_until:
|
||||
case cm_while:
|
||||
{
|
||||
register WHILE_COM *c;
|
||||
|
||||
c = command->value.While;
|
||||
dispose_command (c->test);
|
||||
dispose_command (c->action);
|
||||
free (c);
|
||||
break;
|
||||
}
|
||||
|
||||
case cm_if:
|
||||
{
|
||||
register IF_COM *c;
|
||||
|
||||
c = command->value.If;
|
||||
dispose_command (c->test);
|
||||
dispose_command (c->true_case);
|
||||
dispose_command (c->false_case);
|
||||
free (c);
|
||||
break;
|
||||
}
|
||||
|
||||
case cm_simple:
|
||||
{
|
||||
register SIMPLE_COM *c;
|
||||
|
||||
c = command->value.Simple;
|
||||
dispose_words (c->words);
|
||||
dispose_redirects (c->redirects);
|
||||
free (c);
|
||||
break;
|
||||
}
|
||||
|
||||
case cm_connection:
|
||||
{
|
||||
register CONNECTION *c;
|
||||
|
||||
c = command->value.Connection;
|
||||
dispose_command (c->first);
|
||||
dispose_command (c->second);
|
||||
free (c);
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined (DPAREN_ARITHMETIC)
|
||||
case cm_arith:
|
||||
{
|
||||
register ARITH_COM *c;
|
||||
|
||||
c = command->value.Arith;
|
||||
dispose_words (c->exp);
|
||||
free (c);
|
||||
break;
|
||||
}
|
||||
#endif /* DPAREN_ARITHMETIC */
|
||||
|
||||
#if defined (COND_COMMAND)
|
||||
case cm_cond:
|
||||
{
|
||||
register COND_COM *c;
|
||||
|
||||
c = command->value.Cond;
|
||||
dispose_cond_node (c);
|
||||
break;
|
||||
}
|
||||
#endif /* COND_COMMAND */
|
||||
|
||||
case cm_function_def:
|
||||
{
|
||||
register FUNCTION_DEF *c;
|
||||
|
||||
c = command->value.Function_def;
|
||||
dispose_function_def (c);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
command_error ("dispose_command", CMDERR_BADTYPE, command->type, 0);
|
||||
break;
|
||||
}
|
||||
free (command);
|
||||
}
|
||||
|
||||
#if defined (COND_COMMAND)
|
||||
/* How to free a node in a conditional command. */
|
||||
void
|
||||
dispose_cond_node (cond)
|
||||
COND_COM *cond;
|
||||
{
|
||||
if (cond)
|
||||
{
|
||||
if (cond->left)
|
||||
dispose_cond_node (cond->left);
|
||||
if (cond->right)
|
||||
dispose_cond_node (cond->right);
|
||||
if (cond->op)
|
||||
dispose_word (cond->op);
|
||||
free (cond);
|
||||
}
|
||||
}
|
||||
#endif /* COND_COMMAND */
|
||||
|
||||
void
|
||||
dispose_function_def_contents (c)
|
||||
FUNCTION_DEF *c;
|
||||
{
|
||||
dispose_word (c->name);
|
||||
dispose_command (c->command);
|
||||
FREE (c->source_file);
|
||||
}
|
||||
|
||||
void
|
||||
dispose_function_def (c)
|
||||
FUNCTION_DEF *c;
|
||||
{
|
||||
dispose_function_def_contents (c);
|
||||
free (c);
|
||||
}
|
||||
|
||||
/* How to free a WORD_DESC. */
|
||||
void
|
||||
dispose_word (w)
|
||||
WORD_DESC *w;
|
||||
{
|
||||
FREE (w->word);
|
||||
ocache_free (wdcache, WORD_DESC, w);
|
||||
}
|
||||
|
||||
/* Free a WORD_DESC, but not the word contained within. */
|
||||
void
|
||||
dispose_word_desc (w)
|
||||
WORD_DESC *w;
|
||||
{
|
||||
w->word = 0;
|
||||
ocache_free (wdcache, WORD_DESC, w);
|
||||
}
|
||||
|
||||
/* How to get rid of a linked list of words. A WORD_LIST. */
|
||||
void
|
||||
dispose_words (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
WORD_LIST *t;
|
||||
|
||||
while (list)
|
||||
{
|
||||
t = list;
|
||||
list = list->next;
|
||||
dispose_word (t->word);
|
||||
#if 0
|
||||
free (t);
|
||||
#else
|
||||
ocache_free (wlcache, WORD_LIST, t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_UNUSED
|
||||
/* How to dispose of an array of pointers to char. This is identical to
|
||||
free_array in stringlib.c. */
|
||||
void
|
||||
dispose_word_array (array)
|
||||
char **array;
|
||||
{
|
||||
register int count;
|
||||
|
||||
if (array == 0)
|
||||
return;
|
||||
|
||||
for (count = 0; array[count]; count++)
|
||||
free (array[count]);
|
||||
|
||||
free (array);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* How to dispose of an list of redirections. A REDIRECT. */
|
||||
void
|
||||
dispose_redirects (list)
|
||||
REDIRECT *list;
|
||||
{
|
||||
register REDIRECT *t;
|
||||
|
||||
while (list)
|
||||
{
|
||||
t = list;
|
||||
list = list->next;
|
||||
|
||||
if (t->rflags & REDIR_VARASSIGN)
|
||||
dispose_word (t->redirector.filename);
|
||||
|
||||
switch (t->instruction)
|
||||
{
|
||||
case r_reading_until:
|
||||
case r_deblank_reading_until:
|
||||
free (t->here_doc_eof);
|
||||
/*FALLTHROUGH*/
|
||||
case r_reading_string:
|
||||
case r_output_direction:
|
||||
case r_input_direction:
|
||||
case r_inputa_direction:
|
||||
case r_appending_to:
|
||||
case r_err_and_out:
|
||||
case r_append_err_and_out:
|
||||
case r_input_output:
|
||||
case r_output_force:
|
||||
case r_duplicating_input_word:
|
||||
case r_duplicating_output_word:
|
||||
case r_move_input_word:
|
||||
case r_move_output_word:
|
||||
dispose_word (t->redirectee.filename);
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free (t);
|
||||
}
|
||||
}
|
40
third_party/bash/dispose_cmd.h
vendored
Normal file
40
third_party/bash/dispose_cmd.h
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
/* dispose_cmd.h -- Functions appearing in dispose_cmd.c. */
|
||||
|
||||
/* Copyright (C) 1993-2020 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (_DISPOSE_CMD_H_)
|
||||
#define _DISPOSE_CMD_H_
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
extern void dispose_command PARAMS((COMMAND *));
|
||||
extern void dispose_word_desc PARAMS((WORD_DESC *));
|
||||
extern void dispose_word PARAMS((WORD_DESC *));
|
||||
extern void dispose_words PARAMS((WORD_LIST *));
|
||||
extern void dispose_word_array PARAMS((char **));
|
||||
extern void dispose_redirects PARAMS((REDIRECT *));
|
||||
|
||||
#if defined (COND_COMMAND)
|
||||
extern void dispose_cond_node PARAMS((COND_COM *));
|
||||
#endif
|
||||
|
||||
extern void dispose_function_def_contents PARAMS((FUNCTION_DEF *));
|
||||
extern void dispose_function_def PARAMS((FUNCTION_DEF *));
|
||||
|
||||
#endif /* !_DISPOSE_CMD_H_ */
|
244
third_party/bash/eaccess.c
vendored
Normal file
244
third_party/bash/eaccess.c
vendored
Normal file
|
@ -0,0 +1,244 @@
|
|||
/* eaccess.c - eaccess replacement for the shell, plus other access functions. */
|
||||
|
||||
/* Copyright (C) 2006-2020 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined (HAVE_CONFIG_H)
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bashtypes.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
|
||||
#include <errno.h>
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
#if !defined (_POSIX_VERSION) && defined (HAVE_SYS_FILE_H)
|
||||
# include <sys/file.h>
|
||||
#endif /* !_POSIX_VERSION */
|
||||
#include "posixstat.h"
|
||||
#include "filecntl.h"
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
#if !defined (R_OK)
|
||||
#define R_OK 4
|
||||
#define W_OK 2
|
||||
#define X_OK 1
|
||||
#define F_OK 0
|
||||
#endif /* R_OK */
|
||||
|
||||
static int path_is_devfd PARAMS((const char *));
|
||||
static int sh_stataccess PARAMS((const char *, int));
|
||||
#if HAVE_DECL_SETREGID
|
||||
static int sh_euidaccess PARAMS((const char *, int));
|
||||
#endif
|
||||
|
||||
static int
|
||||
path_is_devfd (path)
|
||||
const char *path;
|
||||
{
|
||||
if (path[0] == '/' && path[1] == 'd' && strncmp (path, "/dev/fd/", 8) == 0)
|
||||
return 1;
|
||||
else if (STREQN (path, "/dev/std", 8))
|
||||
{
|
||||
if (STREQ (path+8, "in") || STREQ (path+8, "out") || STREQ (path+8, "err"))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A wrapper for stat () which disallows pathnames that are empty strings
|
||||
and handles /dev/fd emulation on systems that don't have it. */
|
||||
int
|
||||
sh_stat (path, finfo)
|
||||
const char *path;
|
||||
struct stat *finfo;
|
||||
{
|
||||
static char *pbuf = 0;
|
||||
|
||||
if (*path == '\0')
|
||||
{
|
||||
errno = ENOENT;
|
||||
return (-1);
|
||||
}
|
||||
if (path[0] == '/' && path[1] == 'd' && strncmp (path, "/dev/fd/", 8) == 0)
|
||||
{
|
||||
/* If stating /dev/fd/n doesn't produce the same results as fstat of
|
||||
FD N, then define DEV_FD_STAT_BROKEN */
|
||||
#if !defined (HAVE_DEV_FD) || defined (DEV_FD_STAT_BROKEN)
|
||||
intmax_t fd;
|
||||
int r;
|
||||
|
||||
if (legal_number (path + 8, &fd) && fd == (int)fd)
|
||||
{
|
||||
r = fstat ((int)fd, finfo);
|
||||
if (r == 0 || errno != EBADF)
|
||||
return (r);
|
||||
}
|
||||
errno = ENOENT;
|
||||
return (-1);
|
||||
#else
|
||||
/* If HAVE_DEV_FD is defined, DEV_FD_PREFIX is defined also, and has a
|
||||
trailing slash. Make sure /dev/fd/xx really uses DEV_FD_PREFIX/xx.
|
||||
On most systems, with the notable exception of linux, this is
|
||||
effectively a no-op. */
|
||||
pbuf = xrealloc (pbuf, sizeof (DEV_FD_PREFIX) + strlen (path + 8));
|
||||
strcpy (pbuf, DEV_FD_PREFIX);
|
||||
strcat (pbuf, path + 8);
|
||||
return (stat (pbuf, finfo));
|
||||
#endif /* !HAVE_DEV_FD */
|
||||
}
|
||||
#if !defined (HAVE_DEV_STDIN)
|
||||
else if (STREQN (path, "/dev/std", 8))
|
||||
{
|
||||
if (STREQ (path+8, "in"))
|
||||
return (fstat (0, finfo));
|
||||
else if (STREQ (path+8, "out"))
|
||||
return (fstat (1, finfo));
|
||||
else if (STREQ (path+8, "err"))
|
||||
return (fstat (2, finfo));
|
||||
else
|
||||
return (stat (path, finfo));
|
||||
}
|
||||
#endif /* !HAVE_DEV_STDIN */
|
||||
return (stat (path, finfo));
|
||||
}
|
||||
|
||||
/* Do the same thing access(2) does, but use the effective uid and gid,
|
||||
and don't make the mistake of telling root that any file is
|
||||
executable. This version uses stat(2). */
|
||||
static int
|
||||
sh_stataccess (path, mode)
|
||||
const char *path;
|
||||
int mode;
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (sh_stat (path, &st) < 0)
|
||||
return (-1);
|
||||
|
||||
if (current_user.euid == 0)
|
||||
{
|
||||
/* Root can read or write any file. */
|
||||
if ((mode & X_OK) == 0)
|
||||
return (0);
|
||||
|
||||
/* Root can execute any file that has any one of the execute
|
||||
bits set. */
|
||||
if (st.st_mode & S_IXUGO)
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (st.st_uid == current_user.euid) /* owner */
|
||||
mode <<= 6;
|
||||
else if (group_member (st.st_gid))
|
||||
mode <<= 3;
|
||||
|
||||
if (st.st_mode & mode)
|
||||
return (0);
|
||||
|
||||
errno = EACCES;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
#if HAVE_DECL_SETREGID
|
||||
/* Version to call when uid != euid or gid != egid. We temporarily swap
|
||||
the effective and real uid and gid as appropriate. */
|
||||
static int
|
||||
sh_euidaccess (path, mode)
|
||||
const char *path;
|
||||
int mode;
|
||||
{
|
||||
int r, e;
|
||||
|
||||
if (current_user.uid != current_user.euid)
|
||||
setreuid (current_user.euid, current_user.uid);
|
||||
if (current_user.gid != current_user.egid)
|
||||
setregid (current_user.egid, current_user.gid);
|
||||
|
||||
r = access (path, mode);
|
||||
e = errno;
|
||||
|
||||
if (current_user.uid != current_user.euid)
|
||||
setreuid (current_user.uid, current_user.euid);
|
||||
if (current_user.gid != current_user.egid)
|
||||
setregid (current_user.gid, current_user.egid);
|
||||
|
||||
errno = e;
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
sh_eaccess (path, mode)
|
||||
const char *path;
|
||||
int mode;
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (path_is_devfd (path))
|
||||
return (sh_stataccess (path, mode));
|
||||
|
||||
#if (defined (HAVE_FACCESSAT) && defined (AT_EACCESS)) || defined (HAVE_EACCESS)
|
||||
# if defined (HAVE_FACCESSAT) && defined (AT_EACCESS)
|
||||
ret = faccessat (AT_FDCWD, path, mode, AT_EACCESS);
|
||||
# else /* HAVE_EACCESS */ /* FreeBSD */
|
||||
ret = eaccess (path, mode); /* XXX -- not always correct for X_OK */
|
||||
# endif /* HAVE_EACCESS */
|
||||
# if defined (__FreeBSD__) || defined (SOLARIS) || defined (_AIX)
|
||||
if (ret == 0 && current_user.euid == 0 && mode == X_OK)
|
||||
return (sh_stataccess (path, mode));
|
||||
# endif /* __FreeBSD__ || SOLARIS || _AIX */
|
||||
return ret;
|
||||
#elif defined (EFF_ONLY_OK) /* SVR4(?), SVR4.2 */
|
||||
return access (path, mode|EFF_ONLY_OK);
|
||||
#else
|
||||
if (mode == F_OK)
|
||||
return (sh_stataccess (path, mode));
|
||||
|
||||
# if HAVE_DECL_SETREGID
|
||||
if (current_user.uid != current_user.euid || current_user.gid != current_user.egid)
|
||||
return (sh_euidaccess (path, mode));
|
||||
# endif
|
||||
|
||||
if (current_user.uid == current_user.euid && current_user.gid == current_user.egid)
|
||||
{
|
||||
ret = access (path, mode);
|
||||
#if defined (__FreeBSD__) || defined (SOLARIS)
|
||||
if (ret == 0 && current_user.euid == 0 && mode == X_OK)
|
||||
return (sh_stataccess (path, mode));
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
return (sh_stataccess (path, mode));
|
||||
#endif
|
||||
}
|
537
third_party/bash/error.c
vendored
Normal file
537
third_party/bash/error.c
vendored
Normal file
|
@ -0,0 +1,537 @@
|
|||
/* error.c -- Functions for handling errors. */
|
||||
|
||||
/* Copyright (C) 1993-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "bashtypes.h"
|
||||
#include <fcntl.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined (PREFER_STDARG)
|
||||
# include <stdarg.h>
|
||||
#else
|
||||
# include <varargs.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <errno.h>
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "execute_cmd.h"
|
||||
#include "flags.h"
|
||||
#include "input.h"
|
||||
|
||||
#if defined (HISTORY)
|
||||
# include "bashhist.h"
|
||||
#endif
|
||||
|
||||
extern int executing_line_number PARAMS((void));
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
extern pid_t shell_pgrp;
|
||||
extern int give_terminal_to PARAMS((pid_t, int));
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
extern const char * const bash_badsub_errmsg;
|
||||
#endif
|
||||
|
||||
static void error_prolog PARAMS((int));
|
||||
|
||||
/* The current maintainer of the shell. You change this in the
|
||||
Makefile. */
|
||||
#if !defined (MAINTAINER)
|
||||
#define MAINTAINER "bash-maintainers@gnu.org"
|
||||
#endif
|
||||
|
||||
const char * const the_current_maintainer = MAINTAINER;
|
||||
|
||||
int gnu_error_format = 0;
|
||||
|
||||
static void
|
||||
error_prolog (print_lineno)
|
||||
int print_lineno;
|
||||
{
|
||||
char *ename;
|
||||
int line;
|
||||
|
||||
ename = get_name_for_error ();
|
||||
line = (print_lineno && interactive_shell == 0) ? executing_line_number () : -1;
|
||||
|
||||
if (line > 0)
|
||||
fprintf (stderr, "%s:%s%d: ", ename, gnu_error_format ? "" : _(" line "), line);
|
||||
else
|
||||
fprintf (stderr, "%s: ", ename);
|
||||
}
|
||||
|
||||
/* Return the name of the shell or the shell script for error reporting. */
|
||||
char *
|
||||
get_name_for_error ()
|
||||
{
|
||||
char *name;
|
||||
#if defined (ARRAY_VARS)
|
||||
SHELL_VAR *bash_source_v;
|
||||
ARRAY *bash_source_a;
|
||||
#endif
|
||||
|
||||
name = (char *)NULL;
|
||||
if (interactive_shell == 0)
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
bash_source_v = find_variable ("BASH_SOURCE");
|
||||
if (bash_source_v && array_p (bash_source_v) &&
|
||||
(bash_source_a = array_cell (bash_source_v)))
|
||||
name = array_reference (bash_source_a, 0);
|
||||
if (name == 0 || *name == '\0') /* XXX - was just name == 0 */
|
||||
#endif
|
||||
name = dollar_vars[0];
|
||||
}
|
||||
if (name == 0 && shell_name && *shell_name)
|
||||
name = base_pathname (shell_name);
|
||||
if (name == 0)
|
||||
#if defined (PROGRAM)
|
||||
name = PROGRAM;
|
||||
#else
|
||||
name = "bash";
|
||||
#endif
|
||||
|
||||
return (name);
|
||||
}
|
||||
|
||||
/* Report an error having to do with FILENAME. This does not use
|
||||
sys_error so the filename is not interpreted as a printf-style
|
||||
format string. */
|
||||
void
|
||||
file_error (filename)
|
||||
const char *filename;
|
||||
{
|
||||
report_error ("%s: %s", filename, strerror (errno));
|
||||
}
|
||||
|
||||
void
|
||||
#if defined (PREFER_STDARG)
|
||||
programming_error (const char *format, ...)
|
||||
#else
|
||||
programming_error (format, va_alist)
|
||||
const char *format;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list args;
|
||||
char *h;
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
give_terminal_to (shell_pgrp, 0);
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
SH_VA_START (args, format);
|
||||
|
||||
vfprintf (stderr, format, args);
|
||||
fprintf (stderr, "\n");
|
||||
va_end (args);
|
||||
|
||||
#if defined (HISTORY)
|
||||
if (remember_on_history)
|
||||
{
|
||||
h = last_history_line ();
|
||||
fprintf (stderr, _("last command: %s\n"), h ? h : "(null)");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
fprintf (stderr, "Report this to %s\n", the_current_maintainer);
|
||||
#endif
|
||||
|
||||
fprintf (stderr, _("Aborting..."));
|
||||
fflush (stderr);
|
||||
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* Print an error message and, if `set -e' has been executed, exit the
|
||||
shell. Used in this file by file_error and programming_error. Used
|
||||
outside this file mostly to report substitution and expansion errors,
|
||||
and for bad invocation options. */
|
||||
void
|
||||
#if defined (PREFER_STDARG)
|
||||
report_error (const char *format, ...)
|
||||
#else
|
||||
report_error (format, va_alist)
|
||||
const char *format;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list args;
|
||||
|
||||
error_prolog (1);
|
||||
|
||||
SH_VA_START (args, format);
|
||||
|
||||
vfprintf (stderr, format, args);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
va_end (args);
|
||||
if (exit_immediately_on_error)
|
||||
{
|
||||
if (last_command_exit_value == 0)
|
||||
last_command_exit_value = EXECUTION_FAILURE;
|
||||
exit_shell (last_command_exit_value);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
#if defined (PREFER_STDARG)
|
||||
fatal_error (const char *format, ...)
|
||||
#else
|
||||
fatal_error (format, va_alist)
|
||||
const char *format;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list args;
|
||||
|
||||
error_prolog (0);
|
||||
|
||||
SH_VA_START (args, format);
|
||||
|
||||
vfprintf (stderr, format, args);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
va_end (args);
|
||||
sh_exit (2);
|
||||
}
|
||||
|
||||
void
|
||||
#if defined (PREFER_STDARG)
|
||||
internal_error (const char *format, ...)
|
||||
#else
|
||||
internal_error (format, va_alist)
|
||||
const char *format;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list args;
|
||||
|
||||
error_prolog (1);
|
||||
|
||||
SH_VA_START (args, format);
|
||||
|
||||
vfprintf (stderr, format, args);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
void
|
||||
#if defined (PREFER_STDARG)
|
||||
internal_warning (const char *format, ...)
|
||||
#else
|
||||
internal_warning (format, va_alist)
|
||||
const char *format;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list args;
|
||||
|
||||
error_prolog (1);
|
||||
fprintf (stderr, _("warning: "));
|
||||
|
||||
SH_VA_START (args, format);
|
||||
|
||||
vfprintf (stderr, format, args);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
void
|
||||
#if defined (PREFER_STDARG)
|
||||
internal_inform (const char *format, ...)
|
||||
#else
|
||||
internal_inform (format, va_alist)
|
||||
const char *format;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list args;
|
||||
|
||||
error_prolog (1);
|
||||
/* TRANSLATORS: this is a prefix for informational messages. */
|
||||
fprintf (stderr, _("INFORM: "));
|
||||
|
||||
SH_VA_START (args, format);
|
||||
|
||||
vfprintf (stderr, format, args);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
void
|
||||
#if defined (PREFER_STDARG)
|
||||
internal_debug (const char *format, ...)
|
||||
#else
|
||||
internal_debug (format, va_alist)
|
||||
const char *format;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
#ifdef DEBUG
|
||||
va_list args;
|
||||
|
||||
error_prolog (1);
|
||||
fprintf (stderr, _("DEBUG warning: "));
|
||||
|
||||
SH_VA_START (args, format);
|
||||
|
||||
vfprintf (stderr, format, args);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
va_end (args);
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
#if defined (PREFER_STDARG)
|
||||
sys_error (const char *format, ...)
|
||||
#else
|
||||
sys_error (format, va_alist)
|
||||
const char *format;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
int e;
|
||||
va_list args;
|
||||
|
||||
e = errno;
|
||||
error_prolog (0);
|
||||
|
||||
SH_VA_START (args, format);
|
||||
|
||||
vfprintf (stderr, format, args);
|
||||
fprintf (stderr, ": %s\n", strerror (e));
|
||||
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
/* An error from the parser takes the general form
|
||||
|
||||
shell_name: input file name: line number: message
|
||||
|
||||
The input file name and line number are omitted if the shell is
|
||||
currently interactive. If the shell is not currently interactive,
|
||||
the input file name is inserted only if it is different from the
|
||||
shell name. */
|
||||
void
|
||||
#if defined (PREFER_STDARG)
|
||||
parser_error (int lineno, const char *format, ...)
|
||||
#else
|
||||
parser_error (lineno, format, va_alist)
|
||||
int lineno;
|
||||
const char *format;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list args;
|
||||
char *ename, *iname;
|
||||
|
||||
ename = get_name_for_error ();
|
||||
iname = yy_input_name ();
|
||||
|
||||
if (interactive)
|
||||
fprintf (stderr, "%s: ", ename);
|
||||
else if (interactive_shell)
|
||||
fprintf (stderr, "%s: %s:%s%d: ", ename, iname, gnu_error_format ? "" : _(" line "), lineno);
|
||||
else if (STREQ (ename, iname))
|
||||
fprintf (stderr, "%s:%s%d: ", ename, gnu_error_format ? "" : _(" line "), lineno);
|
||||
else
|
||||
fprintf (stderr, "%s: %s:%s%d: ", ename, iname, gnu_error_format ? "" : _(" line "), lineno);
|
||||
|
||||
SH_VA_START (args, format);
|
||||
|
||||
vfprintf (stderr, format, args);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
va_end (args);
|
||||
|
||||
if (exit_immediately_on_error)
|
||||
exit_shell (last_command_exit_value = 2);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
/* This assumes ASCII and is suitable only for debugging */
|
||||
char *
|
||||
strescape (str)
|
||||
const char *str;
|
||||
{
|
||||
char *r, *result;
|
||||
unsigned char *s;
|
||||
|
||||
r = result = (char *)xmalloc (strlen (str) * 2 + 1);
|
||||
|
||||
for (s = (unsigned char *)str; s && *s; s++)
|
||||
{
|
||||
if (*s < ' ')
|
||||
{
|
||||
*r++ = '^';
|
||||
*r++ = *s+64;
|
||||
}
|
||||
else if (*s == 127)
|
||||
{
|
||||
*r++ = '^';
|
||||
*r++ = '?';
|
||||
}
|
||||
else
|
||||
*r++ = *s;
|
||||
}
|
||||
|
||||
*r = '\0';
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
#if defined (PREFER_STDARG)
|
||||
itrace (const char *format, ...)
|
||||
#else
|
||||
itrace (format, va_alist)
|
||||
const char *format;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list args;
|
||||
|
||||
fprintf(stderr, "TRACE: pid %ld: ", (long)getpid());
|
||||
|
||||
SH_VA_START (args, format);
|
||||
|
||||
vfprintf (stderr, format, args);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
va_end (args);
|
||||
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
/* A trace function for silent debugging -- doesn't require a control
|
||||
terminal. */
|
||||
void
|
||||
#if defined (PREFER_STDARG)
|
||||
trace (const char *format, ...)
|
||||
#else
|
||||
trace (format, va_alist)
|
||||
const char *format;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list args;
|
||||
static FILE *tracefp = (FILE *)NULL;
|
||||
|
||||
if (tracefp == NULL)
|
||||
tracefp = fopen("/tmp/bash-trace.log", "a+");
|
||||
|
||||
if (tracefp == NULL)
|
||||
tracefp = stderr;
|
||||
else
|
||||
fcntl (fileno (tracefp), F_SETFD, 1); /* close-on-exec */
|
||||
|
||||
fprintf(tracefp, "TRACE: pid %ld: ", (long)getpid());
|
||||
|
||||
SH_VA_START (args, format);
|
||||
|
||||
vfprintf (tracefp, format, args);
|
||||
fprintf (tracefp, "\n");
|
||||
|
||||
va_end (args);
|
||||
|
||||
fflush(tracefp);
|
||||
}
|
||||
|
||||
#endif /* DEBUG */
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Common error reporting */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
|
||||
static const char * const cmd_error_table[] = {
|
||||
N_("unknown command error"), /* CMDERR_DEFAULT */
|
||||
N_("bad command type"), /* CMDERR_BADTYPE */
|
||||
N_("bad connector"), /* CMDERR_BADCONN */
|
||||
N_("bad jump"), /* CMDERR_BADJUMP */
|
||||
0
|
||||
};
|
||||
|
||||
void
|
||||
command_error (func, code, e, flags)
|
||||
const char *func;
|
||||
int code, e, flags; /* flags currently unused */
|
||||
{
|
||||
if (code > CMDERR_LAST)
|
||||
code = CMDERR_DEFAULT;
|
||||
|
||||
programming_error ("%s: %s: %d", func, _(cmd_error_table[code]), e);
|
||||
}
|
||||
|
||||
char *
|
||||
command_errstr (code)
|
||||
int code;
|
||||
{
|
||||
if (code > CMDERR_LAST)
|
||||
code = CMDERR_DEFAULT;
|
||||
|
||||
return (_(cmd_error_table[code]));
|
||||
}
|
||||
|
||||
#ifdef ARRAY_VARS
|
||||
void
|
||||
err_badarraysub (s)
|
||||
const char *s;
|
||||
{
|
||||
report_error ("%s: %s", s, _(bash_badsub_errmsg));
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
err_unboundvar (s)
|
||||
const char *s;
|
||||
{
|
||||
report_error (_("%s: unbound variable"), s);
|
||||
}
|
||||
|
||||
void
|
||||
err_readonly (s)
|
||||
const char *s;
|
||||
{
|
||||
report_error (_("%s: readonly variable"), s);
|
||||
}
|
82
third_party/bash/error.h
vendored
Normal file
82
third_party/bash/error.h
vendored
Normal file
|
@ -0,0 +1,82 @@
|
|||
/* error.h -- External declarations of functions appearing in error.c. */
|
||||
|
||||
/* Copyright (C) 1993-2020 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (_ERROR_H_)
|
||||
#define _ERROR_H_
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
/* Get the name of the shell or shell script for an error message. */
|
||||
extern char *get_name_for_error PARAMS((void));
|
||||
|
||||
/* Report an error having to do with FILENAME. */
|
||||
extern void file_error PARAMS((const char *));
|
||||
|
||||
/* Report a programmer's error, and abort. Pass REASON, and ARG1 ... ARG5. */
|
||||
extern void programming_error PARAMS((const char *, ...)) __attribute__((__format__ (printf, 1, 2)));
|
||||
|
||||
/* General error reporting. Pass FORMAT and ARG1 ... ARG5. */
|
||||
extern void report_error PARAMS((const char *, ...)) __attribute__((__format__ (printf, 1, 2)));
|
||||
|
||||
/* Error messages for parts of the parser that don't call report_syntax_error */
|
||||
extern void parser_error PARAMS((int, const char *, ...)) __attribute__((__format__ (printf, 2, 3)));
|
||||
|
||||
/* Report an unrecoverable error and exit. Pass FORMAT and ARG1 ... ARG5. */
|
||||
extern void fatal_error PARAMS((const char *, ...)) __attribute__((__format__ (printf, 1, 2)));
|
||||
|
||||
/* Report a system error, like BSD warn(3). */
|
||||
extern void sys_error PARAMS((const char *, ...)) __attribute__((__format__ (printf, 1, 2)));
|
||||
|
||||
/* Report an internal error. */
|
||||
extern void internal_error PARAMS((const char *, ...)) __attribute__((__format__ (printf, 1, 2)));
|
||||
|
||||
/* Report an internal warning. */
|
||||
extern void internal_warning PARAMS((const char *, ...)) __attribute__((__format__ (printf, 1, 2)));
|
||||
|
||||
/* Report an internal warning for debugging purposes. */
|
||||
extern void internal_debug PARAMS((const char *, ...)) __attribute__((__format__ (printf, 1, 2)));
|
||||
|
||||
/* Report an internal informational notice. */
|
||||
extern void internal_inform PARAMS((const char *, ...)) __attribute__((__format__ (printf, 1, 2)));
|
||||
|
||||
/* Debugging functions, not enabled in released version. */
|
||||
extern char *strescape PARAMS((const char *));
|
||||
extern void itrace PARAMS((const char *, ...)) __attribute__ ((__format__ (printf, 1, 2)));
|
||||
extern void trace PARAMS((const char *, ...)) __attribute__ ((__format__ (printf, 1, 2)));
|
||||
|
||||
/* Report an error having to do with command parsing or execution. */
|
||||
extern void command_error PARAMS((const char *, int, int, int));
|
||||
|
||||
extern char *command_errstr PARAMS((int));
|
||||
|
||||
/* Specific error message functions that eventually call report_error or
|
||||
internal_error. */
|
||||
|
||||
extern void err_badarraysub PARAMS((const char *));
|
||||
extern void err_unboundvar PARAMS((const char *));
|
||||
extern void err_readonly PARAMS((const char *));
|
||||
|
||||
#ifdef DEBUG
|
||||
# define INTERNAL_DEBUG(x) internal_debug x
|
||||
#else
|
||||
# define INTERNAL_DEBUG(x)
|
||||
#endif
|
||||
|
||||
#endif /* !_ERROR_H_ */
|
401
third_party/bash/eval.c
vendored
Normal file
401
third_party/bash/eval.c
vendored
Normal file
|
@ -0,0 +1,401 @@
|
|||
/* eval.c -- reading and evaluating commands. */
|
||||
|
||||
/* Copyright (C) 1996-2022 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "parser.h"
|
||||
#include "flags.h"
|
||||
#include "trap.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "input.h"
|
||||
#include "execute_cmd.h"
|
||||
|
||||
#if defined (HISTORY)
|
||||
# include "bashhist.h"
|
||||
#endif
|
||||
|
||||
static void send_pwd_to_eterm PARAMS((void));
|
||||
static sighandler alrm_catcher PARAMS((int));
|
||||
|
||||
/* Read and execute commands until EOF is reached. This assumes that
|
||||
the input source has already been initialized. */
|
||||
int
|
||||
reader_loop ()
|
||||
{
|
||||
int our_indirection_level;
|
||||
COMMAND * volatile current_command;
|
||||
|
||||
USE_VAR(current_command);
|
||||
|
||||
current_command = (COMMAND *)NULL;
|
||||
|
||||
our_indirection_level = ++indirection_level;
|
||||
|
||||
if (just_one_command)
|
||||
reset_readahead_token ();
|
||||
|
||||
while (EOF_Reached == 0)
|
||||
{
|
||||
int code;
|
||||
|
||||
code = setjmp_nosigs (top_level);
|
||||
|
||||
#if defined (PROCESS_SUBSTITUTION)
|
||||
unlink_fifo_list ();
|
||||
#endif /* PROCESS_SUBSTITUTION */
|
||||
|
||||
/* XXX - why do we set this every time through the loop? And why do
|
||||
it if SIGINT is trapped in an interactive shell? */
|
||||
if (interactive_shell && signal_is_ignored (SIGINT) == 0 && signal_is_trapped (SIGINT) == 0)
|
||||
set_signal_handler (SIGINT, sigint_sighandler);
|
||||
|
||||
if (code != NOT_JUMPED)
|
||||
{
|
||||
indirection_level = our_indirection_level;
|
||||
|
||||
switch (code)
|
||||
{
|
||||
/* Some kind of throw to top_level has occurred. */
|
||||
case ERREXIT:
|
||||
if (exit_immediately_on_error)
|
||||
reset_local_contexts (); /* not in a function */
|
||||
case FORCE_EOF:
|
||||
case EXITPROG:
|
||||
case EXITBLTIN:
|
||||
current_command = (COMMAND *)NULL;
|
||||
EOF_Reached = EOF;
|
||||
goto exec_done;
|
||||
|
||||
case DISCARD:
|
||||
/* Make sure the exit status is reset to a non-zero value, but
|
||||
leave existing non-zero values (e.g., > 128 on signal)
|
||||
alone. */
|
||||
if (last_command_exit_value == 0)
|
||||
set_exit_status (EXECUTION_FAILURE);
|
||||
if (subshell_environment)
|
||||
{
|
||||
current_command = (COMMAND *)NULL;
|
||||
EOF_Reached = EOF;
|
||||
goto exec_done;
|
||||
}
|
||||
/* Obstack free command elements, etc. */
|
||||
if (current_command)
|
||||
{
|
||||
dispose_command (current_command);
|
||||
current_command = (COMMAND *)NULL;
|
||||
}
|
||||
|
||||
restore_sigmask ();
|
||||
break;
|
||||
|
||||
default:
|
||||
command_error ("reader_loop", CMDERR_BADJUMP, code, 0);
|
||||
}
|
||||
}
|
||||
|
||||
executing = 0;
|
||||
if (temporary_env)
|
||||
dispose_used_env_vars ();
|
||||
|
||||
#if (defined (ultrix) && defined (mips)) || defined (C_ALLOCA)
|
||||
/* Attempt to reclaim memory allocated with alloca (). */
|
||||
(void) alloca (0);
|
||||
#endif
|
||||
|
||||
if (read_command () == 0)
|
||||
{
|
||||
if (interactive_shell == 0 && read_but_dont_execute)
|
||||
{
|
||||
set_exit_status (last_command_exit_value);
|
||||
dispose_command (global_command);
|
||||
global_command = (COMMAND *)NULL;
|
||||
}
|
||||
else if (current_command = global_command)
|
||||
{
|
||||
global_command = (COMMAND *)NULL;
|
||||
|
||||
/* If the shell is interactive, expand and display $PS0 after reading a
|
||||
command (possibly a list or pipeline) and before executing it. */
|
||||
if (interactive && ps0_prompt)
|
||||
{
|
||||
char *ps0_string;
|
||||
|
||||
ps0_string = decode_prompt_string (ps0_prompt);
|
||||
if (ps0_string && *ps0_string)
|
||||
{
|
||||
fprintf (stderr, "%s", ps0_string);
|
||||
fflush (stderr);
|
||||
}
|
||||
free (ps0_string);
|
||||
}
|
||||
|
||||
current_command_number++;
|
||||
|
||||
executing = 1;
|
||||
stdin_redir = 0;
|
||||
|
||||
execute_command (current_command);
|
||||
|
||||
exec_done:
|
||||
QUIT;
|
||||
|
||||
if (current_command)
|
||||
{
|
||||
dispose_command (current_command);
|
||||
current_command = (COMMAND *)NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Parse error, maybe discard rest of stream if not interactive. */
|
||||
if (interactive == 0)
|
||||
EOF_Reached = EOF;
|
||||
}
|
||||
if (just_one_command)
|
||||
EOF_Reached = EOF;
|
||||
}
|
||||
indirection_level--;
|
||||
return (last_command_exit_value);
|
||||
}
|
||||
|
||||
/* Pretty print shell scripts */
|
||||
int
|
||||
pretty_print_loop ()
|
||||
{
|
||||
COMMAND *current_command;
|
||||
char *command_to_print;
|
||||
int code;
|
||||
int global_posix_mode, last_was_newline;
|
||||
|
||||
global_posix_mode = posixly_correct;
|
||||
last_was_newline = 0;
|
||||
while (EOF_Reached == 0)
|
||||
{
|
||||
code = setjmp_nosigs (top_level);
|
||||
if (code)
|
||||
return (EXECUTION_FAILURE);
|
||||
if (read_command() == 0)
|
||||
{
|
||||
current_command = global_command;
|
||||
global_command = 0;
|
||||
posixly_correct = 1; /* print posix-conformant */
|
||||
if (current_command && (command_to_print = make_command_string (current_command)))
|
||||
{
|
||||
printf ("%s\n", command_to_print); /* for now */
|
||||
last_was_newline = 0;
|
||||
}
|
||||
else if (last_was_newline == 0)
|
||||
{
|
||||
printf ("\n");
|
||||
last_was_newline = 1;
|
||||
}
|
||||
posixly_correct = global_posix_mode;
|
||||
dispose_command (current_command);
|
||||
}
|
||||
else
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
static sighandler
|
||||
alrm_catcher(i)
|
||||
int i;
|
||||
{
|
||||
char *msg;
|
||||
|
||||
msg = _("\007timed out waiting for input: auto-logout\n");
|
||||
write (1, msg, strlen (msg));
|
||||
|
||||
bash_logout (); /* run ~/.bash_logout if this is a login shell */
|
||||
jump_to_top_level (EXITPROG);
|
||||
SIGRETURN (0);
|
||||
}
|
||||
|
||||
/* Send an escape sequence to emacs term mode to tell it the
|
||||
current working directory. */
|
||||
static void
|
||||
send_pwd_to_eterm ()
|
||||
{
|
||||
char *pwd, *f;
|
||||
|
||||
f = 0;
|
||||
pwd = get_string_value ("PWD");
|
||||
if (pwd == 0)
|
||||
f = pwd = get_working_directory ("eterm");
|
||||
fprintf (stderr, "\032/%s\n", pwd);
|
||||
free (f);
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
/* Caller ensures that A has a non-zero number of elements */
|
||||
int
|
||||
execute_array_command (a, v)
|
||||
ARRAY *a;
|
||||
void *v;
|
||||
{
|
||||
char *tag;
|
||||
char **argv;
|
||||
int argc, i;
|
||||
|
||||
tag = (char *)v;
|
||||
argc = 0;
|
||||
argv = array_to_argv (a, &argc);
|
||||
for (i = 0; i < argc; i++)
|
||||
{
|
||||
if (argv[i] && argv[i][0])
|
||||
execute_variable_command (argv[i], tag);
|
||||
}
|
||||
strvec_dispose (argv);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
execute_prompt_command ()
|
||||
{
|
||||
char *command_to_execute;
|
||||
SHELL_VAR *pcv;
|
||||
#if defined (ARRAY_VARS)
|
||||
ARRAY *pcmds;
|
||||
#endif
|
||||
|
||||
pcv = find_variable ("PROMPT_COMMAND");
|
||||
if (pcv == 0 || var_isset (pcv) == 0 || invisible_p (pcv))
|
||||
return;
|
||||
#if defined (ARRAY_VARS)
|
||||
if (array_p (pcv))
|
||||
{
|
||||
if ((pcmds = array_cell (pcv)) && array_num_elements (pcmds) > 0)
|
||||
execute_array_command (pcmds, "PROMPT_COMMAND");
|
||||
return;
|
||||
}
|
||||
else if (assoc_p (pcv))
|
||||
return; /* currently don't allow associative arrays here */
|
||||
#endif
|
||||
|
||||
command_to_execute = value_cell (pcv);
|
||||
if (command_to_execute && *command_to_execute)
|
||||
execute_variable_command (command_to_execute, "PROMPT_COMMAND");
|
||||
}
|
||||
|
||||
/* Call the YACC-generated parser and return the status of the parse.
|
||||
Input is read from the current input stream (bash_input). yyparse
|
||||
leaves the parsed command in the global variable GLOBAL_COMMAND.
|
||||
This is where PROMPT_COMMAND is executed. */
|
||||
int
|
||||
parse_command ()
|
||||
{
|
||||
int r;
|
||||
|
||||
need_here_doc = 0;
|
||||
run_pending_traps ();
|
||||
|
||||
/* Allow the execution of a random command just before the printing
|
||||
of each primary prompt. If the shell variable PROMPT_COMMAND
|
||||
is set then its value (array or string) is the command(s) to execute. */
|
||||
/* The tests are a combination of SHOULD_PROMPT() and prompt_again()
|
||||
from parse.y, which are the conditions under which the prompt is
|
||||
actually printed. */
|
||||
if (interactive && bash_input.type != st_string && parser_expanding_alias() == 0)
|
||||
{
|
||||
#if defined (READLINE)
|
||||
if (no_line_editing || (bash_input.type == st_stdin && parser_will_prompt ()))
|
||||
#endif
|
||||
execute_prompt_command ();
|
||||
|
||||
if (running_under_emacs == 2)
|
||||
send_pwd_to_eterm (); /* Yuck */
|
||||
}
|
||||
|
||||
current_command_line_count = 0;
|
||||
r = yyparse ();
|
||||
|
||||
if (need_here_doc)
|
||||
gather_here_documents ();
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
||||
/* Read and parse a command, returning the status of the parse. The command
|
||||
is left in the globval variable GLOBAL_COMMAND for use by reader_loop.
|
||||
This is where the shell timeout code is executed. */
|
||||
int
|
||||
read_command ()
|
||||
{
|
||||
SHELL_VAR *tmout_var;
|
||||
int tmout_len, result;
|
||||
SigHandler *old_alrm;
|
||||
|
||||
set_current_prompt_level (1);
|
||||
global_command = (COMMAND *)NULL;
|
||||
|
||||
/* Only do timeouts if interactive. */
|
||||
tmout_var = (SHELL_VAR *)NULL;
|
||||
tmout_len = 0;
|
||||
old_alrm = (SigHandler *)NULL;
|
||||
|
||||
if (interactive)
|
||||
{
|
||||
tmout_var = find_variable ("TMOUT");
|
||||
|
||||
if (tmout_var && var_isset (tmout_var))
|
||||
{
|
||||
tmout_len = atoi (value_cell (tmout_var));
|
||||
if (tmout_len > 0)
|
||||
{
|
||||
old_alrm = set_signal_handler (SIGALRM, alrm_catcher);
|
||||
alarm (tmout_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QUIT;
|
||||
|
||||
current_command_line_count = 0;
|
||||
result = parse_command ();
|
||||
|
||||
if (interactive && tmout_var && (tmout_len > 0))
|
||||
{
|
||||
alarm(0);
|
||||
set_signal_handler (SIGALRM, old_alrm);
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
384
third_party/bash/evalfile.c
vendored
Normal file
384
third_party/bash/evalfile.c
vendored
Normal file
|
@ -0,0 +1,384 @@
|
|||
/* evalfile.c - read and evaluate commands from a file or file descriptor */
|
||||
|
||||
/* Copyright (C) 1996-2017 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashtypes.h"
|
||||
#include "posixstat.h"
|
||||
#include "filecntl.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "parser.h"
|
||||
#include "jobs.h"
|
||||
#include "builtins.h"
|
||||
#include "flags.h"
|
||||
#include "input.h"
|
||||
#include "execute_cmd.h"
|
||||
#include "trap.h"
|
||||
|
||||
#include "y.tab.h"
|
||||
|
||||
#if defined (HISTORY)
|
||||
# include "bashhist.h"
|
||||
#endif
|
||||
|
||||
#include "typemax.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
/* Flags for _evalfile() */
|
||||
#define FEVAL_ENOENTOK 0x001
|
||||
#define FEVAL_BUILTIN 0x002
|
||||
#define FEVAL_UNWINDPROT 0x004
|
||||
#define FEVAL_NONINT 0x008
|
||||
#define FEVAL_LONGJMP 0x010
|
||||
#define FEVAL_HISTORY 0x020
|
||||
#define FEVAL_CHECKBINARY 0x040
|
||||
#define FEVAL_REGFILE 0x080
|
||||
#define FEVAL_NOPUSHARGS 0x100
|
||||
|
||||
/* How many `levels' of sourced files we have. */
|
||||
int sourcelevel = 0;
|
||||
|
||||
static int
|
||||
_evalfile (filename, flags)
|
||||
const char *filename;
|
||||
int flags;
|
||||
{
|
||||
volatile int old_interactive;
|
||||
procenv_t old_return_catch;
|
||||
int return_val, fd, result, pflags, i, nnull;
|
||||
ssize_t nr; /* return value from read(2) */
|
||||
char *string;
|
||||
struct stat finfo;
|
||||
size_t file_size;
|
||||
sh_vmsg_func_t *errfunc;
|
||||
#if defined (ARRAY_VARS)
|
||||
SHELL_VAR *funcname_v, *bash_source_v, *bash_lineno_v;
|
||||
ARRAY *funcname_a, *bash_source_a, *bash_lineno_a;
|
||||
struct func_array_state *fa;
|
||||
# if defined (DEBUGGER)
|
||||
SHELL_VAR *bash_argv_v, *bash_argc_v;
|
||||
ARRAY *bash_argv_a, *bash_argc_a;
|
||||
# endif
|
||||
char *t, tt[2];
|
||||
#endif
|
||||
|
||||
USE_VAR(pflags);
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a);
|
||||
GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a);
|
||||
GET_ARRAY_FROM_VAR ("BASH_LINENO", bash_lineno_v, bash_lineno_a);
|
||||
# if defined (DEBUGGER)
|
||||
GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
|
||||
GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
fd = open (filename, O_RDONLY);
|
||||
|
||||
if (fd < 0 || (fstat (fd, &finfo) == -1))
|
||||
{
|
||||
i = errno;
|
||||
if (fd >= 0)
|
||||
close (fd);
|
||||
errno = i;
|
||||
|
||||
file_error_and_exit:
|
||||
if (((flags & FEVAL_ENOENTOK) == 0) || errno != ENOENT)
|
||||
file_error (filename);
|
||||
|
||||
if (flags & FEVAL_LONGJMP)
|
||||
{
|
||||
last_command_exit_value = EXECUTION_FAILURE;
|
||||
jump_to_top_level (EXITPROG);
|
||||
}
|
||||
|
||||
return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE
|
||||
: ((errno == ENOENT && (flags & FEVAL_ENOENTOK) != 0) ? 0 : -1));
|
||||
}
|
||||
|
||||
errfunc = ((flags & FEVAL_BUILTIN) ? builtin_error : internal_error);
|
||||
|
||||
if (S_ISDIR (finfo.st_mode))
|
||||
{
|
||||
(*errfunc) (_("%s: is a directory"), filename);
|
||||
close (fd);
|
||||
return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1);
|
||||
}
|
||||
else if ((flags & FEVAL_REGFILE) && S_ISREG (finfo.st_mode) == 0)
|
||||
{
|
||||
(*errfunc) (_("%s: not a regular file"), filename);
|
||||
close (fd);
|
||||
return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1);
|
||||
}
|
||||
|
||||
file_size = (size_t)finfo.st_size;
|
||||
/* Check for overflow with large files. */
|
||||
if (file_size != finfo.st_size || file_size + 1 < file_size)
|
||||
{
|
||||
(*errfunc) (_("%s: file is too large"), filename);
|
||||
close (fd);
|
||||
return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1);
|
||||
}
|
||||
|
||||
if (S_ISREG (finfo.st_mode) && file_size <= SSIZE_MAX)
|
||||
{
|
||||
string = (char *)xmalloc (1 + file_size);
|
||||
nr = read (fd, string, file_size);
|
||||
if (nr >= 0)
|
||||
string[nr] = '\0';
|
||||
}
|
||||
else
|
||||
nr = zmapfd (fd, &string, 0);
|
||||
|
||||
return_val = errno;
|
||||
close (fd);
|
||||
errno = return_val;
|
||||
|
||||
if (nr < 0) /* XXX was != file_size, not < 0 */
|
||||
{
|
||||
free (string);
|
||||
goto file_error_and_exit;
|
||||
}
|
||||
|
||||
if (nr == 0)
|
||||
{
|
||||
free (string);
|
||||
return ((flags & FEVAL_BUILTIN) ? EXECUTION_SUCCESS : 1);
|
||||
}
|
||||
|
||||
if ((flags & FEVAL_CHECKBINARY) &&
|
||||
check_binary_file (string, (nr > 80) ? 80 : nr))
|
||||
{
|
||||
free (string);
|
||||
(*errfunc) (_("%s: cannot execute binary file"), filename);
|
||||
return ((flags & FEVAL_BUILTIN) ? EX_BINARY_FILE : -1);
|
||||
}
|
||||
|
||||
i = strlen (string);
|
||||
if (i < nr)
|
||||
{
|
||||
for (nnull = i = 0; i < nr; i++)
|
||||
if (string[i] == '\0')
|
||||
{
|
||||
memmove (string+i, string+i+1, nr - i);
|
||||
nr--;
|
||||
/* Even if the `check binary' flag is not set, we want to avoid
|
||||
sourcing files with more than 256 null characters -- that
|
||||
probably indicates a binary file. */
|
||||
if ((flags & FEVAL_BUILTIN) && ++nnull > 256)
|
||||
{
|
||||
free (string);
|
||||
(*errfunc) (_("%s: cannot execute binary file"), filename);
|
||||
return ((flags & FEVAL_BUILTIN) ? EX_BINARY_FILE : -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & FEVAL_UNWINDPROT)
|
||||
{
|
||||
begin_unwind_frame ("_evalfile");
|
||||
|
||||
unwind_protect_int (return_catch_flag);
|
||||
unwind_protect_jmp_buf (return_catch);
|
||||
if (flags & FEVAL_NONINT)
|
||||
unwind_protect_int (interactive);
|
||||
unwind_protect_int (sourcelevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
COPY_PROCENV (return_catch, old_return_catch);
|
||||
if (flags & FEVAL_NONINT)
|
||||
old_interactive = interactive;
|
||||
}
|
||||
|
||||
if (flags & FEVAL_NONINT)
|
||||
interactive = 0;
|
||||
|
||||
return_catch_flag++;
|
||||
sourcelevel++;
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
array_push (bash_source_a, (char *)filename);
|
||||
t = itos (executing_line_number ());
|
||||
array_push (bash_lineno_a, t);
|
||||
free (t);
|
||||
array_push (funcname_a, "source"); /* not exactly right */
|
||||
|
||||
fa = (struct func_array_state *)xmalloc (sizeof (struct func_array_state));
|
||||
fa->source_a = bash_source_a;
|
||||
fa->source_v = bash_source_v;
|
||||
fa->lineno_a = bash_lineno_a;
|
||||
fa->lineno_v = bash_lineno_v;
|
||||
fa->funcname_a = funcname_a;
|
||||
fa->funcname_v = funcname_v;
|
||||
if (flags & FEVAL_UNWINDPROT)
|
||||
add_unwind_protect (restore_funcarray_state, fa);
|
||||
|
||||
# if defined (DEBUGGER)
|
||||
/* Have to figure out a better way to do this when `source' is supplied
|
||||
arguments */
|
||||
if ((flags & FEVAL_NOPUSHARGS) == 0)
|
||||
{
|
||||
if (shell_compatibility_level <= 44)
|
||||
init_bash_argv ();
|
||||
array_push (bash_argv_a, (char *)filename); /* XXX - unconditionally? */
|
||||
tt[0] = '1'; tt[1] = '\0';
|
||||
array_push (bash_argc_a, tt);
|
||||
if (flags & FEVAL_UNWINDPROT)
|
||||
add_unwind_protect (pop_args, 0);
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* set the flags to be passed to parse_and_execute */
|
||||
pflags = SEVAL_RESETLINE;
|
||||
pflags |= (flags & FEVAL_HISTORY) ? 0 : SEVAL_NOHIST;
|
||||
|
||||
if (flags & FEVAL_BUILTIN)
|
||||
result = EXECUTION_SUCCESS;
|
||||
|
||||
return_val = setjmp_nosigs (return_catch);
|
||||
|
||||
/* If `return' was seen outside of a function, but in the script, then
|
||||
force parse_and_execute () to clean up. */
|
||||
if (return_val)
|
||||
{
|
||||
parse_and_execute_cleanup (-1);
|
||||
result = return_catch_value;
|
||||
}
|
||||
else
|
||||
result = parse_and_execute (string, filename, pflags);
|
||||
|
||||
if (flags & FEVAL_UNWINDPROT)
|
||||
run_unwind_frame ("_evalfile");
|
||||
else
|
||||
{
|
||||
if (flags & FEVAL_NONINT)
|
||||
interactive = old_interactive;
|
||||
#if defined (ARRAY_VARS)
|
||||
restore_funcarray_state (fa);
|
||||
# if defined (DEBUGGER)
|
||||
if ((flags & FEVAL_NOPUSHARGS) == 0)
|
||||
{
|
||||
/* Don't need to call pop_args here until we do something better
|
||||
when source is passed arguments (see above). */
|
||||
array_pop (bash_argc_a);
|
||||
array_pop (bash_argv_a);
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
return_catch_flag--;
|
||||
sourcelevel--;
|
||||
COPY_PROCENV (old_return_catch, return_catch);
|
||||
}
|
||||
|
||||
/* If we end up with EOF after sourcing a file, which can happen when the file
|
||||
doesn't end with a newline, pretend that it did. */
|
||||
if (current_token == yacc_EOF)
|
||||
push_token ('\n'); /* XXX */
|
||||
|
||||
return ((flags & FEVAL_BUILTIN) ? result : 1);
|
||||
}
|
||||
|
||||
int
|
||||
maybe_execute_file (fname, force_noninteractive)
|
||||
const char *fname;
|
||||
int force_noninteractive;
|
||||
{
|
||||
char *filename;
|
||||
int result, flags;
|
||||
|
||||
filename = bash_tilde_expand (fname, 0);
|
||||
flags = FEVAL_ENOENTOK;
|
||||
if (force_noninteractive)
|
||||
flags |= FEVAL_NONINT;
|
||||
result = _evalfile (filename, flags);
|
||||
free (filename);
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
force_execute_file (fname, force_noninteractive)
|
||||
const char *fname;
|
||||
int force_noninteractive;
|
||||
{
|
||||
char *filename;
|
||||
int result, flags;
|
||||
|
||||
filename = bash_tilde_expand (fname, 0);
|
||||
flags = 0;
|
||||
if (force_noninteractive)
|
||||
flags |= FEVAL_NONINT;
|
||||
result = _evalfile (filename, flags);
|
||||
free (filename);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined (HISTORY)
|
||||
int
|
||||
fc_execute_file (filename)
|
||||
const char *filename;
|
||||
{
|
||||
int flags;
|
||||
|
||||
/* We want these commands to show up in the history list if
|
||||
remember_on_history is set. We use FEVAL_BUILTIN to return
|
||||
the result of parse_and_execute. */
|
||||
flags = FEVAL_ENOENTOK|FEVAL_HISTORY|FEVAL_REGFILE|FEVAL_BUILTIN;
|
||||
return (_evalfile (filename, flags));
|
||||
}
|
||||
#endif /* HISTORY */
|
||||
|
||||
int
|
||||
source_file (filename, sflags)
|
||||
const char *filename;
|
||||
int sflags;
|
||||
{
|
||||
int flags, rval;
|
||||
|
||||
flags = FEVAL_BUILTIN|FEVAL_UNWINDPROT|FEVAL_NONINT;
|
||||
if (sflags)
|
||||
flags |= FEVAL_NOPUSHARGS;
|
||||
/* POSIX shells exit if non-interactive and file error. */
|
||||
if (posixly_correct && interactive_shell == 0 && executing_command_builtin == 0)
|
||||
flags |= FEVAL_LONGJMP;
|
||||
rval = _evalfile (filename, flags);
|
||||
|
||||
run_return_trap ();
|
||||
return rval;
|
||||
}
|
818
third_party/bash/evalstring.c
vendored
Normal file
818
third_party/bash/evalstring.c
vendored
Normal file
|
@ -0,0 +1,818 @@
|
|||
/* evalstring.c - evaluate a string as one or more shell commands. */
|
||||
|
||||
/* Copyright (C) 1996-2022 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "filecntl.h"
|
||||
#include "bashansi.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "jobs.h"
|
||||
#include "builtins.h"
|
||||
#include "flags.h"
|
||||
#include "parser.h"
|
||||
#include "input.h"
|
||||
#include "execute_cmd.h"
|
||||
#include "redir.h"
|
||||
#include "trap.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "y.tab.h"
|
||||
|
||||
#if defined (HISTORY)
|
||||
# include "bashhist.h"
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
#include "builtext.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#define IS_BUILTIN(s) (builtin_address_internal(s, 0) != (struct builtin *)NULL)
|
||||
|
||||
int parse_and_execute_level = 0;
|
||||
|
||||
static int cat_file PARAMS((REDIRECT *));
|
||||
|
||||
#define PE_TAG "parse_and_execute top"
|
||||
#define PS_TAG "parse_string top"
|
||||
|
||||
#if defined (HISTORY)
|
||||
static void
|
||||
set_history_remembering ()
|
||||
{
|
||||
remember_on_history = enable_history_list;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
restore_lastcom (x)
|
||||
char *x;
|
||||
{
|
||||
FREE (the_printed_command_except_trap);
|
||||
the_printed_command_except_trap = x;
|
||||
}
|
||||
|
||||
int
|
||||
should_optimize_fork (command, subshell)
|
||||
COMMAND *command;
|
||||
int subshell;
|
||||
{
|
||||
return (running_trap == 0 &&
|
||||
command->type == cm_simple &&
|
||||
signal_is_trapped (EXIT_TRAP) == 0 &&
|
||||
signal_is_trapped (ERROR_TRAP) == 0 &&
|
||||
any_signals_trapped () < 0 &&
|
||||
(subshell || (command->redirects == 0 && command->value.Simple->redirects == 0)) &&
|
||||
((command->flags & CMD_TIME_PIPELINE) == 0) &&
|
||||
((command->flags & CMD_INVERT_RETURN) == 0));
|
||||
}
|
||||
|
||||
/* This has extra tests to account for STARTUP_STATE == 2, which is for
|
||||
-c command but has been extended to command and process substitution
|
||||
(basically any time you call parse_and_execute in a subshell). */
|
||||
int
|
||||
should_suppress_fork (command)
|
||||
COMMAND *command;
|
||||
{
|
||||
int subshell;
|
||||
|
||||
subshell = subshell_environment & SUBSHELL_PROCSUB; /* salt to taste */
|
||||
return (startup_state == 2 && parse_and_execute_level == 1 &&
|
||||
*bash_input.location.string == '\0' &&
|
||||
parser_expanding_alias () == 0 &&
|
||||
should_optimize_fork (command, subshell));
|
||||
}
|
||||
|
||||
int
|
||||
can_optimize_connection (command)
|
||||
COMMAND *command;
|
||||
{
|
||||
return (*bash_input.location.string == '\0' &&
|
||||
parser_expanding_alias () == 0 &&
|
||||
(command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR || command->value.Connection->connector == ';') &&
|
||||
command->value.Connection->second->type == cm_simple);
|
||||
}
|
||||
|
||||
void
|
||||
optimize_connection_fork (command)
|
||||
COMMAND *command;
|
||||
{
|
||||
if (command->type == cm_connection &&
|
||||
(command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR || command->value.Connection->connector == ';') &&
|
||||
(command->value.Connection->second->flags & CMD_TRY_OPTIMIZING) &&
|
||||
((startup_state == 2 && should_suppress_fork (command->value.Connection->second)) ||
|
||||
((subshell_environment & SUBSHELL_PAREN) && should_optimize_fork (command->value.Connection->second, 0))))
|
||||
{
|
||||
command->value.Connection->second->flags |= CMD_NO_FORK;
|
||||
command->value.Connection->second->value.Simple->flags |= CMD_NO_FORK;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
optimize_subshell_command (command)
|
||||
COMMAND *command;
|
||||
{
|
||||
if (should_optimize_fork (command, 0))
|
||||
{
|
||||
command->flags |= CMD_NO_FORK;
|
||||
command->value.Simple->flags |= CMD_NO_FORK;
|
||||
}
|
||||
else if (command->type == cm_connection &&
|
||||
(command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR || command->value.Connection->connector == ';') &&
|
||||
command->value.Connection->second->type == cm_simple &&
|
||||
parser_expanding_alias () == 0)
|
||||
{
|
||||
command->value.Connection->second->flags |= CMD_TRY_OPTIMIZING;
|
||||
command->value.Connection->second->value.Simple->flags |= CMD_TRY_OPTIMIZING;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
optimize_shell_function (command)
|
||||
COMMAND *command;
|
||||
{
|
||||
COMMAND *fc;
|
||||
|
||||
fc = (command->type == cm_group) ? command->value.Group->command : command;
|
||||
|
||||
if (fc->type == cm_simple && should_suppress_fork (fc))
|
||||
{
|
||||
fc->flags |= CMD_NO_FORK;
|
||||
fc->value.Simple->flags |= CMD_NO_FORK;
|
||||
}
|
||||
else if (fc->type == cm_connection && can_optimize_connection (fc) && should_suppress_fork (fc->value.Connection->second))
|
||||
{
|
||||
fc->value.Connection->second->flags |= CMD_NO_FORK;
|
||||
fc->value.Connection->second->value.Simple->flags |= CMD_NO_FORK;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
can_optimize_cat_file (command)
|
||||
COMMAND *command;
|
||||
{
|
||||
return (command->type == cm_simple && !command->redirects &&
|
||||
(command->flags & CMD_TIME_PIPELINE) == 0 &&
|
||||
command->value.Simple->words == 0 &&
|
||||
command->value.Simple->redirects &&
|
||||
command->value.Simple->redirects->next == 0 &&
|
||||
command->value.Simple->redirects->instruction == r_input_direction &&
|
||||
command->value.Simple->redirects->redirector.dest == 0);
|
||||
}
|
||||
|
||||
/* How to force parse_and_execute () to clean up after itself. */
|
||||
void
|
||||
parse_and_execute_cleanup (old_running_trap)
|
||||
int old_running_trap;
|
||||
{
|
||||
if (running_trap > 0)
|
||||
{
|
||||
/* We assume if we have a different value for running_trap than when
|
||||
we started (the only caller that cares is evalstring()), the
|
||||
original caller will perform the cleanup, and we should not step
|
||||
on them. */
|
||||
if (running_trap != old_running_trap)
|
||||
run_trap_cleanup (running_trap - 1);
|
||||
unfreeze_jobs_list ();
|
||||
}
|
||||
|
||||
if (have_unwind_protects ())
|
||||
run_unwind_frame (PE_TAG);
|
||||
else
|
||||
parse_and_execute_level = 0; /* XXX */
|
||||
}
|
||||
|
||||
static void
|
||||
parse_prologue (string, flags, tag)
|
||||
char *string;
|
||||
int flags;
|
||||
char *tag;
|
||||
{
|
||||
char *orig_string, *lastcom;
|
||||
int x;
|
||||
|
||||
orig_string = string;
|
||||
/* Unwind protect this invocation of parse_and_execute (). */
|
||||
begin_unwind_frame (tag);
|
||||
unwind_protect_int (parse_and_execute_level);
|
||||
unwind_protect_jmp_buf (top_level);
|
||||
unwind_protect_int (indirection_level);
|
||||
unwind_protect_int (line_number);
|
||||
unwind_protect_int (line_number_for_err_trap);
|
||||
unwind_protect_int (loop_level);
|
||||
unwind_protect_int (executing_list);
|
||||
unwind_protect_int (comsub_ignore_return);
|
||||
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
|
||||
unwind_protect_int (interactive);
|
||||
|
||||
#if defined (HISTORY)
|
||||
if (parse_and_execute_level == 0)
|
||||
add_unwind_protect (set_history_remembering, (char *)NULL);
|
||||
else
|
||||
unwind_protect_int (remember_on_history); /* can be used in scripts */
|
||||
# if defined (BANG_HISTORY)
|
||||
unwind_protect_int (history_expansion_inhibited);
|
||||
# endif /* BANG_HISTORY */
|
||||
#endif /* HISTORY */
|
||||
|
||||
if (interactive_shell)
|
||||
{
|
||||
x = get_current_prompt_level ();
|
||||
add_unwind_protect (set_current_prompt_level, x);
|
||||
}
|
||||
|
||||
if (the_printed_command_except_trap)
|
||||
{
|
||||
lastcom = savestring (the_printed_command_except_trap);
|
||||
add_unwind_protect (restore_lastcom, lastcom);
|
||||
}
|
||||
|
||||
add_unwind_protect (pop_stream, (char *)NULL);
|
||||
if (parser_expanding_alias ())
|
||||
add_unwind_protect (parser_restore_alias, (char *)NULL);
|
||||
|
||||
if (orig_string && ((flags & SEVAL_NOFREE) == 0))
|
||||
add_unwind_protect (xfree, orig_string);
|
||||
end_unwind_frame ();
|
||||
|
||||
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
|
||||
interactive = (flags & SEVAL_NONINT) ? 0 : 1;
|
||||
|
||||
#if defined (HISTORY)
|
||||
if (flags & SEVAL_NOHIST)
|
||||
bash_history_disable ();
|
||||
# if defined (BANG_HISTORY)
|
||||
if (flags & SEVAL_NOHISTEXP)
|
||||
history_expansion_inhibited = 1;
|
||||
# endif /* BANG_HISTORY */
|
||||
#endif /* HISTORY */
|
||||
}
|
||||
|
||||
/* Parse and execute the commands in STRING. Returns whatever
|
||||
execute_command () returns. This frees STRING. FLAGS is a
|
||||
flags word; look in common.h for the possible values. Actions
|
||||
are:
|
||||
(flags & SEVAL_NONINT) -> interactive = 0;
|
||||
(flags & SEVAL_INTERACT) -> interactive = 1;
|
||||
(flags & SEVAL_NOHIST) -> call bash_history_disable ()
|
||||
(flags & SEVAL_NOFREE) -> don't free STRING when finished
|
||||
(flags & SEVAL_RESETLINE) -> reset line_number to 1
|
||||
(flags & SEVAL_NOHISTEXP) -> history_expansion_inhibited -> 1
|
||||
*/
|
||||
|
||||
int
|
||||
parse_and_execute (string, from_file, flags)
|
||||
char *string;
|
||||
const char *from_file;
|
||||
int flags;
|
||||
{
|
||||
int code, lreset;
|
||||
volatile int should_jump_to_top_level, last_result;
|
||||
COMMAND *volatile command;
|
||||
volatile sigset_t pe_sigmask;
|
||||
|
||||
parse_prologue (string, flags, PE_TAG);
|
||||
|
||||
parse_and_execute_level++;
|
||||
|
||||
lreset = flags & SEVAL_RESETLINE;
|
||||
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
/* If we longjmp and are going to go on, use this to restore signal mask */
|
||||
sigemptyset ((sigset_t *)&pe_sigmask);
|
||||
sigprocmask (SIG_BLOCK, (sigset_t *)NULL, (sigset_t *)&pe_sigmask);
|
||||
#endif
|
||||
|
||||
/* Reset the line number if the caller wants us to. If we don't reset the
|
||||
line number, we have to subtract one, because we will add one just
|
||||
before executing the next command (resetting the line number sets it to
|
||||
0; the first line number is 1). */
|
||||
push_stream (lreset);
|
||||
if (parser_expanding_alias ())
|
||||
/* push current shell_input_line */
|
||||
parser_save_alias ();
|
||||
|
||||
if (lreset == 0)
|
||||
line_number--;
|
||||
|
||||
indirection_level++;
|
||||
|
||||
code = should_jump_to_top_level = 0;
|
||||
last_result = EXECUTION_SUCCESS;
|
||||
|
||||
/* We need to reset enough of the token state so we can start fresh. */
|
||||
if (current_token == yacc_EOF)
|
||||
current_token = '\n'; /* reset_parser() ? */
|
||||
|
||||
with_input_from_string (string, from_file);
|
||||
clear_shell_input_line ();
|
||||
while (*(bash_input.location.string) || parser_expanding_alias ())
|
||||
{
|
||||
command = (COMMAND *)NULL;
|
||||
|
||||
if (interrupt_state)
|
||||
{
|
||||
last_result = EXECUTION_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Provide a location for functions which `longjmp (top_level)' to
|
||||
jump to. This prevents errors in substitution from restarting
|
||||
the reader loop directly, for example. */
|
||||
code = setjmp_nosigs (top_level);
|
||||
|
||||
if (code)
|
||||
{
|
||||
should_jump_to_top_level = 0;
|
||||
switch (code)
|
||||
{
|
||||
case ERREXIT:
|
||||
/* variable_context -> 0 is what eval.c:reader_loop() does in
|
||||
these circumstances. Don't bother with cleanup here because
|
||||
we don't want to run the function execution cleanup stuff
|
||||
that will cause pop_context and other functions to run.
|
||||
We call reset_local_contexts() instead, which just frees
|
||||
context memory.
|
||||
XXX - change that if we want the function context to be
|
||||
unwound. */
|
||||
if (exit_immediately_on_error && variable_context)
|
||||
{
|
||||
discard_unwind_frame ("pe_dispose");
|
||||
reset_local_contexts (); /* not in a function */
|
||||
}
|
||||
should_jump_to_top_level = 1;
|
||||
goto out;
|
||||
case FORCE_EOF:
|
||||
case EXITPROG:
|
||||
if (command)
|
||||
run_unwind_frame ("pe_dispose");
|
||||
/* Remember to call longjmp (top_level) after the old
|
||||
value for it is restored. */
|
||||
should_jump_to_top_level = 1;
|
||||
goto out;
|
||||
|
||||
case EXITBLTIN:
|
||||
if (command)
|
||||
{
|
||||
if (variable_context && signal_is_trapped (0))
|
||||
{
|
||||
/* Let's make sure we run the exit trap in the function
|
||||
context, as we do when not running parse_and_execute.
|
||||
The pe_dispose unwind frame comes before any unwind-
|
||||
protects installed by the string we're evaluating, so
|
||||
it will undo the current function scope. */
|
||||
dispose_command (command);
|
||||
discard_unwind_frame ("pe_dispose");
|
||||
}
|
||||
else
|
||||
run_unwind_frame ("pe_dispose");
|
||||
}
|
||||
should_jump_to_top_level = 1;
|
||||
goto out;
|
||||
|
||||
case DISCARD:
|
||||
if (command)
|
||||
run_unwind_frame ("pe_dispose");
|
||||
last_result = last_command_exit_value = EXECUTION_FAILURE; /* XXX */
|
||||
set_pipestatus_from_exit (last_command_exit_value);
|
||||
if (subshell_environment)
|
||||
{
|
||||
should_jump_to_top_level = 1;
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if 0
|
||||
dispose_command (command); /* pe_dispose does this */
|
||||
#endif
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
sigprocmask (SIG_SETMASK, (sigset_t *)&pe_sigmask, (sigset_t *)NULL);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
default:
|
||||
command_error ("parse_and_execute", CMDERR_BADJUMP, code, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (parse_command () == 0)
|
||||
{
|
||||
if ((flags & SEVAL_PARSEONLY) || (interactive_shell == 0 && read_but_dont_execute))
|
||||
{
|
||||
last_result = EXECUTION_SUCCESS;
|
||||
dispose_command (global_command);
|
||||
global_command = (COMMAND *)NULL;
|
||||
}
|
||||
else if (command = global_command)
|
||||
{
|
||||
struct fd_bitmap *bitmap;
|
||||
|
||||
if (flags & SEVAL_FUNCDEF)
|
||||
{
|
||||
char *x;
|
||||
|
||||
/* If the command parses to something other than a straight
|
||||
function definition, or if we have not consumed the entire
|
||||
string, or if the parser has transformed the function
|
||||
name (as parsing will if it begins or ends with shell
|
||||
whitespace, for example), reject the attempt */
|
||||
if (command->type != cm_function_def ||
|
||||
((x = parser_remaining_input ()) && *x) ||
|
||||
(STREQ (from_file, command->value.Function_def->name->word) == 0))
|
||||
{
|
||||
internal_warning (_("%s: ignoring function definition attempt"), from_file);
|
||||
should_jump_to_top_level = 0;
|
||||
last_result = last_command_exit_value = EX_BADUSAGE;
|
||||
set_pipestatus_from_exit (last_command_exit_value);
|
||||
reset_parser ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bitmap = new_fd_bitmap (FD_BITMAP_SIZE);
|
||||
begin_unwind_frame ("pe_dispose");
|
||||
add_unwind_protect (dispose_fd_bitmap, bitmap);
|
||||
add_unwind_protect (dispose_command, command); /* XXX */
|
||||
|
||||
global_command = (COMMAND *)NULL;
|
||||
|
||||
if ((subshell_environment & SUBSHELL_COMSUB) && comsub_ignore_return)
|
||||
command->flags |= CMD_IGNORE_RETURN;
|
||||
|
||||
#if defined (ONESHOT)
|
||||
/*
|
||||
* IF
|
||||
* we were invoked as `bash -c' (startup_state == 2) AND
|
||||
* parse_and_execute has not been called recursively AND
|
||||
* we're not running a trap AND
|
||||
* we have parsed the full command (string == '\0') AND
|
||||
* we're not going to run the exit trap AND
|
||||
* we have a simple command without redirections AND
|
||||
* the command is not being timed AND
|
||||
* the command's return status is not being inverted AND
|
||||
* there aren't any traps in effect
|
||||
* THEN
|
||||
* tell the execution code that we don't need to fork
|
||||
*/
|
||||
if (should_suppress_fork (command))
|
||||
{
|
||||
command->flags |= CMD_NO_FORK;
|
||||
command->value.Simple->flags |= CMD_NO_FORK;
|
||||
}
|
||||
|
||||
/* Can't optimize forks out here execept for simple commands.
|
||||
This knows that the parser sets up commands as left-side heavy
|
||||
(&& and || are left-associative) and after the single parse,
|
||||
if we are at the end of the command string, the last in a
|
||||
series of connection commands is
|
||||
command->value.Connection->second. */
|
||||
else if (command->type == cm_connection && can_optimize_connection (command))
|
||||
{
|
||||
command->value.Connection->second->flags |= CMD_TRY_OPTIMIZING;
|
||||
command->value.Connection->second->value.Simple->flags |= CMD_TRY_OPTIMIZING;
|
||||
}
|
||||
#endif /* ONESHOT */
|
||||
|
||||
/* See if this is a candidate for $( <file ). */
|
||||
if (startup_state == 2 &&
|
||||
(subshell_environment & SUBSHELL_COMSUB) &&
|
||||
*bash_input.location.string == '\0' &&
|
||||
can_optimize_cat_file (command))
|
||||
{
|
||||
int r;
|
||||
r = cat_file (command->value.Simple->redirects);
|
||||
last_result = (r < 0) ? EXECUTION_FAILURE : EXECUTION_SUCCESS;
|
||||
}
|
||||
else
|
||||
last_result = execute_command_internal
|
||||
(command, 0, NO_PIPE, NO_PIPE, bitmap);
|
||||
dispose_command (command);
|
||||
dispose_fd_bitmap (bitmap);
|
||||
discard_unwind_frame ("pe_dispose");
|
||||
|
||||
if (flags & SEVAL_ONECMD)
|
||||
{
|
||||
reset_parser ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
last_result = EX_BADUSAGE; /* was EXECUTION_FAILURE */
|
||||
|
||||
if (interactive_shell == 0 && this_shell_builtin &&
|
||||
(this_shell_builtin == source_builtin || this_shell_builtin == eval_builtin) &&
|
||||
last_command_exit_value == EX_BADSYNTAX && posixly_correct && executing_command_builtin == 0)
|
||||
{
|
||||
should_jump_to_top_level = 1;
|
||||
code = ERREXIT;
|
||||
last_command_exit_value = EX_BADUSAGE;
|
||||
}
|
||||
|
||||
/* Since we are shell compatible, syntax errors in a script
|
||||
abort the execution of the script. Right? */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
run_unwind_frame (PE_TAG);
|
||||
|
||||
if (interrupt_state && parse_and_execute_level == 0)
|
||||
{
|
||||
/* An interrupt during non-interactive execution in an
|
||||
interactive shell (e.g. via $PROMPT_COMMAND) should
|
||||
not cause the shell to exit. */
|
||||
interactive = interactive_shell;
|
||||
throw_to_top_level ();
|
||||
}
|
||||
|
||||
CHECK_TERMSIG;
|
||||
|
||||
if (should_jump_to_top_level)
|
||||
jump_to_top_level (code);
|
||||
|
||||
return (last_result);
|
||||
}
|
||||
|
||||
/* Parse a command contained in STRING according to FLAGS and return the
|
||||
number of characters consumed from the string. If non-NULL, set *ENDP
|
||||
to the position in the string where the parse ended. Used to validate
|
||||
command substitutions during parsing to obey Posix rules about finding
|
||||
the end of the command and balancing parens. */
|
||||
int
|
||||
parse_string (string, from_file, flags, cmdp, endp)
|
||||
char *string;
|
||||
const char *from_file;
|
||||
int flags;
|
||||
COMMAND **cmdp;
|
||||
char **endp;
|
||||
{
|
||||
int code, nc;
|
||||
volatile int should_jump_to_top_level;
|
||||
COMMAND *volatile command, *oglobal;
|
||||
char *ostring;
|
||||
volatile sigset_t ps_sigmask;
|
||||
|
||||
parse_prologue (string, flags, PS_TAG);
|
||||
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
/* If we longjmp and are going to go on, use this to restore signal mask */
|
||||
sigemptyset ((sigset_t *)&ps_sigmask);
|
||||
sigprocmask (SIG_BLOCK, (sigset_t *)NULL, (sigset_t *)&ps_sigmask);
|
||||
#endif
|
||||
|
||||
/* Reset the line number if the caller wants us to. If we don't reset the
|
||||
line number, we have to subtract one, because we will add one just
|
||||
before executing the next command (resetting the line number sets it to
|
||||
0; the first line number is 1). */
|
||||
push_stream (0);
|
||||
if (parser_expanding_alias ())
|
||||
/* push current shell_input_line */
|
||||
parser_save_alias ();
|
||||
|
||||
code = should_jump_to_top_level = 0;
|
||||
oglobal = global_command;
|
||||
|
||||
with_input_from_string (string, from_file);
|
||||
ostring = bash_input.location.string;
|
||||
while (*(bash_input.location.string)) /* XXX - parser_expanding_alias () ? */
|
||||
{
|
||||
command = (COMMAND *)NULL;
|
||||
|
||||
#if 0
|
||||
if (interrupt_state)
|
||||
break;
|
||||
#endif
|
||||
|
||||
/* Provide a location for functions which `longjmp (top_level)' to
|
||||
jump to. */
|
||||
code = setjmp_nosigs (top_level);
|
||||
|
||||
if (code)
|
||||
{
|
||||
INTERNAL_DEBUG(("parse_string: longjmp executed: code = %d", code));
|
||||
|
||||
should_jump_to_top_level = 0;
|
||||
switch (code)
|
||||
{
|
||||
case FORCE_EOF:
|
||||
case ERREXIT:
|
||||
case EXITPROG:
|
||||
case EXITBLTIN:
|
||||
case DISCARD: /* XXX */
|
||||
if (command)
|
||||
dispose_command (command);
|
||||
/* Remember to call longjmp (top_level) after the old
|
||||
value for it is restored. */
|
||||
should_jump_to_top_level = 1;
|
||||
goto out;
|
||||
|
||||
default:
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
sigprocmask (SIG_SETMASK, (sigset_t *)&ps_sigmask, (sigset_t *)NULL);
|
||||
#endif
|
||||
command_error ("parse_string", CMDERR_BADJUMP, code, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (parse_command () == 0)
|
||||
{
|
||||
if (cmdp)
|
||||
*cmdp = global_command;
|
||||
else
|
||||
dispose_command (global_command);
|
||||
global_command = (COMMAND *)NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((flags & SEVAL_NOLONGJMP) == 0)
|
||||
{
|
||||
should_jump_to_top_level = 1;
|
||||
code = DISCARD;
|
||||
}
|
||||
else
|
||||
reset_parser (); /* XXX - sets token_to_read */
|
||||
break;
|
||||
}
|
||||
|
||||
if (current_token == yacc_EOF || current_token == shell_eof_token)
|
||||
{
|
||||
if (current_token == shell_eof_token)
|
||||
rewind_input_string ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
global_command = oglobal;
|
||||
nc = bash_input.location.string - ostring;
|
||||
if (endp)
|
||||
*endp = bash_input.location.string;
|
||||
|
||||
run_unwind_frame (PS_TAG);
|
||||
|
||||
/* If we return < 0, the caller (xparse_dolparen) will jump_to_top_level for
|
||||
us, after doing cleanup */
|
||||
if (should_jump_to_top_level)
|
||||
{
|
||||
if (parse_and_execute_level == 0)
|
||||
top_level_cleanup ();
|
||||
if (code == DISCARD)
|
||||
return -DISCARD;
|
||||
jump_to_top_level (code);
|
||||
}
|
||||
|
||||
return (nc);
|
||||
}
|
||||
|
||||
int
|
||||
open_redir_file (r, fnp)
|
||||
REDIRECT *r;
|
||||
char **fnp;
|
||||
{
|
||||
char *fn;
|
||||
int fd, rval;
|
||||
|
||||
if (r->instruction != r_input_direction)
|
||||
return -1;
|
||||
|
||||
/* Get the filename. */
|
||||
if (posixly_correct && !interactive_shell)
|
||||
disallow_filename_globbing++;
|
||||
fn = redirection_expand (r->redirectee.filename);
|
||||
if (posixly_correct && !interactive_shell)
|
||||
disallow_filename_globbing--;
|
||||
|
||||
if (fn == 0)
|
||||
{
|
||||
redirection_error (r, AMBIGUOUS_REDIRECT, fn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = open(fn, O_RDONLY);
|
||||
if (fd < 0)
|
||||
{
|
||||
file_error (fn);
|
||||
free (fn);
|
||||
if (fnp)
|
||||
*fnp = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fnp)
|
||||
*fnp = fn;
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* Handle a $( < file ) command substitution. This expands the filename,
|
||||
returning errors as appropriate, then just cats the file to the standard
|
||||
output. */
|
||||
static int
|
||||
cat_file (r)
|
||||
REDIRECT *r;
|
||||
{
|
||||
char *fn;
|
||||
int fd, rval;
|
||||
|
||||
fd = open_redir_file (r, &fn);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
rval = zcatfd (fd, 1, fn);
|
||||
|
||||
free (fn);
|
||||
close (fd);
|
||||
|
||||
return (rval);
|
||||
}
|
||||
|
||||
int
|
||||
evalstring (string, from_file, flags)
|
||||
char *string;
|
||||
const char *from_file;
|
||||
int flags;
|
||||
{
|
||||
volatile int r, rflag, rcatch;
|
||||
volatile int was_trap;
|
||||
|
||||
/* Are we running a trap when we execute this function? */
|
||||
was_trap = running_trap;
|
||||
|
||||
rcatch = 0;
|
||||
rflag = return_catch_flag;
|
||||
/* If we are in a place where `return' is valid, we have to catch
|
||||
`eval "... return"' and make sure parse_and_execute cleans up. Then
|
||||
we can trampoline to the previous saved return_catch location. */
|
||||
if (rflag)
|
||||
{
|
||||
begin_unwind_frame ("evalstring");
|
||||
|
||||
unwind_protect_int (return_catch_flag);
|
||||
unwind_protect_jmp_buf (return_catch);
|
||||
|
||||
return_catch_flag++; /* increment so we have a counter */
|
||||
rcatch = setjmp_nosigs (return_catch);
|
||||
}
|
||||
|
||||
if (rcatch)
|
||||
{
|
||||
/* We care about whether or not we are running the same trap we were
|
||||
when we entered this function. */
|
||||
parse_and_execute_cleanup (was_trap);
|
||||
r = return_catch_value;
|
||||
}
|
||||
else
|
||||
/* Note that parse_and_execute () frees the string it is passed. */
|
||||
r = parse_and_execute (string, from_file, flags);
|
||||
|
||||
if (rflag)
|
||||
{
|
||||
run_unwind_frame ("evalstring");
|
||||
if (rcatch && return_catch_flag)
|
||||
{
|
||||
return_catch_value = r;
|
||||
sh_longjmp (return_catch, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return (r);
|
||||
}
|
6229
third_party/bash/execute_cmd.c
vendored
Normal file
6229
third_party/bash/execute_cmd.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
123
third_party/bash/execute_cmd.h
vendored
Normal file
123
third_party/bash/execute_cmd.h
vendored
Normal file
|
@ -0,0 +1,123 @@
|
|||
/* execute_cmd.h - functions from execute_cmd.c. */
|
||||
|
||||
/* Copyright (C) 1993-2017 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (_EXECUTE_CMD_H_)
|
||||
#define _EXECUTE_CMD_H_
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
struct func_array_state
|
||||
{
|
||||
ARRAY *funcname_a;
|
||||
SHELL_VAR *funcname_v;
|
||||
ARRAY *source_a;
|
||||
SHELL_VAR *source_v;
|
||||
ARRAY *lineno_a;
|
||||
SHELL_VAR *lineno_v;
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Placeholder for later expansion to include more execution state */
|
||||
/* XXX - watch out for pid_t */
|
||||
struct execstate
|
||||
{
|
||||
pid_t pid;
|
||||
int subshell_env;
|
||||
};
|
||||
|
||||
|
||||
/* Variables declared in execute_cmd.c, used by many other files */
|
||||
extern int return_catch_flag;
|
||||
extern int return_catch_value;
|
||||
extern volatile int last_command_exit_value;
|
||||
extern int last_command_exit_signal;
|
||||
extern int builtin_ignoring_errexit;
|
||||
extern int executing_builtin;
|
||||
extern int executing_list;
|
||||
extern int comsub_ignore_return;
|
||||
extern int subshell_level;
|
||||
extern int match_ignore_case;
|
||||
extern int executing_command_builtin;
|
||||
extern int funcnest, funcnest_max;
|
||||
extern int evalnest, evalnest_max;
|
||||
extern int sourcenest, sourcenest_max;
|
||||
extern int stdin_redir;
|
||||
extern int line_number_for_err_trap;
|
||||
|
||||
extern char *the_printed_command_except_trap;
|
||||
|
||||
extern char *this_command_name;
|
||||
extern SHELL_VAR *this_shell_function;
|
||||
|
||||
/* Functions declared in execute_cmd.c, used by many other files */
|
||||
|
||||
extern struct fd_bitmap *new_fd_bitmap PARAMS((int));
|
||||
extern void dispose_fd_bitmap PARAMS((struct fd_bitmap *));
|
||||
extern void close_fd_bitmap PARAMS((struct fd_bitmap *));
|
||||
extern int executing_line_number PARAMS((void));
|
||||
extern int execute_command PARAMS((COMMAND *));
|
||||
extern int execute_command_internal PARAMS((COMMAND *, int, int, int, struct fd_bitmap *));
|
||||
extern int shell_execve PARAMS((char *, char **, char **));
|
||||
extern void setup_async_signals PARAMS((void));
|
||||
extern void async_redirect_stdin PARAMS((void));
|
||||
|
||||
extern void undo_partial_redirects PARAMS((void));
|
||||
extern void dispose_partial_redirects PARAMS((void));
|
||||
extern void dispose_exec_redirects PARAMS((void));
|
||||
|
||||
extern int execute_shell_function PARAMS((SHELL_VAR *, WORD_LIST *));
|
||||
|
||||
extern struct coproc *getcoprocbypid PARAMS((pid_t));
|
||||
extern struct coproc *getcoprocbyname PARAMS((const char *));
|
||||
|
||||
extern void coproc_init PARAMS((struct coproc *));
|
||||
extern struct coproc *coproc_alloc PARAMS((char *, pid_t));
|
||||
extern void coproc_dispose PARAMS((struct coproc *));
|
||||
extern void coproc_flush PARAMS((void));
|
||||
extern void coproc_close PARAMS((struct coproc *));
|
||||
extern void coproc_closeall PARAMS((void));
|
||||
extern void coproc_reap PARAMS((void));
|
||||
extern pid_t coproc_active PARAMS((void));
|
||||
|
||||
extern void coproc_rclose PARAMS((struct coproc *, int));
|
||||
extern void coproc_wclose PARAMS((struct coproc *, int));
|
||||
extern void coproc_fdclose PARAMS((struct coproc *, int));
|
||||
|
||||
extern void coproc_checkfd PARAMS((struct coproc *, int));
|
||||
extern void coproc_fdchk PARAMS((int));
|
||||
|
||||
extern void coproc_pidchk PARAMS((pid_t, int));
|
||||
|
||||
extern void coproc_fdsave PARAMS((struct coproc *));
|
||||
extern void coproc_fdrestore PARAMS((struct coproc *));
|
||||
|
||||
extern void coproc_setvars PARAMS((struct coproc *));
|
||||
extern void coproc_unsetvars PARAMS((struct coproc *));
|
||||
|
||||
#if defined (PROCESS_SUBSTITUTION)
|
||||
extern void close_all_files PARAMS((void));
|
||||
#endif
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
extern void restore_funcarray_state PARAMS((struct func_array_state *));
|
||||
#endif
|
||||
|
||||
#endif /* _EXECUTE_CMD_H_ */
|
1693
third_party/bash/expr.c
vendored
Normal file
1693
third_party/bash/expr.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
554
third_party/bash/externs.h
vendored
Normal file
554
third_party/bash/externs.h
vendored
Normal file
|
@ -0,0 +1,554 @@
|
|||
/* externs.h -- extern function declarations which do not appear in their
|
||||
own header file. */
|
||||
|
||||
/* Copyright (C) 1993-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Make sure that this is included *after* config.h! */
|
||||
|
||||
#if !defined (_EXTERNS_H_)
|
||||
# define _EXTERNS_H_
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
/* Functions from expr.c. */
|
||||
#define EXP_EXPANDED 0x01
|
||||
|
||||
extern intmax_t evalexp PARAMS((char *, int, int *));
|
||||
|
||||
/* Functions from print_cmd.c. */
|
||||
#define FUNC_MULTILINE 0x01
|
||||
#define FUNC_EXTERNAL 0x02
|
||||
|
||||
extern char *make_command_string PARAMS((COMMAND *));
|
||||
extern char *print_comsub PARAMS((COMMAND *));
|
||||
extern char *named_function_string PARAMS((char *, COMMAND *, int));
|
||||
|
||||
extern void print_command PARAMS((COMMAND *));
|
||||
extern void print_simple_command PARAMS((SIMPLE_COM *));
|
||||
extern void print_word_list PARAMS((WORD_LIST *, char *));
|
||||
|
||||
/* debugger support */
|
||||
extern void print_for_command_head PARAMS((FOR_COM *));
|
||||
#if defined (SELECT_COMMAND)
|
||||
extern void print_select_command_head PARAMS((SELECT_COM *));
|
||||
#endif
|
||||
extern void print_case_command_head PARAMS((CASE_COM *));
|
||||
#if defined (DPAREN_ARITHMETIC)
|
||||
extern void print_arith_command PARAMS((WORD_LIST *));
|
||||
#endif
|
||||
#if defined (COND_COMMAND)
|
||||
extern void print_cond_command PARAMS((COND_COM *));
|
||||
#endif
|
||||
|
||||
/* set -x support */
|
||||
extern void xtrace_init PARAMS((void));
|
||||
#ifdef NEED_XTRACE_SET_DECL
|
||||
extern void xtrace_set PARAMS((int, FILE *));
|
||||
#endif
|
||||
extern void xtrace_fdchk PARAMS((int));
|
||||
extern void xtrace_reset PARAMS((void));
|
||||
extern char *indirection_level_string PARAMS((void));
|
||||
extern void xtrace_print_assignment PARAMS((char *, char *, int, int));
|
||||
extern void xtrace_print_word_list PARAMS((WORD_LIST *, int));
|
||||
extern void xtrace_print_for_command_head PARAMS((FOR_COM *));
|
||||
#if defined (SELECT_COMMAND)
|
||||
extern void xtrace_print_select_command_head PARAMS((SELECT_COM *));
|
||||
#endif
|
||||
extern void xtrace_print_case_command_head PARAMS((CASE_COM *));
|
||||
#if defined (DPAREN_ARITHMETIC)
|
||||
extern void xtrace_print_arith_cmd PARAMS((WORD_LIST *));
|
||||
#endif
|
||||
#if defined (COND_COMMAND)
|
||||
extern void xtrace_print_cond_term PARAMS((int, int, WORD_DESC *, char *, char *));
|
||||
#endif
|
||||
|
||||
/* Functions from shell.c. */
|
||||
extern void exit_shell PARAMS((int)) __attribute__((__noreturn__));
|
||||
extern void sh_exit PARAMS((int)) __attribute__((__noreturn__));
|
||||
extern void subshell_exit PARAMS((int)) __attribute__((__noreturn__));
|
||||
extern void set_exit_status PARAMS((int));
|
||||
extern void disable_priv_mode PARAMS((void));
|
||||
extern void unbind_args PARAMS((void));
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
extern int shell_is_restricted PARAMS((char *));
|
||||
extern int maybe_make_restricted PARAMS((char *));
|
||||
#endif
|
||||
|
||||
extern void unset_bash_input PARAMS((int));
|
||||
extern void get_current_user_info PARAMS((void));
|
||||
|
||||
/* Functions from eval.c. */
|
||||
extern int reader_loop PARAMS((void));
|
||||
extern int pretty_print_loop PARAMS((void));
|
||||
extern int parse_command PARAMS((void));
|
||||
extern int read_command PARAMS((void));
|
||||
|
||||
/* Functions from braces.c. */
|
||||
#if defined (BRACE_EXPANSION)
|
||||
extern char **brace_expand PARAMS((char *));
|
||||
#endif
|
||||
|
||||
/* Miscellaneous functions from parse.y */
|
||||
extern int yyparse PARAMS((void));
|
||||
extern int return_EOF PARAMS((void));
|
||||
extern void push_token PARAMS((int));
|
||||
extern char *xparse_dolparen PARAMS((char *, char *, int *, int));
|
||||
extern COMMAND *parse_string_to_command PARAMS((char *, int));
|
||||
extern void reset_parser PARAMS((void));
|
||||
extern void reset_readahead_token PARAMS((void));
|
||||
extern WORD_LIST *parse_string_to_word_list PARAMS((char *, int, const char *));
|
||||
|
||||
extern int parser_will_prompt PARAMS((void));
|
||||
extern int parser_in_command_position PARAMS((void));
|
||||
|
||||
extern void free_pushed_string_input PARAMS((void));
|
||||
|
||||
extern int parser_expanding_alias PARAMS((void));
|
||||
extern void parser_save_alias PARAMS((void));
|
||||
extern void parser_restore_alias PARAMS((void));
|
||||
|
||||
extern void clear_shell_input_line PARAMS((void));
|
||||
|
||||
extern char *decode_prompt_string PARAMS((char *));
|
||||
|
||||
extern int get_current_prompt_level PARAMS((void));
|
||||
extern void set_current_prompt_level PARAMS((int));
|
||||
|
||||
#if defined (HISTORY)
|
||||
extern char *history_delimiting_chars PARAMS((const char *));
|
||||
#endif
|
||||
|
||||
/* Declarations for functions defined in locale.c */
|
||||
extern void set_default_locale PARAMS((void));
|
||||
extern void set_default_locale_vars PARAMS((void));
|
||||
extern int set_locale_var PARAMS((char *, char *));
|
||||
extern int set_lang PARAMS((char *, char *));
|
||||
extern void set_default_lang PARAMS((void));
|
||||
extern char *get_locale_var PARAMS((char *));
|
||||
extern char *localetrans PARAMS((char *, int, int *));
|
||||
extern char *mk_msgstr PARAMS((char *, int *));
|
||||
extern char *locale_expand PARAMS((char *, int, int, int, int *));
|
||||
#ifndef locale_decpoint
|
||||
extern int locale_decpoint PARAMS((void));
|
||||
#endif
|
||||
|
||||
/* Declarations for functions defined in list.c. */
|
||||
extern void list_walk PARAMS((GENERIC_LIST *, sh_glist_func_t *));
|
||||
extern void wlist_walk PARAMS((WORD_LIST *, sh_icpfunc_t *));
|
||||
extern GENERIC_LIST *list_reverse ();
|
||||
extern int list_length ();
|
||||
extern GENERIC_LIST *list_append ();
|
||||
extern GENERIC_LIST *list_remove ();
|
||||
|
||||
/* Declarations for functions defined in stringlib.c */
|
||||
extern int find_string_in_alist PARAMS((char *, STRING_INT_ALIST *, int));
|
||||
extern char *find_token_in_alist PARAMS((int, STRING_INT_ALIST *, int));
|
||||
extern int find_index_in_alist PARAMS((char *, STRING_INT_ALIST *, int));
|
||||
|
||||
extern char *substring PARAMS((const char *, int, int));
|
||||
extern char *strsub PARAMS((char *, char *, char *, int));
|
||||
extern char *strcreplace PARAMS((char *, int, const char *, int));
|
||||
extern void strip_leading PARAMS((char *));
|
||||
extern void strip_trailing PARAMS((char *, int, int));
|
||||
extern void xbcopy PARAMS((char *, char *, int));
|
||||
|
||||
/* Functions from version.c. */
|
||||
extern char *shell_version_string PARAMS((void));
|
||||
extern void show_shell_version PARAMS((int));
|
||||
|
||||
/* Functions from the bash library, lib/sh/libsh.a. These should really
|
||||
go into a separate include file. */
|
||||
|
||||
/* declarations for functions defined in lib/sh/casemod.c */
|
||||
extern char *sh_modcase PARAMS((const char *, char *, int));
|
||||
|
||||
/* Defines for flags argument to sh_modcase. These need to agree with what's
|
||||
in lib/sh/casemode.c */
|
||||
#define CASE_LOWER 0x0001
|
||||
#define CASE_UPPER 0x0002
|
||||
#define CASE_CAPITALIZE 0x0004
|
||||
#define CASE_UNCAP 0x0008
|
||||
#define CASE_TOGGLE 0x0010
|
||||
#define CASE_TOGGLEALL 0x0020
|
||||
#define CASE_UPFIRST 0x0040
|
||||
#define CASE_LOWFIRST 0x0080
|
||||
|
||||
#define CASE_USEWORDS 0x1000
|
||||
|
||||
/* declarations for functions defined in lib/sh/clktck.c */
|
||||
extern long get_clk_tck PARAMS((void));
|
||||
|
||||
/* declarations for functions defined in lib/sh/clock.c */
|
||||
extern void clock_t_to_secs ();
|
||||
extern void print_clock_t ();
|
||||
|
||||
/* Declarations for functions defined in lib/sh/dprintf.c */
|
||||
#if !defined (HAVE_DPRINTF)
|
||||
extern void dprintf PARAMS((int, const char *, ...)) __attribute__((__format__ (printf, 2, 3)));
|
||||
#endif
|
||||
|
||||
/* Declarations for functions defined in lib/sh/fmtulong.c */
|
||||
#define FL_PREFIX 0x01 /* add 0x, 0X, or 0 prefix as appropriate */
|
||||
#define FL_ADDBASE 0x02 /* add base# prefix to converted value */
|
||||
#define FL_HEXUPPER 0x04 /* use uppercase when converting to hex */
|
||||
#define FL_UNSIGNED 0x08 /* don't add any sign */
|
||||
|
||||
extern char *fmtulong PARAMS((unsigned long int, int, char *, size_t, int));
|
||||
|
||||
/* Declarations for functions defined in lib/sh/fmtulong.c */
|
||||
#if defined (HAVE_LONG_LONG_INT)
|
||||
extern char *fmtullong PARAMS((unsigned long long int, int, char *, size_t, int));
|
||||
#endif
|
||||
|
||||
/* Declarations for functions defined in lib/sh/fmtumax.c */
|
||||
extern char *fmtumax PARAMS((uintmax_t, int, char *, size_t, int));
|
||||
|
||||
/* Declarations for functions defined in lib/sh/fnxform.c */
|
||||
extern char *fnx_fromfs PARAMS((char *, size_t));
|
||||
extern char *fnx_tofs PARAMS((char *, size_t));
|
||||
|
||||
/* Declarations for functions defined in lib/sh/fpurge.c */
|
||||
|
||||
#if defined NEED_FPURGE_DECL
|
||||
#if !HAVE_DECL_FPURGE
|
||||
|
||||
#if HAVE_FPURGE
|
||||
# define fpurge _bash_fpurge
|
||||
#endif
|
||||
extern int fpurge PARAMS((FILE *stream));
|
||||
|
||||
#endif /* HAVE_DECL_FPURGE */
|
||||
#endif /* NEED_FPURGE_DECL */
|
||||
|
||||
/* Declarations for functions defined in lib/sh/getcwd.c */
|
||||
#if !defined (HAVE_GETCWD)
|
||||
extern char *getcwd PARAMS((char *, size_t));
|
||||
#endif
|
||||
|
||||
/* Declarations for functions defined in lib/sh/input_avail.c */
|
||||
extern int input_avail PARAMS((int));
|
||||
|
||||
/* Declarations for functions defined in lib/sh/itos.c */
|
||||
extern char *inttostr PARAMS((intmax_t, char *, size_t));
|
||||
extern char *itos PARAMS((intmax_t));
|
||||
extern char *mitos PARAMS((intmax_t));
|
||||
extern char *uinttostr PARAMS((uintmax_t, char *, size_t));
|
||||
extern char *uitos PARAMS((uintmax_t));
|
||||
|
||||
/* declarations for functions defined in lib/sh/makepath.c */
|
||||
#define MP_DOTILDE 0x01
|
||||
#define MP_DOCWD 0x02
|
||||
#define MP_RMDOT 0x04
|
||||
#define MP_IGNDOT 0x08
|
||||
|
||||
extern char *sh_makepath PARAMS((const char *, const char *, int));
|
||||
|
||||
/* declarations for functions defined in lib/sh/mbscasecmp.c */
|
||||
#if !defined (HAVE_MBSCASECMP)
|
||||
extern char *mbscasecmp PARAMS((const char *, const char *));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/mbschr.c */
|
||||
#if !defined (HAVE_MBSCHR)
|
||||
extern char *mbschr PARAMS((const char *, int));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/mbscmp.c */
|
||||
#if !defined (HAVE_MBSCMP)
|
||||
extern char *mbscmp PARAMS((const char *, const char *));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/netconn.c */
|
||||
extern int isnetconn PARAMS((int));
|
||||
|
||||
/* declarations for functions defined in lib/sh/netopen.c */
|
||||
extern int netopen PARAMS((char *));
|
||||
|
||||
/* Declarations for functions defined in lib/sh/oslib.c */
|
||||
|
||||
#if !defined (HAVE_DUP2) || defined (DUP2_BROKEN)
|
||||
extern int dup2 PARAMS((int, int));
|
||||
#endif
|
||||
|
||||
#if !defined (HAVE_GETDTABLESIZE)
|
||||
extern int getdtablesize PARAMS((void));
|
||||
#endif /* !HAVE_GETDTABLESIZE */
|
||||
|
||||
#if !defined (HAVE_GETHOSTNAME)
|
||||
extern int gethostname PARAMS((char *, int));
|
||||
#endif /* !HAVE_GETHOSTNAME */
|
||||
|
||||
extern int getmaxgroups PARAMS((void));
|
||||
extern long getmaxchild PARAMS((void));
|
||||
|
||||
/* declarations for functions defined in lib/sh/pathcanon.c */
|
||||
#define PATH_CHECKDOTDOT 0x0001
|
||||
#define PATH_CHECKEXISTS 0x0002
|
||||
#define PATH_HARDPATH 0x0004
|
||||
#define PATH_NOALLOC 0x0008
|
||||
|
||||
extern char *sh_canonpath PARAMS((char *, int));
|
||||
|
||||
/* declarations for functions defined in lib/sh/pathphys.c */
|
||||
extern char *sh_physpath PARAMS((char *, int));
|
||||
extern char *sh_realpath PARAMS((const char *, char *));
|
||||
|
||||
/* declarations for functions defined in lib/sh/random.c */
|
||||
extern int brand PARAMS((void));
|
||||
extern void sbrand PARAMS((unsigned long)); /* set bash random number generator. */
|
||||
extern void seedrand PARAMS((void)); /* seed generator randomly */
|
||||
extern void seedrand32 PARAMS((void));
|
||||
extern u_bits32_t get_urandom32 PARAMS((void));
|
||||
|
||||
/* declarations for functions defined in lib/sh/setlinebuf.c */
|
||||
#ifdef NEED_SH_SETLINEBUF_DECL
|
||||
extern int sh_setlinebuf PARAMS((FILE *));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/shaccess.c */
|
||||
extern int sh_eaccess PARAMS((const char *, int));
|
||||
|
||||
/* declarations for functions defined in lib/sh/shmatch.c */
|
||||
extern int sh_regmatch PARAMS((const char *, const char *, int));
|
||||
|
||||
/* defines for flags argument to sh_regmatch. */
|
||||
#define SHMAT_SUBEXP 0x001 /* save subexpressions in SH_REMATCH */
|
||||
#define SHMAT_PWARN 0x002 /* print a warning message on invalid regexp */
|
||||
|
||||
/* declarations for functions defined in lib/sh/shmbchar.c */
|
||||
extern size_t mbstrlen PARAMS((const char *));
|
||||
extern char *mbsmbchar PARAMS((const char *));
|
||||
extern int sh_mbsnlen PARAMS((const char *, size_t, int));
|
||||
|
||||
/* declarations for functions defined in lib/sh/shquote.c */
|
||||
extern char *sh_single_quote PARAMS((const char *));
|
||||
extern char *sh_double_quote PARAMS((const char *));
|
||||
extern char *sh_mkdoublequoted PARAMS((const char *, int, int));
|
||||
extern char *sh_un_double_quote PARAMS((char *));
|
||||
extern char *sh_backslash_quote PARAMS((char *, const char *, int));
|
||||
extern char *sh_backslash_quote_for_double_quotes PARAMS((char *, int));
|
||||
extern char *sh_quote_reusable PARAMS((char *, int));
|
||||
extern int sh_contains_shell_metas PARAMS((const char *));
|
||||
extern int sh_contains_quotes PARAMS((const char *));
|
||||
|
||||
/* declarations for functions defined in lib/sh/spell.c */
|
||||
extern int spname PARAMS((char *, char *));
|
||||
extern char *dirspell PARAMS((char *));
|
||||
|
||||
/* declarations for functions defined in lib/sh/strcasecmp.c */
|
||||
#if !defined (HAVE_STRCASECMP)
|
||||
extern int strncasecmp PARAMS((const char *, const char *, size_t));
|
||||
extern int strcasecmp PARAMS((const char *, const char *));
|
||||
#endif /* HAVE_STRCASECMP */
|
||||
|
||||
/* declarations for functions defined in lib/sh/strcasestr.c */
|
||||
#if ! HAVE_STRCASESTR
|
||||
extern char *strcasestr PARAMS((const char *, const char *));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strchrnul.c */
|
||||
#if ! HAVE_STRCHRNUL
|
||||
extern char *strchrnul PARAMS((const char *, int));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strerror.c */
|
||||
#if !defined (HAVE_STRERROR) && !defined (strerror)
|
||||
extern char *strerror PARAMS((int));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strftime.c */
|
||||
#if !defined (HAVE_STRFTIME) && defined (NEED_STRFTIME_DECL)
|
||||
extern size_t strftime PARAMS((char *, size_t, const char *, const struct tm *));
|
||||
#endif
|
||||
|
||||
/* declarations for functions and structures defined in lib/sh/stringlist.c */
|
||||
|
||||
/* This is a general-purpose argv-style array struct. */
|
||||
typedef struct _list_of_strings {
|
||||
char **list;
|
||||
int list_size;
|
||||
int list_len;
|
||||
} STRINGLIST;
|
||||
|
||||
typedef int sh_strlist_map_func_t PARAMS((char *));
|
||||
|
||||
extern STRINGLIST *strlist_create PARAMS((int));
|
||||
extern STRINGLIST *strlist_resize PARAMS((STRINGLIST *, int));
|
||||
extern void strlist_flush PARAMS((STRINGLIST *));
|
||||
extern void strlist_dispose PARAMS((STRINGLIST *));
|
||||
extern int strlist_remove PARAMS((STRINGLIST *, char *));
|
||||
extern STRINGLIST *strlist_copy PARAMS((STRINGLIST *));
|
||||
extern STRINGLIST *strlist_merge PARAMS((STRINGLIST *, STRINGLIST *));
|
||||
extern STRINGLIST *strlist_append PARAMS((STRINGLIST *, STRINGLIST *));
|
||||
extern STRINGLIST *strlist_prefix_suffix PARAMS((STRINGLIST *, char *, char *));
|
||||
extern void strlist_print PARAMS((STRINGLIST *, char *));
|
||||
extern void strlist_walk PARAMS((STRINGLIST *, sh_strlist_map_func_t *));
|
||||
extern void strlist_sort PARAMS((STRINGLIST *));
|
||||
|
||||
/* declarations for functions defined in lib/sh/stringvec.c */
|
||||
|
||||
extern char **strvec_create PARAMS((int));
|
||||
extern char **strvec_resize PARAMS((char **, int));
|
||||
extern char **strvec_mcreate PARAMS((int));
|
||||
extern char **strvec_mresize PARAMS((char **, int));
|
||||
extern void strvec_flush PARAMS((char **));
|
||||
extern void strvec_dispose PARAMS((char **));
|
||||
extern int strvec_remove PARAMS((char **, char *));
|
||||
extern int strvec_len PARAMS((char **));
|
||||
extern int strvec_search PARAMS((char **, char *));
|
||||
extern char **strvec_copy PARAMS((char **));
|
||||
extern int strvec_posixcmp PARAMS((char **, char **));
|
||||
extern int strvec_strcmp PARAMS((char **, char **));
|
||||
extern void strvec_sort PARAMS((char **, int));
|
||||
|
||||
extern char **strvec_from_word_list PARAMS((WORD_LIST *, int, int, int *));
|
||||
extern WORD_LIST *strvec_to_word_list PARAMS((char **, int, int));
|
||||
|
||||
/* declarations for functions defined in lib/sh/strnlen.c */
|
||||
#if !defined (HAVE_STRNLEN)
|
||||
extern size_t strnlen PARAMS((const char *, size_t));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strpbrk.c */
|
||||
#if !defined (HAVE_STRPBRK)
|
||||
extern char *strpbrk PARAMS((const char *, const char *));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strtod.c */
|
||||
#if !defined (HAVE_STRTOD)
|
||||
extern double strtod PARAMS((const char *, char **));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strtol.c */
|
||||
#if !HAVE_DECL_STRTOL
|
||||
extern long strtol PARAMS((const char *, char **, int));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strtoll.c */
|
||||
#if defined (HAVE_LONG_LONG_INT) && !HAVE_DECL_STRTOLL
|
||||
extern long long strtoll PARAMS((const char *, char **, int));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strtoul.c */
|
||||
#if !HAVE_DECL_STRTOUL
|
||||
extern unsigned long strtoul PARAMS((const char *, char **, int));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strtoull.c */
|
||||
#if defined (HAVE_UNSIGNED_LONG_LONG_INT) && !HAVE_DECL_STRTOULL
|
||||
extern unsigned long long strtoull PARAMS((const char *, char **, int));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strimax.c */
|
||||
#if !HAVE_DECL_STRTOIMAX
|
||||
extern intmax_t strtoimax PARAMS((const char *, char **, int));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strumax.c */
|
||||
#if !HAVE_DECL_STRTOUMAX
|
||||
extern uintmax_t strtoumax PARAMS((const char *, char **, int));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strtrans.c */
|
||||
extern char *ansicstr PARAMS((char *, int, int, int *, int *));
|
||||
extern char *ansic_quote PARAMS((char *, int, int *));
|
||||
extern int ansic_shouldquote PARAMS((const char *));
|
||||
extern char *ansiexpand PARAMS((char *, int, int, int *));
|
||||
|
||||
/* declarations for functions defined in lib/sh/strvis.c */
|
||||
extern int sh_charvis PARAMS((const char *, size_t *, size_t, char *, size_t *));
|
||||
extern char *sh_strvis PARAMS((const char *));
|
||||
|
||||
/* declarations for functions defined in lib/sh/timeval.c. No prototypes
|
||||
so we don't have to count on having a definition of struct timeval in
|
||||
scope when this file is included. */
|
||||
extern void timeval_to_secs ();
|
||||
extern void print_timeval ();
|
||||
|
||||
/* declarations for functions defined in lib/sh/tmpfile.c */
|
||||
#define MT_USETMPDIR 0x0001
|
||||
#define MT_READWRITE 0x0002
|
||||
#define MT_USERANDOM 0x0004
|
||||
#define MT_TEMPLATE 0x0008
|
||||
|
||||
extern char *sh_mktmpname PARAMS((char *, int));
|
||||
extern int sh_mktmpfd PARAMS((char *, int, char **));
|
||||
/* extern FILE *sh_mktmpfp PARAMS((char *, int, char **)); */
|
||||
extern char *sh_mktmpdir PARAMS((char *, int));
|
||||
|
||||
/* declarations for functions defined in lib/sh/uconvert.c */
|
||||
extern int uconvert PARAMS((char *, long *, long *, char **));
|
||||
|
||||
/* declarations for functions defined in lib/sh/ufuncs.c */
|
||||
extern unsigned int falarm PARAMS((unsigned int, unsigned int));
|
||||
extern unsigned int fsleep PARAMS((unsigned int, unsigned int));
|
||||
|
||||
/* declarations for functions defined in lib/sh/unicode.c */
|
||||
extern int u32cconv PARAMS((unsigned long, char *));
|
||||
extern void u32reset PARAMS((void));
|
||||
|
||||
/* declarations for functions defined in lib/sh/utf8.c */
|
||||
extern char *utf8_mbschr PARAMS((const char *, int));
|
||||
extern int utf8_mbscmp PARAMS((const char *, const char *));
|
||||
extern char *utf8_mbsmbchar PARAMS((const char *));
|
||||
extern int utf8_mbsnlen PARAMS((const char *, size_t, int));
|
||||
extern int utf8_mblen PARAMS((const char *, size_t));
|
||||
extern size_t utf8_mbstrlen PARAMS((const char *));
|
||||
|
||||
/* declarations for functions defined in lib/sh/wcsnwidth.c */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
extern int wcsnwidth PARAMS((const wchar_t *, size_t, int));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/winsize.c */
|
||||
extern void get_new_window_size PARAMS((int, int *, int *));
|
||||
|
||||
/* declarations for functions defined in lib/sh/zcatfd.c */
|
||||
extern int zcatfd PARAMS((int, int, char *));
|
||||
|
||||
/* declarations for functions defined in lib/sh/zgetline.c */
|
||||
extern ssize_t zgetline PARAMS((int, char **, size_t *, int, int));
|
||||
|
||||
/* declarations for functions defined in lib/sh/zmapfd.c */
|
||||
extern int zmapfd PARAMS((int, char **, char *));
|
||||
|
||||
/* declarations for functions defined in lib/sh/zread.c */
|
||||
extern ssize_t zread PARAMS((int, char *, size_t));
|
||||
extern ssize_t zreadretry PARAMS((int, char *, size_t));
|
||||
extern ssize_t zreadintr PARAMS((int, char *, size_t));
|
||||
extern ssize_t zreadc PARAMS((int, char *));
|
||||
extern ssize_t zreadcintr PARAMS((int, char *));
|
||||
extern ssize_t zreadn PARAMS((int, char *, size_t));
|
||||
extern void zreset PARAMS((void));
|
||||
extern void zsyncfd PARAMS((int));
|
||||
|
||||
/* declarations for functions defined in lib/sh/zwrite.c */
|
||||
extern int zwrite PARAMS((int, char *, size_t));
|
||||
|
||||
/* declarations for functions defined in lib/glob/gmisc.c */
|
||||
extern int match_pattern_char PARAMS((char *, char *, int));
|
||||
extern int umatchlen PARAMS((char *, size_t));
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
extern int match_pattern_wchar PARAMS((wchar_t *, wchar_t *, int));
|
||||
extern int wmatchlen PARAMS((wchar_t *, size_t));
|
||||
#endif
|
||||
|
||||
#endif /* _EXTERNS_H_ */
|
53
third_party/bash/filecntl.h
vendored
Normal file
53
third_party/bash/filecntl.h
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* filecntl.h - Definitions to set file descriptors to close-on-exec. */
|
||||
|
||||
/* Copyright (C) 1993 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (_FILECNTL_H_)
|
||||
#define _FILECNTL_H_
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
/* Definitions to set file descriptors to close-on-exec, the Posix way. */
|
||||
#if !defined (FD_CLOEXEC)
|
||||
#define FD_CLOEXEC 1
|
||||
#endif
|
||||
|
||||
#define FD_NCLOEXEC 0
|
||||
|
||||
#define SET_CLOSE_ON_EXEC(fd) (fcntl ((fd), F_SETFD, FD_CLOEXEC))
|
||||
#define SET_OPEN_ON_EXEC(fd) (fcntl ((fd), F_SETFD, FD_NCLOEXEC))
|
||||
|
||||
/* How to open a file in non-blocking mode, the Posix.1 way. */
|
||||
#if !defined (O_NONBLOCK)
|
||||
# if defined (O_NDELAY)
|
||||
# define O_NONBLOCK O_NDELAY
|
||||
# else
|
||||
# define O_NONBLOCK 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Make sure O_BINARY and O_TEXT are defined to avoid Windows-specific code. */
|
||||
#if !defined (O_BINARY)
|
||||
# define O_BINARY 0
|
||||
#endif
|
||||
#if !defined (O_TEXT)
|
||||
# define O_TEXT 0
|
||||
#endif
|
||||
|
||||
#endif /* ! _FILECNTL_H_ */
|
696
third_party/bash/findcmd.c
vendored
Normal file
696
third_party/bash/findcmd.c
vendored
Normal file
|
@ -0,0 +1,696 @@
|
|||
/* findcmd.c -- Functions to search for commands by name. */
|
||||
|
||||
/* Copyright (C) 1997-2022 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "chartypes.h"
|
||||
#include "bashtypes.h"
|
||||
#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
|
||||
# include <sys/file.h>
|
||||
#endif
|
||||
#include "filecntl.h"
|
||||
#include "posixstat.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
#include "bashansi.h"
|
||||
|
||||
#include "memalloc.h"
|
||||
#include "shell.h"
|
||||
#include "execute_cmd.h"
|
||||
#include "flags.h"
|
||||
#include "hashlib.h"
|
||||
#include "pathexp.h"
|
||||
#include "hashcmd.h"
|
||||
#include "findcmd.h" /* matching prototypes and declarations */
|
||||
|
||||
#include "strmatch.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
/* Static functions defined and used in this file. */
|
||||
static char *_find_user_command_internal PARAMS((const char *, int));
|
||||
static char *find_user_command_internal PARAMS((const char *, int));
|
||||
static char *find_user_command_in_path PARAMS((const char *, char *, int, int *));
|
||||
static char *find_in_path_element PARAMS((const char *, char *, int, int, struct stat *, int *));
|
||||
static char *find_absolute_program PARAMS((const char *, int));
|
||||
|
||||
static char *get_next_path_element PARAMS((char *, int *));
|
||||
|
||||
/* The file name which we would try to execute, except that it isn't
|
||||
possible to execute it. This is the first file that matches the
|
||||
name that we are looking for while we are searching $PATH for a
|
||||
suitable one to execute. If we cannot find a suitable executable
|
||||
file, then we use this one. */
|
||||
static char *file_to_lose_on;
|
||||
|
||||
/* Non-zero if we should stat every command found in the hash table to
|
||||
make sure it still exists. */
|
||||
int check_hashed_filenames = CHECKHASH_DEFAULT;
|
||||
|
||||
/* DOT_FOUND_IN_SEARCH becomes non-zero when find_user_command ()
|
||||
encounters a `.' as the directory pathname while scanning the
|
||||
list of possible pathnames; i.e., if `.' comes before the directory
|
||||
containing the file of interest. */
|
||||
int dot_found_in_search = 0;
|
||||
|
||||
/* Set up EXECIGNORE; a blacklist of patterns that executable files should not
|
||||
match. */
|
||||
static struct ignorevar execignore =
|
||||
{
|
||||
"EXECIGNORE",
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
void
|
||||
setup_exec_ignore (varname)
|
||||
char *varname;
|
||||
{
|
||||
setup_ignore_patterns (&execignore);
|
||||
}
|
||||
|
||||
static int
|
||||
exec_name_should_ignore (name)
|
||||
const char *name;
|
||||
{
|
||||
struct ign *p;
|
||||
|
||||
for (p = execignore.ignores; p && p->val; p++)
|
||||
if (strmatch (p->val, (char *)name, FNMATCH_EXTFLAG|FNM_CASEFOLD) != FNM_NOMATCH)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return some flags based on information about this file.
|
||||
The EXISTS bit is non-zero if the file is found.
|
||||
The EXECABLE bit is non-zero the file is executable.
|
||||
Zero is returned if the file is not found. */
|
||||
int
|
||||
file_status (name)
|
||||
const char *name;
|
||||
{
|
||||
struct stat finfo;
|
||||
int r;
|
||||
|
||||
/* Determine whether this file exists or not. */
|
||||
if (stat (name, &finfo) < 0)
|
||||
return (0);
|
||||
|
||||
/* If the file is a directory, then it is not "executable" in the
|
||||
sense of the shell. */
|
||||
if (S_ISDIR (finfo.st_mode))
|
||||
return (FS_EXISTS|FS_DIRECTORY);
|
||||
|
||||
r = FS_EXISTS;
|
||||
|
||||
#if defined (HAVE_EACCESS)
|
||||
/* Use eaccess(2) if we have it to take things like ACLs and other
|
||||
file access mechanisms into account. eaccess uses the effective
|
||||
user and group IDs, not the real ones. We could use sh_eaccess,
|
||||
but we don't want any special treatment for /dev/fd. */
|
||||
if (exec_name_should_ignore (name) == 0 && eaccess (name, X_OK) == 0)
|
||||
r |= FS_EXECABLE;
|
||||
if (eaccess (name, R_OK) == 0)
|
||||
r |= FS_READABLE;
|
||||
|
||||
return r;
|
||||
#elif defined (AFS)
|
||||
/* We have to use access(2) to determine access because AFS does not
|
||||
support Unix file system semantics. This may produce wrong
|
||||
answers for non-AFS files when ruid != euid. I hate AFS. */
|
||||
if (exec_name_should_ignore (name) == 0 && access (name, X_OK) == 0)
|
||||
r |= FS_EXECABLE;
|
||||
if (access (name, R_OK) == 0)
|
||||
r |= FS_READABLE;
|
||||
|
||||
return r;
|
||||
#else /* !HAVE_EACCESS && !AFS */
|
||||
|
||||
/* Find out if the file is actually executable. By definition, the
|
||||
only other criteria is that the file has an execute bit set that
|
||||
we can use. The same with whether or not a file is readable. */
|
||||
|
||||
/* Root only requires execute permission for any of owner, group or
|
||||
others to be able to exec a file, and can read any file. */
|
||||
if (current_user.euid == (uid_t)0)
|
||||
{
|
||||
r |= FS_READABLE;
|
||||
if (exec_name_should_ignore (name) == 0 && (finfo.st_mode & S_IXUGO))
|
||||
r |= FS_EXECABLE;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* If we are the owner of the file, the owner bits apply. */
|
||||
if (current_user.euid == finfo.st_uid)
|
||||
{
|
||||
if (exec_name_should_ignore (name) == 0 && (finfo.st_mode & S_IXUSR))
|
||||
r |= FS_EXECABLE;
|
||||
if (finfo.st_mode & S_IRUSR)
|
||||
r |= FS_READABLE;
|
||||
}
|
||||
|
||||
/* If we are in the owning group, the group permissions apply. */
|
||||
else if (group_member (finfo.st_gid))
|
||||
{
|
||||
if (exec_name_should_ignore (name) == 0 && (finfo.st_mode & S_IXGRP))
|
||||
r |= FS_EXECABLE;
|
||||
if (finfo.st_mode & S_IRGRP)
|
||||
r |= FS_READABLE;
|
||||
}
|
||||
|
||||
/* Else we check whether `others' have permission to execute the file */
|
||||
else
|
||||
{
|
||||
if (exec_name_should_ignore (name) == 0 && finfo.st_mode & S_IXOTH)
|
||||
r |= FS_EXECABLE;
|
||||
if (finfo.st_mode & S_IROTH)
|
||||
r |= FS_READABLE;
|
||||
}
|
||||
|
||||
return r;
|
||||
#endif /* !AFS */
|
||||
}
|
||||
|
||||
/* Return non-zero if FILE exists and is executable.
|
||||
Note that this function is the definition of what an
|
||||
executable file is; do not change this unless YOU know
|
||||
what an executable file is. */
|
||||
int
|
||||
executable_file (file)
|
||||
const char *file;
|
||||
{
|
||||
int s;
|
||||
|
||||
s = file_status (file);
|
||||
#if defined (EISDIR)
|
||||
if (s & FS_DIRECTORY)
|
||||
errno = EISDIR; /* let's see if we can improve error messages */
|
||||
#endif
|
||||
return ((s & FS_EXECABLE) && ((s & FS_DIRECTORY) == 0));
|
||||
}
|
||||
|
||||
int
|
||||
is_directory (file)
|
||||
const char *file;
|
||||
{
|
||||
return (file_status (file) & FS_DIRECTORY);
|
||||
}
|
||||
|
||||
int
|
||||
executable_or_directory (file)
|
||||
const char *file;
|
||||
{
|
||||
int s;
|
||||
|
||||
s = file_status (file);
|
||||
return ((s & FS_EXECABLE) || (s & FS_DIRECTORY));
|
||||
}
|
||||
|
||||
/* Locate the executable file referenced by NAME, searching along
|
||||
the contents of the shell PATH variable. Return a new string
|
||||
which is the full pathname to the file, or NULL if the file
|
||||
couldn't be found. If a file is found that isn't executable,
|
||||
and that is the only match, then return that. */
|
||||
char *
|
||||
find_user_command (name)
|
||||
const char *name;
|
||||
{
|
||||
return (find_user_command_internal (name, FS_EXEC_PREFERRED|FS_NODIRS));
|
||||
}
|
||||
|
||||
/* Locate the file referenced by NAME, searching along the contents
|
||||
of the shell PATH variable. Return a new string which is the full
|
||||
pathname to the file, or NULL if the file couldn't be found. This
|
||||
returns the first readable file found; designed to be used to look
|
||||
for shell scripts or files to source. */
|
||||
char *
|
||||
find_path_file (name)
|
||||
const char *name;
|
||||
{
|
||||
return (find_user_command_internal (name, FS_READABLE));
|
||||
}
|
||||
|
||||
static char *
|
||||
_find_user_command_internal (name, flags)
|
||||
const char *name;
|
||||
int flags;
|
||||
{
|
||||
char *path_list, *cmd;
|
||||
SHELL_VAR *var;
|
||||
|
||||
/* Search for the value of PATH in both the temporary environments and
|
||||
in the regular list of variables. */
|
||||
if (var = find_variable_tempenv ("PATH")) /* XXX could be array? */
|
||||
path_list = value_cell (var);
|
||||
else
|
||||
path_list = (char *)NULL;
|
||||
|
||||
if (path_list == 0 || *path_list == '\0')
|
||||
return (savestring (name));
|
||||
|
||||
cmd = find_user_command_in_path (name, path_list, flags, (int *)0);
|
||||
|
||||
return (cmd);
|
||||
}
|
||||
|
||||
static char *
|
||||
find_user_command_internal (name, flags)
|
||||
const char *name;
|
||||
int flags;
|
||||
{
|
||||
#ifdef __WIN32__
|
||||
char *res, *dotexe;
|
||||
|
||||
dotexe = (char *)xmalloc (strlen (name) + 5);
|
||||
strcpy (dotexe, name);
|
||||
strcat (dotexe, ".exe");
|
||||
res = _find_user_command_internal (dotexe, flags);
|
||||
free (dotexe);
|
||||
if (res == 0)
|
||||
res = _find_user_command_internal (name, flags);
|
||||
return res;
|
||||
#else
|
||||
return (_find_user_command_internal (name, flags));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return the next element from PATH_LIST, a colon separated list of
|
||||
paths. PATH_INDEX_POINTER is the address of an index into PATH_LIST;
|
||||
the index is modified by this function.
|
||||
Return the next element of PATH_LIST or NULL if there are no more. */
|
||||
static char *
|
||||
get_next_path_element (path_list, path_index_pointer)
|
||||
char *path_list;
|
||||
int *path_index_pointer;
|
||||
{
|
||||
char *path;
|
||||
|
||||
path = extract_colon_unit (path_list, path_index_pointer);
|
||||
|
||||
if (path == 0)
|
||||
return (path);
|
||||
|
||||
if (*path == '\0')
|
||||
{
|
||||
free (path);
|
||||
path = savestring (".");
|
||||
}
|
||||
|
||||
return (path);
|
||||
}
|
||||
|
||||
/* Look for PATHNAME in $PATH. Returns either the hashed command
|
||||
corresponding to PATHNAME or the first instance of PATHNAME found
|
||||
in $PATH. If (FLAGS&CMDSRCH_HASH) is non-zero, insert the instance of
|
||||
PATHNAME found in $PATH into the command hash table.
|
||||
If (FLAGS&CMDSRCH_STDPATH) is non-zero, we are running in a `command -p'
|
||||
environment and should use the Posix standard path.
|
||||
Returns a newly-allocated string. */
|
||||
char *
|
||||
search_for_command (pathname, flags)
|
||||
const char *pathname;
|
||||
int flags;
|
||||
{
|
||||
char *hashed_file, *command, *path_list;
|
||||
int temp_path, st;
|
||||
SHELL_VAR *path;
|
||||
|
||||
hashed_file = command = (char *)NULL;
|
||||
|
||||
/* If PATH is in the temporary environment for this command, don't use the
|
||||
hash table to search for the full pathname. */
|
||||
path = find_variable_tempenv ("PATH");
|
||||
temp_path = path && tempvar_p (path);
|
||||
|
||||
/* Don't waste time trying to find hashed data for a pathname
|
||||
that is already completely specified or if we're using a command-
|
||||
specific value for PATH. */
|
||||
if (temp_path == 0 && (flags & CMDSRCH_STDPATH) == 0 && absolute_program (pathname) == 0)
|
||||
hashed_file = phash_search (pathname);
|
||||
|
||||
/* If a command found in the hash table no longer exists, we need to
|
||||
look for it in $PATH. Thank you Posix.2. This forces us to stat
|
||||
every command found in the hash table. */
|
||||
|
||||
if (hashed_file && (posixly_correct || check_hashed_filenames))
|
||||
{
|
||||
st = file_status (hashed_file);
|
||||
if ((st & (FS_EXISTS|FS_EXECABLE)) != (FS_EXISTS|FS_EXECABLE))
|
||||
{
|
||||
phash_remove (pathname);
|
||||
free (hashed_file);
|
||||
hashed_file = (char *)NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (hashed_file)
|
||||
command = hashed_file;
|
||||
else if (absolute_program (pathname))
|
||||
/* A command containing a slash is not looked up in PATH or saved in
|
||||
the hash table. */
|
||||
command = savestring (pathname);
|
||||
else
|
||||
{
|
||||
if (flags & CMDSRCH_STDPATH)
|
||||
path_list = conf_standard_path ();
|
||||
else if (temp_path || path)
|
||||
path_list = value_cell (path);
|
||||
else
|
||||
path_list = 0;
|
||||
|
||||
command = find_user_command_in_path (pathname, path_list, FS_EXEC_PREFERRED|FS_NODIRS, &st);
|
||||
|
||||
if (command && hashing_enabled && temp_path == 0 && (flags & CMDSRCH_HASH))
|
||||
{
|
||||
/* If we found the full pathname the same as the command name, the
|
||||
command probably doesn't exist. Don't put it into the hash
|
||||
table unless it's an executable file in the current directory. */
|
||||
if (STREQ (command, pathname))
|
||||
{
|
||||
if (st & FS_EXECABLE)
|
||||
phash_insert ((char *)pathname, command, dot_found_in_search, 1);
|
||||
}
|
||||
/* If we're in posix mode, don't add files without the execute bit
|
||||
to the hash table. */
|
||||
else if (posixly_correct || check_hashed_filenames)
|
||||
{
|
||||
if (st & FS_EXECABLE)
|
||||
phash_insert ((char *)pathname, command, dot_found_in_search, 1);
|
||||
}
|
||||
else
|
||||
phash_insert ((char *)pathname, command, dot_found_in_search, 1);
|
||||
}
|
||||
|
||||
if (flags & CMDSRCH_STDPATH)
|
||||
free (path_list);
|
||||
}
|
||||
|
||||
return (command);
|
||||
}
|
||||
|
||||
char *
|
||||
user_command_matches (name, flags, state)
|
||||
const char *name;
|
||||
int flags, state;
|
||||
{
|
||||
register int i;
|
||||
int path_index, name_len;
|
||||
char *path_list, *path_element, *match;
|
||||
struct stat dotinfo;
|
||||
static char **match_list = NULL;
|
||||
static int match_list_size = 0;
|
||||
static int match_index = 0;
|
||||
|
||||
if (state == 0)
|
||||
{
|
||||
/* Create the list of matches. */
|
||||
if (match_list == 0)
|
||||
{
|
||||
match_list_size = 5;
|
||||
match_list = strvec_create (match_list_size);
|
||||
}
|
||||
|
||||
/* Clear out the old match list. */
|
||||
for (i = 0; i < match_list_size; i++)
|
||||
match_list[i] = 0;
|
||||
|
||||
/* We haven't found any files yet. */
|
||||
match_index = 0;
|
||||
|
||||
if (absolute_program (name))
|
||||
{
|
||||
match_list[0] = find_absolute_program (name, flags);
|
||||
match_list[1] = (char *)NULL;
|
||||
path_list = (char *)NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
name_len = strlen (name);
|
||||
file_to_lose_on = (char *)NULL;
|
||||
dot_found_in_search = 0;
|
||||
if (stat (".", &dotinfo) < 0)
|
||||
dotinfo.st_dev = dotinfo.st_ino = 0; /* so same_file won't match */
|
||||
path_list = get_string_value ("PATH");
|
||||
path_index = 0;
|
||||
}
|
||||
|
||||
while (path_list && path_list[path_index])
|
||||
{
|
||||
path_element = get_next_path_element (path_list, &path_index);
|
||||
|
||||
if (path_element == 0)
|
||||
break;
|
||||
|
||||
match = find_in_path_element (name, path_element, flags, name_len, &dotinfo, (int *)0);
|
||||
free (path_element);
|
||||
|
||||
if (match == 0)
|
||||
continue;
|
||||
|
||||
if (match_index + 1 == match_list_size)
|
||||
{
|
||||
match_list_size += 10;
|
||||
match_list = strvec_resize (match_list, (match_list_size + 1));
|
||||
}
|
||||
|
||||
match_list[match_index++] = match;
|
||||
match_list[match_index] = (char *)NULL;
|
||||
FREE (file_to_lose_on);
|
||||
file_to_lose_on = (char *)NULL;
|
||||
}
|
||||
|
||||
/* We haven't returned any strings yet. */
|
||||
match_index = 0;
|
||||
}
|
||||
|
||||
match = match_list[match_index];
|
||||
|
||||
if (match)
|
||||
match_index++;
|
||||
|
||||
return (match);
|
||||
}
|
||||
|
||||
static char *
|
||||
find_absolute_program (name, flags)
|
||||
const char *name;
|
||||
int flags;
|
||||
{
|
||||
int st;
|
||||
|
||||
st = file_status (name);
|
||||
|
||||
/* If the file doesn't exist, quit now. */
|
||||
if ((st & FS_EXISTS) == 0)
|
||||
return ((char *)NULL);
|
||||
|
||||
/* If we only care about whether the file exists or not, return
|
||||
this filename. Otherwise, maybe we care about whether this
|
||||
file is executable. If it is, and that is what we want, return it. */
|
||||
if ((flags & FS_EXISTS) || ((flags & FS_EXEC_ONLY) && (st & FS_EXECABLE)))
|
||||
return (savestring (name));
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static char *
|
||||
find_in_path_element (name, path, flags, name_len, dotinfop, rflagsp)
|
||||
const char *name;
|
||||
char *path;
|
||||
int flags, name_len;
|
||||
struct stat *dotinfop;
|
||||
int *rflagsp;
|
||||
{
|
||||
int status;
|
||||
char *full_path, *xpath;
|
||||
|
||||
xpath = (posixly_correct == 0 && *path == '~') ? bash_tilde_expand (path, 0) : path;
|
||||
|
||||
/* Remember the location of "." in the path, in all its forms
|
||||
(as long as they begin with a `.', e.g. `./.') */
|
||||
/* We could also do this or something similar for all relative pathnames
|
||||
found while searching PATH. */
|
||||
if (dot_found_in_search == 0 && *xpath == '.')
|
||||
dot_found_in_search = same_file (".", xpath, dotinfop, (struct stat *)NULL);
|
||||
|
||||
full_path = sh_makepath (xpath, name, 0);
|
||||
|
||||
status = file_status (full_path);
|
||||
|
||||
if (xpath != path)
|
||||
free (xpath);
|
||||
|
||||
if (rflagsp)
|
||||
*rflagsp = status;
|
||||
|
||||
if ((status & FS_EXISTS) == 0)
|
||||
{
|
||||
free (full_path);
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
/* The file exists. If the caller simply wants the first file, here it is. */
|
||||
if (flags & FS_EXISTS)
|
||||
return (full_path);
|
||||
|
||||
/* If we have a readable file, and the caller wants a readable file, this
|
||||
is it. */
|
||||
if ((flags & FS_READABLE) && (status & FS_READABLE))
|
||||
return (full_path);
|
||||
|
||||
/* If the file is executable, then it satisfies the cases of
|
||||
EXEC_ONLY and EXEC_PREFERRED. Return this file unconditionally. */
|
||||
if ((status & FS_EXECABLE) && (flags & (FS_EXEC_ONLY|FS_EXEC_PREFERRED)) &&
|
||||
(((flags & FS_NODIRS) == 0) || ((status & FS_DIRECTORY) == 0)))
|
||||
{
|
||||
FREE (file_to_lose_on);
|
||||
file_to_lose_on = (char *)NULL;
|
||||
return (full_path);
|
||||
}
|
||||
|
||||
/* The file is not executable, but it does exist. If we prefer
|
||||
an executable, then remember this one if it is the first one
|
||||
we have found. */
|
||||
if ((flags & FS_EXEC_PREFERRED) && file_to_lose_on == 0 && exec_name_should_ignore (full_path) == 0)
|
||||
file_to_lose_on = savestring (full_path);
|
||||
|
||||
/* If we want only executable files, or we don't want directories and
|
||||
this file is a directory, or we want a readable file and this file
|
||||
isn't readable, fail. */
|
||||
if ((flags & (FS_EXEC_ONLY|FS_EXEC_PREFERRED)) ||
|
||||
((flags & FS_NODIRS) && (status & FS_DIRECTORY)) ||
|
||||
((flags & FS_READABLE) && (status & FS_READABLE) == 0))
|
||||
{
|
||||
free (full_path);
|
||||
return ((char *)NULL);
|
||||
}
|
||||
else
|
||||
return (full_path);
|
||||
}
|
||||
|
||||
/* This does the dirty work for find_user_command_internal () and
|
||||
user_command_matches ().
|
||||
NAME is the name of the file to search for.
|
||||
PATH_LIST is a colon separated list of directories to search.
|
||||
FLAGS contains bit fields which control the files which are eligible.
|
||||
Some values are:
|
||||
FS_EXEC_ONLY: The file must be an executable to be found.
|
||||
FS_EXEC_PREFERRED: If we can't find an executable, then the
|
||||
the first file matching NAME will do.
|
||||
FS_EXISTS: The first file found will do.
|
||||
FS_NODIRS: Don't find any directories.
|
||||
*/
|
||||
static char *
|
||||
find_user_command_in_path (name, path_list, flags, rflagsp)
|
||||
const char *name;
|
||||
char *path_list;
|
||||
int flags, *rflagsp;
|
||||
{
|
||||
char *full_path, *path;
|
||||
int path_index, name_len, rflags;
|
||||
struct stat dotinfo;
|
||||
|
||||
/* We haven't started looking, so we certainly haven't seen
|
||||
a `.' as the directory path yet. */
|
||||
dot_found_in_search = 0;
|
||||
|
||||
if (rflagsp)
|
||||
*rflagsp = 0;
|
||||
|
||||
if (absolute_program (name))
|
||||
{
|
||||
full_path = find_absolute_program (name, flags);
|
||||
return (full_path);
|
||||
}
|
||||
|
||||
if (path_list == 0 || *path_list == '\0')
|
||||
return (savestring (name)); /* XXX */
|
||||
|
||||
file_to_lose_on = (char *)NULL;
|
||||
name_len = strlen (name);
|
||||
if (stat (".", &dotinfo) < 0)
|
||||
dotinfo.st_dev = dotinfo.st_ino = 0;
|
||||
path_index = 0;
|
||||
|
||||
while (path_list[path_index])
|
||||
{
|
||||
/* Allow the user to interrupt out of a lengthy path search. */
|
||||
QUIT;
|
||||
|
||||
path = get_next_path_element (path_list, &path_index);
|
||||
if (path == 0)
|
||||
break;
|
||||
|
||||
/* Side effects: sets dot_found_in_search, possibly sets
|
||||
file_to_lose_on. */
|
||||
full_path = find_in_path_element (name, path, flags, name_len, &dotinfo, &rflags);
|
||||
free (path);
|
||||
|
||||
/* We use the file status flag bits to check whether full_path is a
|
||||
directory, which we reject here. */
|
||||
if (full_path && (rflags & FS_DIRECTORY))
|
||||
{
|
||||
free (full_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (full_path)
|
||||
{
|
||||
if (rflagsp)
|
||||
*rflagsp = rflags;
|
||||
FREE (file_to_lose_on);
|
||||
return (full_path);
|
||||
}
|
||||
}
|
||||
|
||||
/* We didn't find exactly what the user was looking for. Return
|
||||
the contents of FILE_TO_LOSE_ON which is NULL when the search
|
||||
required an executable, or non-NULL if a file was found and the
|
||||
search would accept a non-executable as a last resort. If the
|
||||
caller specified FS_NODIRS, and file_to_lose_on is a directory,
|
||||
return NULL. */
|
||||
if (file_to_lose_on && (flags & FS_NODIRS) && file_isdir (file_to_lose_on))
|
||||
{
|
||||
free (file_to_lose_on);
|
||||
file_to_lose_on = (char *)NULL;
|
||||
}
|
||||
|
||||
return (file_to_lose_on);
|
||||
}
|
||||
|
||||
/* External interface to find a command given a $PATH. Separate from
|
||||
find_user_command_in_path to allow future customization. */
|
||||
char *
|
||||
find_in_path (name, path_list, flags)
|
||||
const char *name;
|
||||
char *path_list;
|
||||
int flags;
|
||||
{
|
||||
return (find_user_command_in_path (name, path_list, flags, (int *)0));
|
||||
}
|
47
third_party/bash/findcmd.h
vendored
Normal file
47
third_party/bash/findcmd.h
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* findcmd.h - functions from findcmd.c. */
|
||||
|
||||
/* Copyright (C) 1997-2015,2020 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (_FINDCMD_H_)
|
||||
#define _FINDCMD_H_
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
/* Flags for search_for_command */
|
||||
#define CMDSRCH_HASH 0x01
|
||||
#define CMDSRCH_STDPATH 0x02
|
||||
#define CMDSRCH_TEMPENV 0x04
|
||||
|
||||
extern int file_status PARAMS((const char *));
|
||||
extern int executable_file PARAMS((const char *));
|
||||
extern int is_directory PARAMS((const char *));
|
||||
extern int executable_or_directory PARAMS((const char *));
|
||||
extern char *find_user_command PARAMS((const char *));
|
||||
extern char *find_in_path PARAMS((const char *, char *, int));
|
||||
extern char *find_path_file PARAMS((const char *));
|
||||
extern char *search_for_command PARAMS((const char *, int));
|
||||
extern char *user_command_matches PARAMS((const char *, int, int));
|
||||
extern void setup_exec_ignore PARAMS((char *));
|
||||
|
||||
extern int dot_found_in_search;
|
||||
|
||||
/* variables managed via shopt */
|
||||
extern int check_hashed_filenames;
|
||||
|
||||
#endif /* _FINDCMD_H_ */
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue