From 14bf57180f30ca80f265fee01662ff122778193d Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Thu, 30 Nov 2023 20:50:10 -0800 Subject: [PATCH] Import GNU Make 4.4.1 Landlock Make hasn't been working well on AARCH64 systems. Let's do this over the right way, using our new build tools. --- libc/calls/ttyname_r.c | 2 +- third_party/make/AUTHORS | 90 - third_party/make/BUILD.mk | 85 +- third_party/make/COPYING | 674 ----- third_party/make/README.cosmo | 5 +- third_party/make/alloca.h | 68 - third_party/make/ar.c | 90 +- third_party/make/arscan.c | 407 ++- third_party/make/basename-lgpl.c | 74 - third_party/make/commands.c | 193 +- third_party/make/commands.h | 11 +- third_party/make/concat-filename.c | 31 +- third_party/make/concat-filename.h | 25 +- third_party/make/config.h | 1315 +++++---- third_party/make/debug.h | 10 +- third_party/make/default.c | 429 ++- third_party/make/dep.h | 39 +- third_party/make/dir.c | 1497 ++++++---- third_party/make/dirname-lgpl.c | 85 - third_party/make/dirname.h | 52 - third_party/make/error.c | 187 -- third_party/make/error.h | 75 - third_party/make/exitfail.c | 18 - third_party/make/exitfail.h | 18 - third_party/make/expand.c | 65 +- third_party/make/fcntl.c | 555 ---- third_party/make/fcntl.h | 810 ------ third_party/make/fd-hook.c | 114 - third_party/make/fd-hook.h | 119 - third_party/make/file.c | 397 ++- third_party/make/filedef.h | 24 +- third_party/make/filename.h | 98 +- third_party/make/findprog-in.c | 37 +- third_party/make/findprog.h | 16 +- third_party/make/function.c | 1133 ++++++-- third_party/make/getopt.c | 78 +- third_party/make/getopt.h | 11 +- third_party/make/getopt1.c | 36 +- third_party/make/getprogname.c | 34 - third_party/make/getprogname.h | 38 - third_party/make/gettext.h | 279 +- third_party/make/glob.c | 1318 +++++++++ third_party/make/glob.h | 163 ++ third_party/make/gnumake.h | 12 +- third_party/make/guile.c | 142 +- third_party/make/hash.c | 82 +- third_party/make/hash.h | 13 +- third_party/make/implicit.c | 378 ++- third_party/make/intprops.h | 583 ---- third_party/make/job.c | 2743 ++++++++++++------- third_party/make/job.h | 28 +- third_party/make/load.c | 243 +- third_party/make/loadapi.c | 12 +- third_party/make/main.c | 1933 +++++++++---- third_party/make/{makeint.inc => makeint.h} | 416 ++- third_party/make/misc.c | 896 ++++-- third_party/make/mkconfig.h | 37 + third_party/make/mkcustom.h | 65 + third_party/make/os.h | 123 +- third_party/make/output.c | 318 +-- third_party/make/output.h | 54 +- third_party/make/posixos.c | 898 ++++-- third_party/make/read.c | 687 +++-- third_party/make/remake.c | 411 ++- third_party/make/remote-cstms.c | 297 ++ third_party/make/remote-stub.c | 12 +- third_party/make/rule.c | 122 +- third_party/make/rule.h | 6 +- third_party/make/shuffle.c | 237 ++ third_party/make/shuffle.h | 26 + third_party/make/signame.c | 254 ++ third_party/make/stddef.h | 119 - third_party/make/stdint.h | 735 ----- third_party/make/stdio.h | 1906 ------------- third_party/make/stdlib.h | 1615 ----------- third_party/make/strcache.c | 17 +- third_party/make/stripslash.c | 45 - third_party/make/unistd.c | 4 - third_party/make/unistd.h | 2173 --------------- third_party/make/variable.c | 1003 +++++-- third_party/make/variable.h | 40 +- third_party/make/version.c | 10 +- third_party/make/vpath.c | 99 +- third_party/make/xalloc-die.c | 41 - third_party/make/xalloc-oversized.h | 58 - third_party/make/xalloc.h | 261 -- third_party/make/xconcat-filename.c | 41 - third_party/make/xmalloc.c | 122 - 88 files changed, 13931 insertions(+), 16191 deletions(-) delete mode 100644 third_party/make/AUTHORS delete mode 100644 third_party/make/COPYING delete mode 100644 third_party/make/alloca.h delete mode 100644 third_party/make/basename-lgpl.c delete mode 100644 third_party/make/dirname-lgpl.c delete mode 100644 third_party/make/dirname.h delete mode 100644 third_party/make/error.c delete mode 100644 third_party/make/error.h delete mode 100644 third_party/make/exitfail.c delete mode 100644 third_party/make/exitfail.h delete mode 100644 third_party/make/fcntl.c delete mode 100644 third_party/make/fcntl.h delete mode 100644 third_party/make/fd-hook.c delete mode 100644 third_party/make/fd-hook.h delete mode 100644 third_party/make/getprogname.c delete mode 100644 third_party/make/getprogname.h create mode 100644 third_party/make/glob.c create mode 100644 third_party/make/glob.h delete mode 100644 third_party/make/intprops.h rename third_party/make/{makeint.inc => makeint.h} (65%) create mode 100644 third_party/make/mkconfig.h create mode 100644 third_party/make/mkcustom.h create mode 100644 third_party/make/remote-cstms.c create mode 100644 third_party/make/shuffle.c create mode 100644 third_party/make/shuffle.h create mode 100644 third_party/make/signame.c delete mode 100644 third_party/make/stddef.h delete mode 100644 third_party/make/stdint.h delete mode 100644 third_party/make/stdio.h delete mode 100644 third_party/make/stdlib.h delete mode 100644 third_party/make/stripslash.c delete mode 100644 third_party/make/unistd.c delete mode 100644 third_party/make/unistd.h delete mode 100644 third_party/make/xalloc-die.c delete mode 100644 third_party/make/xalloc-oversized.h delete mode 100644 third_party/make/xalloc.h delete mode 100644 third_party/make/xconcat-filename.c delete mode 100644 third_party/make/xmalloc.c diff --git a/libc/calls/ttyname_r.c b/libc/calls/ttyname_r.c index 0f505264c..7b08449db 100644 --- a/libc/calls/ttyname_r.c +++ b/libc/calls/ttyname_r.c @@ -98,7 +98,7 @@ errno_t ttyname_r(int fd, char *buf, size_t size) { } } errno = e; - STRACE("ttyname_r(%d, %#.*hhs) → %s", fd, (int)size, buf, + STRACE("ttyname_r(%d, %#.*hhs) → %s", fd, (int)strnlen(buf, size), buf, !res ? "0" : _strerrno(res)); return res; } diff --git a/third_party/make/AUTHORS b/third_party/make/AUTHORS deleted file mode 100644 index dc9127e46..000000000 --- a/third_party/make/AUTHORS +++ /dev/null @@ -1,90 +0,0 @@ ------------------------------------ - -GNU make development up to version 3.75 by: - Roland McGrath - - -Development starting with GNU make 3.76 by: - Paul D. Smith - - Additional development starting with GNU make 3.81 by: - Boris Kolpackov - - -GNU Make User's Manual - Written by: - Richard M. Stallman - - Edited by: - Roland McGrath - Bob Chassell - Melissa Weisshaus - Paul D. Smith - ------------------------------------ -GNU make porting efforts: - - Port to VMS by: - Klaus Kaempf - Hartmut Becker - Archive support/Bug fixes by: - John W. Eaton - Martin Zinser - - Port to Amiga by: - Aaron Digulla - - Port to MS-DOS (DJGPP), OS/2, and MS-Windows (native/MinGW) by: - DJ Delorie - Rob Tulloh - Eli Zaretskii - Jonathan Grant - Andreas Beuning - Earnie Boyd - Troy Runkel - ------------------------------------ -Other contributors: - - Janet Carson - Howard Chu - Ludovic Courtès - Paul Eggert - Ramon Garcia Fernandez - Klaus Heinz - Michael Joosten - Jim Kelton - David Lubbren - Tim Magill - Markus Mauhart - Greg McGary - Thien-Thi Nguyen - Thomas Riedl - Han-Wen Nienhuys - Andreas Schwab - Carl Staelin (Princeton University) - Ian Stewartson (Data Logic Limited) - David A. Wheeler - David Boyce - Frank Heckenbach - Kaz Kylheku - Christof Warlich - -With suggestions/comments/bug reports from a cast of ... well ... -hundreds, anyway :) - -------------------------------------------------------------------------------- -Copyright (C) 1997-2020 Free Software Foundation, Inc. -This file is part of GNU Make. - -GNU Make 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. - -GNU Make 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 . diff --git a/third_party/make/BUILD.mk b/third_party/make/BUILD.mk index 2bbb13933..99b840a65 100644 --- a/third_party/make/BUILD.mk +++ b/third_party/make/BUILD.mk @@ -14,67 +14,42 @@ THIRD_PARTY_MAKE_A = \ o/$(MODE)/third_party/make/make.a THIRD_PARTY_MAKE_HDRS = \ - third_party/make/filename.h \ - third_party/make/dirname.h \ - third_party/make/stddef.h \ - third_party/make/error.h \ - third_party/make/gnumake.h \ - third_party/make/gettext.h \ - third_party/make/stdlib.h \ - third_party/make/xalloc.h \ - third_party/make/xalloc-oversized.h \ - third_party/make/os.h \ - third_party/make/stdint.h \ - third_party/make/fd-hook.h \ - third_party/make/job.h \ - third_party/make/unistd.h \ - third_party/make/getprogname.h \ - third_party/make/config.h \ third_party/make/concat-filename.h \ - third_party/make/findprog.h \ - third_party/make/intprops.h \ - third_party/make/exitfail.h \ - third_party/make/alloca.h \ - third_party/make/hash.h \ - third_party/make/rule.h \ - third_party/make/filedef.h \ - third_party/make/fcntl.h \ - third_party/make/stdio.h \ - third_party/make/variable.h \ + third_party/make/commands.h \ + third_party/make/glob.h \ + third_party/make/config.h \ third_party/make/debug.h \ - third_party/make/output.h \ - third_party/make/getopt.h \ third_party/make/dep.h \ - third_party/make/commands.h - + third_party/make/findprog.h \ + third_party/make/filedef.h \ + third_party/make/filename.h \ + third_party/make/getopt.h \ + third_party/make/gettext.h \ + third_party/make/gnumake.h \ + third_party/make/hash.h \ + third_party/make/job.h \ + third_party/make/makeint.h \ + third_party/make/mkconfig.h \ + third_party/make/mkcustom.h \ + third_party/make/os.h \ + third_party/make/output.h \ + third_party/make/rule.h \ + third_party/make/shuffle.h \ + third_party/make/variable.h THIRD_PARTY_MAKE_INCS = \ - third_party/make/makeint.inc + third_party/make/makeint.h THIRD_PARTY_MAKE_CHECKS = \ $(THIRD_PARTY_MAKE_A).pkg -# libgnu.a recipe -THIRD_PARTY_MAKE_SRCS_LIB = \ - third_party/make/basename-lgpl.c \ - third_party/make/concat-filename.c \ - third_party/make/dirname-lgpl.c \ - third_party/make/error.c \ - third_party/make/exitfail.c \ - third_party/make/fcntl.c \ - third_party/make/fd-hook.c \ - third_party/make/findprog-in.c \ - third_party/make/getprogname.c \ - third_party/make/stripslash.c \ - third_party/make/unistd.c \ - third_party/make/xalloc-die.c \ - third_party/make/xconcat-filename.c \ - third_party/make/xmalloc.c - -THIRD_PARTY_MAKE_SRCS_BASE = \ +THIRD_PARTY_MAKE_SRCS = \ + third_party/make/glob.c \ third_party/make/commands.c \ third_party/make/default.c \ third_party/make/dir.c \ + third_party/make/concat-filename.c \ + third_party/make/findprog-in.c \ third_party/make/expand.c \ third_party/make/file.c \ third_party/make/function.c \ @@ -97,12 +72,9 @@ THIRD_PARTY_MAKE_SRCS_BASE = \ third_party/make/strcache.c \ third_party/make/variable.c \ third_party/make/version.c \ + third_party/make/shuffle.c \ third_party/make/vpath.c -THIRD_PARTY_MAKE_SRCS = \ - $(THIRD_PARTY_MAKE_SRCS_BASE) \ - $(THIRD_PARTY_MAKE_SRCS_LIB) - THIRD_PARTY_MAKE_OBJS = \ $(THIRD_PARTY_MAKE_SRCS:%.c=o/$(MODE)/%.o) @@ -170,12 +142,9 @@ o/$(MODE)/third_party/make/hash.o: private \ $(THIRD_PARTY_MAKE_OBJS): private \ CFLAGS += \ + -fportcosmo \ -DNO_ARCHIVES \ - -DHAVE_CONFIG_H \ - -DSTACK_FRAME_UNLIMITED \ - -DINCLUDEDIR=\".\" \ - -DLIBDIR=\".\" \ - -DLOCALEDIR=\".\" + -DHAVE_CONFIG_H .PHONY: o/$(MODE)/third_party/make o/$(MODE)/third_party/make: \ diff --git a/third_party/make/COPYING b/third_party/make/COPYING deleted file mode 100644 index 94a9ed024..000000000 --- a/third_party/make/COPYING +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - 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. - - - Copyright (C) - - 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 . - -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: - - Copyright (C) - 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 -. - - 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 -. diff --git a/third_party/make/README.cosmo b/third_party/make/README.cosmo index 20283f965..b46479593 100644 --- a/third_party/make/README.cosmo +++ b/third_party/make/README.cosmo @@ -5,8 +5,8 @@ DESCRIPTION ORIGIN - GNU Make 4.3 - http://ftp.gnu.org/gnu/make/make-4.3.tar.gz + GNU Make 4.4.1 + http://ftp.gnu.org/gnu/make/make-4.4.1.tar.gz LICENSE @@ -30,4 +30,3 @@ LOCAL CHANGES - .MAXCORE variable to set upper limit on core dumps - Do automatic setup and teardown of TMPDIR per rule - Remove code that forces slow path if not using /bin/sh - - Remove 200,000 lines of VAX/OS2/DOS/AMIGA/etc. code diff --git a/third_party/make/alloca.h b/third_party/make/alloca.h deleted file mode 100644 index 7d23d903a..000000000 --- a/third_party/make/alloca.h +++ /dev/null @@ -1,68 +0,0 @@ -/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ -/* Memory allocation on the stack. - - Copyright (C) 1995, 1999, 2001-2004, 2006-2020 Free Software Foundation, - Inc. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, 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 - . - */ - -/* Avoid using the symbol _ALLOCA_H here, as Bison assumes _ALLOCA_H - means there is a real alloca function. */ -#ifndef _GL_ALLOCA_H -#define _GL_ALLOCA_H - -/* alloca (N) returns a pointer to N bytes of memory - allocated on the stack, which will last until the function returns. - Use of alloca should be avoided: - - inside arguments of function calls - undefined behaviour, - - in inline functions - the allocation may actually last until the - calling function returns, - - for huge N (say, N >= 65536) - you never know how large (or small) - the stack is, and when the stack cannot fulfill the memory allocation - request, the program just crashes. - */ - -#ifndef alloca -# ifdef __GNUC__ - /* Some version of mingw have an that causes trouble when - included after 'alloca' gets defined as a macro. As a workaround, include - this first and define 'alloca' as a macro afterwards. */ -# if (defined _WIN32 && ! defined __CYGWIN__) && 1 -# endif -# define alloca __builtin_alloca -# elif defined _AIX -# define alloca __alloca -# elif defined _MSC_VER -# define alloca _alloca -# elif defined __DECC && defined __VMS -# define alloca __ALLOCA -# elif defined __TANDEM && defined _TNS_E_TARGET -# ifdef __cplusplus -extern "C" -# endif -void *_alloca (unsigned short); -# pragma intrinsic (_alloca) -# define alloca _alloca -# elif defined __MVS__ -# else -# ifdef __cplusplus -extern "C" -# endif -void *alloca (size_t); -# endif -#endif - -#endif /* _GL_ALLOCA_H */ diff --git a/third_party/make/ar.c b/third_party/make/ar.c index 93a0305f8..73fc09566 100644 --- a/third_party/make/ar.c +++ b/third_party/make/ar.c @@ -1,5 +1,5 @@ /* Interface to 'ar' archives for GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. @@ -13,13 +13,16 @@ 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 . */ -#include "third_party/make/makeint.inc" -/**/ -#include "libc/mem/alg.h" -#include "third_party/make/dep.h" -#include "third_party/make/filedef.h" -#include "third_party/musl/fnmatch.h" +this program. If not, see . */ + +#include "makeint.h" + +#ifndef NO_ARCHIVES + +#include "filedef.h" +#include "dep.h" +#include +#include /* Return nonzero if NAME is an archive-member reference, zero if not. An archive-member reference is a name like 'lib(member)' where member is a @@ -33,7 +36,7 @@ ar_name (const char *name) const char *p = strchr (name, '('); const char *end; - if (p == 0 || p == name) + if (p == NULL || p == name) return 0; end = p + strlen (p) - 1; @@ -58,6 +61,9 @@ ar_parse_name (const char *name, char **arname_p, char **memname_p) *arname_p = xstrdup (name); p = strchr (*arname_p, '('); + /* This is never called unless ar_name() is true so p cannot be NULL. */ + if (!p) + OS (fatal, NILF, "Internal: ar_parse_name: bad name '%s'", *arname_p); *(p++) = '\0'; p[strlen (p) - 1] = '\0'; *memname_p = p; @@ -67,10 +73,10 @@ ar_parse_name (const char *name, char **arname_p, char **memname_p) /* This function is called by 'ar_scan' to find which member to look at. */ /* ARGSUSED */ -static long int +static intmax_t ar_member_date_1 (int desc UNUSED, const char *mem, int truncated, long int hdrpos UNUSED, long int datapos UNUSED, - long int size UNUSED, long int date, + long int size UNUSED, intmax_t date, int uid UNUSED, int gid UNUSED, unsigned int mode UNUSED, const void *name) { @@ -84,7 +90,7 @@ ar_member_date (const char *name) { char *arname; char *memname; - long int val; + intmax_t val; ar_parse_name (name, &arname, &memname); @@ -109,11 +115,19 @@ ar_member_date (const char *name) free (arname); - return (val <= 0 ? (time_t) -1 : (time_t) val); + return 0 < val && val <= TYPE_MAXIMUM (time_t) ? val : -1; } /* Set the archive-member NAME's modtime to now. */ +#ifdef VMS +int +ar_touch (const char *name) +{ + O (error, NILF, _("touch archive member is not available on VMS")); + return -1; +} +#else int ar_touch (const char *name) { @@ -158,7 +172,7 @@ ar_touch (const char *name) return val; } - +#endif /* !VMS */ /* State of an 'ar_glob' run, passed to 'ar_glob_match'. */ @@ -173,6 +187,9 @@ struct ar_glob_state { const char *arname; const char *pattern; +#ifdef VMS + char *suffix; +#endif size_t size; struct nameseq *chain; unsigned int n; @@ -181,10 +198,10 @@ struct ar_glob_state /* This function is called by 'ar_scan' to match one archive element against the pattern in STATE. */ -static long int +static intmax_t ar_glob_match (int desc UNUSED, const char *mem, int truncated UNUSED, long int hdrpos UNUSED, long int datapos UNUSED, - long int size UNUSED, long int date UNUSED, int uid UNUSED, + long int size UNUSED, intmax_t date UNUSED, int uid UNUSED, int gid UNUSED, unsigned int mode UNUSED, const void *arg) { struct ar_glob_state *state = (struct ar_glob_state *)arg; @@ -192,14 +209,20 @@ ar_glob_match (int desc UNUSED, const char *mem, int truncated UNUSED, if (fnmatch (state->pattern, mem, FNM_PATHNAME|FNM_PERIOD) == 0) { /* We have a match. Add it to the chain. */ - struct nameseq *new = xcalloc (1, state->size); + struct nameseq *new = xcalloc (state->size); +#ifdef VMS + if (state->suffix) + new->name = strcache_add( + concat(5, state->arname, "(", mem, state->suffix, ")")); + else +#endif new->name = strcache_add(concat(4, state->arname, "(", mem, ")")); new->next = state->chain; state->chain = new; ++state->n; } - return 0L; + return 0; } /* Return nonzero if PATTERN contains any metacharacters. @@ -245,7 +268,9 @@ ar_glob (const char *arname, const char *member_pattern, size_t size) struct nameseq *n; const char **names; unsigned int i; - +#ifdef VMS + char *vms_member_pattern; +#endif if (! ar_glob_pattern_p (member_pattern, 1)) return 0; @@ -253,11 +278,36 @@ ar_glob (const char *arname, const char *member_pattern, size_t size) ar_glob_match will accumulate them in STATE.chain. */ state.arname = arname; state.pattern = member_pattern; +#ifdef VMS + { + /* In a copy of the pattern, find the suffix, save it and remove it from + the pattern */ + char *lastdot; + vms_member_pattern = xstrdup(member_pattern); + lastdot = strrchr(vms_member_pattern, '.'); + state.suffix = lastdot; + if (lastdot) + { + state.suffix = xstrdup(lastdot); + *lastdot = 0; + } + state.pattern = vms_member_pattern; + } +#endif state.size = size; state.chain = 0; state.n = 0; ar_scan (arname, ar_glob_match, &state); +#ifdef VMS + /* Deallocate any duplicated string */ + free(vms_member_pattern); + if (state.suffix) + { + free(state.suffix); + } +#endif + if (state.chain == 0) return 0; @@ -278,3 +328,5 @@ ar_glob (const char *arname, const char *member_pattern, size_t size) return state.chain; } + +#endif /* Not NO_ARCHIVES. */ diff --git a/third_party/make/arscan.c b/third_party/make/arscan.c index bd948bad5..edd4070c3 100644 --- a/third_party/make/arscan.c +++ b/third_party/make/arscan.c @@ -1,5 +1,5 @@ /* Library function for scanning an archive file. -Copyright (C) 1987-2020 Free Software Foundation, Inc. +Copyright (C) 1987-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,16 +12,290 @@ 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 . */ +this program. If not, see . */ -#include "libc/sysv/consts/o.h" -#include "third_party/make/makeint.inc" +#include "makeint.h" #ifdef TEST /* Hack, the real error() routine eventually pulls in die from main.c */ #define error(a, b, c, d) #endif +#ifdef HAVE_FCNTL_H +#include +#else +#include +#endif + +#ifndef NO_ARCHIVES + +#ifdef VMS +#include +#include +#include +#include +#include +#include +#include +#include + +/* This symbol should be present in lbrdef.h. */ +#if !defined LBR$_HDRTRUNC +#pragma extern_model save +#pragma extern_model globalvalue +extern unsigned int LBR$_HDRTRUNC; +#pragma extern_model restore +#endif + +#include +#include + +const char * +vmsify (const char *name, int type); + +/* Time conversion from VMS to Unix + Conversion from local time (stored in library) to GMT (needed for gmake) + Note: The tm_gmtoff element is a VMS extension to the ANSI standard. */ +static time_t +vms_time_to_unix(void *vms_time) +{ + struct tm *tmp; + time_t unix_time; + + unix_time = decc$fix_time(vms_time); + tmp = localtime(&unix_time); + unix_time -= tmp->tm_gmtoff; + + return unix_time; +} + + +/* VMS library routines need static variables for callback */ +static void *VMS_lib_idx; + +static const void *VMS_saved_arg; + +static intmax_t (*VMS_function) (); + +static intmax_t VMS_function_ret; + + +/* This is a callback procedure for lib$get_index */ +static int +VMS_get_member_info(struct dsc$descriptor_s *module, unsigned long *rfa) +{ + int status, i; + const int truncated = 0; /* Member name may be truncated */ + time_t member_date; /* Member date */ + char *filename; + unsigned int buffer_length; /* Actual buffer length */ + + /* Unused constants - Make does not actually use most of these */ + const int file_desc = -1; /* archive file descriptor for reading the data */ + const int header_position = 0; /* Header position */ + const int data_position = 0; /* Data position in file */ + const int data_size = 0; /* Data size */ + const int uid = 0; /* member gid */ + const int gid = 0; /* member gid */ + const int mode = 0; /* member protection mode */ + /* End of unused constants */ + + static struct dsc$descriptor_s bufdesc = + { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL }; + + /* Only need the module definition */ + struct mhddef *mhd; + + /* If a previous callback is non-zero, just return that status */ + if (VMS_function_ret) + { + return SS$_NORMAL; + } + + /* lbr_set_module returns more than just the module header. So allocate + a buffer which is big enough: the maximum LBR$C_MAXHDRSIZ. That's at + least bigger than the size of struct mhddef. + If the request is too small, a buffer truncated warning is issued so + it can be reissued with a larger buffer. + We do not care if the buffer is truncated, so that is still a success. */ + mhd = xmalloc(LBR$C_MAXHDRSIZ); + bufdesc.dsc$a_pointer = (char *) mhd; + bufdesc.dsc$w_length = LBR$C_MAXHDRSIZ; + + status = lbr$set_module(&VMS_lib_idx, rfa, &bufdesc, &buffer_length, 0); + + if ((status != LBR$_HDRTRUNC) && !$VMS_STATUS_SUCCESS(status)) + { + ON(error, NILF, + _("lbr$set_module() failed to extract module info, status = %d"), + status); + + lbr$close(&VMS_lib_idx); + + return status; + } + +#ifdef TEST + /* When testing this code, it is useful to know the length returned */ + printf ("Input length = %d, actual = %u\n", + bufdesc.dsc$w_length, buffer_length); +#endif + + /* Conversion from VMS time to C time. + VMS defectlet - mhddef is sub-optimal, for the time, it has a 32 bit + longword, mhd$l_datim, and a 32 bit fill instead of two longwords, or + equivalent. */ + member_date = vms_time_to_unix(&mhd->mhd$l_datim); + free(mhd); + + /* Here we have a problem. The module name on VMS does not have + a file type, but the filename pattern in the "VMS_saved_arg" + may have one. + But only the method being called knows how to interpret the + filename pattern. + There are currently two different formats being used. + This means that we need a VMS specific code in those methods + to handle it. */ + filename = xmalloc(module->dsc$w_length + 1); + + /* TODO: We may need an option to preserve the case of the module + For now force the module name to lower case */ + for (i = 0; i < module->dsc$w_length; i++) + filename[i] = _tolower((unsigned char )module->dsc$a_pointer[i]); + + filename[i] = '\0'; + + VMS_function_ret = (*VMS_function)(file_desc, filename, truncated, + header_position, data_position, data_size, member_date, uid, gid, mode, + VMS_saved_arg); + + free(filename); + return SS$_NORMAL; +} + + +/* Takes three arguments ARCHIVE, FUNCTION and ARG. + + Open the archive named ARCHIVE, find its members one by one, + and for each one call FUNCTION with the following arguments: + archive file descriptor for reading the data, + member name, + member name might be truncated flag, + member header position in file, + member data position in file, + member data size, + member date, + member uid, + member gid, + member protection mode, + ARG. + + NOTE: on VMS systems, only name, date, and arg are meaningful! + + The descriptor is poised to read the data of the member + when FUNCTION is called. It does not matter how much + data FUNCTION reads. + + If FUNCTION returns nonzero, we immediately return + what FUNCTION returned. + + Returns -1 if archive does not exist, + Returns -2 if archive has invalid format. + Returns 0 if have scanned successfully. */ + +intmax_t +ar_scan (const char *archive, ar_member_func_t function, const void *varg) +{ + char *vms_archive; + + static struct dsc$descriptor_s libdesc = + { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL }; + + const unsigned long func = LBR$C_READ; + const unsigned long type = LBR$C_TYP_UNK; + const unsigned long index = 1; + unsigned long lib_idx; + int status; + + VMS_saved_arg = varg; + + /* Null archive string can show up in test and cause an access violation */ + if (archive == NULL) + { + /* Null filenames do not exist */ + return -1; + } + + /* archive path name must be in VMS format */ + vms_archive = (char *) vmsify(archive, 0); + + status = lbr$ini_control(&VMS_lib_idx, &func, &type, 0); + + if (!$VMS_STATUS_SUCCESS(status)) + { + ON(error, NILF, _("lbr$ini_control() failed with status = %d"), status); + return -2; + } + + libdesc.dsc$a_pointer = vms_archive; + libdesc.dsc$w_length = strlen(vms_archive); + + status = lbr$open(&VMS_lib_idx, &libdesc, 0, NULL, 0, NULL, 0); + + if (!$VMS_STATUS_SUCCESS(status)) + { + + /* TODO: A library format failure could mean that this is a file + generated by the GNU AR utility and in that case, we need to + take the UNIX codepath. This will also take a change to the + GNV AR wrapper program. */ + + switch (status) + { + case RMS$_FNF: + /* Archive does not exist */ + return -1; + default: +#ifndef TEST + OSN(error, NILF, + _("unable to open library '%s' to lookup member status %d"), + archive, status); +#endif + /* For library format errors, specification says to return -2 */ + return -2; + } + } + + VMS_function = function; + + /* Clear the return status, as we are supposed to stop calling the + callback function if it becomes non-zero, and this is a static + variable. */ + VMS_function_ret = 0; + + status = lbr$get_index(&VMS_lib_idx, &index, VMS_get_member_info, NULL, 0); + + lbr$close(&VMS_lib_idx); + + /* Unless a failure occurred in the lbr$ routines, return the + the status from the 'function' routine. */ + if ($VMS_STATUS_SUCCESS(status)) + { + return VMS_function_ret; + } + + /* This must be something wrong with the library and an error + message should already have been printed. */ + return -2; +} + +#else /* !VMS */ + +/* SCO Unix's compiler defines both of these. */ +#ifdef M_UNIX +#undef M_XENIX +#endif + /* On the sun386i and in System V rel 3, ar.h defines two different archive formats depending upon whether you have defined PORTAR (normal) or PORT5AR (System V Release 1). There is no default, one or the other must be defined @@ -57,7 +331,8 @@ this program. If not, see . */ #endif #ifndef WINDOWS32 -# if 0 && !defined (__ANDROID__) && !defined (__BEOS__) +# if !defined (__ANDROID__) && !defined (__BEOS__) && !defined(MK_OS_ZOS) +# include # else /* These platforms don't have but have archives in the same format * as many other Unices. This was taken from GNU binutils for BeOS. @@ -80,6 +355,9 @@ struct ar_hdr /* These should allow us to read Windows (VC++) libraries (according to Frank * Libbrecht ) */ +# include +# include +# include # define ARMAG IMAGE_ARCHIVE_START # define SARMAG IMAGE_ARCHIVE_START_SIZE # define ar_hdr _IMAGE_ARCHIVE_MEMBER_HEADER @@ -98,8 +376,41 @@ struct ar_hdr # define AR_HDR_SIZE (sizeof (struct ar_hdr)) #endif -#include "third_party/make/output.h" +#include "intprops.h" + +#include "output.h" + +static uintmax_t +parse_int (const char *ptr, const size_t len, const int base, uintmax_t max, + const char *type, const char *archive, const char *name) +{ + const char *const ep = ptr + len; + const int maxchar = '0' + base - 1; + uintmax_t val = 0; + + /* In all the versions I know of the spaces come last, but be safe. */ + while (ptr < ep && *ptr == ' ') + ++ptr; + + while (ptr < ep && *ptr != ' ') + { + uintmax_t nv; + + if (*ptr < '0' || *ptr > maxchar) + OSSS (fatal, NILF, + _("Invalid %s for archive %s member %s"), type, archive, name); + nv = (val * base) + (*ptr - '0'); + if (nv < val || nv > max) + OSSS (fatal, NILF, + _("Invalid %s for archive %s member %s"), type, archive, name); + val = nv; + ++ptr; + } + + return val; +} + /* Takes three arguments ARCHIVE, FUNCTION and ARG. Open the archive named ARCHIVE, find its members one by one, @@ -127,7 +438,7 @@ struct ar_hdr Returns -2 if archive has invalid format. Returns 0 if have scanned successfully. */ -long int +intmax_t ar_scan (const char *archive, ar_member_func_t function, const void *arg) { #ifdef AIAMAG @@ -138,7 +449,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg) # endif #endif char *namemap = 0; - int namemap_size = 0; + unsigned int namemap_size = 0; int desc = open (archive, O_RDONLY, 0); if (desc < 0) return -1; @@ -238,7 +549,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg) while (1) { - int nread; + ssize_t nread; struct ar_hdr member_header; #ifdef AIAMAGBIG struct ar_hdr_big member_header_big; @@ -247,7 +558,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg) # define ARNAME_MAX 255 char name[ARNAME_MAX + 1]; int name_len; - long int dateval; + intmax_t dateval; int uidval, gidval; long int data_offset; #else @@ -259,9 +570,13 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg) #endif long int eltsize; unsigned int eltmode; - long int fnval; + intmax_t eltdate; + int eltuid, eltgid; + intmax_t fnval; off_t o; + memset(&member_header, '\0', sizeof (member_header)); + EINTRLOOP (o, lseek (desc, member_offset, 0)); if (o < 0) goto invalid; @@ -288,7 +603,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg) name[name_len] = '\0'; - sscanf (member_header_big.ar_date, "%12ld", &dateval); + sscanf (member_header_big.ar_date, "%12" SCNdMAX, &dateval); sscanf (member_header_big.ar_uid, "%12d", &uidval); sscanf (member_header_big.ar_gid, "%12d", &gidval); sscanf (member_header_big.ar_mode, "%12o", &eltmode); @@ -316,7 +631,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg) name[name_len] = '\0'; - sscanf (member_header.ar_date, "%12ld", &dateval); + sscanf (member_header.ar_date, "%12" SCNdMAX, &dateval); sscanf (member_header.ar_uid, "%12d", &uidval); sscanf (member_header.ar_gid, "%12d", &gidval); sscanf (member_header.ar_mode, "%12o", &eltmode); @@ -391,10 +706,11 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg) && (name[0] == ' ' || name[0] == '/') && namemap != 0) { - int name_off = atoi (name + 1); - int name_len; + const char* err; + unsigned int name_off = make_toui (name + 1, &err); + size_t name_len; - if (name_off < 0 || name_off >= namemap_size) + if (err|| name_off >= namemap_size) goto invalid; name = namemap + name_off; @@ -407,14 +723,15 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg) && name[1] == '1' && name[2] == '/') { - int name_len = atoi (name + 3); + const char* err; + unsigned int name_len = make_toui (name + 3, &err); - if (name_len < 1) + if (err || name_len == 0 || name_len >= MIN (PATH_MAX, INT_MAX)) goto invalid; name = alloca (name_len + 1); nread = readbuf (desc, name, name_len); - if (nread != name_len) + if (nread < 0 || (unsigned int) nread != name_len) goto invalid; name[name_len] = '\0'; @@ -425,8 +742,16 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg) } #ifndef M_XENIX - sscanf (TOCHAR (member_header.ar_mode), "%8o", &eltmode); - eltsize = atol (TOCHAR (member_header.ar_size)); +#define PARSE_INT(_m, _t, _b, _n) \ + (_t) parse_int (TOCHAR (member_header._m), sizeof (member_header._m), \ + _b, TYPE_MAXIMUM (_t), _n, archive, name) + + eltmode = PARSE_INT (ar_mode, unsigned int, 8, "mode"); + eltsize = PARSE_INT (ar_size, long, 10, "size"); + eltdate = PARSE_INT (ar_date, intmax_t, 10, "date"); + eltuid = PARSE_INT (ar_uid, int, 10, "uid"); + eltgid = PARSE_INT (ar_gid, int, 10, "gid"); +#undef PARSE_INT #else /* Xenix. */ eltmode = (unsigned short int) member_header.ar_mode; eltsize = member_header.ar_size; @@ -436,9 +761,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg) (*function) (desc, name, ! long_name, member_offset, member_offset + AR_HDR_SIZE, eltsize, #ifndef M_XENIX - atol (TOCHAR (member_header.ar_date)), - atoi (TOCHAR (member_header.ar_uid)), - atoi (TOCHAR (member_header.ar_gid)), + eltdate, eltuid, eltgid, #else /* Xenix. */ member_header.ar_date, member_header.ar_uid, @@ -518,7 +841,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg) close (desc); return -2; } - +#endif /* !VMS */ /* Return nonzero iff NAME matches MEM. If TRUNCATED is nonzero, MEM may be truncated to @@ -578,10 +901,10 @@ ar_name_equal (const char *name, const char *mem, int truncated) #ifndef VMS /* ARGSUSED */ -static long int +static intmax_t ar_member_pos (int desc UNUSED, const char *mem, int truncated, long int hdrpos, long int datapos UNUSED, long int size UNUSED, - long int date UNUSED, int uid UNUSED, int gid UNUSED, + intmax_t date UNUSED, int uid UNUSED, int gid UNUSED, unsigned int mode UNUSED, const void *name) { if (!ar_name_equal (name, mem, truncated)) @@ -599,12 +922,13 @@ ar_member_pos (int desc UNUSED, const char *mem, int truncated, int ar_member_touch (const char *arname, const char *memname) { - long int pos = ar_scan (arname, ar_member_pos, memname); + intmax_t pos = ar_scan (arname, ar_member_pos, memname); + off_t opos; int fd; struct ar_hdr ar_hdr; off_t o; int r; - unsigned int ui; + int datelen; struct stat statbuf; if (pos < 0) @@ -612,11 +936,13 @@ ar_member_touch (const char *arname, const char *memname) if (!pos) return 1; + opos = (off_t) pos; + EINTRLOOP (fd, open (arname, O_RDWR, 0666)); if (fd < 0) return -3; /* Read in this member's header */ - EINTRLOOP (o, lseek (fd, pos, 0)); + EINTRLOOP (o, lseek (fd, opos, 0)); if (o < 0) goto lose; r = readbuf (fd, &ar_hdr, AR_HDR_SIZE); @@ -628,15 +954,16 @@ ar_member_touch (const char *arname, const char *memname) goto lose; /* Advance member's time to that time */ #if defined(ARFMAG) || defined(ARFZMAG) || defined(AIAMAG) || defined(WINDOWS32) - for (ui = 0; ui < sizeof ar_hdr.ar_date; ui++) - ar_hdr.ar_date[ui] = ' '; - sprintf (TOCHAR (ar_hdr.ar_date), "%lu", (long unsigned) statbuf.st_mtime); - ar_hdr.ar_date[strlen ((char *) ar_hdr.ar_date)] = ' '; + datelen = snprintf (TOCHAR (ar_hdr.ar_date), sizeof ar_hdr.ar_date, + "%" PRIdMAX, (intmax_t) statbuf.st_mtime); + if (! (0 <= datelen && datelen < (int) sizeof ar_hdr.ar_date)) + goto lose; + memset (ar_hdr.ar_date + datelen, ' ', sizeof ar_hdr.ar_date - datelen); #else ar_hdr.ar_date = statbuf.st_mtime; #endif /* Write back this member's header */ - EINTRLOOP (o, lseek (fd, pos, 0)); + EINTRLOOP (o, lseek (fd, opos, 0)); if (o < 0) goto lose; r = writebuf (fd, &ar_hdr, AR_HDR_SIZE); @@ -655,18 +982,21 @@ ar_member_touch (const char *arname, const char *memname) #ifdef TEST -long int +intmax_t describe_member (int desc, const char *name, int truncated, long int hdrpos, long int datapos, long int size, - long int date, int uid, int gid, unsigned int mode, + intmax_t date, int uid, int gid, unsigned int mode, const void *arg) { extern char *ctime (); + time_t d = date; + char const *ds; printf (_("Member '%s'%s: %ld bytes at %ld (%ld).\n"), name, truncated ? _(" (name might be truncated)") : "", size, hdrpos, datapos); - printf (_(" Date %s"), ctime (&date)); + ds = ctime (&d); + printf (_(" Date %s"), ds ? ds : "?"); printf (_(" uid = %d, gid = %d, mode = 0%o.\n"), uid, gid, mode); return 0; @@ -680,3 +1010,4 @@ main (int argc, char **argv) } #endif /* TEST. */ +#endif /* NO_ARCHIVES. */ diff --git a/third_party/make/basename-lgpl.c b/third_party/make/basename-lgpl.c deleted file mode 100644 index 682bd1847..000000000 --- a/third_party/make/basename-lgpl.c +++ /dev/null @@ -1,74 +0,0 @@ -/* basename.c -- return the last element in a file name - - Copyright (C) 1990, 1998-2001, 2003-2006, 2009-2020 Free Software - Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -#include "third_party/make/config.h" -/**/ -#include "libc/str/str.h" -#include "third_party/make/dirname.h" - -/* Return the address of the last file name component of NAME. If - NAME has no relative file name components because it is a file - system root, return the empty string. */ - -char * -last_component (char const *name) -{ - char const *base = name + FILE_SYSTEM_PREFIX_LEN (name); - char const *p; - bool saw_slash = false; - - while (ISSLASH (*base)) - base++; - - for (p = base; *p; p++) - { - if (ISSLASH (*p)) - saw_slash = true; - else if (saw_slash) - { - base = p; - saw_slash = false; - } - } - - return (char *) base; -} - -/* Return the length of the basename NAME. Typically NAME is the - value returned by base_name or last_component. Act like strlen - (NAME), except omit all trailing slashes. */ - -size_t -base_len (char const *name) -{ - size_t len; - size_t prefix_len = FILE_SYSTEM_PREFIX_LEN (name); - - for (len = strlen (name); 1 < len && ISSLASH (name[len - 1]); len--) - continue; - - if (DOUBLE_SLASH_IS_DISTINCT_ROOT && len == 1 - && ISSLASH (name[0]) && ISSLASH (name[1]) && ! name[2]) - return 2; - - if (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE && prefix_len - && len == prefix_len && ISSLASH (name[prefix_len])) - return prefix_len + 1; - - return len; -} diff --git a/third_party/make/commands.c b/third_party/make/commands.c index 11e344239..72ecdf581 100644 --- a/third_party/make/commands.c +++ b/third_party/make/commands.c @@ -1,5 +1,5 @@ /* Command processing for GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,20 +12,22 @@ 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 . */ +this program. If not, see . */ -#include "third_party/make/makeint.inc" -/**/ -#include "third_party/make/dep.h" -#include "third_party/make/filedef.h" -#include "third_party/make/job.h" -#include "third_party/make/variable.h" -/**/ -#include "libc/runtime/runtime.h" -#include "libc/sysv/consts/sig.h" -#include "third_party/make/commands.h" +#include "makeint.h" +#include "filedef.h" +#include "os.h" +#include "dep.h" +#include "variable.h" +#include "job.h" +#include "commands.h" -#define FILE_LIST_SEPARATOR ' ' +#if VMS +# define FILE_LIST_SEPARATOR (vms_comma_separator ? ',' : ' ') +#else +# define FILE_LIST_SEPARATOR ' ' +#endif + static unsigned long dep_hash_1 (const void *key) @@ -49,10 +51,13 @@ dep_hash_cmp (const void *x, const void *y) return strcmp (dep_name (dx), dep_name (dy)); } -/* Set FILE's automatic variables up. */ +/* Set FILE's automatic variables up. + * Use STEM to set $*. + * If STEM is 0, then set FILE->STEM and $* to the target name with any + * suffix in the .SUFFIXES list stripped off. */ void -set_file_variables (struct file *file) +set_file_variables (struct file *file, const char *stem) { struct dep *d; const char *at, *percent, *star, *less; @@ -86,7 +91,7 @@ set_file_variables (struct file *file) } /* $* is the stem from an implicit or static pattern rule. */ - if (file->stem == 0) + if (stem == 0) { /* In Unix make, $* is set to the target name with any suffix in the .SUFFIXES list stripped off for @@ -109,25 +114,25 @@ set_file_variables (struct file *file) for (d = enter_file (strcache_add (".SUFFIXES"))->deps; d ; d = d->next) { - size_t slen = strlen (dep_name (d)); - if (len > slen && strneq (dep_name (d), name + (len - slen), slen)) + const char *dn = dep_name (d); + size_t slen = strlen (dn); + if (len > slen && memcmp (dn, name + (len - slen), slen) == 0) { - file->stem = strcache_add_len (name, len - slen); + file->stem = stem = strcache_add_len (name, len - slen); break; } } if (d == 0) - file->stem = ""; + file->stem = stem = ""; } - star = file->stem; + star = stem; /* $< is the first not order-only dependency. */ less = ""; for (d = file->deps; d != 0; d = d->next) - if (!d->ignore_mtime && !d->ignore_automatic_vars) + if (!d->ignore_mtime && !d->ignore_automatic_vars && !d->need_2nd_expansion) { - if (!d->need_2nd_expansion) - less = dep_name (d); + less = dep_name (d); break; } @@ -205,8 +210,7 @@ set_file_variables (struct file *file) #endif len = strlen (c); - memcpy (cp, c, len); - cp += len; + cp = mempcpy (cp, c, len); *cp++ = FILE_LIST_SEPARATOR; if (! (d->changed || always_make_flag)) qmark_len -= len + 1; /* Don't space in $? for this one. */ @@ -276,19 +280,16 @@ set_file_variables (struct file *file) if (d->ignore_mtime) { - memcpy (bp, c, len); - bp += len; + bp = mempcpy (bp, c, len); *bp++ = FILE_LIST_SEPARATOR; } else { - memcpy (cp, c, len); - cp += len; + cp = mempcpy (cp, c, len); *cp++ = FILE_LIST_SEPARATOR; if (d->changed || always_make_flag) { - memcpy (qp, c, len); - qp += len; + qp = mempcpy (qp, c, len); *qp++ = FILE_LIST_SEPARATOR; } } @@ -317,14 +318,12 @@ set_file_variables (struct file *file) void chop_commands (struct commands *cmds) { - unsigned int nlines; - unsigned short idx; + unsigned short nlines; + unsigned short i; char **lines; - /* If we don't have any commands, - or we already parsed them, never mind. */ - - if (!cmds || cmds->command_lines != 0) + /* If we don't have any commands, or we already parsed them, never mind. */ + if (!cmds || cmds->command_lines != NULL) return; /* Chop CMDS->commands up into lines in CMDS->command_lines. */ @@ -343,25 +342,27 @@ chop_commands (struct commands *cmds) } else { - const char *p; + const char *p = cmds->commands; + size_t max = 5; - nlines = 5; - lines = xmalloc (nlines * sizeof (char *)); - idx = 0; - p = cmds->commands; + nlines = 0; + lines = xmalloc (max * sizeof (char *)); while (*p != '\0') { const char *end = p; find_end:; end = strchr (end, '\n'); - if (end == 0) + if (end == NULL) end = p + strlen (p); else if (end > p && end[-1] == '\\') { int backslash = 1; - const char *b; - for (b = end - 2; b >= p && *b == '\\'; --b) - backslash = !backslash; + if (end > p + 1) + { + const char *b; + for (b = end - 2; b >= p && *b == '\\'; --b) + backslash = !backslash; + } if (backslash) { ++end; @@ -369,40 +370,36 @@ chop_commands (struct commands *cmds) } } - if (idx == nlines) + if (nlines == USHRT_MAX) + ON (fatal, &cmds->fileinfo, + _("Recipe has too many lines (limit %hu)"), nlines); + + if (nlines == max) { - nlines += 2; - lines = xrealloc (lines, nlines * sizeof (char *)); + max += 2; + lines = xrealloc (lines, max * sizeof (char *)); } - lines[idx++] = xstrndup (p, (size_t) (end - p)); + + lines[nlines++] = xstrndup (p, (size_t) (end - p)); p = end; if (*p != '\0') ++p; } - - if (idx != nlines) - { - nlines = idx; - lines = xrealloc (lines, nlines * sizeof (char *)); - } } /* Finally, set the corresponding CMDS->lines_flags elements and the CMDS->any_recurse flag. */ - if (nlines > USHRT_MAX) - ON (fatal, &cmds->fileinfo, _("Recipe has too many lines (%ud)"), nlines); - - cmds->ncommand_lines = (unsigned short)nlines; + cmds->ncommand_lines = nlines; cmds->command_lines = lines; cmds->any_recurse = 0; cmds->lines_flags = xmalloc (nlines); - for (idx = 0; idx < nlines; ++idx) + for (i = 0; i < nlines; ++i) { unsigned char flags = 0; - const char *p = lines[idx]; + const char *p = lines[i]; while (ISBLANK (*p) || *p == '-' || *p == '@' || *p == '+') switch (*(p++)) @@ -419,12 +416,12 @@ chop_commands (struct commands *cmds) } /* If no explicit '+' was given, look for MAKE variable references. */ - if (!(flags & COMMANDS_RECURSE) + if (! ANY_SET (flags, COMMANDS_RECURSE) && (strstr (p, "$(MAKE)") != 0 || strstr (p, "${MAKE}") != 0)) flags |= COMMANDS_RECURSE; - cmds->lines_flags[idx] = flags; - cmds->any_recurse |= flags & COMMANDS_RECURSE ? 1 : 0; + cmds->lines_flags[i] = flags; + cmds->any_recurse |= ANY_SET (flags, COMMANDS_RECURSE) ? 1 : 0; } } @@ -456,12 +453,17 @@ execute_file_commands (struct file *file) initialize_file_variables (file, 0); - set_file_variables (file); + set_file_variables (file, file->stem); - /* If this is a loaded dynamic object, unload it before remaking. - Some systems don't support overwriting a loaded object. */ - if (file->loaded) - unload_file (file->name); + /* Some systems don't support overwriting a loaded object so if this one + unload it before remaking. Keep its name in .LOADED: it will be rebuilt + and loaded again. If rebuilding or loading again fail, then we'll exit + anyway and it won't matter. */ + if (file->loaded && unload_file (file->name) == 0) + { + file->loaded = 0; + file->unloaded = 1; + } /* Start the commands running. */ new_job (file); @@ -470,17 +472,36 @@ execute_file_commands (struct file *file) /* This is set while we are inside fatal_error_signal, so things can avoid nonreentrant operations. */ -int handling_fatal_signal = 0; +volatile sig_atomic_t handling_fatal_signal = 0; /* Handle fatal signals. */ -RETSIGTYPE +void fatal_error_signal (int sig) { +#ifdef __MSDOS__ + extern int dos_status, dos_command_running; + + if (dos_command_running) + { + /* That was the child who got the signal, not us. */ + dos_status |= (sig << 8); + return; + } + remove_intermediates (1); + exit (EXIT_FAILURE); +#else /* not __MSDOS__ */ +#ifdef _AMIGA + remove_intermediates (1); + if (sig == SIGINT) + fputs (_("*** Break.\n"), stderr); + + exit (10); +#else /* not Amiga */ #ifdef WINDOWS32 extern HANDLE main_thread; - /* Windows creates a sperate thread for handling Ctrl+C, so we need + /* Windows creates a separate thread for handling Ctrl+C, so we need to suspend the main thread, or else we will have race conditions when both threads call reap_children. */ if (main_thread) @@ -488,12 +509,12 @@ fatal_error_signal (int sig) DWORD susp_count = SuspendThread (main_thread); if (susp_count != 0) - fprintf (stderr, "SuspendThread: suspend count = %ld\n", susp_count); + fprintf (stderr, "SuspendThread: suspend count = %lu\n", susp_count); else if (susp_count == (DWORD)-1) { DWORD ierr = GetLastError (); - fprintf (stderr, "SuspendThread: error %ld: %s\n", + fprintf (stderr, "SuspendThread: error %lu: %s\n", ierr, map_windows32_error_to_string (ierr)); } } @@ -504,6 +525,10 @@ fatal_error_signal (int sig) It is blocked now while we run this handler. */ signal (sig, SIG_DFL); + temp_stdin_unlink (); + osync_clear (); + jobserver_clear (); + /* A termination signal won't be sent to the entire process group, but it means we want to kill the children. */ @@ -519,9 +544,12 @@ fatal_error_signal (int sig) wanted to kill make, remove pending targets. */ if (sig == SIGTERM || sig == SIGINT +#ifdef SIGHUP || sig == SIGHUP +#endif +#ifdef SIGQUIT || sig == SIGQUIT - || sig == SIGPIPE +#endif ) { struct child *c; @@ -533,10 +561,7 @@ fatal_error_signal (int sig) (void) remote_kill (c->pid, sig); for (c = children; c != 0; c = c->next) - { - delete_child_targets (c); - delete_tmpdir (c); - } + delete_child_targets (c); /* Clean up the children. We don't just use the call below because we don't want to print the "Waiting for children" message. */ @@ -552,10 +577,12 @@ fatal_error_signal (int sig) remove_intermediates (1); +#ifdef SIGQUIT if (sig == SIGQUIT) /* We don't want to send ourselves SIGQUIT, because it will cause a core dump. Just exit instead. */ exit (MAKE_TROUBLE); +#endif #ifdef WINDOWS32 if (main_thread) @@ -566,9 +593,11 @@ fatal_error_signal (int sig) #else /* Signal the same code; this time it will really be fatal. The signal will be unblocked when we return and arrive then to kill us. */ - if (kill (getpid (), sig) < 0) + if (kill (make_pid (), sig) < 0) pfatal_with_name ("kill"); #endif /* not WINDOWS32 */ +#endif /* not Amiga */ +#endif /* not __MSDOS__ */ } /* Delete FILE unless it's precious or not actually a file (phony), diff --git a/third_party/make/commands.h b/third_party/make/commands.h index d86752c8b..97d1c15f2 100644 --- a/third_party/make/commands.h +++ b/third_party/make/commands.h @@ -1,5 +1,5 @@ /* Definition of data structures describing shell commands for GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,7 +12,7 @@ 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 . */ +this program. If not, see . */ /* Structure that gives the commands to make a file and information about where these commands came from. */ @@ -34,9 +34,12 @@ struct commands #define COMMANDS_SILENT 2 /* Silent: @. */ #define COMMANDS_NOERROR 4 /* No errors: -. */ -RETSIGTYPE fatal_error_signal (int sig); +struct file; +struct child; + +void fatal_error_signal (int sig); void execute_file_commands (struct file *file); void print_commands (const struct commands *cmds); void delete_child_targets (struct child *child); void chop_commands (struct commands *cmds); -void set_file_variables (struct file *file); +void set_file_variables (struct file *file, const char *stem); diff --git a/third_party/make/concat-filename.c b/third_party/make/concat-filename.c index 1b84fe860..dcc93a6a6 100644 --- a/third_party/make/concat-filename.c +++ b/third_party/make/concat-filename.c @@ -1,26 +1,31 @@ /* Construct a full filename from a directory and a relative filename. - Copyright (C) 2001-2004, 2006-2020 Free Software Foundation, Inc. + Copyright (C) 2001-2004, 2006-2023 Free Software Foundation, Inc. - This program is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 3 of the License, or any - later version. + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. - This program is distributed in the hope that it will be useful, + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + GNU Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ /* Written by Bruno Haible . */ -#include "libc/mem/mem.h" -#include "libc/str/str.h" -#include "third_party/make/concat-filename.h" -#include "third_party/make/filename.h" -#include "third_party/make/config.h" +#include "config.h" + +/* Specification. */ +#include "concat-filename.h" + +#include +#include +#include + +#include "filename.h" /* Concatenate a directory filename, a relative filename and an optional suffix. The directory may end with the directory separator. The second diff --git a/third_party/make/concat-filename.h b/third_party/make/concat-filename.h index 64b461e39..091222638 100644 --- a/third_party/make/concat-filename.h +++ b/third_party/make/concat-filename.h @@ -1,22 +1,24 @@ /* Construct a full filename from a directory and a relative filename. - Copyright (C) 2001-2004, 2007-2020 Free Software Foundation, Inc. + Copyright (C) 2001-2004, 2007-2023 Free Software Foundation, Inc. - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. - This program is distributed in the hope that it will be useful, + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + GNU Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef _CONCAT_FILENAME_H #define _CONCAT_FILENAME_H +#include + #ifdef __cplusplus extern "C" { #endif @@ -26,12 +28,15 @@ extern "C" { suffix. Return a freshly allocated filename. Return NULL and set errno upon memory allocation failure. */ extern char *concatenated_filename (const char *directory, - const char *filename, const char *suffix); + const char *filename, const char *suffix) + _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE; /* Concatenate a directory filename, a relative filename and an optional suffix. Return a freshly allocated filename. */ extern char *xconcatenated_filename (const char *directory, - const char *filename, const char *suffix); + const char *filename, const char *suffix) + _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE + _GL_ATTRIBUTE_RETURNS_NONNULL; #ifdef __cplusplus diff --git a/third_party/make/config.h b/third_party/make/config.h index a94336401..c39b40a7f 100644 --- a/third_party/make/config.h +++ b/third_party/make/config.h @@ -1,104 +1,144 @@ /* src/config.h. Generated from config.h.in by configure. */ /* src/config.h.in. Generated from configure.ac by autoheader. */ -#include "libc/calls/calls.h" -#define LANDLOCKMAKE_VERSION "1.5" +/* CPU and C ABI indicator */ +#ifndef __i386__ +#define __i386__ 1 +#endif +#ifndef __x86_64_x32__ +/* #undef __x86_64_x32__ */ +#endif +#ifndef __x86_64__ +/* #undef __x86_64__ */ +#endif +#ifndef __alpha__ +/* #undef __alpha__ */ +#endif +#ifndef __arm__ +/* #undef __arm__ */ +#endif +#ifndef __armhf__ +/* #undef __armhf__ */ +#endif +#ifndef __arm64_ilp32__ +/* #undef __arm64_ilp32__ */ +#endif +#ifndef __arm64__ +/* #undef __arm64__ */ +#endif +#ifndef __hppa__ +/* #undef __hppa__ */ +#endif +#ifndef __hppa64__ +/* #undef __hppa64__ */ +#endif +#ifndef __ia64_ilp32__ +/* #undef __ia64_ilp32__ */ +#endif +#ifndef __ia64__ +/* #undef __ia64__ */ +#endif +#ifndef __loongarch64__ +/* #undef __loongarch64__ */ +#endif +#ifndef __m68k__ +/* #undef __m68k__ */ +#endif +#ifndef __mips__ +/* #undef __mips__ */ +#endif +#ifndef __mipsn32__ +/* #undef __mipsn32__ */ +#endif +#ifndef __mips64__ +/* #undef __mips64__ */ +#endif +#ifndef __powerpc__ +/* #undef __powerpc__ */ +#endif +#ifndef __powerpc64__ +/* #undef __powerpc64__ */ +#endif +#ifndef __powerpc64_elfv2__ +/* #undef __powerpc64_elfv2__ */ +#endif +#ifndef __riscv32__ +/* #undef __riscv32__ */ +#endif +#ifndef __riscv64__ +/* #undef __riscv64__ */ +#endif +#ifndef __riscv32_ilp32__ +/* #undef __riscv32_ilp32__ */ +#endif +#ifndef __riscv32_ilp32f__ +/* #undef __riscv32_ilp32f__ */ +#endif +#ifndef __riscv32_ilp32d__ +/* #undef __riscv32_ilp32d__ */ +#endif +#ifndef __riscv64_ilp32__ +/* #undef __riscv64_ilp32__ */ +#endif +#ifndef __riscv64_ilp32f__ +/* #undef __riscv64_ilp32f__ */ +#endif +#ifndef __riscv64_ilp32d__ +/* #undef __riscv64_ilp32d__ */ +#endif +#ifndef __riscv64_lp64__ +/* #undef __riscv64_lp64__ */ +#endif +#ifndef __riscv64_lp64f__ +/* #undef __riscv64_lp64f__ */ +#endif +#ifndef __riscv64_lp64d__ +/* #undef __riscv64_lp64d__ */ +#endif +#ifndef __s390__ +/* #undef __s390__ */ +#endif +#ifndef __s390x__ +/* #undef __s390x__ */ +#endif +#ifndef __sh__ +/* #undef __sh__ */ +#endif +#ifndef __sparc__ +/* #undef __sparc__ */ +#endif +#ifndef __sparc64__ +/* #undef __sparc64__ */ +#endif -/* Define to the number of bits in type 'ptrdiff_t'. */ -#define BITSIZEOF_PTRDIFF_T 64 -/* Define to the number of bits in type 'sig_atomic_t'. */ -#define BITSIZEOF_SIG_ATOMIC_T 32 +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ -/* Define to the number of bits in type 'size_t'. */ -#define BITSIZEOF_SIZE_T 64 - -/* Define to the number of bits in type 'wchar_t'. */ -#define BITSIZEOF_WCHAR_T 32 - -/* Define to the number of bits in type 'wint_t'. */ -#define BITSIZEOF_WINT_T 32 - -/* Define to 1 if the `closedir' function returns void instead of `int'. */ +/* Define to 1 if the `closedir' function returns void instead of int. */ /* #undef CLOSEDIR_VOID */ -/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP - systems. This function is required for `alloca.c' support on those systems. - */ -/* #undef CRAY_STACKSEG_END */ - -/* Define to 1 if using `alloca.c'. */ +/* Define to 1 if using 'alloca.c'. */ /* #undef C_ALLOCA */ /* Define to 1 for DGUX with . */ /* #undef DGUX */ -/* Define to 1 if // is a file system root distinct from /. */ -/* #undef DOUBLE_SLASH_IS_DISTINCT_ROOT */ - /* Define to 1 if translation of program messages to the user's native language is requested. */ /* #undef ENABLE_NLS */ -/* Define this to 1 if F_DUPFD behavior does not match POSIX */ -/* #undef FCNTL_DUPFD_BUGGY */ - /* Use high resolution file timestamps if nonzero. */ #define FILE_TIMESTAMP_HI_RES 1 -/* Define to a C preprocessor expression that evaluates to 1 or 0, depending - whether the gnulib module fscanf shall be considered present. */ -#define GNULIB_FSCANF 1 - -/* Define to a C preprocessor expression that evaluates to 1 or 0, depending - whether the gnulib module msvc-nothrow shall be considered present. */ -#define GNULIB_MSVC_NOTHROW 1 - -/* Define to 1 if printf and friends should be labeled with attribute - "__gnu_printf__" instead of "__printf__" */ -/* #undef GNULIB_PRINTF_ATTRIBUTE_FLAVOR_GNU */ - -/* Define to a C preprocessor expression that evaluates to 1 or 0, depending - whether the gnulib module scanf shall be considered present. */ -#define GNULIB_SCANF 1 - -/* Define to a C preprocessor expression that evaluates to 1 or 0, depending - whether the gnulib module strerror shall be considered present. */ -#define GNULIB_STRERROR 1 - -/* Define to 1 when the gnulib module access should be tested. */ -#define GNULIB_TEST_ACCESS 1 - -/* Define to 1 when the gnulib module close should be tested. */ -#define GNULIB_TEST_CLOSE 1 - -/* Define to 1 when the gnulib module dup2 should be tested. */ -#define GNULIB_TEST_DUP2 1 - -/* Define to 1 when the gnulib module fcntl should be tested. */ -#define GNULIB_TEST_FCNTL 1 - -/* Define to 1 when the gnulib module getdtablesize should be tested. */ -#define GNULIB_TEST_GETDTABLESIZE 1 - /* Define to 1 when the gnulib module getloadavg should be tested. */ #define GNULIB_TEST_GETLOADAVG 1 -/* Define to 1 when the gnulib module malloc-posix should be tested. */ -#define GNULIB_TEST_MALLOC_POSIX 1 - -/* Define to 1 when the gnulib module stpcpy should be tested. */ -#define GNULIB_TEST_STPCPY 1 - -/* Define to 1 when the gnulib module strerror should be tested. */ -#define GNULIB_TEST_STRERROR 1 - /* Define to 1 if you have 'alloca' after including , a header that may be supplied by this distribution. */ #define HAVE_ALLOCA 1 -/* Define to 1 if you have and it should be used (not on Ultrix). - */ +/* Define to 1 if works. */ #define HAVE_ALLOCA_H 1 /* Define to 1 if you have the `atexit' function. */ @@ -115,8 +155,14 @@ the CoreFoundation framework. */ /* #undef HAVE_CFPREFERENCESCOPYAPPVALUE */ +/* Define to 1 if you have the clock_gettime function. */ +#define HAVE_CLOCK_GETTIME 1 + +/* Define to 1 if bool, true and false work as per C2023. */ +/* #undef HAVE_C_BOOL */ + /* Define if the GNU dcgettext() function is already present or preinstalled. - */ + */ /* #undef HAVE_DCGETTEXT */ /* Define to 1 if you have the declaration of `bsd_signal', and to 0 if you @@ -125,31 +171,18 @@ /* Define to 1 if you have the declaration of `dlerror', and to 0 if you don't. */ -#define HAVE_DECL_DLERROR 1 +/* #define HAVE_DECL_DLERROR 1 */ /* Define to 1 if you have the declaration of `dlopen', and to 0 if you don't. - */ -#define HAVE_DECL_DLOPEN 1 + */ +/* #define HAVE_DECL_DLOPEN 1 */ /* Define to 1 if you have the declaration of `dlsym', and to 0 if you don't. - */ -#define HAVE_DECL_DLSYM 1 + */ +/* #define HAVE_DECL_DLSYM 1 */ -/* Define to 1 if you have the declaration of `getdtablesize', and to 0 if you - don't. */ -#define HAVE_DECL_GETDTABLESIZE 1 - -/* Define to 1 if you have the declaration of `program_invocation_name', and - to 0 if you don't. */ -#define HAVE_DECL_PROGRAM_INVOCATION_NAME 1 - -/* Define to 1 if you have the declaration of `program_invocation_short_name', - and to 0 if you don't. */ -#define HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME 1 - -/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you - don't. */ -#define HAVE_DECL_STRERROR_R 1 +/* Define to 1 if you have the declaration of 'getloadavg'. */ +#define HAVE_DECL_GETLOADAVG 1 /* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you don't. */ @@ -159,19 +192,15 @@ don't. */ #define HAVE_DECL__SYS_SIGLIST 0 -/* Define to 1 if you have the declaration of `__argv', and to 0 if you don't. - */ -#define HAVE_DECL___ARGV 1 - /* Define to 1 if you have the declaration of `__sys_siglist', and to 0 if you don't. */ #define HAVE_DECL___SYS_SIGLIST 0 /* Define to 1 if you have the header file, and it defines `DIR'. - */ + */ #define HAVE_DIRENT_H 1 -/* Use platform specific coding */ +/* Support DOS-style pathnames. */ /* #undef HAVE_DOS_PATHS */ /* Define to 1 if you have the `dup' function. */ @@ -180,9 +209,6 @@ /* Define to 1 if you have the `dup2' function. */ #define HAVE_DUP2 1 -/* Define to 1 if you have the `fcntl' function. */ -#define HAVE_FCNTL 1 - /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 @@ -195,12 +221,6 @@ /* Define to 1 if you have the `getcwd' function. */ #define HAVE_GETCWD 1 -/* Define to 1 if you have the `getdtablesize' function. */ -#define HAVE_GETDTABLESIZE 1 - -/* Define to 1 if you have the `getexecname' function. */ -/* #undef HAVE_GETEXECNAME */ - /* Define to 1 if you have the `getgroups' function. */ #define HAVE_GETGROUPS 1 @@ -210,9 +230,6 @@ /* Define to 1 if you have the `gethostname' function. */ /* #undef HAVE_GETHOSTNAME */ -/* Define to 1 if you have the `getprogname' function. */ -/* #undef HAVE_GETPROGNAME */ - /* Define to 1 if you have the `getrlimit' function. */ #define HAVE_GETRLIMIT 1 @@ -226,7 +243,10 @@ /* #undef HAVE_GUILE */ /* Define if you have the iconv() function and it works. */ -/* #undef HAVE_ICONV */ +#define HAVE_ICONV 1 + +/* Define to 1 if the system has the type `intmax_t'. */ +#define HAVE_INTMAX_T 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 @@ -258,25 +278,27 @@ /* Define to 1 if you have the header file. */ /* #undef HAVE_MACH_MACH_H */ -/* Define if the 'malloc' function is POSIX compliant. */ -#define HAVE_MALLOC_POSIX 1 - /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 +/* Define to 1 if you have the `mempcpy' function. */ +#define HAVE_MEMPCPY 1 + /* Define to 1 if you have the `memrchr' function. */ #define HAVE_MEMRCHR 1 +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MINIX_CONFIG_H */ + +/* Define to 1 if you have the `mkfifo' function. */ +/* #undef HAVE_MKFIFO */ + /* Define to 1 if you have the `mkstemp' function. */ #define HAVE_MKSTEMP 1 /* Define to 1 if you have the `mktemp' function. */ #define HAVE_MKTEMP 1 -/* Define to 1 on MSVC platforms that have the "invalid parameter handler" - concept. */ -/* #undef HAVE_MSVC_INVALID_PARAMETER_HANDLER */ - /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_NDIR_H */ @@ -286,6 +308,12 @@ /* Define to 1 if you have the `pipe' function. */ #define HAVE_PIPE 1 +/* Define to 1 if you have the `posix_spawn' function. */ +#define HAVE_POSIX_SPAWN 1 + +/* Define to 1 if you have the `posix_spawnattr_setsigmask' function. */ +#define HAVE_POSIX_SPAWNATTR_SETSIGMASK 1 + /* Define to 1 if you have the `pselect' function. */ #define HAVE_PSELECT 1 @@ -301,9 +329,6 @@ /* Define to 1 if defines the SA_RESTART constant. */ #define HAVE_SA_RESTART 1 -/* Define to 1 if you have the `setdtablesize' function. */ -/* #undef HAVE_SETDTABLESIZE */ - /* Define to 1 if you have the `setegid' function. */ #define HAVE_SETEGID 1 @@ -328,21 +353,27 @@ /* Define to 1 if you have the `sigaction' function. */ #define HAVE_SIGACTION 1 -/* Define to 1 if 'sig_atomic_t' is a signed integer type. */ -#define HAVE_SIGNED_SIG_ATOMIC_T 1 +/* Define to 1 if you have the `sigsetmask' function. */ +/* #undef HAVE_SIGSETMASK */ -/* Define to 1 if 'wchar_t' is a signed integer type. */ -#define HAVE_SIGNED_WCHAR_T 1 +/* Define to 1 if the system has the type `sig_atomic_t'. */ +#define HAVE_SIG_ATOMIC_T 1 -/* Define to 1 if 'wint_t' is a signed integer type. */ -/* #undef HAVE_SIGNED_WINT_T */ +/* Define to 1 if you have the `socket' function. */ +/* #undef HAVE_SOCKET */ /* Define to 1 if you have the header file. */ #define HAVE_SPAWN_H 1 +/* Define to 1 if you have the header file. */ +#define HAVE_STDBOOL_H 1 + /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 +/* Define to 1 if you have the header file. */ +#define HAVE_STDIO_H 1 + /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 @@ -356,14 +387,14 @@ /* #undef HAVE_STRCMPI */ /* Define to 1 if you have the `strcoll' function and it is properly defined. - */ + */ #define HAVE_STRCOLL 1 /* Define to 1 if you have the `strdup' function. */ #define HAVE_STRDUP 1 -/* Define to 1 if you have the `strerror_r' function. */ -#define HAVE_STRERROR_R 1 +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 /* Define to 1 if you have the `stricmp' function. */ /* #undef HAVE_STRICMP */ @@ -389,33 +420,27 @@ /* Define to 1 if you have the `strsignal' function. */ #define HAVE_STRSIGNAL 1 +/* Define to 1 if you have the `strtoll' function. */ +#define HAVE_STRTOLL 1 + /* Define to 1 if `d_type' is a member of `struct dirent'. */ #define HAVE_STRUCT_DIRENT_D_TYPE 1 /* Define to 1 if `n_un.n_name' is a member of `struct nlist'. */ /* #undef HAVE_STRUCT_NLIST_N_UN_N_NAME */ -/* Define to 1 if you have the `symlink' function. */ -#define HAVE_SYMLINK 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_BITYPES_H */ - /* Define to 1 if you have the header file, and it defines `DIR'. - */ + */ /* #undef HAVE_SYS_DIR_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_FILE_H 1 -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_INTTYPES_H */ - /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_LOADAVG_H */ /* Define to 1 if you have the header file, and it defines `DIR'. - */ + */ /* #undef HAVE_SYS_NDIR_H */ /* Define to 1 if you have the header file. */ @@ -427,9 +452,6 @@ /* Define to 1 if you have the header file. */ #define HAVE_SYS_SELECT_H 1 -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_SOCKET_H 1 - /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 @@ -463,8 +485,11 @@ /* Define to 1 if the system has the type 'unsigned long long int'. */ #define HAVE_UNSIGNED_LONG_LONG_INT 1 -/* Define if you have a global __progname variable */ -/* #undef HAVE_VAR___PROGNAME */ +/* Define to 1 if you have the `vfork' function. */ +#define HAVE_VFORK 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_VFORK_H */ /* Define to 1 if you have the `wait3' function. */ #define HAVE_WAIT3 1 @@ -475,39 +500,30 @@ /* Define to 1 if you have the header file. */ #define HAVE_WCHAR_H 1 -/* Define if you have the 'wchar_t' type. */ -#define HAVE_WCHAR_T 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_WINSOCK2_H */ - -/* Define if you have the 'wint_t' type. */ -#define HAVE_WINT_T 1 - /* Define to 1 if `fork' works. */ #define HAVE_WORKING_FORK 1 -/* Define to 1 if O_NOATIME works. */ -#define HAVE_WORKING_O_NOATIME 0 +/* Define to 1 if `vfork' works. */ +#define HAVE_WORKING_VFORK 1 -/* Define to 1 if O_NOFOLLOW works. */ -#define HAVE_WORKING_O_NOFOLLOW 0 - -/* Define to 1 if the system has the type `_Bool'. */ -#define HAVE__BOOL 1 - -/* Define to 1 if you have the `_set_invalid_parameter_handler' function. */ -/* #undef HAVE__SET_INVALID_PARAMETER_HANDLER */ +/* Default C++ compiler. */ +#define MAKE_CXX "/opt/cosmocc/bin/aarch64-unknown-cosmo-c++" /* Build host information. */ -#define MAKE_HOST "x86_64-cosmopolitan" +#define MAKE_HOST "x86_64-pc-linux-musl" -/* Define to 1 to enable job server support in GNU make. */ +/* Define to 1 to enable job server support in GNU Make. */ #define MAKE_JOBSERVER 1 +/* Define to 1 to enable 'load' support in GNU Make. */ +/* #define MAKE_LOAD 1 */ + /* Define to 1 to enable symbolic link timestamp checking. */ #define MAKE_SYMLINKS 1 +/* Define to 1 if config.h is generated by running the configure script. */ +#define MK_CONFIGURE 1 + /* Define to 1 if the nlist n_name member is a pointer */ /* #undef N_NAME_POINTER */ @@ -518,73 +534,51 @@ #define PACKAGE_BUGREPORT "bug-make@gnu.org" /* Define to the full name of this package. */ -#define PACKAGE_NAME "GNU make" +#define PACKAGE_NAME "GNU Make" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "GNU make 4.3" +#define PACKAGE_STRING "GNU Make 4.4.1" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "make" /* Define to the home page for this package. */ -#define PACKAGE_URL "http://www.gnu.org/software/make/" +#define PACKAGE_URL "https://www.gnu.org/software/make/" /* Define to the version of this package. */ -#define PACKAGE_VERSION "4.3" +#define PACKAGE_VERSION "4.4.1" /* Define to the character that separates directories in PATH. */ #define PATH_SEPARATOR_CHAR ':' -/* Define to l, ll, u, ul, ull, etc., as suitable for constants of type - 'ptrdiff_t'. */ -#define PTRDIFF_T_SUFFIX l - -/* Define to 1 if strerror(0) does not return a message implying success. */ -/* #undef REPLACE_STRERROR_0 */ - -/* Define as the return type of signal handlers (`int' or `void'). */ -#define RETSIGTYPE void - /* Define to the name of the SCCS 'get' command. */ #define SCCS_GET "get" /* Define to 1 if the SCCS 'get' command understands the '-G' option. */ /* #undef SCCS_GET_MINUS_G */ -/* Define to l, ll, u, ul, ull, etc., as suitable for constants of type - 'sig_atomic_t'. */ -#define SIG_ATOMIC_T_SUFFIX - -/* Define to l, ll, u, ul, ull, etc., as suitable for constants of type - 'size_t'. */ -#define SIZE_T_SUFFIX ul - /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at runtime. - STACK_DIRECTION > 0 => grows toward higher addresses - STACK_DIRECTION < 0 => grows toward lower addresses - STACK_DIRECTION = 0 => direction of growth unknown */ + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ /* #undef STACK_DIRECTION */ /* Define to 1 if the `S_IS*' macros in do not work properly. */ /* #undef STAT_MACROS_BROKEN */ -/* Define to 1 if you have the ANSI C header files. */ +/* Define to 1 if all of the C90 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ #define STDC_HEADERS 1 -/* Define to 1 if strerror_r returns char *. */ -/* #undef STRERROR_R_CHAR_P */ - /* Define if struct stat contains a nanoseconds field */ #define ST_MTIM_NSEC st_mtim.tv_nsec /* Define to 1 on System V Release 4. */ /* #undef SVR4 */ -/* Define to 1 if you can safely include both and . */ -#define TIME_WITH_SYS_TIME 1 - /* Define to 1 for Encore UMAX. */ /* #undef UMAX */ @@ -592,165 +586,181 @@ . */ /* #undef UMAX4_3 */ +/* Define to 1 to use posix_spawn(). */ +#define USE_POSIX_SPAWN 1 + /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE -#define _ALL_SOURCE 1 +# define _ALL_SOURCE 1 #endif /* Enable general extensions on macOS. */ #ifndef _DARWIN_C_SOURCE -#define _DARWIN_C_SOURCE 1 +# define _DARWIN_C_SOURCE 1 +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# define __EXTENSIONS__ 1 #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE -#define _GNU_SOURCE 1 -#endif -/* Enable NetBSD extensions on NetBSD. */ -#ifndef _NETBSD_SOURCE -#define _NETBSD_SOURCE 1 -#endif -/* Enable OpenBSD extensions on NetBSD. */ -#ifndef _OPENBSD_SOURCE -#define _OPENBSD_SOURCE 1 -#endif -/* Enable threading extensions on Solaris. */ -#ifndef _POSIX_PTHREAD_SEMANTICS -#define _POSIX_PTHREAD_SEMANTICS 1 -#endif -/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ -#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ -#define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1 -#endif -/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ -#ifndef __STDC_WANT_IEC_60559_BFP_EXT__ -#define __STDC_WANT_IEC_60559_BFP_EXT__ 1 -#endif -/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ -#ifndef __STDC_WANT_IEC_60559_DFP_EXT__ -#define __STDC_WANT_IEC_60559_DFP_EXT__ 1 -#endif -/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ -#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ -#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1 -#endif -/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */ -#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ -#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1 -#endif -/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ -#ifndef __STDC_WANT_LIB_EXT2__ -#define __STDC_WANT_LIB_EXT2__ 1 -#endif -/* Enable extensions specified by ISO/IEC 24747:2009. */ -#ifndef __STDC_WANT_MATH_SPEC_FUNCS__ -#define __STDC_WANT_MATH_SPEC_FUNCS__ 1 -#endif -/* Enable extensions on HP NonStop. */ -#ifndef _TANDEM_SOURCE -#define _TANDEM_SOURCE 1 -#endif -/* Enable X/Open extensions if necessary. HP-UX 11.11 defines - mbstate_t only if _XOPEN_SOURCE is defined to 500, regardless of - whether compiling with -Ae or -D_HPUX_SOURCE=1. */ -#ifndef _XOPEN_SOURCE -/* # undef _XOPEN_SOURCE */ +# define _GNU_SOURCE 1 #endif /* Enable X/Open compliant socket functions that do not require linking with -lxnet on HP-UX 11.11. */ #ifndef _HPUX_ALT_XOPEN_SOCKET_API -#define _HPUX_ALT_XOPEN_SOCKET_API 1 +# define _HPUX_ALT_XOPEN_SOCKET_API 1 #endif -/* Enable general extensions on Solaris. */ -#ifndef __EXTENSIONS__ -#define __EXTENSIONS__ 1 +/* Identify the host operating system as Minix. + This macro does not affect the system headers' behavior. + A future release of Autoconf may stop defining this macro. */ +#ifndef _MINIX +/* # undef _MINIX */ #endif +/* Enable general extensions on NetBSD. + Enable NetBSD compatibility extensions on Minix. */ +#ifndef _NETBSD_SOURCE +# define _NETBSD_SOURCE 1 +#endif +/* Enable OpenBSD compatibility extensions on NetBSD. + Oddly enough, this does nothing on OpenBSD. */ +#ifndef _OPENBSD_SOURCE +# define _OPENBSD_SOURCE 1 +#endif +/* Define to 1 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_SOURCE +/* # undef _POSIX_SOURCE */ +#endif +/* Define to 2 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_1_SOURCE +/* # undef _POSIX_1_SOURCE */ +#endif +/* Enable POSIX-compatible threading on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ +#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ +# define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ +#ifndef __STDC_WANT_IEC_60559_BFP_EXT__ +# define __STDC_WANT_IEC_60559_BFP_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ +#ifndef __STDC_WANT_IEC_60559_DFP_EXT__ +# define __STDC_WANT_IEC_60559_DFP_EXT__ 1 +#endif +/* Enable extensions specified by C23 Annex F. */ +#ifndef __STDC_WANT_IEC_60559_EXT__ +# define __STDC_WANT_IEC_60559_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ +#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ +# define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1 +#endif +/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */ +#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ +# define __STDC_WANT_IEC_60559_TYPES_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ +#ifndef __STDC_WANT_LIB_EXT2__ +# define __STDC_WANT_LIB_EXT2__ 1 +#endif +/* Enable extensions specified by ISO/IEC 24747:2009. */ +#ifndef __STDC_WANT_MATH_SPEC_FUNCS__ +# define __STDC_WANT_MATH_SPEC_FUNCS__ 1 +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# define _TANDEM_SOURCE 1 +#endif +/* Enable X/Open extensions. Define to 500 only if necessary + to make mbstate_t available. */ +#ifndef _XOPEN_SOURCE +/* # undef _XOPEN_SOURCE */ +#endif + /* Version number of package */ -#define VERSION "4.3" +#define VERSION "4.4.1" -/* Define to l, ll, u, ul, ull, etc., as suitable for constants of type - 'wchar_t'. */ -#define WCHAR_T_SUFFIX - -/* Use platform specific coding */ +/* Build for the WINDOWS32 API. */ /* #undef WINDOWS32 */ -/* Define to l, ll, u, ul, ull, etc., as suitable for constants of type - 'wint_t'. */ -#define WINT_T_SUFFIX u - /* Define if using the dmalloc debugging malloc package */ /* #undef WITH_DMALLOC */ /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD -#if defined __BIG_ENDIAN__ -#define WORDS_BIGENDIAN 1 -#endif +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif #else -#ifndef WORDS_BIGENDIAN +# ifndef WORDS_BIGENDIAN /* # undef WORDS_BIGENDIAN */ -#endif -#endif - -/* Enable large inode numbers on Mac OS X 10.5. */ -#ifndef _DARWIN_USE_64_BIT_INODE -#define _DARWIN_USE_64_BIT_INODE 1 +# endif #endif /* Number of bits in a file offset, on hosts where this is settable. */ /* #undef _FILE_OFFSET_BITS */ -/* Define for large files, on AIX-style hosts. */ +/* True if the compiler says it groks GNU C version MAJOR.MINOR. */ +#if defined __GNUC__ && defined __GNUC_MINOR__ +# define _GL_GNUC_PREREQ(major, minor) \ + ((major) < __GNUC__ + ((minor) <= __GNUC_MINOR__)) +#else +# define _GL_GNUC_PREREQ(major, minor) 0 +#endif + + +/* Define to enable the declarations of ISO C 11 types and functions. */ +/* #undef _ISOC11_SOURCE */ + +/* Define to 1 on platforms where this makes off_t a 64-bit type. */ /* #undef _LARGE_FILES */ -/* Define to 1 if on MINIX. */ -/* #undef _MINIX */ - -/* Define to 1 to make NetBSD features available. MINIX 3 needs this. */ -#define _NETBSD_SOURCE 1 - /* The _Noreturn keyword of C11. */ #ifndef _Noreturn -#if (defined __cplusplus && \ - ((201103 <= __cplusplus && !(__GNUC__ == 4 && __GNUC_MINOR__ == 7)) || \ - (defined _MSC_VER && 1900 <= _MSC_VER)) && \ - 0) -/* [[noreturn]] is not practically usable, because with it the syntax - extern _Noreturn void func (...); - would not be valid; such a declaration would only be valid with 'extern' - and '_Noreturn' swapped, or without the 'extern' keyword. However, some - AIX system header files and several gnulib header files use precisely - this syntax with 'extern'. */ -#define _Noreturn [[noreturn]] -#elif ((!defined __cplusplus || defined __clang__) && \ - (201112 <= (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) || \ - 4 < __GNUC__ + (7 <= __GNUC_MINOR__))) -/* _Noreturn works as-is. */ -#elif 2 < __GNUC__ + (8 <= __GNUC_MINOR__) || 0x5110 <= __SUNPRO_C -#define _Noreturn __attribute__((__noreturn__)) -#elif 1200 <= (defined _MSC_VER ? _MSC_VER : 0) -#define _Noreturn __declspec(noreturn) -#else -#define _Noreturn -#endif +# if (defined __cplusplus \ + && ((201103 <= __cplusplus && !(__GNUC__ == 4 && __GNUC_MINOR__ == 7)) \ + || (defined _MSC_VER && 1900 <= _MSC_VER)) \ + && 0) + /* [[noreturn]] is not practically usable, because with it the syntax + extern _Noreturn void func (...); + would not be valid; such a declaration would only be valid with 'extern' + and '_Noreturn' swapped, or without the 'extern' keyword. However, some + AIX system header files and several gnulib header files use precisely + this syntax with 'extern'. */ +# define _Noreturn [[noreturn]] +# elif (defined __clang__ && __clang_major__ < 16 \ + && defined _GL_WORK_AROUND_LLVM_BUG_59792) + /* Compile with -D_GL_WORK_AROUND_LLVM_BUG_59792 to work around + that rare LLVM bug, though you may get many false-alarm warnings. */ +# define _Noreturn +# elif ((!defined __cplusplus || defined __clang__) \ + && (201112 <= (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) \ + || (!defined __STRICT_ANSI__ \ + && (_GL_GNUC_PREREQ (4, 7) \ + || (defined __apple_build_version__ \ + ? 6000000 <= __apple_build_version__ \ + : 3 < __clang_major__ + (5 <= __clang_minor__)))))) + /* _Noreturn works as-is. */ +# elif _GL_GNUC_PREREQ (2, 8) || defined __clang__ || 0x5110 <= __SUNPRO_C +# define _Noreturn __attribute__ ((__noreturn__)) +# elif 1200 <= (defined _MSC_VER ? _MSC_VER : 0) +# define _Noreturn __declspec (noreturn) +# else +# define _Noreturn +# endif #endif -/* Define to 2 if the system does not provide POSIX.1 features except with - this defined. */ -/* #undef _POSIX_1_SOURCE */ -/* Define to 1 if you need to in order for 'stat' and other things to work. */ -/* #undef _POSIX_SOURCE */ +/* Number of bits in time_t, on hosts where this is settable. */ +/* #undef _TIME_BITS */ -/* For standard stat data types on VMS. */ -#define _USE_STD_STAT 1 - -/* Define to 1 if the system predates C++11. */ -/* #undef __STDC_CONSTANT_MACROS */ - -/* Define to 1 if the system predates C++11. */ -/* #undef __STDC_LIMIT_MACROS */ +/* Define to 1 on platforms where this makes time_t a 64-bit type. */ +/* #undef __MINGW_USE_VC2005_COMPAT */ /* The _GL_ASYNC_SAFE marker should be attached to functions that are signal handlers (for signals other than SIGABRT, SIGPIPE) or can be @@ -778,151 +788,511 @@ errno. */ #define _GL_ASYNC_SAFE + +/* Attributes. */ +#if (defined __has_attribute \ + && (!defined __clang_minor__ \ + || (defined __apple_build_version__ \ + ? 6000000 <= __apple_build_version__ \ + : 3 < __clang_major__ + (5 <= __clang_minor__)))) +# define _GL_HAS_ATTRIBUTE(attr) __has_attribute (__##attr##__) +#else +# define _GL_HAS_ATTRIBUTE(attr) _GL_ATTR_##attr +# define _GL_ATTR_alloc_size _GL_GNUC_PREREQ (4, 3) +# define _GL_ATTR_always_inline _GL_GNUC_PREREQ (3, 2) +# define _GL_ATTR_artificial _GL_GNUC_PREREQ (4, 3) +# define _GL_ATTR_cold _GL_GNUC_PREREQ (4, 3) +# define _GL_ATTR_const _GL_GNUC_PREREQ (2, 95) +# define _GL_ATTR_deprecated _GL_GNUC_PREREQ (3, 1) +# define _GL_ATTR_diagnose_if 0 +# define _GL_ATTR_error _GL_GNUC_PREREQ (4, 3) +# define _GL_ATTR_externally_visible _GL_GNUC_PREREQ (4, 1) +# define _GL_ATTR_fallthrough _GL_GNUC_PREREQ (7, 0) +# define _GL_ATTR_format _GL_GNUC_PREREQ (2, 7) +# define _GL_ATTR_leaf _GL_GNUC_PREREQ (4, 6) +# define _GL_ATTR_malloc _GL_GNUC_PREREQ (3, 0) +# ifdef _ICC +# define _GL_ATTR_may_alias 0 +# else +# define _GL_ATTR_may_alias _GL_GNUC_PREREQ (3, 3) +# endif +# define _GL_ATTR_noinline _GL_GNUC_PREREQ (3, 1) +# define _GL_ATTR_nonnull _GL_GNUC_PREREQ (3, 3) +# define _GL_ATTR_nonstring _GL_GNUC_PREREQ (8, 0) +# define _GL_ATTR_nothrow _GL_GNUC_PREREQ (3, 3) +# define _GL_ATTR_packed _GL_GNUC_PREREQ (2, 7) +# define _GL_ATTR_pure _GL_GNUC_PREREQ (2, 96) +# define _GL_ATTR_returns_nonnull _GL_GNUC_PREREQ (4, 9) +# define _GL_ATTR_sentinel _GL_GNUC_PREREQ (4, 0) +# define _GL_ATTR_unused _GL_GNUC_PREREQ (2, 7) +# define _GL_ATTR_warn_unused_result _GL_GNUC_PREREQ (3, 4) +#endif + +/* Disable GCC -Wpedantic if using __has_c_attribute and this is not C23+. */ +#if (defined __has_c_attribute && _GL_GNUC_PREREQ (4, 6) \ + && (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) <= 201710) +# pragma GCC diagnostic ignored "-Wpedantic" +#endif + + +/* _GL_ATTRIBUTE_ALLOC_SIZE ((N)) declares that the Nth argument of the function + is the size of the returned memory block. + _GL_ATTRIBUTE_ALLOC_SIZE ((M, N)) declares that the Mth argument multiplied + by the Nth argument of the function is the size of the returned memory block. + */ +/* Applies to: function, pointer to function, function types. */ +#ifndef _GL_ATTRIBUTE_ALLOC_SIZE +# if _GL_HAS_ATTRIBUTE (alloc_size) +# define _GL_ATTRIBUTE_ALLOC_SIZE(args) __attribute__ ((__alloc_size__ args)) +# else +# define _GL_ATTRIBUTE_ALLOC_SIZE(args) +# endif +#endif + +/* _GL_ATTRIBUTE_ALWAYS_INLINE tells that the compiler should always inline the + function and report an error if it cannot do so. */ +/* Applies to: function. */ +#ifndef _GL_ATTRIBUTE_ALWAYS_INLINE +# if _GL_HAS_ATTRIBUTE (always_inline) +# define _GL_ATTRIBUTE_ALWAYS_INLINE __attribute__ ((__always_inline__)) +# else +# define _GL_ATTRIBUTE_ALWAYS_INLINE +# endif +#endif + +/* _GL_ATTRIBUTE_ARTIFICIAL declares that the function is not important to show + in stack traces when debugging. The compiler should omit the function from + stack traces. */ +/* Applies to: function. */ +#ifndef _GL_ATTRIBUTE_ARTIFICIAL +# if _GL_HAS_ATTRIBUTE (artificial) +# define _GL_ATTRIBUTE_ARTIFICIAL __attribute__ ((__artificial__)) +# else +# define _GL_ATTRIBUTE_ARTIFICIAL +# endif +#endif + +/* _GL_ATTRIBUTE_COLD declares that the function is rarely executed. */ +/* Applies to: functions. */ +/* Avoid __attribute__ ((cold)) on MinGW; see thread starting at + . + Also, Oracle Studio 12.6 requires 'cold' not '__cold__'. */ +#ifndef _GL_ATTRIBUTE_COLD +# if _GL_HAS_ATTRIBUTE (cold) && !defined __MINGW32__ +# ifndef __SUNPRO_C +# define _GL_ATTRIBUTE_COLD __attribute__ ((__cold__)) +# else +# define _GL_ATTRIBUTE_COLD __attribute__ ((cold)) +# endif +# else +# define _GL_ATTRIBUTE_COLD +# endif +#endif + +/* _GL_ATTRIBUTE_CONST declares that it is OK for a compiler to omit duplicate + calls to the function with the same arguments. + This attribute is safe for a function that neither depends on nor affects + observable state, and always returns exactly once - e.g., does not loop + forever, and does not call longjmp. + (This attribute is stricter than _GL_ATTRIBUTE_PURE.) */ +/* Applies to: functions. */ +#ifndef _GL_ATTRIBUTE_CONST +# if _GL_HAS_ATTRIBUTE (const) +# define _GL_ATTRIBUTE_CONST __attribute__ ((__const__)) +# else +# define _GL_ATTRIBUTE_CONST +# endif +#endif + +/* _GL_ATTRIBUTE_DEALLOC (F, I) declares that the function returns pointers + that can be freed by passing them as the Ith argument to the + function F. + _GL_ATTRIBUTE_DEALLOC_FREE declares that the function returns pointers that + can be freed via 'free'; it can be used only after declaring 'free'. */ +/* Applies to: functions. Cannot be used on inline functions. */ +#ifndef _GL_ATTRIBUTE_DEALLOC +# if _GL_GNUC_PREREQ (11, 0) +# define _GL_ATTRIBUTE_DEALLOC(f, i) __attribute__ ((__malloc__ (f, i))) +# else +# define _GL_ATTRIBUTE_DEALLOC(f, i) +# endif +#endif +/* If gnulib's or has already defined this macro, continue + to use this earlier definition, since may not have been included + yet. */ +#ifndef _GL_ATTRIBUTE_DEALLOC_FREE +# if defined __cplusplus && defined __GNUC__ && !defined __clang__ +/* Work around GCC bug */ +# define _GL_ATTRIBUTE_DEALLOC_FREE \ + _GL_ATTRIBUTE_DEALLOC ((void (*) (void *)) free, 1) +# else +# define _GL_ATTRIBUTE_DEALLOC_FREE \ + _GL_ATTRIBUTE_DEALLOC (free, 1) +# endif +#endif + +/* _GL_ATTRIBUTE_DEPRECATED: Declares that an entity is deprecated. + The compiler may warn if the entity is used. */ +/* Applies to: + - function, variable, + - struct, union, struct/union member, + - enumeration, enumeration item, + - typedef, + in C++ also: namespace, class, template specialization. */ +#ifndef _GL_ATTRIBUTE_DEPRECATED +# ifdef __has_c_attribute +# if __has_c_attribute (__deprecated__) +# define _GL_ATTRIBUTE_DEPRECATED [[__deprecated__]] +# endif +# endif +# if !defined _GL_ATTRIBUTE_DEPRECATED && _GL_HAS_ATTRIBUTE (deprecated) +# define _GL_ATTRIBUTE_DEPRECATED __attribute__ ((__deprecated__)) +# endif +# ifndef _GL_ATTRIBUTE_DEPRECATED +# define _GL_ATTRIBUTE_DEPRECATED +# endif +#endif + +/* _GL_ATTRIBUTE_ERROR(msg) requests an error if a function is called and + the function call is not optimized away. + _GL_ATTRIBUTE_WARNING(msg) requests a warning if a function is called and + the function call is not optimized away. */ +/* Applies to: functions. */ +#if !(defined _GL_ATTRIBUTE_ERROR && defined _GL_ATTRIBUTE_WARNING) +# if _GL_HAS_ATTRIBUTE (error) +# define _GL_ATTRIBUTE_ERROR(msg) __attribute__ ((__error__ (msg))) +# define _GL_ATTRIBUTE_WARNING(msg) __attribute__ ((__warning__ (msg))) +# elif _GL_HAS_ATTRIBUTE (diagnose_if) +# define _GL_ATTRIBUTE_ERROR(msg) __attribute__ ((__diagnose_if__ (1, msg, "error"))) +# define _GL_ATTRIBUTE_WARNING(msg) __attribute__ ((__diagnose_if__ (1, msg, "warning"))) +# else +# define _GL_ATTRIBUTE_ERROR(msg) +# define _GL_ATTRIBUTE_WARNING(msg) +# endif +#endif + +/* _GL_ATTRIBUTE_EXTERNALLY_VISIBLE declares that the entity should remain + visible to debuggers etc., even with '-fwhole-program'. */ +/* Applies to: functions, variables. */ +#ifndef _GL_ATTRIBUTE_EXTERNALLY_VISIBLE +# if _GL_HAS_ATTRIBUTE (externally_visible) +# define _GL_ATTRIBUTE_EXTERNALLY_VISIBLE __attribute__ ((externally_visible)) +# else +# define _GL_ATTRIBUTE_EXTERNALLY_VISIBLE +# endif +#endif + +/* _GL_ATTRIBUTE_FALLTHROUGH declares that it is not a programming mistake if + the control flow falls through to the immediately following 'case' or + 'default' label. The compiler should not warn in this case. */ +/* Applies to: Empty statement (;), inside a 'switch' statement. */ +/* Always expands to something. */ +#ifndef _GL_ATTRIBUTE_FALLTHROUGH +# ifdef __has_c_attribute +# if __has_c_attribute (__fallthrough__) +# define _GL_ATTRIBUTE_FALLTHROUGH [[__fallthrough__]] +# endif +# endif +# if !defined _GL_ATTRIBUTE_FALLTHROUGH && _GL_HAS_ATTRIBUTE (fallthrough) +# define _GL_ATTRIBUTE_FALLTHROUGH __attribute__ ((__fallthrough__)) +# endif +# ifndef _GL_ATTRIBUTE_FALLTHROUGH +# define _GL_ATTRIBUTE_FALLTHROUGH ((void) 0) +# endif +#endif + +/* _GL_ATTRIBUTE_FORMAT ((ARCHETYPE, STRING-INDEX, FIRST-TO-CHECK)) + declares that the STRING-INDEXth function argument is a format string of + style ARCHETYPE, which is one of: + printf, gnu_printf + scanf, gnu_scanf, + strftime, gnu_strftime, + strfmon, + or the same thing prefixed and suffixed with '__'. + If FIRST-TO-CHECK is not 0, arguments starting at FIRST-TO_CHECK + are suitable for the format string. */ +/* Applies to: functions. */ +#ifndef _GL_ATTRIBUTE_FORMAT +# if _GL_HAS_ATTRIBUTE (format) +# define _GL_ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec)) +# else +# define _GL_ATTRIBUTE_FORMAT(spec) +# endif +#endif + +/* _GL_ATTRIBUTE_LEAF declares that if the function is called from some other + compilation unit, it executes code from that unit only by return or by + exception handling. This declaration lets the compiler optimize that unit + more aggressively. */ +/* Applies to: functions. */ +#ifndef _GL_ATTRIBUTE_LEAF +# if _GL_HAS_ATTRIBUTE (leaf) +# define _GL_ATTRIBUTE_LEAF __attribute__ ((__leaf__)) +# else +# define _GL_ATTRIBUTE_LEAF +# endif +#endif + +/* _GL_ATTRIBUTE_MALLOC declares that the function returns a pointer to freshly + allocated memory. */ +/* Applies to: functions. */ +#ifndef _GL_ATTRIBUTE_MALLOC +# if _GL_HAS_ATTRIBUTE (malloc) +# define _GL_ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) +# else +# define _GL_ATTRIBUTE_MALLOC +# endif +#endif + +/* _GL_ATTRIBUTE_MAY_ALIAS declares that pointers to the type may point to the + same storage as pointers to other types. Thus this declaration disables + strict aliasing optimization. */ +/* Applies to: types. */ +/* Oracle Studio 12.6 mishandles may_alias despite __has_attribute OK. */ +#ifndef _GL_ATTRIBUTE_MAY_ALIAS +# if _GL_HAS_ATTRIBUTE (may_alias) && !defined __SUNPRO_C +# define _GL_ATTRIBUTE_MAY_ALIAS __attribute__ ((__may_alias__)) +# else +# define _GL_ATTRIBUTE_MAY_ALIAS +# endif +#endif + +/* _GL_ATTRIBUTE_MAYBE_UNUSED declares that it is not a programming mistake if + the entity is not used. The compiler should not warn if the entity is not + used. */ +/* Applies to: + - function, variable, + - struct, union, struct/union member, + - enumeration, enumeration item, + - typedef, + in C++ also: class. */ +/* In C++ and C23, this is spelled [[__maybe_unused__]]. + GCC's syntax is __attribute__ ((__unused__)). + clang supports both syntaxes. Except that with clang ≥ 6, < 10, in C++ mode, + __has_c_attribute (__maybe_unused__) yields true but the use of + [[__maybe_unused__]] nevertheless produces a warning. */ +#ifndef _GL_ATTRIBUTE_MAYBE_UNUSED +# if defined __clang__ && defined __cplusplus +# if !defined __apple_build_version__ && __clang_major__ >= 10 +# define _GL_ATTRIBUTE_MAYBE_UNUSED [[__maybe_unused__]] +# endif +# elif defined __has_c_attribute +# if __has_c_attribute (__maybe_unused__) +# define _GL_ATTRIBUTE_MAYBE_UNUSED [[__maybe_unused__]] +# endif +# endif +# ifndef _GL_ATTRIBUTE_MAYBE_UNUSED +# define _GL_ATTRIBUTE_MAYBE_UNUSED _GL_ATTRIBUTE_UNUSED +# endif +#endif +/* Alternative spelling of this macro, for convenience and for + compatibility with glibc/include/libc-symbols.h. */ +#define _GL_UNUSED _GL_ATTRIBUTE_MAYBE_UNUSED +/* Earlier spellings of this macro. */ +#define _UNUSED_PARAMETER_ _GL_ATTRIBUTE_MAYBE_UNUSED + +/* _GL_ATTRIBUTE_NODISCARD declares that the caller of the function should not + discard the return value. The compiler may warn if the caller does not use + the return value, unless the caller uses something like ignore_value. */ +/* Applies to: function, enumeration, class. */ +#ifndef _GL_ATTRIBUTE_NODISCARD +# if defined __clang__ && defined __cplusplus + /* With clang up to 15.0.6 (at least), in C++ mode, [[__nodiscard__]] produces + a warning. + The 1000 below means a yet unknown threshold. When clang++ version X + starts supporting [[__nodiscard__]] without warning about it, you can + replace the 1000 with X. */ +# if __clang_major__ >= 1000 +# define _GL_ATTRIBUTE_NODISCARD [[__nodiscard__]] +# endif +# elif defined __has_c_attribute +# if __has_c_attribute (__nodiscard__) +# define _GL_ATTRIBUTE_NODISCARD [[__nodiscard__]] +# endif +# endif +# if !defined _GL_ATTRIBUTE_NODISCARD && _GL_HAS_ATTRIBUTE (warn_unused_result) +# define _GL_ATTRIBUTE_NODISCARD __attribute__ ((__warn_unused_result__)) +# endif +# ifndef _GL_ATTRIBUTE_NODISCARD +# define _GL_ATTRIBUTE_NODISCARD +# endif +#endif + +/* _GL_ATTRIBUTE_NOINLINE tells that the compiler should not inline the + function. */ +/* Applies to: functions. */ +#ifndef _GL_ATTRIBUTE_NOINLINE +# if _GL_HAS_ATTRIBUTE (noinline) +# define _GL_ATTRIBUTE_NOINLINE __attribute__ ((__noinline__)) +# else +# define _GL_ATTRIBUTE_NOINLINE +# endif +#endif + +/* _GL_ATTRIBUTE_NONNULL ((N1, N2,...)) declares that the arguments N1, N2,... + must not be NULL. + _GL_ATTRIBUTE_NONNULL () declares that all pointer arguments must not be + null. */ +/* Applies to: functions. */ +#ifndef _GL_ATTRIBUTE_NONNULL +# if _GL_HAS_ATTRIBUTE (nonnull) +# define _GL_ATTRIBUTE_NONNULL(args) __attribute__ ((__nonnull__ args)) +# else +# define _GL_ATTRIBUTE_NONNULL(args) +# endif +#endif + +/* _GL_ATTRIBUTE_NONSTRING declares that the contents of a character array is + not meant to be NUL-terminated. */ +/* Applies to: struct/union members and variables that are arrays of element + type '[[un]signed] char'. */ +#ifndef _GL_ATTRIBUTE_NONSTRING +# if _GL_HAS_ATTRIBUTE (nonstring) +# define _GL_ATTRIBUTE_NONSTRING __attribute__ ((__nonstring__)) +# else +# define _GL_ATTRIBUTE_NONSTRING +# endif +#endif + +/* There is no _GL_ATTRIBUTE_NORETURN; use _Noreturn instead. */ + +/* _GL_ATTRIBUTE_NOTHROW declares that the function does not throw exceptions. + */ +/* Applies to: functions. */ +#ifndef _GL_ATTRIBUTE_NOTHROW +# if _GL_HAS_ATTRIBUTE (nothrow) && !defined __cplusplus +# define _GL_ATTRIBUTE_NOTHROW __attribute__ ((__nothrow__)) +# else +# define _GL_ATTRIBUTE_NOTHROW +# endif +#endif + +/* _GL_ATTRIBUTE_PACKED declares: + For struct members: The member has the smallest possible alignment. + For struct, union, class: All members have the smallest possible alignment, + minimizing the memory required. */ +/* Applies to: struct members, struct, union, + in C++ also: class. */ +#ifndef _GL_ATTRIBUTE_PACKED +# if _GL_HAS_ATTRIBUTE (packed) +# define _GL_ATTRIBUTE_PACKED __attribute__ ((__packed__)) +# else +# define _GL_ATTRIBUTE_PACKED +# endif +#endif + +/* _GL_ATTRIBUTE_PURE declares that It is OK for a compiler to omit duplicate + calls to the function with the same arguments if observable state is not + changed between calls. + This attribute is safe for a function that does not affect + observable state, and always returns exactly once. + (This attribute is looser than _GL_ATTRIBUTE_CONST.) */ +/* Applies to: functions. */ +#ifndef _GL_ATTRIBUTE_PURE +# if _GL_HAS_ATTRIBUTE (pure) +# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__)) +# else +# define _GL_ATTRIBUTE_PURE +# endif +#endif + +/* _GL_ATTRIBUTE_RETURNS_NONNULL declares that the function's return value is + a non-NULL pointer. */ +/* Applies to: functions. */ +#ifndef _GL_ATTRIBUTE_RETURNS_NONNULL +# if _GL_HAS_ATTRIBUTE (returns_nonnull) +# define _GL_ATTRIBUTE_RETURNS_NONNULL __attribute__ ((__returns_nonnull__)) +# else +# define _GL_ATTRIBUTE_RETURNS_NONNULL +# endif +#endif + +/* _GL_ATTRIBUTE_SENTINEL(pos) declares that the variadic function expects a + trailing NULL argument. + _GL_ATTRIBUTE_SENTINEL () - The last argument is NULL (requires C99). + _GL_ATTRIBUTE_SENTINEL ((N)) - The (N+1)st argument from the end is NULL. */ +/* Applies to: functions. */ +#ifndef _GL_ATTRIBUTE_SENTINEL +# if _GL_HAS_ATTRIBUTE (sentinel) +# define _GL_ATTRIBUTE_SENTINEL(pos) __attribute__ ((__sentinel__ pos)) +# else +# define _GL_ATTRIBUTE_SENTINEL(pos) +# endif +#endif + +/* A helper macro. Don't use it directly. */ +#ifndef _GL_ATTRIBUTE_UNUSED +# if _GL_HAS_ATTRIBUTE (unused) +# define _GL_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +# else +# define _GL_ATTRIBUTE_UNUSED +# endif +#endif + + +/* _GL_UNUSED_LABEL; declares that it is not a programming mistake if the + immediately preceding label is not used. The compiler should not warn + if the label is not used. */ +/* Applies to: label (both in C and C++). */ +/* Note that g++ < 4.5 does not support the '__attribute__ ((__unused__)) ;' + syntax. But clang does. */ +#ifndef _GL_UNUSED_LABEL +# if !(defined __cplusplus && !_GL_GNUC_PREREQ (4, 5)) || defined __clang__ +# define _GL_UNUSED_LABEL _GL_ATTRIBUTE_UNUSED +# else +# define _GL_UNUSED_LABEL +# endif +#endif + + /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ /* Define as 'access' if you don't have the eaccess() function. */ -#define eaccess access - -/* Please see the Gnulib manual for how to use these macros. - - Suppress extern inline with HP-UX cc, as it appears to be broken; see - . - - Suppress extern inline with Sun C in standards-conformance mode, as it - mishandles inline functions that call each other. E.g., for 'inline void f - (void) { } inline void g (void) { f (); }', c99 incorrectly complains - 'reference to static identifier "f" in extern inline function'. - This bug was observed with Sun C 5.12 SunOS_i386 2011/11/16. - - Suppress extern inline (with or without __attribute__ ((__gnu_inline__))) - on configurations that mistakenly use 'static inline' to implement - functions or macros in standard C headers like . For example, - if isdigit is mistakenly implemented via a static inline function, - a program containing an extern inline function that calls isdigit - may not work since the C standard prohibits extern inline functions - from calling static functions (ISO C 99 section 6.7.4.(3). - This bug is known to occur on: - - OS X 10.8 and earlier; see: - https://lists.gnu.org/r/bug-gnulib/2012-12/msg00023.html - - DragonFly; see - http://muscles.dragonflybsd.org/bulk/clang-master-potential/20141111_102002/logs/ah-tty-0.3.12.log - - FreeBSD; see: - https://lists.gnu.org/r/bug-gnulib/2014-07/msg00104.html - - OS X 10.9 has a macro __header_inline indicating the bug is fixed for C and - for clang but remains for g++; see . - Assume DragonFly and FreeBSD will be similar. - - GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99 - inline semantics, unless -fgnu89-inline is used. It defines a macro - __GNUC_STDC_INLINE__ to indicate this situation or a macro - __GNUC_GNU_INLINE__ to indicate the opposite situation. - GCC 4.2 with -std=c99 or -std=gnu99 implements the GNU C inline - semantics but warns, unless -fgnu89-inline is used: - warning: C99 inline functions are not supported; using GNU89 - warning: to disable this warning use -fgnu89-inline or the gnu_inline - function attribute It defines a macro __GNUC_GNU_INLINE__ to indicate this - situation. - */ -#if (((defined __APPLE__ && defined __MACH__) || defined __DragonFly__ || \ - defined __FreeBSD__) && \ - (defined __header_inline \ - ? (defined __cplusplus && defined __GNUC_STDC_INLINE__ && \ - !defined __clang__) \ - : ((!defined _DONT_USE_CTYPE_INLINE_ && \ - (defined __GNUC__ || defined __cplusplus)) || \ - (defined _FORTIFY_SOURCE && 0 < _FORTIFY_SOURCE && \ - defined __GNUC__ && !defined __cplusplus)))) -#define _GL_EXTERN_INLINE_STDHEADER_BUG -#endif -#if ((__GNUC__ ? defined __GNUC_STDC_INLINE__ && __GNUC_STDC_INLINE__ \ - : (199901L <= __STDC_VERSION__ && !defined __HP_cc && \ - !defined __PGI && !(defined __SUNPRO_C && __STDC__))) && \ - !defined _GL_EXTERN_INLINE_STDHEADER_BUG) -#define _GL_INLINE inline -#define _GL_EXTERN_INLINE extern inline -#define _GL_EXTERN_INLINE_IN_USE -#elif (2 < __GNUC__ + (7 <= __GNUC_MINOR__) && !defined __STRICT_ANSI__ && \ - !defined _GL_EXTERN_INLINE_STDHEADER_BUG) -#if defined __GNUC_GNU_INLINE__ && __GNUC_GNU_INLINE__ -/* __gnu_inline__ suppresses a GCC 4.2 diagnostic. */ -#define _GL_INLINE extern inline __attribute__((__gnu_inline__)) -#else -#define _GL_INLINE extern inline -#endif -#define _GL_EXTERN_INLINE extern -#define _GL_EXTERN_INLINE_IN_USE -#else -#define _GL_INLINE static _GL_UNUSED -#define _GL_EXTERN_INLINE static _GL_UNUSED -#endif - -/* In GCC 4.6 (inclusive) to 5.1 (exclusive), - suppress bogus "no previous prototype for 'FOO'" - and "no previous declaration for 'FOO'" diagnostics, - when FOO is an inline function in the header; see - and - . */ -#if __GNUC__ == 4 && 6 <= __GNUC_MINOR__ -#if defined __GNUC_STDC_INLINE__ && __GNUC_STDC_INLINE__ -#define _GL_INLINE_HEADER_CONST_PRAGMA -#else -#define _GL_INLINE_HEADER_CONST_PRAGMA \ - _Pragma("GCC diagnostic ignored \"-Wsuggest-attribute=const\"") -#endif -#define _GL_INLINE_HEADER_BEGIN \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wmissing-prototypes\"") \ - _Pragma("GCC diagnostic ignored \"-Wmissing-declarations\"") \ - _GL_INLINE_HEADER_CONST_PRAGMA -#define _GL_INLINE_HEADER_END _Pragma("GCC diagnostic pop") -#else -#define _GL_INLINE_HEADER_BEGIN -#define _GL_INLINE_HEADER_END -#endif +/* #undef eaccess */ /* Define to `int' if doesn't define. */ /* #undef gid_t */ +/* Define to the widest signed integer type if and do + not define. */ +/* #undef intmax_t */ + /* Work around a bug in Apple GCC 4.0.1 build 5465: In C99 mode, it supports the ISO C 99 semantics of 'extern inline' (unlike the GNU C semantics of earlier versions), but does not display it by setting __GNUC_STDC_INLINE__. __APPLE__ && __MACH__ test for Mac OS X. __APPLE_CC__ tests for the Apple compiler and its version. __STDC_VERSION__ tests for the C99 mode. */ -#if defined __APPLE__ && defined __MACH__ && __APPLE_CC__ >= 5465 && \ - !defined __cplusplus && __STDC_VERSION__ >= 199901L && \ - !defined __GNUC_STDC_INLINE__ -#define __GNUC_STDC_INLINE__ 1 +#if defined __APPLE__ && defined __MACH__ && __APPLE_CC__ >= 5465 && !defined __cplusplus && __STDC_VERSION__ >= 199901L && !defined __GNUC_STDC_INLINE__ +# define __GNUC_STDC_INLINE__ 1 #endif -/* Define to `int' if does not define. */ -/* #undef mode_t */ +/* _GL_CMP (n1, n2) performs a three-valued comparison on n1 vs. n2, where + n1 and n2 are expressions without side effects, that evaluate to real + numbers (excluding NaN). + It returns + 1 if n1 > n2 + 0 if n1 == n2 + -1 if n1 < n2 + The naïve code (n1 > n2 ? 1 : n1 < n2 ? -1 : 0) produces a conditional + jump with nearly all GCC versions up to GCC 10. + This variant (n1 < n2 ? -1 : n1 > n2) produces a conditional with many + GCC versions up to GCC 9. + The better code (n1 > n2) - (n1 < n2) from Hacker's Delight § 2-9 + avoids conditional jumps in all GCC versions >= 3.4. */ +#define _GL_CMP(n1, n2) (((n1) > (n2)) - ((n1) < (n2))) + /* Define to `long int' if does not define. */ /* #undef off_t */ -/* Define to `int' if does not define. */ +/* Define as a signed integer type capable of holding a process identifier. */ /* #undef pid_t */ -/* Define to the equivalent of the C99 'restrict' keyword, or to - nothing if this is not supported. Do not define if restrict is - supported directly. */ -#define restrict __restrict -/* Work around a bug in older versions of Sun C++, which did not - #define __restrict__ or support _Restrict or __restrict__ - even though the corresponding Sun C compiler ended up with - "#define restrict _Restrict" or "#define restrict __restrict__" - in the previous line. This workaround can be removed once - we assume Oracle Developer Studio 12.5 (2016) or later. */ -#if defined __SUNPRO_CC && !defined __RESTRICT && !defined __restrict__ -#define _Restrict -#define __restrict__ -#endif +/* Define as an integer type suitable for memory locations that can be + accessed atomically even in the presence of asynchronous signals. */ +/* #undef sig_atomic_t */ /* Define to `unsigned int' if does not define. */ /* #undef size_t */ @@ -937,45 +1307,22 @@ do not define. */ /* #undef uintmax_t */ -/* Define as a marker that can be attached to declarations that might not - be used. This helps to reduce warnings, such as from - GCC -Wunused-parameter. */ -#if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7) -#define _GL_UNUSED __attribute__((__unused__)) -#else -#define _GL_UNUSED -#endif -/* The name _UNUSED_PARAMETER_ is an earlier spelling, although the name - is a misnomer outside of parameter lists. */ -#define _UNUSED_PARAMETER_ _GL_UNUSED +/* Define as `fork' if `vfork' does not work. */ +/* #undef vfork */ -/* gcc supports the "unused" attribute on possibly unused labels, and - g++ has since version 4.5. Note to support C++ as well as C, - _GL_UNUSED_LABEL should be used with a trailing ; */ -#if !defined __cplusplus || __GNUC__ > 4 || \ - (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) -#define _GL_UNUSED_LABEL _GL_UNUSED -#else -#define _GL_UNUSED_LABEL -#endif - -/* The __pure__ attribute was added in gcc 2.96. */ -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) -#define _GL_ATTRIBUTE_PURE __attribute__((__pure__)) -#else -#define _GL_ATTRIBUTE_PURE /* empty */ -#endif - -/* The __const__ attribute was added in gcc 2.95. */ -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) -#define _GL_ATTRIBUTE_CONST __attribute__((__const__)) -#else -#define _GL_ATTRIBUTE_CONST /* empty */ -#endif - -/* The __malloc__ attribute was added in gcc 3. */ -#if 3 <= __GNUC__ -#define _GL_ATTRIBUTE_MALLOC __attribute__((__malloc__)) -#else -#define _GL_ATTRIBUTE_MALLOC /* empty */ +#ifndef HAVE_C_BOOL +# if !defined __cplusplus && !defined __bool_true_false_are_defined +# if HAVE_STDBOOL_H +# include +# else +# if defined __SUNPRO_C +# error " is not usable with this configuration. To make it usable, add -D_STDC_C99= to $CC." +# else +# error " does not exist on this platform. Use gnulib module 'stdbool-c99' instead of gnulib module 'stdbool'." +# endif +# endif +# endif +# if !true +# define true (!false) +# endif #endif diff --git a/third_party/make/debug.h b/third_party/make/debug.h index 66e17ff15..210689162 100644 --- a/third_party/make/debug.h +++ b/third_party/make/debug.h @@ -1,5 +1,5 @@ /* Debugging macros and interface. -Copyright (C) 1999-2020 Free Software Foundation, Inc. +Copyright (C) 1999-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,22 +12,22 @@ 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 . */ - -#include "libc/intrin/likely.h" +this program. If not, see . */ #define DB_NONE (0x000) #define DB_BASIC (0x001) #define DB_VERBOSE (0x002) #define DB_JOBS (0x004) #define DB_IMPLICIT (0x008) +#define DB_PRINT (0x010) +#define DB_WHY (0x020) #define DB_MAKEFILES (0x100) #define DB_ALL (0xfff) extern int db_level; -#define ISDB(_l) UNLIKELY((_l)&db_level) +#define ISDB(_l) ((_l)&db_level) /* When adding macros to this list be sure to update the value of XGETTEXT_OPTIONS in the po/Makevars file. */ diff --git a/third_party/make/default.c b/third_party/make/default.c index c97040e97..e396269bc 100644 --- a/third_party/make/default.c +++ b/third_party/make/default.c @@ -1,5 +1,5 @@ /* Data base of default implicit rules for GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,37 +12,74 @@ 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 . */ +this program. If not, see . */ + +#include "makeint.h" + +#include + +#include "filedef.h" +#include "variable.h" +#include "rule.h" +#include "dep.h" +#include "job.h" +#include "commands.h" + +/* Define GCC_IS_NATIVE if gcc is the native development environment on + your system (gcc/bison/flex vs cc/yacc/lex). */ +#if defined(__MSDOS__) || defined(__EMX__) +# define GCC_IS_NATIVE +#endif -#include "third_party/make/makeint.inc" -/**/ -#include "third_party/make/filedef.h" -#include "third_party/make/variable.h" -#include "third_party/make/rule.h" -#include "third_party/make/dep.h" -#include "third_party/make/job.h" -#include "libc/assert.h" -#include "third_party/make/commands.h" /* This is the default list of suffixes for suffix rules. '.s' must come last, so that a '.o' file will be made from a '.c' or '.p' or ... file rather than from a .s file. */ static char default_suffixes[] +#ifdef VMS + /* VMS should include all UNIX/POSIX + some VMS extensions */ + = ".out .exe .a .olb .hlb .tlb .mlb .ln .o .obj .c .cxx .cc .cpp .pas .p \ +.for .f .r .y .l .ym .yl .mar .s .ss .i .ii .mod .sym .def .h .info .dvi \ +.tex .texinfo .texi .txinfo .mem .hlp .brn .rnh .rno .rnt .rnx .w .ch .cweb \ +.web .com .sh .elc .el"; +#elif defined(__EMX__) + = ".out .a .ln .o .c .cc .C .cpp .p .f .F .m .r .y .l .ym .yl .s .S \ +.mod .sym .def .h .info .dvi .tex .texinfo .texi .txinfo \ +.w .ch .web .sh .elc .el .obj .exe .dll .lib"; +#else = ".out .a .ln .o .c .cc .C .cpp .p .f .F .m .r .y .l .ym .yl .s .S \ .mod .sym .def .h .info .dvi .tex .texinfo .texi .txinfo \ .w .ch .web .sh .elc .el"; +#endif static struct pspec default_pattern_rules[] = { +#ifdef VMS + { "(%)", "%", + "@if f$$search(\"$@\") .eqs. \"\" then $(LIBRARY)/CREATE/" + "$(or " + "$(patsubst %,TEXT,$(filter %.tlb %.TLB,$@))," + "$(patsubst %,HELP,$(filter %.hlb %.HLB,$@))," + "$(patsubst %,MACRO,$(filter %.mlb %.MLB,$@))," + "$(and " + "$(patsubst %,SHARE,$(filter %.olb %.OLB,$@))," + "$(patsubst %,SHARE,$(filter %.exe %.EXE,$<)))," + "OBJECT)" + " $@\n" + "$(AR) $(ARFLAGS) $@ $<" }, + +#else { "(%)", "%", "$(AR) $(ARFLAGS) $@ $<" }, +#endif /* The X.out rules are only in BSD's default set because BSD Make has no null-suffix rules, so 'foo.out' and 'foo' are the same thing. */ -#ifdef __COSMOPOLITAN__ +#ifdef VMS { "%.exe", "%", "$(CP) $< $@" }, + #endif { "%.out", "%", "@rm -f $@ \n cp $< $@" }, @@ -58,6 +95,22 @@ static struct pspec default_pattern_rules[] = static struct pspec default_terminal_rules[] = { +#ifdef VMS + + /* RCS. */ + { "%", "%$$5lv", /* Multinet style */ + "if f$$search(\"$@\") .nes. \"\" then +$(CHECKOUT,v)" }, + { "%", "[.$$rcs]%$$5lv", /* Multinet style */ + "if f$$search(\"$@\") .nes. \"\" then +$(CHECKOUT,v)" }, + { "%", "%_v", /* Normal style */ + "if f$$search(\"$@\") .nes. \"\" then +$(CHECKOUT,v)" }, + { "%", "[.rcs]%_v", /* Normal style */ + "if f$$search(\"$@\") .nes. \"\" then +$(CHECKOUT,v)" }, + + /* SCCS. */ + /* ain't no SCCS on vms */ + +#else /* RCS. */ { "%", "%,v", "$(CHECKOUT,v)" }, @@ -71,12 +124,147 @@ static struct pspec default_terminal_rules[] = "$(GET) $(GFLAGS) $(SCCS_OUTPUT_OPTION) $<" }, { "%", "SCCS/s.%", "$(GET) $(GFLAGS) $(SCCS_OUTPUT_OPTION) $<" }, - +#endif /* !VMS */ { 0, 0, 0 } }; static const char *default_suffix_rules[] = { +#ifdef VMS + ".o", + "$(LINK.obj) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".obj", + "$(LINK.obj) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".s", + "$(LINK.s) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".S", + "$(LINK.S) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".c", + "$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".cc", + "$(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".C", + "$(LINK.C) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".cpp", + "$(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".f", + "$(LINK.f) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".m", + "$(LINK.m) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".p", + "$(LINK.p) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".F", + "$(LINK.F) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".r", + "$(LINK.r) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".mod", + "$(COMPILE.mod) -o $@ -e $@ $^", + + ".def.sym", + "$(COMPILE.def) -o $@ $<", + + ".sh", + "copy $< >$@", + + ".obj.exe", + "$(LINK.obj) $^ $(LOADLIBES) $(LDLIBS) $(CRT0) /exe=$@", + ".mar.exe", + "$(COMPILE.mar) $^ \n $(LINK.obj) $(subst .mar,.obj,$^) $(LOADLIBES) $(LDLIBS) $(CRT0) /exe=$@", + ".s.o", + "$(COMPILE.s) -o $@ $<", + ".s.exe", + "$(COMPILE.s) $^ \n $(LINK.obj) $(subst .s,.obj,$^) $(LOADLIBES) $(LDLIBS) $(CRT0) /exe=$@", + ".c.exe", + "$(COMPILE.c) $^ \n $(LINK.obj) $(subst .c,.obj,$^) $(LOADLIBES) $(LDLIBS) $(CRT0) /exe=$@", + ".cc.exe", +#ifdef GCC_IS_NATIVE + "$(COMPILE.cc) $^ \n $(LINK.obj) $(CXXSTARTUP),sys$$disk:[]$(subst .cc,.obj,$^) $(LOADLIBES) $(LXLIBS) $(LDLIBS) $(CXXRT0) /exe=$@", +#else + "$(COMPILE.cc) $^ \n $(CXXLINK.obj) $(subst .cc,.obj,$^) $(LOADLIBES) $(LXLIBS) $(LDLIBS) $(CXXRT0) /exe=$@", + ".cxx.exe", + "$(COMPILE.cxx) $^ \n $(CXXLINK.obj) $(subst .cxx,.obj,$^) $(LOADLIBES) $(LXLIBS) $(LDLIBS) $(CXXRT0) /exe=$@", +#endif + ".for.exe", + "$(COMPILE.for) $^ \n $(LINK.obj) $(subst .for,.obj,$^) $(LOADLIBES) $(LDLIBS) /exe=$@", + ".pas.exe", + "$(COMPILE.pas) $^ \n $(LINK.obj) $(subst .pas,.obj,$^) $(LOADLIBES) $(LDLIBS) /exe=$@", + + ".com", + "copy $< >$@", + + ".mar.obj", + "$(COMPILE.mar) /obj=$@ $<", + ".s.obj", + "$(COMPILE.s) /obj=$@ $<", + ".ss.obj", + "$(COMPILE.s) /obj=$@ $<", + ".c.i", + "$(COMPILE.c)/prep /list=$@ $<", + ".c.s", + "$(COMPILE.c)/noobj/machine /list=$@ $<", + ".i.s", + "$(COMPILE.c)/noprep/noobj/machine /list=$@ $<", + ".c.obj", + "$(COMPILE.c) /obj=$@ $<", + ".c.o", + "$(COMPILE.c) /obj=$@ $<", + ".cc.ii", + "$(COMPILE.cc)/prep /list=$@ $<", + ".cc.ss", + "$(COMPILE.cc)/noobj/machine /list=$@ $<", + ".ii.ss", + "$(COMPILE.cc)/noprep/noobj/machine /list=$@ $<", + ".cc.obj", + "$(COMPILE.cc) /obj=$@ $<", + ".cc.o", + "$(COMPILE.cc) /obj=$@ $<", + ".cxx.obj", + "$(COMPILE.cxx) /obj=$@ $<", + ".cxx.o", + "$(COMPILE.cxx) /obj=$@ $<", + ".for.obj", + "$(COMPILE.for) /obj=$@ $<", + ".for.o", + "$(COMPILE.for) /obj=$@ $<", + ".pas.obj", + "$(COMPILE.pas) /obj=$@ $<", + ".pas.o", + "$(COMPILE.pas) /obj=$@ $<", + + ".y.c", + "$(YACC.y) $< \n rename y_tab.c $@", + ".l.c", + "$(LEX.l) $< \n rename lexyy.c $@", + + ".texinfo.info", + "$(MAKEINFO) $<", + + ".tex.dvi", + "$(TEX) $<", + + ".cpp.o", + "$(COMPILE.cpp) $(OUTPUT_OPTION) $<", + ".f.o", + "$(COMPILE.f) $(OUTPUT_OPTION) $<", + ".m.o", + "$(COMPILE.m) $(OUTPUT_OPTION) $<", + ".p.o", + "$(COMPILE.p) $(OUTPUT_OPTION) $<", + ".r.o", + "$(COMPILE.r) $(OUTPUT_OPTION) $<", + ".mod.o", + "$(COMPILE.mod) -o $@ $<", + + ".c.ln", + "$(LINT.c) -C$* $<", + ".y.ln", + "$(YACC.y) $< \n rename y_tab.c $@", + + ".l.ln", + "@$(RM) $*.c\n $(LEX.l) $< > $*.c\n$(LINT.c) -i $*.c -o $@\n $(RM) $*.c", + +#else /* ! VMS */ + ".o", "$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".s", @@ -138,12 +326,20 @@ static const char *default_suffix_rules[] = ".c.ln", "$(LINT.c) -C$* $<", ".y.ln", +#ifndef __MSDOS__ "$(YACC.y) $< \n $(LINT.c) -C$* y.tab.c \n $(RM) y.tab.c", +#else + "$(YACC.y) $< \n $(LINT.c) -C$* y_tab.c \n $(RM) y_tab.c", +#endif ".l.ln", "@$(RM) $*.c\n $(LEX.l) $< > $*.c\n$(LINT.c) -i $*.c -o $@\n $(RM) $*.c", ".y.c", +#ifndef __MSDOS__ "$(YACC.y) $< \n mv -f y.tab.c $@", +#else + "$(YACC.y) $< \n mv -f y_tab.c $@", +#endif ".l.c", "@$(RM) $@ \n $(LEX.l) $< > $@", ".ym.m", @@ -197,24 +393,158 @@ static const char *default_suffix_rules[] = ".web.tex", "$(WEAVE) $<", +#endif /* !VMS */ + 0, 0, }; static const char *default_variables[] = { +#ifdef VMS +#ifdef __ALPHA + "ARCH", "ALPHA", +#endif +#ifdef __ia64 + "ARCH", "IA64", +#endif +#ifdef __VAX + "ARCH", "VAX", +#endif + "AR", "library", + "LIBRARY", "library", + "ARFLAGS", "/replace", + "AS", "macro", + "MACRO", "macro", +#ifdef GCC_IS_NATIVE + "CC", "gcc", +#else + "CC", "cc", +#endif + "CD", "builtin_cd", + "ECHO", "builtin_echo", +#ifdef GCC_IS_NATIVE + "C++", "gcc/plus", + "CXX", "gcc/plus", +#else + "C++", "cxx", + "CXX", "cxx", +#ifndef __ia64 + "CXXLD", "cxxlink", + "CXXLINK", "cxxlink", +#else + /* CXXLINK is not used on VMS/IA64 */ + "CXXLD", "link", + "CXXLINK", "link", +#endif +#endif + "CO", "co", + "CPP", "$(CC) /preprocess_only", + "FC", "fortran", + /* System V uses these, so explicit rules using them should work. + However, there is no way to make implicit rules use them and FC. */ + "F77", "$(FC)", + "F77FLAGS", "$(FFLAGS)", + "LD", "link", + "LEX", "lex", + "PC", "pascal", + "YACC", "bison/yacc", + "YFLAGS", "/Define/Verbose", + "BISON", "bison", + "MAKEINFO", "makeinfo", + "TEX", "tex", + "TEXINDEX", "texindex", + + "RM", "delete/nolog", + + "CSTARTUP", "", +#ifdef GCC_IS_NATIVE + "CRT0", ",sys$$library:vaxcrtl.olb/lib,gnu_cc_library:crt0.obj", + "CXXSTARTUP", "gnu_cc_library:crtbegin.obj", + "CXXRT0", ",sys$$library:vaxcrtl.olb/lib,gnu_cc_library:crtend.obj,gnu_cc_library:gxx_main.obj", + "LXLIBS", ",gnu_cc_library:libstdcxx.olb/lib,gnu_cc_library:libgccplus.olb/lib", + "LDLIBS", ",gnu_cc_library:libgcc.olb/lib", +#else + "CRT0", "", + "CXXSTARTUP", "", + "CXXRT0", "", + "LXLIBS", "", + "LDLIBS", "", +#endif + + "LINK.o", "$(LD) $(LDFLAGS)", + "LINK.obj", "$(LD) $(LDFLAGS)", +#ifndef GCC_IS_NATIVE + "CXXLINK.obj", "$(CXXLD) $(LDFLAGS)", + "COMPILE.cxx", "$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH)", +#endif + "COMPILE.c", "$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH)", + "LINK.c", "$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH)", + "COMPILE.m", "$(OBJC) $(OBJCFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c", + "LINK.m", "$(OBJC) $(OBJCFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)", + "COMPILE.cc", "$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH)", + "COMPILE.C", "$(COMPILE.cc)", + "COMPILE.cpp", "$(COMPILE.cc)", + "LINK.C", "$(LINK.cc)", + "LINK.cpp", "$(LINK.cc)", + "YACC.y", "$(YACC) $(YFLAGS)", + "LEX.l", "$(LEX) $(LFLAGS)", + "YACC.m", "$(YACC) $(YFLAGS)", + "LEX.m", "$(LEX) $(LFLAGS) -t", + "COMPILE.for", "$(FC) $(FFLAGS) $(TARGET_ARCH)", + "COMPILE.f", "$(FC) $(FFLAGS) $(TARGET_ARCH) -c", + "LINK.f", "$(FC) $(FFLAGS) $(LDFLAGS) $(TARGET_ARCH)", + "COMPILE.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c", + "LINK.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)", + "COMPILE.r", "$(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -c", + "LINK.r", "$(FC) $(FFLAGS) $(RFLAGS) $(LDFLAGS) $(TARGET_ARCH)", + "COMPILE.pas", "$(PC) $(PFLAGS) $(CPPFLAGS) $(TARGET_ARCH)", + "COMPILE.def", "$(M2C) $(M2FLAGS) $(DEFFLAGS) $(TARGET_ARCH)", + "COMPILE.mod", "$(M2C) $(M2FLAGS) $(MODFLAGS) $(TARGET_ARCH)", + "COMPILE.p", "$(PC) $(PFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c", + "LINK.p", "$(PC) $(PFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)", + "COMPILE.mar", "$(MACRO) $(MACROFLAGS)", + "COMPILE.s", "$(AS) $(ASFLAGS) $(TARGET_MACH)", + "LINK.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_MACH)", + "COMPILE.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(TARGET_MACH) -c", + "PREPROCESS.S", "$(CPP) $(CPPFLAGS)", + "PREPROCESS.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -F", + "PREPROCESS.r", "$(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -F", + "LINT.c", "$(LINT) $(LINTFLAGS) $(CPPFLAGS) $(TARGET_ARCH)", + + "MV", "rename/new_version", + "CP", "copy", + ".LIBPATTERNS", "%.olb lib%.a", + +#else /* !VMS */ + "AR", "ar", - "ARFLAGS", "rv", +#ifdef _AIX + /* AIX requires object file format specification: choose -Xany. */ + "ARFLAGS", "-Xany -rv", +#else + "ARFLAGS", "-rv", +#endif "AS", "as", #ifdef GCC_IS_NATIVE "CC", "gcc", - "CXX", "gcc", "OBJC", "gcc", #else "CC", "cc", - "CXX", "g++", "OBJC", "cc", #endif - +#ifdef MAKE_CXX + "CXX", MAKE_CXX, +#else +# ifdef GCC_IS_NATIVE +# ifdef __MSDOS__ + "CXX", "gpp", /* g++ is an invalid name on MSDOS */ +# else + "CXX", "gcc", +# endif /* __MSDOS__ */ +# else + "CXX", "g++", +# endif +#endif /* This expands to $(CO) $(COFLAGS) $< $@ if $@ does not exist, and to the empty string if $@ does exist. */ "CHECKOUT,v", "+$(if $(wildcard $@),,$(CO) $(COFLAGS) $< $@)", @@ -222,11 +552,27 @@ static const char *default_variables[] = "COFLAGS", "", "CPP", "$(CC) -E", +#ifdef CRAY + "CF77PPFLAGS", "-P", + "CF77PP", "/lib/cpp", + "CFT", "cft77", + "CF", "cf77", + "FC", "$(CF)", +#else /* Not CRAY. */ +#ifdef _IBMR2 + "FC", "xlf", +#else +#ifdef __convex__ + "FC", "fc", +#else "FC", "f77", +#endif /* __convex__ */ +#endif /* _IBMR2 */ /* System V uses these, so explicit rules using them should work. However, there is no way to make implicit rules use them and FC. */ "F77", "$(FC)", "F77FLAGS", "$(FFLAGS)", +#endif /* Cray. */ "GET", SCCS_GET, "LD", "ld", #ifdef GCC_IS_NATIVE @@ -238,8 +584,13 @@ static const char *default_variables[] = "M2C", "m2c", #ifdef pyr "PC", "pascal", +#else +#ifdef CRAY + "PC", "PASCAL", + "SEGLDR", "segldr", #else "PC", "pc", +#endif /* CRAY. */ #endif /* pyr. */ #ifdef GCC_IS_NATIVE "YACC", "bison -y", @@ -296,14 +647,34 @@ static const char *default_variables[] = "COMPILE.s", "$(AS) $(ASFLAGS) $(TARGET_MACH)", "LINK.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_MACH)", "COMPILE.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(TARGET_MACH) -c", - "PREPROCESS.S", "$(CC) -E $(CPPFLAGS)", + "PREPROCESS.S", "$(CPP) $(CPPFLAGS)", "PREPROCESS.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -F", "PREPROCESS.r", "$(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -F", "LINT.c", "$(LINT) $(LINTFLAGS) $(CPPFLAGS) $(TARGET_ARCH)", + +#ifndef NO_MINUS_C_MINUS_O "OUTPUT_OPTION", "-o $@", +#endif + +#ifdef SCCS_GET_MINUS_G + "SCCS_OUTPUT_OPTION", "-G$@", +#endif + +#if defined(_AMIGA) + ".LIBPATTERNS", "%.lib", +#elif defined(__MSDOS__) + ".LIBPATTERNS", "lib%.a $(DJDIR)/lib/lib%.a", +#elif defined(__APPLE__) + ".LIBPATTERNS", "lib%.dylib lib%.a", +#elif defined(__CYGWIN__) || defined(WINDOWS32) + ".LIBPATTERNS", "lib%.dll.a %.dll.a lib%.a %.lib lib%.dll %.dll", +#else ".LIBPATTERNS", "lib%.so lib%.a", +#endif + +#endif /* !VMS */ /* Make this assignment to avoid undefined variable warnings. */ - "GNUMAKEFLAGS", "", + GNUMAKEFLAGS_NAME, "", 0, 0 }; @@ -336,7 +707,7 @@ set_default_suffixes (void) installed after. */ void -install_default_suffix_rules (void) +install_default_suffix_rules () { const char **s; @@ -346,14 +717,16 @@ install_default_suffix_rules (void) for (s = default_suffix_rules; *s != 0; s += 2) { struct file *f = enter_file (strcache_add (s[0])); - /* This function should run before any makefile is parsed. */ - assert (f->cmds == 0); - f->cmds = xmalloc (sizeof (struct commands)); - f->cmds->fileinfo.filenm = 0; - f->cmds->commands = xstrdup (s[1]); - f->cmds->command_lines = 0; - f->cmds->recipe_prefix = RECIPEPREFIX_DEFAULT; - f->builtin = 1; + /* Install the default rule only if there is no user defined rule. */ + if (!f->cmds) + { + f->cmds = xmalloc (sizeof (struct commands)); + f->cmds->fileinfo.filenm = NULL; + f->cmds->commands = xstrdup (s[1]); + f->cmds->command_lines = NULL; + f->cmds->recipe_prefix = RECIPEPREFIX_DEFAULT; + f->builtin = 1; + } } } diff --git a/third_party/make/dep.h b/third_party/make/dep.h index 84319f15a..7157d459a 100644 --- a/third_party/make/dep.h +++ b/third_party/make/dep.h @@ -1,5 +1,5 @@ /* Definitions of dependency data structures for GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,9 +12,8 @@ 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 . */ +this program. If not, see . */ -#include "libc/x/x.h" /* Structure used in chains of names, for parsing and globbing. */ @@ -31,26 +30,32 @@ struct nameseq These flags are saved in the 'flags' field of each 'struct goaldep' in the chain returned by 'read_all_makefiles'. */ +#define RM_NOFLAG 0 #define RM_NO_DEFAULT_GOAL (1 << 0) /* Do not set default goal. */ #define RM_INCLUDED (1 << 1) /* Search makefile search path. */ #define RM_DONTCARE (1 << 2) /* No error if it doesn't exist. */ #define RM_NO_TILDE (1 << 3) /* Don't expand ~ in file name. */ -#define RM_NOFLAG 0 /* Structure representing one dependency of a file. Each struct file's 'deps' points to a chain of these, through 'next'. - 'stem' is the stem for this dep line of static pattern rule or NULL. */ + 'stem' is the stem for this dep line of static pattern rule or NULL. + explicit is set when implicit rule search is performed and the prerequisite + does not contain %. When explicit is set the file is not intermediate. */ + #define DEP(_t) \ NAMESEQ (_t); \ struct file *file; \ + _t *shuf; \ const char *stem; \ unsigned int flags : 8; \ unsigned int changed : 1; \ unsigned int ignore_mtime : 1; \ unsigned int staticpattern : 1; \ unsigned int need_2nd_expansion : 1; \ - unsigned int ignore_automatic_vars : 1 + unsigned int ignore_automatic_vars : 1; \ + unsigned int is_explicit : 1; \ + unsigned int wait_here : 1 struct dep { @@ -77,6 +82,7 @@ struct goaldep #define PARSEFS_EXISTS 0x0008 #define PARSEFS_NOCACHE 0x0010 #define PARSEFS_ONEWORD 0x0020 +#define PARSEFS_WAIT 0x0040 #define PARSE_FILE_SEQ(_s,_t,_c,_p,_f) \ (_t *)parse_file_seq ((_s),sizeof (_t),(_c),(_p),(_f)) @@ -96,24 +102,23 @@ char *tilde_expand (const char *name); struct nameseq *ar_glob (const char *arname, const char *member_pattern, size_t size); #endif -#define dep_name(d) ((d)->name ? (d)->name : (d)->file->name) +#define dep_name(d) ((d)->name ? (d)->name : (d)->file->name) -#define alloc_seq_elt(_t) xcalloc (1, sizeof (_t)) +#define alloc_seq_elt(_t) xcalloc (sizeof (_t)) void free_ns_chain (struct nameseq *n); #if defined(MAKE_MAINTAINER_MODE) && defined(__GNUC__) && !defined(__STRICT_ANSI__) /* Use inline to get real type-checking. */ #define SI static inline -SI struct nameseq *alloc_ns() { return alloc_seq_elt (struct nameseq); } -SI struct dep *alloc_dep() { return alloc_seq_elt (struct dep); } -SI struct goaldep *alloc_goaldep() { return alloc_seq_elt (struct goaldep); } +SI struct nameseq *alloc_ns (void) { return alloc_seq_elt (struct nameseq); } +SI struct dep *alloc_dep (void) { return alloc_seq_elt (struct dep); } +SI struct goaldep *alloc_goaldep (void) { return alloc_seq_elt (struct goaldep); } -SI void free_ns(struct nameseq *n) { free (n); } -SI void free_dep(struct dep *d) { free_ns ((struct nameseq *)d); } -SI void free_goaldep(struct goaldep *g) { free_dep ((struct dep *)g); } - -SI void free_dep_chain(struct dep *d) { free_ns_chain((struct nameseq *)d); } -SI void free_goal_chain(struct goaldep *g) { free_dep_chain((struct dep *)g); } +SI void free_ns (struct nameseq *n) { free (n); } +SI void free_dep (struct dep *d) { free_ns ((struct nameseq *)d); } +SI void free_goaldep (struct goaldep *g) { free_dep ((struct dep *)g); } +SI void free_dep_chain (struct dep *d) { free_ns_chain((struct nameseq *)d); } +SI void free_goal_chain (struct goaldep *g) { free_dep_chain((struct dep *)g); } #else # define alloc_ns() alloc_seq_elt (struct nameseq) # define alloc_dep() alloc_seq_elt (struct dep) diff --git a/third_party/make/dir.c b/third_party/make/dir.c index 0e0fabc7f..367359374 100644 --- a/third_party/make/dir.c +++ b/third_party/make/dir.c @@ -1,5 +1,5 @@ /* Directory hashing for GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,121 +12,315 @@ 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 . */ +this program. If not, see . */ -#include "third_party/make/makeint.inc" -/**/ -#include "libc/calls/struct/dirent.h" -#include "libc/x/x.h" -#include "third_party/make/dep.h" -#include "third_party/make/filedef.h" -#include "third_party/make/hash.h" -#include "third_party/musl/glob.h" +#include "makeint.h" +#include "hash.h" +#include "filedef.h" +#include "dep.h" +#include "debug.h" +#include "glob.h" -#ifndef __ptr_t -#define __ptr_t void * -#endif -#define gl_readdir __dummy2[1] -#define gl_opendir __dummy2[2] -#define gl_closedir __dummy2[0] -#define gl_lstat __dummy2[3] -#define gl_stat __dummy2[4] - -#ifdef HAVE_DIRENT_H -#define NAMLEN(dirent) strlen((dirent)->d_name) +#ifdef HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +# ifdef VMS +/* its prototype is in vmsdir.h, which is not needed for HAVE_DIRENT_H */ +const char *vmsify (const char *name, int type); +# endif #else -#define dirent direct -#define NAMLEN(dirent) (dirent)->d_namlen +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# ifdef HAVE_SYS_NDIR_H +# include +# endif +# ifdef HAVE_SYS_DIR_H +# include +# endif +# ifdef HAVE_NDIR_H +# include +# endif #endif /* In GNU systems, defines this macro for us. */ #ifdef _D_NAMLEN -#undef NAMLEN -#define NAMLEN(d) _D_NAMLEN(d) +# undef NAMLEN +# define NAMLEN(d) _D_NAMLEN(d) #endif -#if (defined(POSIX) || defined(VMS) || defined(WINDOWS32)) && \ - !defined(__GNU_LIBRARY__) +#if (defined (POSIX) || defined (VMS) || defined (WINDOWS32)) && !defined (__GNU_LIBRARY__) /* Posix does not require that the d_ino field be present, and some systems do not provide it. */ -#define REAL_DIR_ENTRY(dp) 1 -#define FAKE_DIR_ENTRY(dp) +# define REAL_DIR_ENTRY(dp) 1 +# define FAKE_DIR_ENTRY(dp) #else -#define REAL_DIR_ENTRY(dp) (dp->d_ino != 0) -#define FAKE_DIR_ENTRY(dp) (dp->d_ino = 1) +# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0) +# define FAKE_DIR_ENTRY(dp) (dp->d_ino = 1) #endif /* POSIX */ + +#ifdef __MSDOS__ +#include +#include + +/* If it's MSDOS that doesn't have _USE_LFN, disable LFN support. */ +#ifndef _USE_LFN +#define _USE_LFN 0 +#endif + +static const char * +dosify (const char *filename) +{ + static char dos_filename[14]; + char *df; + int i; + + if (filename == NULL || _USE_LFN) + return filename; + + /* FIXME: what about filenames which violate + 8+3 constraints, like "config.h.in", or ".emacs"? */ + if (strpbrk (filename, "\"*+,;<=>?[\\]|") != NULL) + return filename; + + df = dos_filename; + + /* First, transform the name part. */ + for (i = 0; i < 8 && ! STOP_SET (*filename, MAP_DOT|MAP_NUL); ++i) + *df++ = tolower ((unsigned char)*filename++); + + /* Now skip to the next dot. */ + while (! STOP_SET (*filename, MAP_DOT|MAP_NUL)) + ++filename; + if (*filename != '\0') + { + *df++ = *filename++; + for (i = 0; i < 3 && ! STOP_SET (*filename, MAP_DOT|MAP_NUL); ++i) + *df++ = tolower ((unsigned char)*filename++); + } + + /* Look for more dots. */ + while (! STOP_SET (*filename, MAP_DOT|MAP_NUL)) + ++filename; + if (*filename == '.') + return filename; + *df = '\0'; + return dos_filename; +} +#endif /* __MSDOS__ */ #ifdef HAVE_CASE_INSENSITIVE_FS -static const char *downcase(const char *filename) { - static PATH_VAR(new_filename); +static const char * +downcase (const char *filename) +{ + static PATH_VAR (new_filename); char *df; - if (filename == 0) return 0; + if (filename == NULL) + return NULL; df = new_filename; - while (*filename != '\0') { - *df++ = tolower((unsigned char)*filename); - ++filename; - } + while (*filename != '\0') + { + *df++ = tolower ((unsigned char)*filename); + ++filename; + } - *df = 0; + *df = '\0'; return new_filename; } #endif /* HAVE_CASE_INSENSITIVE_FS */ +#ifdef VMS + +static char * +downcase_inplace(char *filename) +{ + char *name; + name = filename; + while (*name != '\0') + { + *name = tolower ((unsigned char)*name); + ++name; + } + return filename; +} + +#ifndef _USE_STD_STAT +/* VMS 8.2 fixed the VMS stat output to have unique st_dev and st_ino + when _USE_STD_STAT is used on the compile line. + + Prior to _USE_STD_STAT support, the st_dev is a pointer to thread + static memory containing the device of the last filename looked up. + + Todo: find out if the ino_t still needs to be faked on a directory. + */ + +/* Define this if the older VMS_INO_T is needed */ +#define VMS_INO_T 1 + +static int +vms_hash (const char *name) +{ + int h = 0; + + while (*name) + { + unsigned char uc = (unsigned char) *name; + int g; +#ifdef HAVE_CASE_INSENSITIVE_FS + h = (h << 4) + (isupper (uc) ? tolower (uc) : uc); +#else + h = (h << 4) + uc; +#endif + name++; + g = h & 0xf0000000; + if (g) + { + h = h ^ (g >> 24); + h = h ^ g; + } + } + return h; +} + +/* fake stat entry for a directory */ +static int +vmsstat_dir (const char *name, struct stat *st) +{ + char *s; + int h; + DIR *dir; + + dir = opendir (name); + if (dir == NULL) + return -1; + closedir (dir); + s = strchr (name, ':'); /* find device */ + if (s) + { + /* to keep the compiler happy we said "const char *name", now we cheat */ + *s++ = '\0'; + st->st_dev = (char *)vms_hash (name); + h = vms_hash (s); + *(s-1) = ':'; + } + else + { + st->st_dev = 0; + h = vms_hash (name); + } + + st->st_ino[0] = h & 0xff; + st->st_ino[1] = h & 0xff00; + st->st_ino[2] = h >> 16; + + return 0; +} + +# define stat(__path, __sbuf) vmsstat_dir (__path, __sbuf) + +#endif /* _USE_STD_STAT */ +#endif /* VMS */ + +/* Never have more than this many directories open at once. */ + +#define MAX_OPEN_DIRECTORIES 10 + +static unsigned int open_directories = 0; + /* Hash table of directories. */ #ifndef DIRECTORY_BUCKETS #define DIRECTORY_BUCKETS 199 #endif -struct directory_contents { - dev_t dev; /* Device and inode numbers of this dir. */ +struct directory_contents + { + dev_t dev; /* Device and inode numbers of this dir. */ #ifdef WINDOWS32 - /* Inode means nothing on WINDOWS32. Even file key information is - * unreliable because it is random per file open and undefined for remote - * filesystems. The most unique attribute I can come up with is the fully - * qualified name of the directory. Beware though, this is also - * unreliable. I'm open to suggestion on a better way to emulate inode. */ - char *path_key; - time_t ctime; - time_t mtime; /* controls check for stale directory cache */ - int fs_flags; /* FS_FAT, FS_NTFS, ... */ -#define FS_FAT 0x1 -#define FS_NTFS 0x2 -#define FS_UNKNOWN 0x4 + /* Inode means nothing on WINDOWS32. Even file key information is + * unreliable because it is random per file open and undefined for remote + * filesystems. The most unique attribute I can come up with is the fully + * qualified name of the directory. Beware though, this is also + * unreliable. I'm open to suggestion on a better way to emulate inode. */ + char *path_key; + time_t ctime; + time_t mtime; /* controls check for stale directory cache */ + int fs_flags; /* FS_FAT, FS_NTFS, ... */ +# define FS_FAT 0x1 +# define FS_NTFS 0x2 +# define FS_UNKNOWN 0x4 #else - ino_t ino; +# ifdef VMS_INO_T + ino_t ino[3]; +# else + ino_t ino; +# endif #endif /* WINDOWS32 */ - struct hash_table dirfiles; /* Files in this directory. */ - DIR *dirstream; /* Stream reading this directory. */ -}; + struct hash_table dirfiles; /* Files in this directory. */ + unsigned long counter; /* command_count value when last read. */ + DIR *dirstream; /* Stream reading this directory. */ + }; -static unsigned long directory_contents_hash_1(const void *key_0) { +static struct directory_contents * +clear_directory_contents (struct directory_contents *dc) +{ + dc->counter = 0; + if (dc->dirstream) + { + --open_directories; + closedir (dc->dirstream); + dc->dirstream = NULL; + } + if (dc->dirfiles.ht_vec != NULL) + hash_free (&dc->dirfiles, 1); + + return NULL; +} + +static unsigned long +directory_contents_hash_1 (const void *key_0) +{ const struct directory_contents *key = key_0; unsigned long hash; #ifdef WINDOWS32 hash = 0; - ISTRING_HASH_1(key->path_key, hash); - hash ^= ((unsigned int)key->dev << 4) ^ (unsigned int)key->ctime; + ISTRING_HASH_1 (key->path_key, hash); + hash ^= ((unsigned int) key->dev << 4) ^ (unsigned int) key->ctime; #else - hash = ((unsigned int)key->dev << 4) ^ (unsigned int)key->ino; +# ifdef VMS_INO_T + hash = (((unsigned int) key->dev << 4) + ^ ((unsigned int) key->ino[0] + + (unsigned int) key->ino[1] + + (unsigned int) key->ino[2])); +# else + hash = ((unsigned int) key->dev << 4) ^ (unsigned int) key->ino; +# endif #endif /* WINDOWS32 */ return hash; } -static unsigned long directory_contents_hash_2(const void *key_0) { +static unsigned long +directory_contents_hash_2 (const void *key_0) +{ const struct directory_contents *key = key_0; unsigned long hash; #ifdef WINDOWS32 hash = 0; - ISTRING_HASH_2(key->path_key, hash); - hash ^= ((unsigned int)key->dev << 4) ^ (unsigned int)~key->ctime; + ISTRING_HASH_2 (key->path_key, hash); + hash ^= ((unsigned int) key->dev << 4) ^ (unsigned int) ~key->ctime; #else - hash = ((unsigned int)key->dev << 4) ^ (unsigned int)~key->ino; +# ifdef VMS_INO_T + hash = (((unsigned int) key->dev << 4) + ^ ~((unsigned int) key->ino[0] + + (unsigned int) key->ino[1] + + (unsigned int) key->ino[2])); +# else + hash = ((unsigned int) key->dev << 4) ^ (unsigned int) ~key->ino; +# endif #endif /* WINDOWS32 */ return hash; @@ -141,21 +335,38 @@ static unsigned long directory_contents_hash_2(const void *key_0) { NOTE! This macro has side-effects! */ -#define MAKECMP(_x, _y) ((_x) < (_y) ? -1 : ((_x) == (_y) ? 0 : 1)) +#define MAKECMP(_x,_y) ((_x)<(_y)?-1:((_x)==(_y)?0:1)) -static int directory_contents_hash_cmp(const void *xv, const void *yv) { +static int +directory_contents_hash_cmp (const void *xv, const void *yv) +{ const struct directory_contents *x = xv; const struct directory_contents *y = yv; int result; #ifdef WINDOWS32 - ISTRING_COMPARE(x->path_key, y->path_key, result); - if (result) return result; + ISTRING_COMPARE (x->path_key, y->path_key, result); + if (result) + return result; result = MAKECMP(x->ctime, y->ctime); - if (result) return result; + if (result) + return result; #else +# ifdef VMS_INO_T + result = MAKECMP(x->ino[0], y->ino[0]); + if (result) + return result; + result = MAKECMP(x->ino[1], y->ino[1]); + if (result) + return result; + result = MAKECMP(x->ino[2], y->ino[2]); + if (result) + return result; +# else result = MAKECMP(x->ino, y->ino); - if (result) return result; + if (result) + return result; +# endif #endif /* WINDOWS32 */ return MAKECMP(x->dev, y->dev); @@ -164,324 +375,412 @@ static int directory_contents_hash_cmp(const void *xv, const void *yv) { /* Table of directory contents hashed by device and inode number. */ static struct hash_table directory_contents; -struct directory { - const char *name; /* Name of the directory. */ +struct directory + { + const char *name; /* Name of the directory. */ + unsigned long counter; /* command_count value when last read. + Used for non-existent directories. */ - /* The directory's contents. This data may be shared by several - entries in the hash table, which refer to the same directory - (identified uniquely by 'dev' and 'ino') under different names. */ - struct directory_contents *contents; -}; + /* The directory's contents. This data may be shared by several + entries in the hash table, which refer to the same directory + (identified uniquely by 'dev' and 'ino') under different names. */ + struct directory_contents *contents; + }; -static unsigned long directory_hash_1(const void *key) { - return_ISTRING_HASH_1(((const struct directory *)key)->name); +static unsigned long +directory_hash_1 (const void *key) +{ + return_ISTRING_HASH_1 (((const struct directory *) key)->name); } -static unsigned long directory_hash_2(const void *key) { - return_ISTRING_HASH_2(((const struct directory *)key)->name); +static unsigned long +directory_hash_2 (const void *key) +{ + return_ISTRING_HASH_2 (((const struct directory *) key)->name); } -static int directory_hash_cmp(const void *x, const void *y) { - return_ISTRING_COMPARE(((const struct directory *)x)->name, - ((const struct directory *)y)->name); +static int +directory_hash_cmp (const void *x, const void *y) +{ + return_ISTRING_COMPARE (((const struct directory *) x)->name, + ((const struct directory *) y)->name); } /* Table of directories hashed by name. */ static struct hash_table directories; -/* Never have more than this many directories open at once. */ - -#define MAX_OPEN_DIRECTORIES 10 - -static unsigned int open_directories = 0; /* Hash table of files in each directory. */ -struct dirfile { - const char *name; /* Name of the file. */ - size_t length; - short impossible; /* This file is impossible. */ - unsigned char type; -}; +struct dirfile + { + const char *name; /* Name of the file. */ + size_t length; + short impossible; /* This file is impossible. */ + unsigned char type; + }; -static unsigned long dirfile_hash_1(const void *key) { - return_ISTRING_HASH_1(((struct dirfile const *)key)->name); +static unsigned long +dirfile_hash_1 (const void *key) +{ + return_ISTRING_HASH_1 (((struct dirfile const *) key)->name); } -static unsigned long dirfile_hash_2(const void *key) { - return_ISTRING_HASH_2(((struct dirfile const *)key)->name); +static unsigned long +dirfile_hash_2 (const void *key) +{ + return_ISTRING_HASH_2 (((struct dirfile const *) key)->name); } -static int dirfile_hash_cmp(const void *xv, const void *yv) { +static int +dirfile_hash_cmp (const void *xv, const void *yv) +{ const struct dirfile *x = xv; const struct dirfile *y = yv; - int result = (int)(x->length - y->length); - if (result) return result; - return_ISTRING_COMPARE(x->name, y->name); + int result = (int) (x->length - y->length); + if (result) + return result; + return_ISTRING_COMPARE (x->name, y->name); } #ifndef DIRFILE_BUCKETS #define DIRFILE_BUCKETS 107 #endif - -static int dir_contents_file_exists_p(struct directory_contents *dir, - const char *filename); -static struct directory *find_directory(const char *name); + +static int dir_contents_file_exists_p (struct directory *dir, + const char *filename); +static struct directory *find_directory (const char *name); /* Find the directory named NAME and return its 'struct directory'. */ -static struct directory *find_directory(const char *name) { +static struct directory * +find_directory (const char *name) +{ struct directory *dir; struct directory **dir_slot; struct directory dir_key; + struct directory_contents *dc; + struct directory_contents **dc_slot; + struct directory_contents dc_key; + + struct stat st; + int r; +#ifdef WINDOWS32 + char *w32_path; +#endif dir_key.name = name; - dir_slot = (struct directory **)hash_find_slot(&directories, &dir_key); + dir_slot = (struct directory **) hash_find_slot (&directories, &dir_key); dir = *dir_slot; - if (HASH_VACANT(dir)) { - /* The directory was not found. Create a new entry for it. */ - const char *p = name + strlen(name); - struct stat st; - int r; + if (!HASH_VACANT (dir)) + { + unsigned long ctr = dir->contents ? dir->contents->counter : dir->counter; - dir = xmalloc(sizeof(struct directory)); + /* No commands have run since we parsed this directory so it's good. */ + if (ctr == command_count) + return dir; + + DB (DB_VERBOSE, ("Directory %s cache invalidated (count %lu != command %lu)\n", + name, ctr, command_count)); + + if (dir->contents) + clear_directory_contents (dir->contents); + } + else + { + /* The directory was not found. Create a new entry for it. */ + size_t len = strlen (name); + + dir = xmalloc (sizeof (struct directory)); #if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) - /* Todo: Why is this only needed on VMS? */ - { - char *lname = downcase_inplace(xstrdup(name)); - dir->name = strcache_add_len(lname, p - name); - free(lname); - } + /* Todo: Why is this only needed on VMS? */ + { + char *lname = downcase_inplace (xstrdup (name)); + dir->name = strcache_add_len (lname, len); + free (lname); + } #else - dir->name = strcache_add_len(name, p - name); + dir->name = strcache_add_len (name, len); #endif - hash_insert_at(&directories, dir, dir_slot); - /* The directory is not in the name hash table. - Find its device and inode numbers, and look it up by them. */ + hash_insert_at (&directories, dir, dir_slot); + } + dir->contents = NULL; + dir->counter = command_count; + + /* See if the directory exists. */ #if defined(WINDOWS32) + { + char tem[MAX_PATH+1], *tstart, *tend; + size_t len = strlen (name); + + /* Remove any trailing slashes. Windows32 stat fails even on + valid directories if they end in a slash. */ + memcpy (tem, name, len + 1); + tstart = tem; + if (tstart[1] == ':') + tstart += 2; + for (tend = tem + (len - 1); tend > tstart && ISDIRSEP (*tend); tend--) + *tend = '\0'; + + r = stat (tem, &st); + } +#else + EINTRLOOP (r, stat (name, &st)); +#endif + + if (r < 0) + /* Couldn't stat the directory; nothing else to do. */ + return dir; + + /* Search the contents hash table; device and inode are the key. */ + + memset (&dc_key, '\0', sizeof (dc_key)); + dc_key.dev = st.st_dev; +#ifdef WINDOWS32 + dc_key.path_key = w32_path = w32ify (name, 1); + dc_key.ctime = st.st_ctime; +#else +# ifdef VMS_INO_T + dc_key.ino[0] = st.st_ino[0]; + dc_key.ino[1] = st.st_ino[1]; + dc_key.ino[2] = st.st_ino[2]; +# else + dc_key.ino = st.st_ino; +# endif +#endif + dc_slot = (struct directory_contents **) hash_find_slot (&directory_contents, &dc_key); + dc = *dc_slot; + + if (HASH_VACANT (dc)) { - char tem[MAXPATHLEN], *tstart, *tend; - - /* Remove any trailing slashes. Windows32 stat fails even on - valid directories if they end in a slash. */ - memcpy(tem, name, p - name + 1); - tstart = tem; - if (tstart[1] == ':') tstart += 2; - for (tend = tem + (p - name - 1); - tend > tstart && (*tend == '/' || *tend == '\\'); tend--) - *tend = '\0'; - - r = stat(tem, &st); - } -#else - EINTRLOOP(r, stat(name, &st)); + /* Nope; this really is a directory we haven't seen before. */ +#ifdef WINDOWS32 + char fs_label[BUFSIZ]; + char fs_type[BUFSIZ]; + unsigned long fs_serno; + unsigned long fs_flags; + unsigned long fs_len; #endif - - if (r < 0) { - /* Couldn't stat the directory. Mark this by - setting the 'contents' member to a nil pointer. */ - dir->contents = 0; - } else { - /* Search the contents hash table; device and inode are the key. */ + /* Enter it in the contents hash table. */ + dc = xcalloc (sizeof (struct directory_contents)); + *dc = dc_key; #ifdef WINDOWS32 - char *w32_path; -#endif - struct directory_contents *dc; - struct directory_contents **dc_slot; - struct directory_contents dc_key; + dc->path_key = xstrdup (w32_path); + dc->mtime = st.st_mtime; - dc_key.dev = st.st_dev; -#ifdef WINDOWS32 - dc_key.path_key = w32_path = w32ify(name, 1); - dc_key.ctime = st.st_ctime; -#else - dc_key.ino = st.st_ino; -#endif - dc_slot = (struct directory_contents **)hash_find_slot( - &directory_contents, &dc_key); - dc = *dc_slot; - - if (HASH_VACANT(dc)) { - /* Nope; this really is a directory we haven't seen before. */ -#ifdef WINDOWS32 - char fs_label[BUFSIZ]; - char fs_type[BUFSIZ]; - unsigned long fs_serno; - unsigned long fs_flags; - unsigned long fs_len; -#endif - dc = (struct directory_contents *)xmalloc( - sizeof(struct directory_contents)); - - /* Enter it in the contents hash table. */ - dc->dev = st.st_dev; -#ifdef WINDOWS32 - dc->path_key = xstrdup(w32_path); - dc->ctime = st.st_ctime; - dc->mtime = st.st_mtime; - - /* NTFS is the only WINDOWS32 filesystem that bumps mtime on a - directory when files are added/deleted from a directory. */ - w32_path[3] = '\0'; - if (GetVolumeInformation(w32_path, fs_label, sizeof(fs_label), - &fs_serno, &fs_len, &fs_flags, fs_type, - sizeof(fs_type)) == FALSE) - dc->fs_flags = FS_UNKNOWN; - else if (!strcmp(fs_type, "FAT")) - dc->fs_flags = FS_FAT; - else if (!strcmp(fs_type, "NTFS")) - dc->fs_flags = FS_NTFS; - else - dc->fs_flags = FS_UNKNOWN; -#else - dc->ino = st.st_ino; + /* NTFS is the only WINDOWS32 filesystem that bumps mtime on a + directory when files are added/deleted from a directory. */ + w32_path[3] = '\0'; + if (GetVolumeInformation (w32_path, fs_label, sizeof (fs_label), + &fs_serno, &fs_len, &fs_flags, fs_type, + sizeof (fs_type)) == FALSE) + dc->fs_flags = FS_UNKNOWN; + else if (!strcmp (fs_type, "FAT")) + dc->fs_flags = FS_FAT; + else if (!strcmp (fs_type, "NTFS")) + dc->fs_flags = FS_NTFS; + else + dc->fs_flags = FS_UNKNOWN; #endif /* WINDOWS32 */ - hash_insert_at(&directory_contents, dc, dc_slot); - ENULLLOOP(dc->dirstream, opendir(name)); - if (dc->dirstream == 0) - /* Couldn't open the directory. Mark this by setting the - 'files' member to a nil pointer. */ - dc->dirfiles.ht_vec = 0; - else { - hash_init(&dc->dirfiles, DIRFILE_BUCKETS, dirfile_hash_1, - dirfile_hash_2, dirfile_hash_cmp); + + hash_insert_at (&directory_contents, dc, dc_slot); + } + + /* Point the name-hashed entry for DIR at its contents data. */ + dir->contents = dc; + + /* If the contents have changed, we need to reseed. */ + if (dc->counter != command_count) + { + if (dc->counter) + clear_directory_contents (dc); + + dc->counter = command_count; + + ENULLLOOP (dc->dirstream, opendir (name)); + if (dc->dirstream == NULL) + /* Couldn't open the directory: mark this by setting files to NULL. */ + dc->dirfiles.ht_vec = NULL; + else + { + hash_init (&dc->dirfiles, DIRFILE_BUCKETS, + dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp); /* Keep track of how many directories are open. */ ++open_directories; if (open_directories == MAX_OPEN_DIRECTORIES) /* We have too many directories open already. Read the entire directory and then close it. */ - dir_contents_file_exists_p(dc, 0); + dir_contents_file_exists_p (dir, NULL); } - } - - /* Point the name-hashed entry for DIR at its contents data. */ - dir->contents = dc; } - } return dir; } - + /* Return 1 if the name FILENAME is entered in DIR's hash table. FILENAME must contain no slashes. */ -static int dir_contents_file_exists_p(struct directory_contents *dir, - const char *filename) { +static int +dir_contents_file_exists_p (struct directory *dir, + const char *filename) +{ struct dirfile *df; struct dirent *d; + struct directory_contents *dc = dir->contents; #ifdef WINDOWS32 struct stat st; int rehash = 0; #endif - if (dir == 0 || dir->dirfiles.ht_vec == 0) + if (dc == NULL || dc->dirfiles.ht_vec == NULL) /* The directory could not be stat'd or opened. */ return 0; -#ifdef HAVE_CASE_INSENSITIVE_FS - filename = downcase(filename); +#ifdef __MSDOS__ + filename = dosify (filename); #endif - if (filename != 0) { - struct dirfile dirfile_key; +#ifdef HAVE_CASE_INSENSITIVE_FS + filename = downcase (filename); +#endif - if (*filename == '\0') { - /* Checking if the directory exists. */ - return 1; +#ifdef __EMX__ + if (filename != NULL) + { + size_t len = strlen (filename); + char *fname = alloca (len + 1); + memcpy (fname, filename, len + 1); + _fnlwr (fname); /* lower case for FAT drives */ + filename = fname; + } +#endif + if (filename != NULL) + { + struct dirfile dirfile_key; + + if (*filename == '\0') + { + /* Checking if the directory exists. */ + return 1; + } + dirfile_key.name = filename; + dirfile_key.length = strlen (filename); + df = hash_find_item (&dc->dirfiles, &dirfile_key); + if (df) + return !df->impossible; } - dirfile_key.name = filename; - dirfile_key.length = strlen(filename); - df = hash_find_item(&dir->dirfiles, &dirfile_key); - if (df) return !df->impossible; - } /* The file was not found in the hashed list. Try to read the directory further. */ - if (dir->dirstream == 0) { + if (dc->dirstream == NULL) + { #ifdef WINDOWS32 - /* - * Check to see if directory has changed since last read. FAT - * filesystems force a rehash always as mtime does not change - * on directories (ugh!). - */ - if (dir->path_key) { - if ((dir->fs_flags & FS_FAT) != 0) { - dir->mtime = time((time_t *)0); - rehash = 1; - } else if (stat(dir->path_key, &st) == 0 && st.st_mtime > dir->mtime) { - /* reset date stamp to show most recent re-process. */ - dir->mtime = st.st_mtime; - rehash = 1; - } + /* + * Check to see if directory has changed since last read. FAT + * filesystems force a rehash always as mtime does not change + * on directories (ugh!). + */ + if (dc->path_key) + { + if ((dc->fs_flags & FS_FAT) != 0) + { + dc->mtime = time (NULL); + rehash = 1; + } + else if (stat (dc->path_key, &st) == 0 && st.st_mtime > dc->mtime) + { + /* reset date stamp to show most recent re-process. */ + dc->mtime = st.st_mtime; + rehash = 1; + } - /* If it has been already read in, all done. */ - if (!rehash) return 0; + /* If it has been already read in, all done. */ + if (!rehash) + return 0; - /* make sure directory can still be opened; if not return. */ - dir->dirstream = opendir(dir->path_key); - if (!dir->dirstream) return 0; - } else + /* make sure directory can still be opened; if not return. */ + dc->dirstream = opendir (dc->path_key); + if (!dc->dirstream) + return 0; + } + else #endif - /* The directory has been all read in. */ - return 0; - } - - while (1) { - /* Enter the file in the hash table. */ - size_t len; - struct dirfile dirfile_key; - struct dirfile **dirfile_slot; - - ENULLLOOP(d, readdir(dir->dirstream)); - if (d == 0) { - if (errno) pfatal_with_name("INTERNAL: readdir"); - break; + /* The directory has been all read in. */ + return 0; } - if (!REAL_DIR_ENTRY(d)) continue; - - len = NAMLEN(d); - dirfile_key.name = d->d_name; - dirfile_key.length = len; - dirfile_slot = - (struct dirfile **)hash_find_slot(&dir->dirfiles, &dirfile_key); -#ifdef WINDOWS32 - /* - * If re-reading a directory, don't cache files that have - * already been discovered. - */ - if (!rehash || HASH_VACANT(*dirfile_slot)) -#endif + while (1) { - df = xmalloc(sizeof(struct dirfile)); + /* Enter the file in the hash table. */ + size_t len; + struct dirfile dirfile_key; + struct dirfile **dirfile_slot; + + ENULLLOOP (d, readdir (dc->dirstream)); + if (d == NULL) + { + if (errno) + OSS (fatal, NILF, "readdir %s: %s", dir->name, strerror (errno)); + break; + } + +#if defined(VMS) && defined(HAVE_DIRENT_H) + /* In VMS we get file versions too, which have to be stripped off. + Some versions of VMS return versions on Unix files even when + the feature option to strip them is set. */ + { + char *p = strrchr (d->d_name, ';'); + if (p) + *p = '\0'; + } +#endif + if (!REAL_DIR_ENTRY (d)) + continue; + + len = NAMLEN (d); + dirfile_key.name = d->d_name; + dirfile_key.length = len; + dirfile_slot = (struct dirfile **) hash_find_slot (&dc->dirfiles, &dirfile_key); +#ifdef WINDOWS32 + /* + * If re-reading a directory, don't cache files that have + * already been discovered. + */ + if (! rehash || HASH_VACANT (*dirfile_slot)) +#endif + { + df = xmalloc (sizeof (struct dirfile)); #if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) - /* TODO: Why is this only needed on VMS? */ - df->name = strcache_add_len(downcase_inplace(d->d_name), len); + /* TODO: Why is this only needed on VMS? */ + df->name = strcache_add_len (downcase_inplace (d->d_name), len); #else - df->name = strcache_add_len(d->d_name, len); + df->name = strcache_add_len (d->d_name, len); #endif #ifdef HAVE_STRUCT_DIRENT_D_TYPE - df->type = d->d_type; + df->type = d->d_type; #endif - df->length = len; - df->impossible = 0; - hash_insert_at(&dir->dirfiles, df, dirfile_slot); + df->length = len; + df->impossible = 0; + hash_insert_at (&dc->dirfiles, df, dirfile_slot); + } + /* Check if the name matches the one we're searching for. */ + if (filename != NULL && patheq (d->d_name, filename)) + return 1; } - /* Check if the name matches the one we're searching for. */ - if (filename != 0 && patheq(d->d_name, filename)) return 1; - } /* If the directory has been completely read in, close the stream and reset the pointer to nil. */ - if (d == 0) { - --open_directories; - closedir(dir->dirstream); - dir->dirstream = 0; - } + if (d == NULL) + { + --open_directories; + closedir (dc->dirstream); + dc->dirstream = NULL; + } + return 0; } @@ -489,335 +788,489 @@ static int dir_contents_file_exists_p(struct directory_contents *dir, is entered in the dir hash table. FILENAME must contain no slashes. */ -int dir_file_exists_p(const char *dirname, const char *filename) { - return dir_contents_file_exists_p(find_directory(dirname)->contents, - filename); +int +dir_file_exists_p (const char *dirname, const char *filename) +{ +#ifdef VMS + if (filename && dirname && strpbrk (dirname, ":<[") != NULL) + filename = vmsify (filename, 0); +#endif + return dir_contents_file_exists_p (find_directory (dirname), + filename); } - + /* Return 1 if the file named NAME exists. */ -int file_exists_p(const char *name) { +int +file_exists_p (const char *name) +{ const char *dirend; const char *dirname; const char *slash; #ifndef NO_ARCHIVES - if (ar_name(name)) return ar_member_date(name) != (time_t)-1; + if (ar_name (name)) + return ar_member_date (name) != (time_t) -1; #endif - dirend = strrchr(name, '/'); + dirend = strrchr (name, '/'); +#ifdef VMS + if (dirend == NULL) + { + dirend = strrchr (name, ']'); + dirend == NULL ? dirend : dirend++; + } + if (dirend == NULL) + { + dirend = strrchr (name, '>'); + dirend == NULL ? dirend : dirend++; + } + if (dirend == NULL) + { + dirend = strrchr (name, ':'); + dirend == NULL ? dirend : dirend++; + } +#endif /* VMS */ #ifdef HAVE_DOS_PATHS /* Forward and backslashes might be mixed. We need the rightmost one. */ { - const char *bslash = strrchr(name, '\\'); - if (!dirend || bslash > dirend) dirend = bslash; + const char *bslash = strrchr (name, '\\'); + if (!dirend || bslash > dirend) + dirend = bslash; /* The case of "d:file". */ - if (!dirend && name[0] && name[1] == ':') dirend = name + 1; + if (!dirend && name[0] && name[1] == ':') + dirend = name + 1; } #endif /* HAVE_DOS_PATHS */ - if (dirend == 0) return dir_file_exists_p(".", name); + if (dirend == NULL) +#ifndef _AMIGA + return dir_file_exists_p (".", name); +#else /* !AMIGA */ + return dir_file_exists_p ("", name); +#endif /* AMIGA */ slash = dirend; if (dirend == name) dirname = "/"; - else { - char *p; + else + { + char *p; #ifdef HAVE_DOS_PATHS - /* d:/ and d: are *very* different... */ - if (dirend < name + 3 && name[1] == ':' && - (*dirend == '/' || *dirend == '\\' || *dirend == ':')) - dirend++; + /* d:/ and d: are *very* different... */ + if (dirend < name + 3 && name[1] == ':' && + (ISDIRSEP (*dirend) || *dirend == ':')) + dirend++; #endif - p = alloca(dirend - name + 1); - memcpy(p, name, dirend - name); - p[dirend - name] = '\0'; - dirname = p; - } + p = alloca (dirend - name + 1); + memcpy (p, name, dirend - name); + p[dirend - name] = '\0'; + dirname = p; + } +#ifdef VMS + if (*slash == '/') + slash++; +#else slash++; - return dir_file_exists_p(dirname, slash); +#endif + return dir_file_exists_p (dirname, slash); } - + /* Mark FILENAME as 'impossible' for 'file_impossible_p'. This means an attempt has been made to search for FILENAME as an intermediate file, and it has failed. */ -void file_impossible(const char *filename) { +void +file_impossible (const char *filename) +{ const char *dirend; const char *p = filename; struct directory *dir; struct dirfile *new; - dirend = strrchr(p, '/'); + dirend = strrchr (p, '/'); +#ifdef VMS + if (dirend == NULL) + { + dirend = strrchr (p, ']'); + dirend == NULL ? dirend : dirend++; + } + if (dirend == NULL) + { + dirend = strrchr (p, '>'); + dirend == NULL ? dirend : dirend++; + } + if (dirend == NULL) + { + dirend = strrchr (p, ':'); + dirend == NULL ? dirend : dirend++; + } +#endif #ifdef HAVE_DOS_PATHS /* Forward and backslashes might be mixed. We need the rightmost one. */ { - const char *bslash = strrchr(p, '\\'); - if (!dirend || bslash > dirend) dirend = bslash; + const char *bslash = strrchr (p, '\\'); + if (!dirend || bslash > dirend) + dirend = bslash; /* The case of "d:file". */ - if (!dirend && p[0] && p[1] == ':') dirend = p + 1; + if (!dirend && p[0] && p[1] == ':') + dirend = p + 1; } #endif /* HAVE_DOS_PATHS */ - if (dirend == 0) - dir = find_directory("."); - else { - const char *dirname; - const char *slash = dirend; - if (dirend == p) - dirname = "/"; - else { - char *cp; + if (dirend == NULL) +#ifdef _AMIGA + dir = find_directory (""); +#else /* !AMIGA */ + dir = find_directory ("."); +#endif /* AMIGA */ + else + { + const char *dirname; + const char *slash = dirend; + if (dirend == p) + dirname = "/"; + else + { + char *cp; #ifdef HAVE_DOS_PATHS - /* d:/ and d: are *very* different... */ - if (dirend < p + 3 && p[1] == ':' && - (*dirend == '/' || *dirend == '\\' || *dirend == ':')) - dirend++; + /* d:/ and d: are *very* different... */ + if (dirend < p + 3 && p[1] == ':' && + (ISDIRSEP (*dirend) || *dirend == ':')) + dirend++; +#endif + cp = alloca (dirend - p + 1); + memcpy (cp, p, dirend - p); + cp[dirend - p] = '\0'; + dirname = cp; + } + dir = find_directory (dirname); +#ifdef VMS + if (*slash == '/') + filename = p = slash + 1; + else + filename = p = slash; +#else + filename = p = slash + 1; #endif - cp = alloca(dirend - p + 1); - memcpy(cp, p, dirend - p); - cp[dirend - p] = '\0'; - dirname = cp; } - dir = find_directory(dirname); - filename = p = slash + 1; - } - if (dir->contents == 0) + if (dir->contents == NULL) /* The directory could not be stat'd. We allocate a contents structure for it, but leave it out of the contents hash table. */ - dir->contents = xcalloc(1, sizeof(struct directory_contents)); + dir->contents = xcalloc (sizeof (struct directory_contents)); - if (dir->contents->dirfiles.ht_vec == 0) { - hash_init(&dir->contents->dirfiles, DIRFILE_BUCKETS, dirfile_hash_1, - dirfile_hash_2, dirfile_hash_cmp); - } + if (dir->contents->dirfiles.ht_vec == NULL) + hash_init (&dir->contents->dirfiles, DIRFILE_BUCKETS, + dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp); /* Make a new entry and put it in the table. */ - new = xmalloc(sizeof(struct dirfile)); - new->length = strlen(filename); + new = xmalloc (sizeof (struct dirfile)); + new->length = strlen (filename); #if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) /* todo: Why is this only needed on VMS? */ - new->name = strcache_add_len(downcase(filename), new->length); + new->name = strcache_add_len (downcase (filename), new->length); #else - new->name = strcache_add_len(filename, new->length); + new->name = strcache_add_len (filename, new->length); #endif new->impossible = 1; - hash_insert(&dir->contents->dirfiles, new); + hash_insert (&dir->contents->dirfiles, new); } - + /* Return nonzero if FILENAME has been marked impossible. */ -int file_impossible_p(const char *filename) { +int +file_impossible_p (const char *filename) +{ const char *dirend; struct directory_contents *dir; struct dirfile *dirfile; struct dirfile dirfile_key; +#ifdef VMS + int want_vmsify = 0; +#endif - dirend = strrchr(filename, '/'); + dirend = strrchr (filename, '/'); +#ifdef VMS + if (dirend == NULL) + { + want_vmsify = (strpbrk (filename, "]>:^") != NULL); + dirend = strrchr (filename, ']'); + } + if (dirend == NULL && want_vmsify) + dirend = strrchr (filename, '>'); + if (dirend == NULL && want_vmsify) + dirend = strrchr (filename, ':'); +#endif #ifdef HAVE_DOS_PATHS /* Forward and backslashes might be mixed. We need the rightmost one. */ { - const char *bslash = strrchr(filename, '\\'); - if (!dirend || bslash > dirend) dirend = bslash; + const char *bslash = strrchr (filename, '\\'); + if (!dirend || bslash > dirend) + dirend = bslash; /* The case of "d:file". */ - if (!dirend && filename[0] && filename[1] == ':') dirend = filename + 1; + if (!dirend && filename[0] && filename[1] == ':') + dirend = filename + 1; } #endif /* HAVE_DOS_PATHS */ - if (dirend == 0) - dir = find_directory(".")->contents; - else { - const char *dirname; - const char *slash = dirend; - if (dirend == filename) - dirname = "/"; - else { - char *cp; + if (dirend == NULL) +#ifdef _AMIGA + dir = find_directory ("")->contents; +#else /* !AMIGA */ + dir = find_directory (".")->contents; +#endif /* AMIGA */ + else + { + const char *dirname; + const char *slash = dirend; + if (dirend == filename) + dirname = "/"; + else + { + char *cp; #ifdef HAVE_DOS_PATHS - /* d:/ and d: are *very* different... */ - if (dirend < filename + 3 && filename[1] == ':' && - (*dirend == '/' || *dirend == '\\' || *dirend == ':')) - dirend++; + /* d:/ and d: are *very* different... */ + if (dirend < filename + 3 && filename[1] == ':' && + (ISDIRSEP (*dirend) || *dirend == ':')) + dirend++; +#endif + cp = alloca (dirend - filename + 1); + memcpy (cp, filename, dirend - filename); + cp[dirend - filename] = '\0'; + dirname = cp; + } + dir = find_directory (dirname)->contents; +#ifdef VMS + if (*slash == '/') + filename = slash + 1; + else + filename = slash; +#else + filename = slash + 1; #endif - cp = alloca(dirend - filename + 1); - memcpy(cp, filename, dirend - filename); - cp[dirend - filename] = '\0'; - dirname = cp; } - dir = find_directory(dirname)->contents; - filename = slash + 1; - } - if (dir == 0 || dir->dirfiles.ht_vec == 0) + if (dir == NULL || dir->dirfiles.ht_vec == NULL) /* There are no files entered for this directory. */ return 0; +#ifdef __MSDOS__ + filename = dosify (filename); +#endif #ifdef HAVE_CASE_INSENSITIVE_FS - filename = downcase(filename); + filename = downcase (filename); +#endif +#ifdef VMS + if (want_vmsify) + filename = vmsify (filename, 1); #endif dirfile_key.name = filename; - dirfile_key.length = strlen(filename); - dirfile = hash_find_item(&dir->dirfiles, &dirfile_key); - if (dirfile) return dirfile->impossible; + dirfile_key.length = strlen (filename); + dirfile = hash_find_item (&dir->dirfiles, &dirfile_key); + if (dirfile) + return dirfile->impossible; return 0; } - + /* Return the already allocated name in the directory hash table that matches DIR. */ -const char *dir_name(const char *dir) { - return find_directory(dir)->name; +const char * +dir_name (const char *dir) +{ + return find_directory (dir)->name; } - + /* Print the data base of directories. */ -void print_dir_data_base(void) { +void +print_dir_data_base (void) +{ unsigned int files; unsigned int impossible; struct directory **dir_slot; struct directory **dir_end; +#ifdef WINDOWS32 + char buf[INTSTR_LENGTH + 1]; +#endif - puts(_("\n# Directories\n")); + puts (_("\n# Directories\n")); files = impossible = 0; - dir_slot = (struct directory **)directories.ht_vec; + dir_slot = (struct directory **) directories.ht_vec; dir_end = dir_slot + directories.ht_size; - for (; dir_slot < dir_end; dir_slot++) { - struct directory *dir = *dir_slot; - if (!HASH_VACANT(dir)) { - if (dir->contents == 0) - printf(_("# %s: could not be stat'd.\n"), dir->name); - else if (dir->contents->dirfiles.ht_vec == 0) { - printf(_("# %s (device %ld, inode %ld): could not be opened.\n"), - dir->name, (long int)dir->contents->dev, - (long int)dir->contents->ino); - } else { - unsigned int f = 0; - unsigned int im = 0; - struct dirfile **files_slot; - struct dirfile **files_end; + for ( ; dir_slot < dir_end; dir_slot++) + { + struct directory *dir = *dir_slot; + if (! HASH_VACANT (dir)) + { + if (dir->contents == NULL) + printf (_("# %s: could not be stat'd.\n"), dir->name); + else if (dir->contents->dirfiles.ht_vec == NULL) +#ifdef WINDOWS32 + printf (_("# %s (key %s, mtime %s): could not be opened.\n"), + dir->name, dir->contents->path_key, + make_ulltoa ((unsigned long long)dir->contents->mtime, buf)); +#elif defined(VMS_INO_T) + printf (_("# %s (device %d, inode [%d,%d,%d]): could not be opened.\n"), + dir->name, dir->contents->dev, + dir->contents->ino[0], dir->contents->ino[1], + dir->contents->ino[2]); +#else + printf (_("# %s (device %ld, inode %ld): could not be opened.\n"), + dir->name, (long) dir->contents->dev, (long) dir->contents->ino); +#endif + else + { + unsigned int f = 0; + unsigned int im = 0; + struct dirfile **files_slot; + struct dirfile **files_end; - files_slot = (struct dirfile **)dir->contents->dirfiles.ht_vec; - files_end = files_slot + dir->contents->dirfiles.ht_size; - for (; files_slot < files_end; files_slot++) { - struct dirfile *df = *files_slot; - if (!HASH_VACANT(df)) { - if (df->impossible) - ++im; - else - ++f; - } + files_slot = (struct dirfile **) dir->contents->dirfiles.ht_vec; + files_end = files_slot + dir->contents->dirfiles.ht_size; + for ( ; files_slot < files_end; files_slot++) + { + struct dirfile *df = *files_slot; + if (! HASH_VACANT (df)) + { + if (df->impossible) + ++im; + else + ++f; + } + } +#ifdef WINDOWS32 + printf (_("# %s (key %s, mtime %s): "), + dir->name, dir->contents->path_key, + make_ulltoa ((unsigned long long)dir->contents->mtime, buf)); +#elif defined(VMS_INO_T) + printf (_("# %s (device %d, inode [%d,%d,%d]): "), + dir->name, dir->contents->dev, + dir->contents->ino[0], dir->contents->ino[1], + dir->contents->ino[2]); +#else + printf (_("# %s (device %ld, inode %ld): "), dir->name, + (long)dir->contents->dev, (long)dir->contents->ino); +#endif + if (f == 0) + fputs (_("No"), stdout); + else + printf ("%u", f); + fputs (_(" files, "), stdout); + if (im == 0) + fputs (_("no"), stdout); + else + printf ("%u", im); + fputs (_(" impossibilities"), stdout); + if (dir->contents->dirstream == NULL) + puts ("."); + else + puts (_(" so far.")); + files += f; + impossible += im; + } } - printf(_("# %s (device %ld, inode %ld): "), dir->name, - (long)dir->contents->dev, (long)dir->contents->ino); - if (f == 0) - fputs(_("No"), stdout); - else - printf("%u", f); - fputs(_(" files, "), stdout); - if (im == 0) - fputs(_("no"), stdout); - else - printf("%u", im); - fputs(_(" impossibilities"), stdout); - if (dir->contents->dirstream == 0) - puts("."); - else - puts(_(" so far.")); - files += f; - impossible += im; - } } - } - fputs("\n# ", stdout); + fputs ("\n# ", stdout); if (files == 0) - fputs(_("No"), stdout); + fputs (_("No"), stdout); else - printf("%u", files); - fputs(_(" files, "), stdout); + printf ("%u", files); + fputs (_(" files, "), stdout); if (impossible == 0) - fputs(_("no"), stdout); + fputs (_("no"), stdout); else - printf("%u", impossible); - printf(_(" impossibilities in %lu directories.\n"), directories.ht_fill); + printf ("%u", impossible); + printf (_(" impossibilities in %lu directories.\n"), directories.ht_fill); } - + /* Hooks for globbing. */ /* Structure describing state of iterating through a directory hash table. */ -struct dirstream { - struct directory_contents *contents; /* The directory being read. */ - struct dirfile **dirfile_slot; /* Current slot in table. */ -}; +struct dirstream + { + struct directory_contents *contents; /* The directory being read. */ + struct dirfile **dirfile_slot; /* Current slot in table. */ + }; /* Forward declarations. */ -static __ptr_t open_dirstream(const char *); -static struct dirent *read_dirstream(__ptr_t); +static void *open_dirstream (const char *); +static struct dirent *read_dirstream (void *); -static __ptr_t open_dirstream(const char *directory) { +static void * +open_dirstream (const char *directory) +{ struct dirstream *new; - struct directory *dir = find_directory(directory); + struct directory *dir = find_directory (directory); - if (dir->contents == 0 || dir->contents->dirfiles.ht_vec == 0) + if (dir->contents == NULL || dir->contents->dirfiles.ht_vec == NULL) /* DIR->contents is nil if the directory could not be stat'd. DIR->contents->dirfiles is nil if it could not be opened. */ - return 0; + return NULL; /* Read all the contents of the directory now. There is no benefit in being lazy, since glob will want to see every file anyway. */ - dir_contents_file_exists_p(dir->contents, 0); + dir_contents_file_exists_p (dir, NULL); - new = xmalloc(sizeof(struct dirstream)); + new = xmalloc (sizeof (struct dirstream)); new->contents = dir->contents; - new->dirfile_slot = (struct dirfile **)new->contents->dirfiles.ht_vec; + new->dirfile_slot = (struct dirfile **) new->contents->dirfiles.ht_vec; - return (__ptr_t) new; + return new; } -static struct dirent *read_dirstream(__ptr_t stream) { +static struct dirent * +read_dirstream (void *stream) +{ static char *buf; static size_t bufsz; - struct dirstream *const ds = (struct dirstream *)stream; + struct dirstream *const ds = (struct dirstream *) stream; struct directory_contents *dc = ds->contents; - struct dirfile **dirfile_end = - (struct dirfile **)dc->dirfiles.ht_vec + dc->dirfiles.ht_size; + struct dirfile **dirfile_end = (struct dirfile **) dc->dirfiles.ht_vec + dc->dirfiles.ht_size; - while (ds->dirfile_slot < dirfile_end) { - struct dirfile *df = *ds->dirfile_slot++; - if (!HASH_VACANT(df) && !df->impossible) { - /* The glob interface wants a 'struct dirent', so mock one up. */ - struct dirent *d; - size_t len = df->length + 1; - size_t sz = sizeof(*d) - sizeof(d->d_name) + len; - if (sz > bufsz) { - bufsz *= 2; - if (sz > bufsz) bufsz = sz; - buf = xrealloc(buf, bufsz); - } - d = (struct dirent *)buf; + while (ds->dirfile_slot < dirfile_end) + { + struct dirfile *df = *ds->dirfile_slot++; + if (! HASH_VACANT (df) && !df->impossible) + { + /* The glob interface wants a 'struct dirent', so mock one up. */ + struct dirent *d; + size_t len = df->length + 1; + size_t sz = sizeof (*d) - sizeof (d->d_name) + len; + if (sz > bufsz) + { + bufsz *= 2; + if (sz > bufsz) + bufsz = sz; + buf = xrealloc (buf, bufsz); + } + d = (struct dirent *) buf; #ifdef __MINGW32__ -#if __MINGW32_MAJOR_VERSION < 3 || \ - (__MINGW32_MAJOR_VERSION == 3 && __MINGW32_MINOR_VERSION == 0) - d->d_name = xmalloc(len); +# if __MINGW32_MAJOR_VERSION < 3 || (__MINGW32_MAJOR_VERSION == 3 && \ + __MINGW32_MINOR_VERSION == 0) + d->d_name = xmalloc (len); +# endif #endif -#endif - FAKE_DIR_ENTRY(d); + FAKE_DIR_ENTRY (d); #ifdef _DIRENT_HAVE_D_NAMLEN - d->d_namlen = len - 1; + d->d_namlen = len - 1; #endif - d->d_type = df->type; - memcpy(d->d_name, df->name, len); - return d; +#ifdef HAVE_STRUCT_DIRENT_D_TYPE + d->d_type = df->type; +#endif + memcpy (d->d_name, df->name, len); + return d; + } } - } - return 0; + return NULL; } /* On 64 bit ReliantUNIX (5.44 and above) in LFS mode, stat() is actually a @@ -828,46 +1281,73 @@ static struct dirent *read_dirstream(__ptr_t stream) { * regular file; fix that here. */ #if !defined(stat) && !defined(WINDOWS32) || defined(VMS) -#define local_stat stat +# ifndef VMS +# ifndef HAVE_SYS_STAT_H +int stat (const char *path, struct stat *sbuf); +# endif +# else + /* We are done with the fake stat. Go back to the real stat */ +# ifdef stat +# undef stat +# endif +# endif +# define local_stat stat #else -static int local_stat(const char *path, struct stat *buf) { +static int +local_stat (const char *path, struct stat *buf) +{ int e; #ifdef WINDOWS32 - size_t plen = strlen(path); + size_t plen = strlen (path); /* Make sure the parent of "." exists and is a directory, not a file. This is because 'stat' on Windows normalizes the argument foo/. => foo without checking first that foo is a directory. */ - if (plen > 1 && path[plen - 1] == '.' && - (path[plen - 2] == '/' || path[plen - 2] == '\\')) { - char parent[MAXPATHLEN]; + if (plen > 2 && path[plen - 1] == '.' && ISDIRSEP (path[plen - 2])) + { + char parent[MAX_PATH+1]; - strncpy(parent, path, plen - 2); - parent[plen - 2] = '\0'; - if (stat(parent, buf) < 0 || !_S_ISDIR(buf->st_mode)) return -1; - } + strncpy (parent, path, MAX_PATH); + parent[MIN(plen - 2, MAX_PATH)] = '\0'; + if (stat (parent, buf) < 0 || !_S_ISDIR (buf->st_mode)) + return -1; + } #endif - EINTRLOOP(e, stat(path, buf)); + EINTRLOOP (e, stat (path, buf)); return e; } #endif /* Similarly for lstat. */ #if !defined(lstat) && !defined(WINDOWS32) || defined(VMS) -#define local_lstat lstat +# ifndef VMS +# ifndef HAVE_SYS_STAT_H +int lstat (const char *path, struct stat *sbuf); +# endif +# else + /* We are done with the fake lstat. Go back to the real lstat */ +# ifdef lstat +# undef lstat +# endif +# endif +# define local_lstat lstat #elif defined(WINDOWS32) /* Windows doesn't support lstat(). */ -#define local_lstat local_stat +# define local_lstat local_stat #else -static int local_lstat(const char *path, struct stat *buf) { +static int +local_lstat (const char *path, struct stat *buf) +{ int e; - EINTRLOOP(e, lstat(path, buf)); + EINTRLOOP (e, lstat (path, buf)); return e; } #endif -void dir_setup_glob(glob_t *gl) { +void +dir_setup_glob (glob_t *gl) +{ gl->gl_offs = 0; gl->gl_opendir = open_dirstream; gl->gl_readdir = read_dirstream; @@ -876,9 +1356,12 @@ void dir_setup_glob(glob_t *gl) { gl->gl_stat = local_stat; } -void hash_init_directories(void) { - hash_init(&directories, DIRECTORY_BUCKETS, directory_hash_1, directory_hash_2, - directory_hash_cmp); - hash_init(&directory_contents, DIRECTORY_BUCKETS, directory_contents_hash_1, - directory_contents_hash_2, directory_contents_hash_cmp); +void +hash_init_directories (void) +{ + hash_init (&directories, DIRECTORY_BUCKETS, + directory_hash_1, directory_hash_2, directory_hash_cmp); + hash_init (&directory_contents, DIRECTORY_BUCKETS, + directory_contents_hash_1, directory_contents_hash_2, + directory_contents_hash_cmp); } diff --git a/third_party/make/dirname-lgpl.c b/third_party/make/dirname-lgpl.c deleted file mode 100644 index 65d686564..000000000 --- a/third_party/make/dirname-lgpl.c +++ /dev/null @@ -1,85 +0,0 @@ -/* dirname.c -- return all but the last element in a file name - - Copyright (C) 1990, 1998, 2000-2001, 2003-2006, 2009-2020 Free Software - Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -#include "third_party/make/config.h" -/**/ -#include "libc/mem/mem.h" -#include "libc/str/str.h" -#include "third_party/make/dirname.h" - -/* Return the length of the prefix of FILE that will be used by - dir_name. If FILE is in the working directory, this returns zero - even though 'dir_name (FILE)' will return ".". Works properly even - if there are trailing slashes (by effectively ignoring them). */ - -size_t -dir_len (char const *file) -{ - size_t prefix_length = FILE_SYSTEM_PREFIX_LEN (file); - size_t length; - - /* Advance prefix_length beyond important leading slashes. */ - prefix_length += (prefix_length != 0 - ? (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE - && ISSLASH (file[prefix_length])) - : (ISSLASH (file[0]) - ? ((DOUBLE_SLASH_IS_DISTINCT_ROOT - && ISSLASH (file[1]) && ! ISSLASH (file[2]) - ? 2 : 1)) - : 0)); - - /* Strip the basename and any redundant slashes before it. */ - for (length = last_component (file) - file; - prefix_length < length; length--) - if (! ISSLASH (file[length - 1])) - break; - return length; -} - - -/* In general, we can't use the builtin 'dirname' function if available, - since it has different meanings in different environments. - In some environments the builtin 'dirname' modifies its argument. - - Return the leading directories part of FILE, allocated with malloc. - Works properly even if there are trailing slashes (by effectively - ignoring them). Return NULL on failure. - - If lstat (FILE) would succeed, then { chdir (dir_name (FILE)); - lstat (base_name (FILE)); } will access the same file. Likewise, - if the sequence { chdir (dir_name (FILE)); - rename (base_name (FILE), "foo"); } succeeds, you have renamed FILE - to "foo" in the same directory FILE was in. */ - -char * -mdir_name (char const *file) -{ - size_t length = dir_len (file); - bool append_dot = (length == 0 - || (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE - && length == FILE_SYSTEM_PREFIX_LEN (file) - && file[2] != '\0' && ! ISSLASH (file[2]))); - char *dir = malloc (length + append_dot + 1); - if (!dir) - return NULL; - memcpy (dir, file, length); - if (append_dot) - dir[length++] = '.'; - dir[length] = '\0'; - return dir; -} diff --git a/third_party/make/dirname.h b/third_party/make/dirname.h deleted file mode 100644 index 80e1b300d..000000000 --- a/third_party/make/dirname.h +++ /dev/null @@ -1,52 +0,0 @@ -/* Take file names apart into directory and base names. - - Copyright (C) 1998, 2001, 2003-2006, 2009-2020 Free Software Foundation, - Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - - -#ifndef DIRNAME_H_ -# define DIRNAME_H_ 1 -#include "third_party/make/filename.h" - -# ifndef DIRECTORY_SEPARATOR -# define DIRECTORY_SEPARATOR '/' -# endif - -# ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT -# define DOUBLE_SLASH_IS_DISTINCT_ROOT 0 -# endif - -#ifdef __cplusplus -extern "C" { -#endif - -# if GNULIB_DIRNAME -char *base_name (char const *file) _GL_ATTRIBUTE_MALLOC; -char *dir_name (char const *file); -# endif - -char *mdir_name (char const *file); -size_t base_len (char const *file) _GL_ATTRIBUTE_PURE; -size_t dir_len (char const *file) _GL_ATTRIBUTE_PURE; -char *last_component (char const *file) _GL_ATTRIBUTE_PURE; - -bool strip_trailing_slashes (char *file); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* not DIRNAME_H_ */ diff --git a/third_party/make/error.c b/third_party/make/error.c deleted file mode 100644 index c663b1b69..000000000 --- a/third_party/make/error.c +++ /dev/null @@ -1,187 +0,0 @@ -/* Error handler for noninteractive utilities - Copyright (C) 1990-1998, 2000-2007, 2009-2020 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - 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 . */ - -/* Written by David MacKenzie . */ - -#include "libc/sysv/consts/f.h" -#include "libc/calls/calls.h" -#include "third_party/make/config.h" -#include "third_party/make/error.h" -#include "libc/stdio/stdio.h" -#include "libc/str/str.h" -#include "libc/runtime/runtime.h" -#include "third_party/make/stdio.h" - -#if !_LIBC && ENABLE_NLS -#include "third_party/make/gettext.h" -# define _(msgid) gettext (msgid) -#endif - -#ifdef _LIBC -# define mbsrtowcs __mbsrtowcs -# define USE_UNLOCKED_IO 0 -# define _GL_ATTRIBUTE_FORMAT_PRINTF(a, b) -# define _GL_ARG_NONNULL(a) -#else -#include "third_party/make/getprogname.h" -#endif - -#ifndef _ -# define _(String) String -#endif - -/* If NULL, error will flush stdout, then print on stderr the program - name, a colon and a space. Otherwise, error will call this - function without parameters instead. */ -void (*error_print_progname) (void); - -/* This variable is incremented each time 'error' is called. */ -unsigned int error_message_count; - -#undef fcntl -#define program_name getprogname () -#define __strerror_r strerror_r - -/* Return non-zero if FD is open. */ -static int -is_open (int fd) -{ - return 0 <= fcntl (fd, F_GETFL); -} - -static void -flush_stdout (void) -{ -#if !_LIBC - int stdout_fd; - -# if GNULIB_FREOPEN_SAFER - /* Use of gnulib's freopen-safer module normally ensures that - fileno (stdout) == 1 - whenever stdout is open. */ - stdout_fd = STDOUT_FILENO; -# else - /* POSIX states that fileno (stdout) after fclose is unspecified. But in - practice it is not a problem, because stdout is statically allocated and - the fd of a FILE stream is stored as a field in its allocated memory. */ - stdout_fd = fileno (stdout); -# endif - /* POSIX states that fflush (stdout) after fclose is unspecified; it - is safe in glibc, but not on all other platforms. fflush (NULL) - is always defined, but too draconian. */ - if (0 <= stdout_fd && is_open (stdout_fd)) -#endif - fflush (stdout); -} - -static void -print_errno_message (int errnum) -{ - char const *s; - s = strerror (errnum); - if (! s) - s = _("Unknown system error"); - fprintf (stderr, ": %s", s); -} - -static void _GL_ATTRIBUTE_FORMAT_PRINTF (3, 0) _GL_ARG_NONNULL ((3)) -error_tail (int status, int errnum, const char *message, va_list args) -{ - vfprintf (stderr, message, args); - ++error_message_count; - if (errnum) - print_errno_message (errnum); - putc ('\n', stderr); - fflush (stderr); - if (status) - exit (status); -} - - -/* Print the program name and error message MESSAGE, which is a printf-style - format string with optional args. - If ERRNUM is nonzero, print its corresponding system error message. - Exit with status STATUS if it is nonzero. */ -void -error (int status, int errnum, const char *message, ...) -{ - va_list args; - - flush_stdout (); - if (error_print_progname) - (*error_print_progname) (); - else - { - fprintf (stderr, "%s: ", program_name); - } - - va_start (args, message); - error_tail (status, errnum, message, args); - va_end (args); -} - -/* Sometimes we want to have at most one error per line. This - variable controls whether this mode is selected or not. */ -int error_one_per_line; - -void -error_at_line (int status, int errnum, const char *file_name, - unsigned int line_number, const char *message, ...) -{ - va_list args; - - if (error_one_per_line) - { - static const char *old_file_name; - static unsigned int old_line_number; - - if (old_line_number == line_number - && (file_name == old_file_name - || (old_file_name != NULL - && file_name != NULL - && strcmp (old_file_name, file_name) == 0))) - - /* Simply return and print nothing. */ - return; - - old_file_name = file_name; - old_line_number = line_number; - } - - flush_stdout (); - if (error_print_progname) - (*error_print_progname) (); - else - { - fprintf (stderr, "%s:", program_name); - } - - fprintf (stderr, file_name != NULL ? "%s:%u: " : " ", - file_name, line_number); - - va_start (args, message); - error_tail (status, errnum, message, args); - va_end (args); -} - -#ifdef _LIBC -/* Make the weak alias. */ -# undef error -# undef error_at_line -weak_alias (__error, error) -weak_alias (__error_at_line, error_at_line) -#endif diff --git a/third_party/make/error.h b/third_party/make/error.h deleted file mode 100644 index bad47a16d..000000000 --- a/third_party/make/error.h +++ /dev/null @@ -1,75 +0,0 @@ -/* Declaration for error-reporting function - Copyright (C) 1995-1997, 2003, 2006, 2008-2020 Free Software Foundation, - Inc. - This file is part of the GNU C Library. - - 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 . */ - -#ifndef _ERROR_H -#define _ERROR_H 1 - -/* The __attribute__ feature is available in gcc versions 2.5 and later. - The __-protected variants of the attributes 'format' and 'printf' are - accepted by gcc versions 2.6.4 (effectively 2.7) and later. - We enable _GL_ATTRIBUTE_FORMAT only if these are supported too, because - gnulib and libintl do '#define printf __printf__' when they override - the 'printf' function. */ -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7) -# define _GL_ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec)) -#else -# define _GL_ATTRIBUTE_FORMAT(spec) /* empty */ -#endif - -/* On mingw, the flavor of printf depends on whether the extensions module - * is in use; the check for determines the witness macro. */ -#ifndef _GL_ATTRIBUTE_SPEC_PRINTF -# if GNULIB_PRINTF_ATTRIBUTE_FLAVOR_GNU -# define _GL_ATTRIBUTE_SPEC_PRINTF __gnu_printf__ -# else -# define _GL_ATTRIBUTE_SPEC_PRINTF __printf__ -# endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Print a message with 'fprintf (stderr, FORMAT, ...)'; - if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM). - If STATUS is nonzero, terminate the program with 'exit (STATUS)'. */ - -extern void error (int __status, int __errnum, const char *__format, ...) - _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF, 3, 4)); - -extern void error_at_line (int __status, int __errnum, const char *__fname, - unsigned int __lineno, const char *__format, ...) - _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF, 5, 6)); - -/* If NULL, error will flush stdout, then print on stderr the program - name, a colon and a space. Otherwise, error will call this - function without parameters instead. */ -extern void (*error_print_progname) (void); - -/* This variable is incremented each time 'error' is called. */ -extern unsigned int error_message_count; - -/* Sometimes we want to have at most one error per line. This - variable controls whether this mode is selected or not. */ -extern int error_one_per_line; - -#ifdef __cplusplus -} -#endif - -#endif /* error.h */ diff --git a/third_party/make/exitfail.c b/third_party/make/exitfail.c deleted file mode 100644 index 6b073520d..000000000 --- a/third_party/make/exitfail.c +++ /dev/null @@ -1,18 +0,0 @@ -/* Failure exit status - - Copyright (C) 2002-2003, 2005-2007, 2009-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -int volatile exit_failure = 1; /*TODO: this should be EXIT_FAILURE; */ diff --git a/third_party/make/exitfail.h b/third_party/make/exitfail.h deleted file mode 100644 index a69a03bbd..000000000 --- a/third_party/make/exitfail.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Failure exit status - - Copyright (C) 2002, 2009-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -extern int volatile exit_failure; diff --git a/third_party/make/expand.c b/third_party/make/expand.c index 0a3aa17bd..c7233e8ce 100644 --- a/third_party/make/expand.c +++ b/third_party/make/expand.c @@ -1,5 +1,5 @@ /* Variable expansion functions for GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,16 +12,18 @@ 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 . */ +this program. If not, see . */ -#include "third_party/make/makeint.inc" -/**/ -#include "third_party/make/filedef.h" -#include "third_party/make/job.h" -#include "third_party/make/commands.h" -#include "third_party/make/variable.h" -#include "libc/x/x.h" -#include "third_party/make/rule.h" +#include "makeint.h" + +#include + +#include "commands.h" +#include "debug.h" +#include "filedef.h" +#include "job.h" +#include "variable.h" +#include "rule.h" /* Initially, any errors reported when expanding strings will be reported against the file where the error appears. */ @@ -66,14 +68,14 @@ variable_buffer_output (char *ptr, const char *string, size_t length) ptr = variable_buffer + offset; } - memcpy (ptr, string, length); - return ptr + length; + return mempcpy (ptr, string, length); } -/* Return a pointer to the beginning of the variable buffer. */ +/* Return a pointer to the beginning of the variable buffer. + This is called from main() and it should never be null afterward. */ -static char * -initialize_variable_output (void) +char * +initialize_variable_output () { /* If we don't have a variable output buffer yet, get one. */ @@ -100,6 +102,29 @@ recursively_expand_for_file (struct variable *v, struct file *file) struct variable_set_list *save = 0; int set_reading = 0; + /* If we're expanding to put into the environment of a shell function then + ignore any recursion issues: for backward-compatibility we will use + the value of the environment variable we were started with. */ + if (v->expanding && env_recursion) + { + size_t nl = strlen (v->name); + char **ep; + DB (DB_VERBOSE, + (_("%s:%lu: not recursively expanding %s to export to shell function\n"), + v->fileinfo.filenm, v->fileinfo.lineno, v->name)); + + /* We could create a hash for the original environment for speed, but a + reasonably written makefile shouldn't hit this situation... */ + for (ep = environ; *ep != 0; ++ep) + if ((*ep)[nl] == '=' && strncmp (*ep, v->name, nl) == 0) + return xstrdup ((*ep) + nl + 1); + + /* If there's nothing in the parent environment, use the empty string. + This isn't quite correct since the variable should not exist at all, + but getting that to work would be involved. */ + return xstrdup (""); + } + /* Don't install a new location if this location is empty. This can happen for command-line variables, builtin variables, etc. */ saved_varp = expanding_var; @@ -152,7 +177,10 @@ recursively_expand_for_file (struct variable *v, struct file *file) /* Expand a simple reference to variable NAME, which is LENGTH chars long. */ -static inline char * +#ifdef __GNUC__ +__inline +#endif +static char * reference_variable (char *o, const char *name, size_t length) { struct variable *v; @@ -203,7 +231,7 @@ variable_expand_string (char *line, const char *string, size_t length) if (length == 0) { variable_buffer_output (o, "", 1); - return (variable_buffer); + return variable_buffer; } /* We need a copy of STRING: due to eval, it's possible that it will get @@ -441,8 +469,7 @@ expand_argument (const char *str, const char *end) r = allocated_variable_expand (tmp); - if (alloc) - free (alloc); + free (alloc); return r; } diff --git a/third_party/make/fcntl.c b/third_party/make/fcntl.c deleted file mode 100644 index a98139605..000000000 --- a/third_party/make/fcntl.c +++ /dev/null @@ -1,555 +0,0 @@ -/* Provide file descriptor control. - - Copyright (C) 2009-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -/* Written by Eric Blake . */ - -#include "libc/calls/calls.h" -#include "libc/errno.h" -#include "libc/sysv/consts/f.h" -#include "third_party/make/config.h" - -/* Specification. */ -#include "third_party/make/fcntl.h" - -#if defined _WIN32 && !defined __CYGWIN__ -/* Get declarations of the native Windows API functions. */ - -/* Upper bound on getdtablesize(). See lib/getdtablesize.c. */ -#define OPEN_MAX_MAX 0x10000 - -/* Duplicate OLDFD into the first available slot of at least NEWFD, - which must be positive, with FLAGS determining whether the duplicate - will be inheritable. */ -static int dupfd(int oldfd, int newfd, int flags) { - /* Mingw has no way to create an arbitrary fd. Iterate until all - file descriptors less than newfd are filled up. */ - HANDLE curr_process = GetCurrentProcess(); - HANDLE old_handle = (HANDLE)_get_osfhandle(oldfd); - unsigned char fds_to_close[OPEN_MAX_MAX / CHAR_BIT]; - unsigned int fds_to_close_bound = 0; - int result; - BOOL inherit = flags & O_CLOEXEC ? FALSE : TRUE; - int mode; - - if (newfd < 0 || getdtablesize() <= newfd) { - errno = EINVAL; - return -1; - } - if (old_handle == INVALID_HANDLE_VALUE || - (mode = setmode(oldfd, O_BINARY)) == -1) { - /* oldfd is not open, or is an unassigned standard file - descriptor. */ - errno = EBADF; - return -1; - } - setmode(oldfd, mode); - flags |= mode; - - for (;;) { - HANDLE new_handle; - int duplicated_fd; - unsigned int index; - - if (!DuplicateHandle(curr_process, /* SourceProcessHandle */ - old_handle, /* SourceHandle */ - curr_process, /* TargetProcessHandle */ - (PHANDLE)&new_handle, /* TargetHandle */ - (DWORD)0, /* DesiredAccess */ - inherit, /* InheritHandle */ - DUPLICATE_SAME_ACCESS)) /* Options */ - { - switch (GetLastError()) { - case ERROR_TOO_MANY_OPEN_FILES: - errno = EMFILE; - break; - case ERROR_INVALID_HANDLE: - case ERROR_INVALID_TARGET_HANDLE: - case ERROR_DIRECT_ACCESS_HANDLE: - errno = EBADF; - break; - case ERROR_INVALID_PARAMETER: - case ERROR_INVALID_FUNCTION: - case ERROR_INVALID_ACCESS: - errno = EINVAL; - break; - default: - errno = EACCES; - break; - } - result = -1; - break; - } - duplicated_fd = _open_osfhandle((intptr_t)new_handle, flags); - if (duplicated_fd < 0) { - CloseHandle(new_handle); - result = -1; - break; - } - if (newfd <= duplicated_fd) { - result = duplicated_fd; - break; - } - - /* Set the bit duplicated_fd in fds_to_close[]. */ - index = (unsigned int)duplicated_fd / CHAR_BIT; - if (fds_to_close_bound <= index) { - if (sizeof fds_to_close <= index) /* Need to increase OPEN_MAX_MAX. */ - abort(); - memset(fds_to_close + fds_to_close_bound, '\0', - index + 1 - fds_to_close_bound); - fds_to_close_bound = index + 1; - } - fds_to_close[index] |= 1 << ((unsigned int)duplicated_fd % CHAR_BIT); - } - - /* Close the previous fds that turned out to be too small. */ - { - int saved_errno = errno; - unsigned int duplicated_fd; - - for (duplicated_fd = 0; duplicated_fd < fds_to_close_bound * CHAR_BIT; - duplicated_fd++) - if ((fds_to_close[duplicated_fd / CHAR_BIT] >> - (duplicated_fd % CHAR_BIT)) & - 1) - close(duplicated_fd); - - errno = saved_errno; - } - -#if REPLACE_FCHDIR - if (0 <= result) result = _gl_register_dup(oldfd, result); -#endif - return result; -} -#endif /* W32 */ - -/* Forward declarations, because we '#undef fcntl' in the middle of this - compilation unit. */ -/* Our implementation of fcntl (fd, F_DUPFD, target). */ -static int rpl_fcntl_DUPFD(int fd, int target); -/* Our implementation of fcntl (fd, F_DUPFD_CLOEXEC, target). */ -static int rpl_fcntl_DUPFD_CLOEXEC(int fd, int target); -#ifdef __KLIBC__ -/* Adds support for fcntl on directories. */ -static int klibc_fcntl(int fd, int action, /* arg */...); -#endif - -/* Perform the specified ACTION on the file descriptor FD, possibly - using the argument ARG further described below. This replacement - handles the following actions, and forwards all others on to the - native fcntl. An unrecognized ACTION returns -1 with errno set to - EINVAL. - - F_DUPFD - duplicate FD, with int ARG being the minimum target fd. - If successful, return the duplicate, which will be inheritable; - otherwise return -1 and set errno. - - F_DUPFD_CLOEXEC - duplicate FD, with int ARG being the minimum - target fd. If successful, return the duplicate, which will not be - inheritable; otherwise return -1 and set errno. - - F_GETFD - ARG need not be present. If successful, return a - non-negative value containing the descriptor flags of FD (only - FD_CLOEXEC is portable, but other flags may be present); otherwise - return -1 and set errno. */ - -int fcntl_(int fd, int action, /* arg */...) -#undef fcntl -#ifdef __KLIBC__ -#define fcntl_ klibc_fcntl -#endif -{ - va_list arg; - int result = -1; - va_start(arg, action); - if (action == F_DUPFD) { - int target = va_arg(arg, int); - result = rpl_fcntl_DUPFD(fd, target); - } - - else if (action == F_DUPFD_CLOEXEC) { - int target = va_arg(arg, int); - result = rpl_fcntl_DUPFD_CLOEXEC(fd, target); - } - -#if !HAVE_FCNTL - else if (action == F_GETFD) { -#if defined _WIN32 && !defined __CYGWIN__ - HANDLE handle = (HANDLE)_get_osfhandle(fd); - DWORD flags; - if (handle == INVALID_HANDLE_VALUE || - GetHandleInformation(handle, &flags) == 0) - errno = EBADF; - else - result = (flags & HANDLE_FLAG_INHERIT) ? 0 : FD_CLOEXEC; -#else /* !W32 */ - /* Use dup2 to reject invalid file descriptors. No way to - access this information, so punt. */ - if (0 <= dup2(fd, fd)) result = 0; -#endif /* !W32 */ - } /* F_GETFD */ -#endif /* !HAVE_FCNTL */ - - /* Implementing F_SETFD on mingw is not trivial - there is no - API for changing the O_NOINHERIT bit on an fd, and merely - changing the HANDLE_FLAG_INHERIT bit on the underlying handle - can lead to odd state. It may be possible by duplicating the - handle, using _open_osfhandle with the right flags, then - using dup2 to move the duplicate onto the original, but that - is not supported for now. */ - - else { -#if 0 - switch (action) - { -#ifdef F_BARRIERFSYNC /* macOS */ - case F_BARRIERFSYNC: -#endif -#ifdef F_CHKCLEAN /* macOS */ - case F_CHKCLEAN: -#endif -#ifdef F_CLOSEM /* NetBSD, HP-UX */ - case F_CLOSEM: -#endif -#ifdef F_FLUSH_DATA /* macOS */ - case F_FLUSH_DATA: -#endif -#ifdef F_FREEZE_FS /* macOS */ - case F_FREEZE_FS: -#endif -#ifdef F_FULLFSYNC /* macOS */ - case F_FULLFSYNC: -#endif -#ifdef F_GETCONFINED /* macOS */ - case F_GETCONFINED: -#endif -#ifdef F_GETDEFAULTPROTLEVEL /* macOS */ - case F_GETDEFAULTPROTLEVEL: -#endif -#ifdef F_GETFD /* POSIX */ - case F_GETFD: -#endif -#ifdef F_GETFL /* POSIX */ - case F_GETFL: -#endif -#ifdef F_GETLEASE /* Linux */ - case F_GETLEASE: -#endif -#ifdef F_GETNOSIGPIPE /* macOS */ - case F_GETNOSIGPIPE: -#endif -#ifdef F_GETOWN /* POSIX */ - case F_GETOWN: -#endif -#ifdef F_GETPIPE_SZ /* Linux */ - case F_GETPIPE_SZ: -#endif -#ifdef F_GETPROTECTIONCLASS /* macOS */ - case F_GETPROTECTIONCLASS: -#endif -#ifdef F_GETPROTECTIONLEVEL /* macOS */ - case F_GETPROTECTIONLEVEL: -#endif -#ifdef F_GET_SEALS /* Linux */ - case F_GET_SEALS: -#endif -#ifdef F_GETSIG /* Linux */ - case F_GETSIG: -#endif -#ifdef F_MAXFD /* NetBSD */ - case F_MAXFD: -#endif -#ifdef F_RECYCLE /* macOS */ - case F_RECYCLE: -#endif -#ifdef F_SETFIFOENH /* HP-UX */ - case F_SETFIFOENH: -#endif -#ifdef F_THAW_FS /* macOS */ - case F_THAW_FS: -#endif - /* These actions take no argument. */ - result = fcntl (fd, action); - break; - -#ifdef F_ADD_SEALS /* Linux */ - case F_ADD_SEALS: -#endif -#ifdef F_BADFD /* Solaris */ - case F_BADFD: -#endif -#ifdef F_CHECK_OPENEVT /* macOS */ - case F_CHECK_OPENEVT: -#endif -#ifdef F_DUP2FD /* FreeBSD, AIX, Solaris */ - case F_DUP2FD: -#endif -#ifdef F_DUP2FD_CLOEXEC /* FreeBSD, Solaris */ - case F_DUP2FD_CLOEXEC: -#endif -#ifdef F_DUP2FD_CLOFORK /* Solaris */ - case F_DUP2FD_CLOFORK: -#endif -#ifdef F_DUPFD /* POSIX */ - case F_DUPFD: -#endif -#ifdef F_DUPFD_CLOEXEC /* POSIX */ - case F_DUPFD_CLOEXEC: -#endif -#ifdef F_DUPFD_CLOFORK /* Solaris */ - case F_DUPFD_CLOFORK: -#endif -#ifdef F_GETXFL /* Solaris */ - case F_GETXFL: -#endif -#ifdef F_GLOBAL_NOCACHE /* macOS */ - case F_GLOBAL_NOCACHE: -#endif -#ifdef F_MAKECOMPRESSED /* macOS */ - case F_MAKECOMPRESSED: -#endif -#ifdef F_MOVEDATAEXTENTS /* macOS */ - case F_MOVEDATAEXTENTS: -#endif -#ifdef F_NOCACHE /* macOS */ - case F_NOCACHE: -#endif -#ifdef F_NODIRECT /* macOS */ - case F_NODIRECT: -#endif -#ifdef F_NOTIFY /* Linux */ - case F_NOTIFY: -#endif -#ifdef F_OPLKACK /* IRIX */ - case F_OPLKACK: -#endif -#ifdef F_OPLKREG /* IRIX */ - case F_OPLKREG: -#endif -#ifdef F_RDAHEAD /* macOS */ - case F_RDAHEAD: -#endif -#ifdef F_SETBACKINGSTORE /* macOS */ - case F_SETBACKINGSTORE: -#endif -#ifdef F_SETCONFINED /* macOS */ - case F_SETCONFINED: -#endif -#ifdef F_SETFD /* POSIX */ - case F_SETFD: -#endif -#ifdef F_SETFL /* POSIX */ - case F_SETFL: -#endif -#ifdef F_SETLEASE /* Linux */ - case F_SETLEASE: -#endif -#ifdef F_SETNOSIGPIPE /* macOS */ - case F_SETNOSIGPIPE: -#endif -#ifdef F_SETOWN /* POSIX */ - case F_SETOWN: -#endif -#ifdef F_SETPIPE_SZ /* Linux */ - case F_SETPIPE_SZ: -#endif -#ifdef F_SETPROTECTIONCLASS /* macOS */ - case F_SETPROTECTIONCLASS: -#endif -#ifdef F_SETSIG /* Linux */ - case F_SETSIG: -#endif -#ifdef F_SINGLE_WRITER /* macOS */ - case F_SINGLE_WRITER: -#endif - /* These actions take an 'int' argument. */ - { - int x = va_arg (arg, int); - result = fcntl (fd, action, x); - } - break; - - default: - /* Other actions take a pointer argument. */ - { - void *p = va_arg (arg, void *); - result = fcntl (fd, action, p); - } - break; - } -#else - errno = EINVAL; -#endif - } - va_end(arg); - return result; -} - -static int rpl_fcntl_DUPFD(int fd, int target) { - int result; -#if !HAVE_FCNTL - result = dupfd(fd, target, 0); -#elif FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR - /* Detect invalid target; needed for cygwin 1.5.x. */ - if (target < 0 || getdtablesize() <= target) { - result = -1; - errno = EINVAL; - } else { - /* Haiku alpha 2 loses fd flags on original. */ - int flags = fcntl(fd, F_GETFD); - if (flags < 0) - result = -1; - else { - result = fcntl(fd, F_DUPFD, target); - if (0 <= result && fcntl(fd, F_SETFD, flags) == -1) { - int saved_errno = errno; - close(result); - result = -1; - errno = saved_errno; - } -#if REPLACE_FCHDIR - if (0 <= result) result = _gl_register_dup(fd, result); -#endif - } - } -#else - result = fcntl(fd, F_DUPFD, target); -#endif - return result; -} - -static int rpl_fcntl_DUPFD_CLOEXEC(int fd, int target) { - int result; -#if !HAVE_FCNTL - result = dupfd(fd, target, O_CLOEXEC); -#else /* HAVE_FCNTL */ -#if defined __HAIKU__ - /* On Haiku, the system fcntl (fd, F_DUPFD_CLOEXEC, target) sets - the FD_CLOEXEC flag on fd, not on target. Therefore avoid the - system fcntl in this case. */ -#define have_dupfd_cloexec -1 -#else - /* Try the system call first, if the headers claim it exists - (that is, if GNULIB_defined_F_DUPFD_CLOEXEC is 0), since we - may be running with a glibc that has the macro but with an - older kernel that does not support it. Cache the - information on whether the system call really works, but - avoid caching failure if the corresponding F_DUPFD fails - for any reason. 0 = unknown, 1 = yes, -1 = no. */ - static int have_dupfd_cloexec = GNULIB_defined_F_DUPFD_CLOEXEC ? -1 : 0; - if (0 <= have_dupfd_cloexec) { - result = fcntl(fd, F_DUPFD_CLOEXEC, target); - if (0 <= result || errno != EINVAL) { - have_dupfd_cloexec = 1; -#if REPLACE_FCHDIR - if (0 <= result) result = _gl_register_dup(fd, result); -#endif - } else { - result = rpl_fcntl_DUPFD(fd, target); - if (result >= 0) have_dupfd_cloexec = -1; - } - } else -#endif - result = rpl_fcntl_DUPFD(fd, target); - if (0 <= result && have_dupfd_cloexec == -1) { - int flags = fcntl(result, F_GETFD); - if (flags < 0 || fcntl(result, F_SETFD, flags | FD_CLOEXEC) == -1) { - int saved_errno = errno; - close(result); - errno = saved_errno; - result = -1; - } - } -#endif /* HAVE_FCNTL */ - return result; -} - -#undef fcntl - -#ifdef __KLIBC__ - -static int klibc_fcntl(int fd, int action, /* arg */...) { - va_list arg_ptr; - int arg; - struct stat sbuf; - int result; - - va_start(arg_ptr, action); - arg = va_arg(arg_ptr, int); - result = fcntl(fd, action, arg); - /* EPERM for F_DUPFD, ENOTSUP for others */ - if (result == -1 && (errno == EPERM || errno == ENOTSUP) && - !fstat(fd, &sbuf) && S_ISDIR(sbuf.st_mode)) { - ULONG ulMode; - - switch (action) { - case F_DUPFD: - /* Find available fd */ - while (fcntl(arg, F_GETFL) != -1 || errno != EBADF) arg++; - - result = dup2(fd, arg); - break; - - /* Using underlying APIs is right ? */ - case F_GETFD: - if (DosQueryFHState(fd, &ulMode)) break; - - result = (ulMode & OPEN_FLAGS_NOINHERIT) ? FD_CLOEXEC : 0; - break; - - case F_SETFD: - if (arg & ~FD_CLOEXEC) break; - - if (DosQueryFHState(fd, &ulMode)) break; - - if (arg & FD_CLOEXEC) - ulMode |= OPEN_FLAGS_NOINHERIT; - else - ulMode &= ~OPEN_FLAGS_NOINHERIT; - - /* Filter supported flags. */ - ulMode &= (OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR | - OPEN_FLAGS_NO_CACHE | OPEN_FLAGS_NOINHERIT); - - if (DosSetFHState(fd, ulMode)) break; - - result = 0; - break; - - case F_GETFL: - result = 0; - break; - - case F_SETFL: - if (arg != 0) break; - - result = 0; - break; - - default: - errno = EINVAL; - break; - } - } - - va_end(arg_ptr); - - return result; -} - -#endif diff --git a/third_party/make/fcntl.h b/third_party/make/fcntl.h deleted file mode 100644 index 54af7da7f..000000000 --- a/third_party/make/fcntl.h +++ /dev/null @@ -1,810 +0,0 @@ -/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ -/* Like , but with non-working flags defined to 0. - - Copyright (C) 2006-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -/* written by Paul Eggert */ - -#if __GNUC__ >= 3 -#pragma GCC system_header -#endif - -#if defined __need_system_fcntl_h -/* Special invocation convention. */ - -/* Needed before . - May also define off_t to a 64-bit type on native Windows. */ - -/* Native Windows platforms declare open(), creat() in . */ -#if (0 || 0 || defined GNULIB_POSIXCHECK) && \ - (defined _WIN32 && !defined __CYGWIN__) -#endif - -#else -/* Normal invocation convention. */ - -#ifndef _GL_FCNTL_H - -/* Needed before . - May also define off_t to a 64-bit type on native Windows. */ -/* On some systems other than glibc, is a prerequisite of - . On glibc systems, we would like to avoid namespace pollution. - But on glibc systems, includes inside an - extern "C" { ... } block, which leads to errors in C++ mode with the - overridden from gnulib. These errors are known to be gone - with g++ version >= 4.3. */ -#if !(defined __GLIBC__ || defined __UCLIBC__) || \ - (defined __cplusplus && defined GNULIB_NAMESPACE && \ - (defined __ICC || \ - !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))) -#endif -/* The include_next requires a split double-inclusion guard. */ - -/* Native Windows platforms declare open(), creat() in . */ -#if (0 || 0 || defined GNULIB_POSIXCHECK) && \ - (defined _WIN32 && !defined __CYGWIN__) -#endif - -#ifndef _GL_FCNTL_H -#define _GL_FCNTL_H - -/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ -/* C++ compatible function declaration macros. - Copyright (C) 2010-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -#ifndef _GL_CXXDEFS_H -#define _GL_CXXDEFS_H - -/* Begin/end the GNULIB_NAMESPACE namespace. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -#define _GL_BEGIN_NAMESPACE namespace GNULIB_NAMESPACE { -#define _GL_END_NAMESPACE } -#else -#define _GL_BEGIN_NAMESPACE -#define _GL_END_NAMESPACE -#endif - -/* The three most frequent use cases of these macros are: - - * For providing a substitute for a function that is missing on some - platforms, but is declared and works fine on the platforms on which - it exists: - - #if @GNULIB_FOO@ - # if !@HAVE_FOO@ - _GL_FUNCDECL_SYS (foo, ...); - # endif - _GL_CXXALIAS_SYS (foo, ...); - _GL_CXXALIASWARN (foo); - #elif defined GNULIB_POSIXCHECK - ... - #endif - - * For providing a replacement for a function that exists on all platforms, - but is broken/insufficient and needs to be replaced on some platforms: - - #if @GNULIB_FOO@ - # if @REPLACE_FOO@ - # if !(defined __cplusplus && defined GNULIB_NAMESPACE) - # undef foo - # define foo rpl_foo - # endif - _GL_FUNCDECL_RPL (foo, ...); - _GL_CXXALIAS_RPL (foo, ...); - # else - _GL_CXXALIAS_SYS (foo, ...); - # endif - _GL_CXXALIASWARN (foo); - #elif defined GNULIB_POSIXCHECK - ... - #endif - - * For providing a replacement for a function that exists on some platforms - but is broken/insufficient and needs to be replaced on some of them and - is additionally either missing or undeclared on some other platforms: - - #if @GNULIB_FOO@ - # if @REPLACE_FOO@ - # if !(defined __cplusplus && defined GNULIB_NAMESPACE) - # undef foo - # define foo rpl_foo - # endif - _GL_FUNCDECL_RPL (foo, ...); - _GL_CXXALIAS_RPL (foo, ...); - # else - # if !@HAVE_FOO@ or if !@HAVE_DECL_FOO@ - _GL_FUNCDECL_SYS (foo, ...); - # endif - _GL_CXXALIAS_SYS (foo, ...); - # endif - _GL_CXXALIASWARN (foo); - #elif defined GNULIB_POSIXCHECK - ... - #endif -*/ - -/* _GL_EXTERN_C declaration; - performs the declaration with C linkage. */ -#if defined __cplusplus -#define _GL_EXTERN_C extern "C" -#else -#define _GL_EXTERN_C extern -#endif - -/* _GL_FUNCDECL_RPL (func, rettype, parameters_and_attributes); - declares a replacement function, named rpl_func, with the given prototype, - consisting of return type, parameters, and attributes. - Example: - _GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...) - _GL_ARG_NONNULL ((1))); - */ -#define _GL_FUNCDECL_RPL(func, rettype, parameters_and_attributes) \ - _GL_FUNCDECL_RPL_1(rpl_##func, rettype, parameters_and_attributes) -#define _GL_FUNCDECL_RPL_1(rpl_func, rettype, parameters_and_attributes) \ - _GL_EXTERN_C rettype rpl_func parameters_and_attributes - -/* _GL_FUNCDECL_SYS (func, rettype, parameters_and_attributes); - declares the system function, named func, with the given prototype, - consisting of return type, parameters, and attributes. - Example: - _GL_FUNCDECL_SYS (open, int, (const char *filename, int flags, ...) - _GL_ARG_NONNULL ((1))); - */ -#define _GL_FUNCDECL_SYS(func, rettype, parameters_and_attributes) \ - _GL_EXTERN_C rettype func parameters_and_attributes - -/* _GL_CXXALIAS_RPL (func, rettype, parameters); - declares a C++ alias called GNULIB_NAMESPACE::func - that redirects to rpl_func, if GNULIB_NAMESPACE is defined. - Example: - _GL_CXXALIAS_RPL (open, int, (const char *filename, int flags, ...)); - - Wrapping rpl_func in an object with an inline conversion operator - avoids a reference to rpl_func unless GNULIB_NAMESPACE::func is - actually used in the program. */ -#define _GL_CXXALIAS_RPL(func, rettype, parameters) \ - _GL_CXXALIAS_RPL_1(func, rpl_##func, rettype, parameters) -#if defined __cplusplus && defined GNULIB_NAMESPACE -#define _GL_CXXALIAS_RPL_1(func, rpl_func, rettype, parameters) \ - namespace GNULIB_NAMESPACE { \ - static const struct _gl_##func##_wrapper { \ - typedef rettype(*type) parameters; \ - \ - inline operator type() const { \ - return ::rpl_func; \ - } \ - } func = {}; \ - } \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#else -#define _GL_CXXALIAS_RPL_1(func, rpl_func, rettype, parameters) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIAS_RPL_CAST_1 (func, rpl_func, rettype, parameters); - is like _GL_CXXALIAS_RPL_1 (func, rpl_func, rettype, parameters); - except that the C function rpl_func may have a slightly different - declaration. A cast is used to silence the "invalid conversion" error - that would otherwise occur. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -#define _GL_CXXALIAS_RPL_CAST_1(func, rpl_func, rettype, parameters) \ - namespace GNULIB_NAMESPACE { \ - static const struct _gl_##func##_wrapper { \ - typedef rettype(*type) parameters; \ - \ - inline operator type() const { \ - return reinterpret_cast(::rpl_func); \ - } \ - } func = {}; \ - } \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#else -#define _GL_CXXALIAS_RPL_CAST_1(func, rpl_func, rettype, parameters) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIAS_SYS (func, rettype, parameters); - declares a C++ alias called GNULIB_NAMESPACE::func - that redirects to the system provided function func, if GNULIB_NAMESPACE - is defined. - Example: - _GL_CXXALIAS_SYS (open, int, (const char *filename, int flags, ...)); - - Wrapping func in an object with an inline conversion operator - avoids a reference to func unless GNULIB_NAMESPACE::func is - actually used in the program. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -#define _GL_CXXALIAS_SYS(func, rettype, parameters) \ - namespace GNULIB_NAMESPACE { \ - static const struct _gl_##func##_wrapper { \ - typedef rettype(*type) parameters; \ - \ - inline operator type() const { \ - return ::func; \ - } \ - } func = {}; \ - } \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#else -#define _GL_CXXALIAS_SYS(func, rettype, parameters) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIAS_SYS_CAST (func, rettype, parameters); - is like _GL_CXXALIAS_SYS (func, rettype, parameters); - except that the C function func may have a slightly different declaration. - A cast is used to silence the "invalid conversion" error that would - otherwise occur. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -#define _GL_CXXALIAS_SYS_CAST(func, rettype, parameters) \ - namespace GNULIB_NAMESPACE { \ - static const struct _gl_##func##_wrapper { \ - typedef rettype(*type) parameters; \ - \ - inline operator type() const { \ - return reinterpret_cast(::func); \ - } \ - } func = {}; \ - } \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#else -#define _GL_CXXALIAS_SYS_CAST(func, rettype, parameters) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIAS_SYS_CAST2 (func, rettype, parameters, rettype2, parameters2); - is like _GL_CXXALIAS_SYS (func, rettype, parameters); - except that the C function is picked among a set of overloaded functions, - namely the one with rettype2 and parameters2. Two consecutive casts - are used to silence the "cannot find a match" and "invalid conversion" - errors that would otherwise occur. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -/* The outer cast must be a reinterpret_cast. - The inner cast: When the function is defined as a set of overloaded - functions, it works as a static_cast<>, choosing the designated variant. - When the function is defined as a single variant, it works as a - reinterpret_cast<>. The parenthesized cast syntax works both ways. */ -#define _GL_CXXALIAS_SYS_CAST2(func, rettype, parameters, rettype2, \ - parameters2) \ - namespace GNULIB_NAMESPACE { \ - static const struct _gl_##func##_wrapper { \ - typedef rettype(*type) parameters; \ - \ - inline operator type() const { \ - return reinterpret_cast((rettype2(*) parameters2)(::func)); \ - } \ - } func = {}; \ - } \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#else -#define _GL_CXXALIAS_SYS_CAST2(func, rettype, parameters, rettype2, \ - parameters2) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIASWARN (func); - causes a warning to be emitted when ::func is used but not when - GNULIB_NAMESPACE::func is used. func must be defined without overloaded - variants. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -#define _GL_CXXALIASWARN(func) _GL_CXXALIASWARN_1(func, GNULIB_NAMESPACE) -#define _GL_CXXALIASWARN_1(func, namespace) _GL_CXXALIASWARN_2(func, namespace) -/* To work around GCC bug , - we enable the warning only when not optimizing. */ -#if !__OPTIMIZE__ -#define _GL_CXXALIASWARN_2(func, namespace) \ - _GL_WARN_ON_USE(func, \ - "The symbol ::" #func " refers to the system function. " \ - "Use " #namespace "::" #func " instead.") -#elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING -#define _GL_CXXALIASWARN_2(func, namespace) extern __typeof__(func) func -#else -#define _GL_CXXALIASWARN_2(func, namespace) _GL_EXTERN_C int _gl_cxxalias_dummy -#endif -#else -#define _GL_CXXALIASWARN(func) _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIASWARN1 (func, rettype, parameters_and_attributes); - causes a warning to be emitted when the given overloaded variant of ::func - is used but not when GNULIB_NAMESPACE::func is used. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -#define _GL_CXXALIASWARN1(func, rettype, parameters_and_attributes) \ - _GL_CXXALIASWARN1_1(func, rettype, parameters_and_attributes, \ - GNULIB_NAMESPACE) -#define _GL_CXXALIASWARN1_1(func, rettype, parameters_and_attributes, \ - namespace) \ - _GL_CXXALIASWARN1_2(func, rettype, parameters_and_attributes, namespace) -/* To work around GCC bug , - we enable the warning only when not optimizing. */ -#if !__OPTIMIZE__ -#define _GL_CXXALIASWARN1_2(func, rettype, parameters_and_attributes, \ - namespace) \ - _GL_WARN_ON_USE_CXX(func, rettype, parameters_and_attributes, \ - "The symbol ::" #func " refers to the system function. " \ - "Use " #namespace "::" #func " instead.") -#elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING -#define _GL_CXXALIASWARN1_2(func, rettype, parameters_and_attributes, \ - namespace) \ - extern __typeof__(func) func -#else -#define _GL_CXXALIASWARN1_2(func, rettype, parameters_and_attributes, \ - namespace) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif -#else -#define _GL_CXXALIASWARN1(func, rettype, parameters_and_attributes) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -#endif /* _GL_CXXDEFS_H */ - -/* The definition of _GL_ARG_NONNULL is copied here. */ -/* A C macro for declaring that specific arguments must not be NULL. - Copyright (C) 2009-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -/* _GL_ARG_NONNULL((n,...,m)) tells the compiler and static analyzer tools - that the values passed as arguments n, ..., m must be non-NULL pointers. - n = 1 stands for the first argument, n = 2 for the second argument etc. */ -#ifndef _GL_ARG_NONNULL -#if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || __GNUC__ > 3 -#define _GL_ARG_NONNULL(params) __attribute__((__nonnull__ params)) -#else -#define _GL_ARG_NONNULL(params) -#endif -#endif - -/* The definition of _GL_WARN_ON_USE is copied here. */ -/* A C macro for emitting warnings if a function is used. - Copyright (C) 2010-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -/* _GL_WARN_ON_USE (function, "literal string") issues a declaration - for FUNCTION which will then trigger a compiler warning containing - the text of "literal string" anywhere that function is called, if - supported by the compiler. If the compiler does not support this - feature, the macro expands to an unused extern declaration. - - _GL_WARN_ON_USE_ATTRIBUTE ("literal string") expands to the - attribute used in _GL_WARN_ON_USE. If the compiler does not support - this feature, it expands to empty. - - These macros are useful for marking a function as a potential - portability trap, with the intent that "literal string" include - instructions on the replacement function that should be used - instead. - _GL_WARN_ON_USE is for functions with 'extern' linkage. - _GL_WARN_ON_USE_ATTRIBUTE is for functions with 'static' or 'inline' - linkage. - - However, one of the reasons that a function is a portability trap is - if it has the wrong signature. Declaring FUNCTION with a different - signature in C is a compilation error, so this macro must use the - same type as any existing declaration so that programs that avoid - the problematic FUNCTION do not fail to compile merely because they - included a header that poisoned the function. But this implies that - _GL_WARN_ON_USE is only safe to use if FUNCTION is known to already - have a declaration. Use of this macro implies that there must not - be any other macro hiding the declaration of FUNCTION; but - undefining FUNCTION first is part of the poisoning process anyway - (although for symbols that are provided only via a macro, the result - is a compilation error rather than a warning containing - "literal string"). Also note that in C++, it is only safe to use if - FUNCTION has no overloads. - - For an example, it is possible to poison 'getline' by: - [getline]) in configure.ac, which potentially defines - HAVE_RAW_DECL_GETLINE - - adding this code to a header that wraps the system : - #undef getline - #if HAVE_RAW_DECL_GETLINE - _GL_WARN_ON_USE (getline, "getline is required by POSIX 2008, but" - "not universally present; use the gnulib module getline"); - #endif - - It is not possible to directly poison global variables. But it is - possible to write a wrapper accessor function, and poison that - (less common usage, like &environ, will cause a compilation error - rather than issue the nice warning, but the end result of informing - the developer about their portability problem is still achieved): - #if HAVE_RAW_DECL_ENVIRON - static char *** - rpl_environ (void) { return &environ; } - _GL_WARN_ON_USE (rpl_environ, "environ is not always properly declared"); - # undef environ - # define environ (*rpl_environ ()) - #endif - or better (avoiding contradictory use of 'static' and 'extern'): - #if HAVE_RAW_DECL_ENVIRON - static char *** - _GL_WARN_ON_USE_ATTRIBUTE ("environ is not always properly declared") - rpl_environ (void) { return &environ; } - # undef environ - # define environ (*rpl_environ ()) - #endif - */ -#ifndef _GL_WARN_ON_USE - -#if 4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) -/* A compiler attribute is available in gcc versions 4.3.0 and later. */ -#define _GL_WARN_ON_USE(function, message) \ - extern __typeof__(function) function __attribute__((__warning__(message))) -#define _GL_WARN_ON_USE_ATTRIBUTE(message) __attribute__((__warning__(message))) -#elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING -/* Verify the existence of the function. */ -#define _GL_WARN_ON_USE(function, message) extern __typeof__(function) function -#define _GL_WARN_ON_USE_ATTRIBUTE(message) -#else /* Unsupported. */ -#define _GL_WARN_ON_USE(function, message) _GL_WARN_EXTERN_C int _gl_warn_on_use -#define _GL_WARN_ON_USE_ATTRIBUTE(message) -#endif -#endif - -/* _GL_WARN_ON_USE_CXX (function, rettype, parameters_and_attributes, "string") - is like _GL_WARN_ON_USE (function, "string"), except that the function is - declared with the given prototype, consisting of return type, parameters, - and attributes. - This variant is useful for overloaded functions in C++. _GL_WARN_ON_USE does - not work in this case. */ -#ifndef _GL_WARN_ON_USE_CXX -#if 4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) -#define _GL_WARN_ON_USE_CXX(function, rettype, parameters_and_attributes, msg) \ - extern rettype function parameters_and_attributes \ - __attribute__((__warning__(msg))) -#elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING -/* Verify the existence of the function. */ -#define _GL_WARN_ON_USE_CXX(function, rettype, parameters_and_attributes, msg) \ - extern rettype function parameters_and_attributes -#else /* Unsupported. */ -#define _GL_WARN_ON_USE_CXX(function, rettype, parameters_and_attributes, msg) \ - _GL_WARN_EXTERN_C int _gl_warn_on_use -#endif -#endif - -/* _GL_WARN_EXTERN_C declaration; - performs the declaration with C linkage. */ -#ifndef _GL_WARN_EXTERN_C -#if defined __cplusplus -#define _GL_WARN_EXTERN_C extern "C" -#else -#define _GL_WARN_EXTERN_C extern -#endif -#endif - -/* Declare overridden functions. */ - -#if 0 -#if 0 -#if !(defined __cplusplus && defined GNULIB_NAMESPACE) -#undef creat -#define creat rpl_creat -#endif -_GL_FUNCDECL_RPL (creat, int, (const char *filename, mode_t mode) - _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (creat, int, (const char *filename, mode_t mode)); -#else -_GL_CXXALIAS_SYS (creat, int, (const char *filename, mode_t mode)); -#endif -_GL_CXXALIASWARN (creat); -#elif defined GNULIB_POSIXCHECK -#undef creat -/* Assume creat is always declared. */ -_GL_WARN_ON_USE(creat, "creat is not always POSIX compliant - " - "use gnulib module creat for portability"); -#endif - -#if 1 -#if 1 -#if !(defined __cplusplus && defined GNULIB_NAMESPACE) -#undef fcntl -#define fcntl rpl_fcntl -#endif -_GL_FUNCDECL_RPL(fcntl, int, (int fd, int action, ...)); -_GL_CXXALIAS_RPL(fcntl, int, (int fd, int action, ...)); -#else -#if !1 -_GL_FUNCDECL_SYS(fcntl, int, (int fd, int action, ...)); -#endif -_GL_CXXALIAS_SYS(fcntl, int, (int fd, int action, ...)); -#endif -_GL_CXXALIASWARN(fcntl); -#elif defined GNULIB_POSIXCHECK -#undef fcntl -#if HAVE_RAW_DECL_FCNTL -_GL_WARN_ON_USE(fcntl, "fcntl is not always POSIX compliant - " - "use gnulib module fcntl for portability"); -#endif -#endif - -#if 0 -#if 0 -#if !(defined __cplusplus && defined GNULIB_NAMESPACE) -#undef open -#define open rpl_open -#endif -_GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...) - _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (open, int, (const char *filename, int flags, ...)); -#else -_GL_CXXALIAS_SYS (open, int, (const char *filename, int flags, ...)); -#endif -/* On HP-UX 11, in C++ mode, open() is defined as an inline function with a - default argument. _GL_CXXALIASWARN does not work in this case. */ -#if !defined __hpux -_GL_CXXALIASWARN (open); -#endif -#elif defined GNULIB_POSIXCHECK -#undef open -/* Assume open is always declared. */ -_GL_WARN_ON_USE(open, "open is not always POSIX compliant - " - "use gnulib module open for portability"); -#endif - -#if 0 -#if 0 -#if !(defined __cplusplus && defined GNULIB_NAMESPACE) -#undef openat -#define openat rpl_openat -#endif -_GL_FUNCDECL_RPL (openat, int, - (int fd, char const *file, int flags, /* mode_t mode */ ...) - _GL_ARG_NONNULL ((2))); -_GL_CXXALIAS_RPL (openat, int, - (int fd, char const *file, int flags, /* mode_t mode */ ...)); -#else -#if !1 -_GL_FUNCDECL_SYS (openat, int, - (int fd, char const *file, int flags, /* mode_t mode */ ...) - _GL_ARG_NONNULL ((2))); -#endif -_GL_CXXALIAS_SYS (openat, int, - (int fd, char const *file, int flags, /* mode_t mode */ ...)); -#endif -_GL_CXXALIASWARN (openat); -#elif defined GNULIB_POSIXCHECK -#undef openat -#if HAVE_RAW_DECL_OPENAT -_GL_WARN_ON_USE(openat, "openat is not portable - " - "use gnulib module openat for portability"); -#endif -#endif - -/* Fix up the FD_* macros, only known to be missing on mingw. */ - -#ifndef FD_CLOEXEC -#define FD_CLOEXEC 1 -#endif - -/* Fix up the supported F_* macros. Intentionally leave other F_* - macros undefined. Only known to be missing on mingw. */ - -#ifndef F_DUPFD_CLOEXEC -#define F_DUPFD_CLOEXEC 0x40000000 -/* Witness variable: 1 if gnulib defined F_DUPFD_CLOEXEC, 0 otherwise. */ -#define GNULIB_defined_F_DUPFD_CLOEXEC 1 -#else -#define GNULIB_defined_F_DUPFD_CLOEXEC 0 -#endif - -#ifndef F_DUPFD -#define F_DUPFD 1 -#endif - -#ifndef F_GETFD -#define F_GETFD 2 -#endif - -/* Fix up the O_* macros. */ - -#if !defined O_DIRECT && defined O_DIRECTIO -/* Tru64 spells it 'O_DIRECTIO'. */ -#define O_DIRECT O_DIRECTIO -#endif - -#if !defined O_CLOEXEC && defined O_NOINHERIT -/* Mingw spells it 'O_NOINHERIT'. */ -#define O_CLOEXEC O_NOINHERIT -#endif - -#ifndef O_CLOEXEC -#define O_CLOEXEC 0x40000000 /* Try to not collide with system O_* flags. */ -#define GNULIB_defined_O_CLOEXEC 1 -#else -#define GNULIB_defined_O_CLOEXEC 0 -#endif - -#ifndef O_DIRECT -#define O_DIRECT 0 -#endif - -#ifndef O_DIRECTORY -#define O_DIRECTORY 0 -#endif - -#ifndef O_DSYNC -#define O_DSYNC 0 -#endif - -#ifndef O_EXEC -#define O_EXEC O_RDONLY /* This is often close enough in older systems. */ -#endif - -#ifndef O_IGNORE_CTTY -#define O_IGNORE_CTTY 0 -#endif - -#ifndef O_NDELAY -#define O_NDELAY 0 -#endif - -#ifndef O_NOATIME -#define O_NOATIME 0 -#endif - -#ifndef O_NONBLOCK -#define O_NONBLOCK O_NDELAY -#endif - -/* If the gnulib module 'nonblocking' is in use, guarantee a working non-zero - value of O_NONBLOCK. Otherwise, O_NONBLOCK is defined (above) to O_NDELAY - or to 0 as fallback. */ -#if 0 -#if O_NONBLOCK -#define GNULIB_defined_O_NONBLOCK 0 -#else -#define GNULIB_defined_O_NONBLOCK 1 -#undef O_NONBLOCK -#define O_NONBLOCK 0x40000000 -#endif -#endif - -#ifndef O_NOCTTY -#define O_NOCTTY 0 -#endif - -#ifndef O_NOFOLLOW -#define O_NOFOLLOW 0 -#endif - -#ifndef O_NOLINK -#define O_NOLINK 0 -#endif - -#ifndef O_NOLINKS -#define O_NOLINKS 0 -#endif - -#ifndef O_NOTRANS -#define O_NOTRANS 0 -#endif - -#ifndef O_RSYNC -#define O_RSYNC 0 -#endif - -#ifndef O_SEARCH -#define O_SEARCH O_RDONLY /* This is often close enough in older systems. */ -#endif - -#ifndef O_SYNC -#define O_SYNC 0 -#endif - -#ifndef O_TTY_INIT -#define O_TTY_INIT 0 -#endif - -#if ~O_ACCMODE & (O_RDONLY | O_WRONLY | O_RDWR | O_EXEC | O_SEARCH) -#undef O_ACCMODE -#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR | O_EXEC | O_SEARCH) -#endif - -/* For systems that distinguish between text and binary I/O. - O_BINARY is usually declared in fcntl.h */ -#if !defined O_BINARY && defined _O_BINARY -/* For MSC-compatible compilers. */ -#define O_BINARY _O_BINARY -#define O_TEXT _O_TEXT -#endif - -#if defined __BEOS__ || defined __HAIKU__ -/* BeOS 5 and Haiku have O_BINARY and O_TEXT, but they have no effect. */ -#undef O_BINARY -#undef O_TEXT -#endif - -#ifndef O_BINARY -#define O_BINARY 0 -#define O_TEXT 0 -#endif - -/* Fix up the AT_* macros. */ - -/* Work around a bug in Solaris 9 and 10: AT_FDCWD is positive. Its - value exceeds INT_MAX, so its use as an int doesn't conform to the - C standard, and GCC and Sun C complain in some cases. If the bug - is present, undef AT_FDCWD here, so it can be redefined below. */ -#if 0 < AT_FDCWD && AT_FDCWD == 0xffd19553 -#undef AT_FDCWD -#endif - -/* Use the same bit pattern as Solaris 9, but with the proper - signedness. The bit pattern is important, in case this actually is - Solaris with the above workaround. */ -#ifndef AT_FDCWD -#define AT_FDCWD (-3041965) -#endif - -/* Use the same values as Solaris 9. This shouldn't matter, but - there's no real reason to differ. */ -#ifndef AT_SYMLINK_NOFOLLOW -#define AT_SYMLINK_NOFOLLOW 4096 -#endif - -#ifndef AT_REMOVEDIR -#define AT_REMOVEDIR 1 -#endif - -/* Solaris 9 lacks these two, so just pick unique values. */ -#ifndef AT_SYMLINK_FOLLOW -#define AT_SYMLINK_FOLLOW 2 -#endif - -#ifndef AT_EACCESS -#define AT_EACCESS 4 -#endif - -#endif /* _GL_FCNTL_H */ -#endif /* _GL_FCNTL_H */ -#endif diff --git a/third_party/make/fd-hook.c b/third_party/make/fd-hook.c deleted file mode 100644 index 852e4ab2c..000000000 --- a/third_party/make/fd-hook.c +++ /dev/null @@ -1,114 +0,0 @@ -/* Hook for making file descriptor functions close(), ioctl() extensible. - Copyright (C) 2009-2020 Free Software Foundation, Inc. - Written by Bruno Haible , 2009. - - 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 . */ - -#include "third_party/make/config.h" - -/* Specification. */ -#include "third_party/make/fd-hook.h" - -/* Currently, this entire code is only needed for the handling of sockets - on native Windows platforms. */ -#if WINDOWS_SOCKETS - -/* The first and last link in the doubly linked list. - Initially the list is empty. */ -static struct fd_hook anchor = { &anchor, &anchor, NULL, NULL }; - -int -execute_close_hooks (const struct fd_hook *remaining_list, gl_close_fn primary, - int fd) -{ - if (remaining_list == &anchor) - /* End of list reached. */ - return primary (fd); - else - return remaining_list->private_close_fn (remaining_list->private_next, - primary, fd); -} - -int -execute_all_close_hooks (gl_close_fn primary, int fd) -{ - return execute_close_hooks (anchor.private_next, primary, fd); -} - -int -execute_ioctl_hooks (const struct fd_hook *remaining_list, gl_ioctl_fn primary, - int fd, int request, void *arg) -{ - if (remaining_list == &anchor) - /* End of list reached. */ - return primary (fd, request, arg); - else - return remaining_list->private_ioctl_fn (remaining_list->private_next, - primary, fd, request, arg); -} - -int -execute_all_ioctl_hooks (gl_ioctl_fn primary, - int fd, int request, void *arg) -{ - return execute_ioctl_hooks (anchor.private_next, primary, fd, request, arg); -} - -void -register_fd_hook (close_hook_fn close_hook, ioctl_hook_fn ioctl_hook, struct fd_hook *link) -{ - if (close_hook == NULL) - close_hook = execute_close_hooks; - if (ioctl_hook == NULL) - ioctl_hook = execute_ioctl_hooks; - - if (link->private_next == NULL && link->private_prev == NULL) - { - /* Add the link to the doubly linked list. */ - link->private_next = anchor.private_next; - link->private_prev = &anchor; - link->private_close_fn = close_hook; - link->private_ioctl_fn = ioctl_hook; - anchor.private_next->private_prev = link; - anchor.private_next = link; - } - else - { - /* The link is already in use. */ - if (link->private_close_fn != close_hook - || link->private_ioctl_fn != ioctl_hook) - abort (); - } -} - -void -unregister_fd_hook (struct fd_hook *link) -{ - struct fd_hook *next = link->private_next; - struct fd_hook *prev = link->private_prev; - - if (next != NULL && prev != NULL) - { - /* The link is in use. Remove it from the doubly linked list. */ - prev->private_next = next; - next->private_prev = prev; - /* Clear the link, to mark it unused. */ - link->private_next = NULL; - link->private_prev = NULL; - link->private_close_fn = NULL; - link->private_ioctl_fn = NULL; - } -} - -#endif diff --git a/third_party/make/fd-hook.h b/third_party/make/fd-hook.h deleted file mode 100644 index ed1a15a23..000000000 --- a/third_party/make/fd-hook.h +++ /dev/null @@ -1,119 +0,0 @@ -/* Hook for making file descriptor functions close(), ioctl() extensible. - Copyright (C) 2009-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - - -#ifndef FD_HOOK_H -#define FD_HOOK_H - -#ifdef __cplusplus -extern "C" { -#endif - - -/* Currently, this entire code is only needed for the handling of sockets - on native Windows platforms. */ -#if WINDOWS_SOCKETS - - -/* Type of function that closes FD. */ -typedef int (*gl_close_fn) (int fd); - -/* Type of function that applies a control request to FD. */ -typedef int (*gl_ioctl_fn) (int fd, int request, void *arg); - -/* An element of the list of file descriptor hooks. - In CLOS (Common Lisp Object System) speak, it consists of an "around" - method for the close() function and an "around" method for the ioctl() - function. - The fields of this structure are considered private. */ -struct fd_hook -{ - /* Doubly linked list. */ - struct fd_hook *private_next; - struct fd_hook *private_prev; - /* Function that treats the types of FD that it knows about and calls - execute_close_hooks (REMAINING_LIST, PRIMARY, FD) as a fallback. */ - int (*private_close_fn) (const struct fd_hook *remaining_list, - gl_close_fn primary, - int fd); - /* Function that treats the types of FD that it knows about and calls - execute_ioctl_hooks (REMAINING_LIST, PRIMARY, FD, REQUEST, ARG) as a - fallback. */ - int (*private_ioctl_fn) (const struct fd_hook *remaining_list, - gl_ioctl_fn primary, - int fd, int request, void *arg); -}; - -/* This type of function closes FD, applying special knowledge for the FD - types it knows about, and calls - execute_close_hooks (REMAINING_LIST, PRIMARY, FD) - for the other FD types. - In CLOS speak, REMAINING_LIST is the remaining list of "around" methods, - and PRIMARY is the "primary" method for close(). */ -typedef int (*close_hook_fn) (const struct fd_hook *remaining_list, - gl_close_fn primary, - int fd); - -/* Execute the close hooks in REMAINING_LIST, with PRIMARY as "primary" method. - Return 0 or -1, like close() would do. */ -extern int execute_close_hooks (const struct fd_hook *remaining_list, - gl_close_fn primary, - int fd); - -/* Execute all close hooks, with PRIMARY as "primary" method. - Return 0 or -1, like close() would do. */ -extern int execute_all_close_hooks (gl_close_fn primary, int fd); - -/* This type of function applies a control request to FD, applying special - knowledge for the FD types it knows about, and calls - execute_ioctl_hooks (REMAINING_LIST, PRIMARY, FD, REQUEST, ARG) - for the other FD types. - In CLOS speak, REMAINING_LIST is the remaining list of "around" methods, - and PRIMARY is the "primary" method for ioctl(). */ -typedef int (*ioctl_hook_fn) (const struct fd_hook *remaining_list, - gl_ioctl_fn primary, - int fd, int request, void *arg); - -/* Execute the ioctl hooks in REMAINING_LIST, with PRIMARY as "primary" method. - Return 0 or -1, like ioctl() would do. */ -extern int execute_ioctl_hooks (const struct fd_hook *remaining_list, - gl_ioctl_fn primary, - int fd, int request, void *arg); - -/* Execute all ioctl hooks, with PRIMARY as "primary" method. - Return 0 or -1, like ioctl() would do. */ -extern int execute_all_ioctl_hooks (gl_ioctl_fn primary, - int fd, int request, void *arg); - -/* Add a function pair to the list of file descriptor hooks. - CLOSE_HOOK and IOCTL_HOOK may be NULL, indicating no change. - The LINK variable points to a piece of memory which is guaranteed to be - accessible until the corresponding call to unregister_fd_hook. */ -extern void register_fd_hook (close_hook_fn close_hook, ioctl_hook_fn ioctl_hook, - struct fd_hook *link); - -/* Removes a hook from the list of file descriptor hooks. */ -extern void unregister_fd_hook (struct fd_hook *link); - - -#endif - - -#ifdef __cplusplus -} -#endif - -#endif /* FD_HOOK_H */ diff --git a/third_party/make/file.c b/third_party/make/file.c index 991a3f5e7..d07af4e59 100644 --- a/third_party/make/file.c +++ b/third_party/make/file.c @@ -1,5 +1,5 @@ /* Target file management for GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,20 +12,20 @@ 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 . */ +this program. If not, see . */ -#include "third_party/make/makeint.inc" -/**/ -#include "third_party/make/filedef.h" -#include "third_party/make/dep.h" -#include "third_party/make/job.h" -#include "third_party/make/commands.h" -#include "third_party/make/variable.h" -#include "third_party/make/debug.h" -#include "libc/assert.h" -#include "libc/sysv/consts/clock.h" -#include "libc/runtime/runtime.h" -#include "third_party/make/hash.h" +#include "makeint.h" + +#include + +#include "filedef.h" +#include "dep.h" +#include "job.h" +#include "commands.h" +#include "variable.h" +#include "debug.h" +#include "hash.h" +#include "shuffle.h" /* Remember whether snap_deps has been invoked: we need this to be sure we @@ -73,23 +73,42 @@ lookup_file (const char *name) { struct file *f; struct file file_key; +#ifdef VMS + int want_vmsify; +#ifndef WANT_CASE_SENSITIVE_TARGETS + char *lname; +#endif +#endif assert (*name != '\0'); - while (name[0] == '.' -#ifdef HAVE_DOS_PATHS - && (name[1] == '/' || name[1] == '\\') -#else - && name[1] == '/' + /* This is also done in parse_file_seq, so this is redundant + for names read from makefiles. It is here for names passed + on the command line. */ +#ifdef VMS + want_vmsify = (strpbrk (name, "]>:^") != NULL); +# ifndef WANT_CASE_SENSITIVE_TARGETS + if (*name != '.') + { + const char *n; + char *ln; + lname = xstrdup (name); + for (n = name, ln = lname; *n != '\0'; ++n, ++ln) + *ln = isupper ((unsigned char)*n) ? tolower ((unsigned char)*n) : *n; + *ln = '\0'; + name = lname; + } +# endif + + while (name[0] == '[' && name[1] == ']' && name[2] != '\0') + name += 2; + while (name[0] == '<' && name[1] == '>' && name[2] != '\0') + name += 2; #endif - && name[2] != '\0') + while (name[0] == '.' && ISDIRSEP (name[1]) && name[2] != '\0') { name += 2; - while (*name == '/' -#ifdef HAVE_DOS_PATHS - || *name == '\\' -#endif - ) + while (ISDIRSEP (*name)) /* Skip following slashes: ".//foo" is "foo", not "/foo". */ ++name; } @@ -97,10 +116,23 @@ lookup_file (const char *name) if (*name == '\0') { /* It was all slashes after a dot. */ +#if defined(_AMIGA) + name = ""; +#else name = "./"; +#endif +#if defined(VMS) + /* TODO - This section is probably not needed. */ + if (want_vmsify) + name = "[]"; +#endif } file_key.hname = name; f = hash_find_item (&files, &file_key); +#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS) + if (*name != '.') + free (lname); +#endif return f; } @@ -121,6 +153,24 @@ enter_file (const char *name) assert (*name != '\0'); assert (! verify_flag || strcache_iscached (name)); +#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS) + if (*name != '.') + { + const char *n; + char *lname, *ln; + lname = xstrdup (name); + for (n = name, ln = lname; *n != '\0'; ++n, ++ln) + if (isupper ((unsigned char)*n)) + *ln = tolower ((unsigned char)*n); + else + *ln = *n; + + *ln = '\0'; + name = strcache_add (lname); + free (lname); + } +#endif + file_key.hname = name; file_slot = (struct file **) hash_find_slot (&files, &file_key); f = *file_slot; @@ -130,7 +180,7 @@ enter_file (const char *name) return f; } - new = xcalloc (1, sizeof (struct file)); + new = xcalloc (sizeof (struct file)); new->name = new->hname = name; new->update_status = us_none; @@ -211,14 +261,14 @@ rehash_file (struct file *from_file, const char *to_hname) { size_t l = strlen (from_file->name); /* We have two sets of commands. We will go with the - one given in the rule explicitly mentioning this name, + one given in the rule found through directory search, but give a message to let the user know what's going on. */ if (to_file->cmds->fileinfo.filenm != 0) error (&from_file->cmds->fileinfo, l + strlen (to_file->cmds->fileinfo.filenm) + INTSTR_LENGTH, _("Recipe was specified for file '%s' at %s:%lu,"), - from_file->name, to_file->cmds->fileinfo.filenm, - to_file->cmds->fileinfo.lineno); + from_file->name, from_file->cmds->fileinfo.filenm, + from_file->cmds->fileinfo.lineno); else error (&from_file->cmds->fileinfo, l, _("Recipe for file '%s' was found by implicit rule search,"), @@ -229,7 +279,7 @@ rehash_file (struct file *from_file, const char *to_hname) from_file->name, to_hname); error (&from_file->cmds->fileinfo, l, _("Recipe for '%s' will be ignored in favor of the one for '%s'."), - to_hname, from_file->name); + from_file->name, to_hname); } } @@ -268,14 +318,19 @@ rehash_file (struct file *from_file, const char *to_hname) #define MERGE(field) to_file->field |= from_file->field MERGE (precious); + MERGE (loaded); MERGE (tried_implicit); MERGE (updating); MERGE (updated); MERGE (is_target); MERGE (cmd_target); MERGE (phony); - MERGE (loaded); + /* Don't merge intermediate because this file might be pre-existing */ + MERGE (is_explicit); + MERGE (secondary); + MERGE (notintermediate); MERGE (ignore_vpath); + MERGE (snapped); #undef MERGE to_file->builtin = 0; @@ -310,7 +365,7 @@ remove_intermediates (int sig) int doneany = 0; /* If there's no way we will ever remove anything anyway, punt early. */ - if (question_flag || touch_flag || all_secondary) + if (question_flag || touch_flag || all_secondary || no_intermediates) return; if (sig && just_print_flag) @@ -327,7 +382,7 @@ remove_intermediates (int sig) given on the command line, and it's either a -include makefile or it's not precious. */ if (f->intermediate && (f->dontcare || !f->precious) - && !f->secondary && !f->cmd_target) + && !f->secondary && !f->notintermediate && !f->cmd_target) { int status; if (f->update_status == us_none) @@ -365,7 +420,11 @@ remove_intermediates (int sig) } } if (status < 0) - perror_with_name ("unlink: ", f->name); + { + perror_with_name ("\nunlink: ", f->name); + /* Start printing over. */ + doneany = 0; + } } } } @@ -383,8 +442,7 @@ remove_intermediates (int sig) struct dep * split_prereqs (char *p) { - struct dep *new = PARSE_FILE_SEQ (&p, struct dep, MAP_PIPE, NULL, - PARSEFS_NONE); + struct dep *new = PARSE_FILE_SEQ (&p, struct dep, MAP_PIPE, NULL, PARSEFS_WAIT); if (*p) { @@ -393,7 +451,7 @@ split_prereqs (char *p) struct dep *ood; ++p; - ood = PARSE_SIMPLE_SEQ (&p, struct dep); + ood = PARSE_FILE_SEQ (&p, struct dep, MAP_NUL, NULL, PARSEFS_WAIT); if (! new) new = ood; @@ -427,7 +485,6 @@ enter_prereqs (struct dep *deps, const char *stem) if (stem) { const char *pattern = "%"; - char *buffer = variable_expand (""); struct dep *dp = deps, *dl = 0; while (dp != 0) @@ -447,14 +504,15 @@ enter_prereqs (struct dep *deps, const char *stem) if (stem[0] == '\0') { memmove (percent, percent+1, strlen (percent)); - o = variable_buffer_output (buffer, nm, strlen (nm) + 1); + o = variable_buffer_output (variable_buffer, nm, + strlen (nm) + 1); } else - o = patsubst_expand_pat (buffer, stem, pattern, nm, + o = patsubst_expand_pat (variable_buffer, stem, pattern, nm, pattern+1, percent+1); /* If the name expanded to the empty string, ignore it. */ - if (buffer[0] == '\0') + if (variable_buffer[0] == '\0') { struct dep *df = dp; if (dp == deps) @@ -466,7 +524,8 @@ enter_prereqs (struct dep *deps, const char *stem) } /* Save the name. */ - dp->name = strcache_add_len (buffer, o - buffer); + dp->name = strcache_add_len (variable_buffer, + o - variable_buffer); } dp->stem = stem; dp->staticpattern = 1; @@ -486,21 +545,29 @@ enter_prereqs (struct dep *deps, const char *stem) d1->file = enter_file (d1->name); d1->staticpattern = 0; d1->name = 0; + if (!stem) + /* This file is explicitly mentioned as a prereq. */ + d1->file->is_explicit = 1; } return deps; } -/* Expand and parse each dependency line. */ -static void +/* Expand and parse each dependency line. + For each dependency of the file, make the 'struct dep' point + at the appropriate 'struct file' (which may have to be created). */ +void expand_deps (struct file *f) { struct dep *d; struct dep **dp; - const char *file_stem = f->stem; + const char *fstem; int initialized = 0; + int changed_dep = 0; - f->updating = 0; + if (f->snapped) + return; + f->snapped = 1; /* Walk through the dependencies. For any dependency that needs 2nd expansion, expand it then insert the result into the list. */ @@ -510,7 +577,6 @@ expand_deps (struct file *f) { char *p; struct dep *new, *next; - char *name = (char *)d->name; if (! d->name || ! d->need_2nd_expansion) { @@ -520,16 +586,46 @@ expand_deps (struct file *f) continue; } - /* If it's from a static pattern rule, convert the patterns into - "$*" so they'll expand properly. */ + /* If it's from a static pattern rule, convert the initial pattern in + each word to "$*" so they'll expand properly. */ if (d->staticpattern) { - char *o = variable_expand (""); - o = subst_expand (o, name, "%", "$*", 1, 2, 0); - *o = '\0'; - free (name); - d->name = name = xstrdup (variable_buffer); - d->staticpattern = 0; + const char *cs = d->name; + size_t nperc = 0; + + /* Count the number of % in the string. */ + while ((cs = strchr (cs, '%')) != NULL) + { + ++nperc; + ++cs; + } + + if (nperc) + { + /* Allocate enough space to replace all % with $*. */ + size_t slen = strlen (d->name) + nperc + 1; + const char *pcs = d->name; + char *name = xmalloc (slen); + char *s = name; + + /* Substitute the first % in each word. */ + cs = strchr (pcs, '%'); + + while (cs) + { + s = mempcpy (s, pcs, cs - pcs); + *(s++) = '$'; + *(s++) = '*'; + pcs = ++cs; + + /* Find the first % after the next whitespace. */ + cs = strchr (end_of_token (cs), '%'); + } + strcpy (s, pcs); + + free ((char*)d->name); + d->name = name; + } } /* We're going to do second expansion so initialize file variables for @@ -541,39 +637,53 @@ expand_deps (struct file *f) initialized = 1; } - if (d->stem != 0) - f->stem = d->stem; - - set_file_variables (f); + set_file_variables (f, d->stem ? d->stem : f->stem); + /* Perform second expansion. */ p = variable_expand_for_file (d->name, f); - if (d->stem != 0) - f->stem = file_stem; - - /* At this point we don't need the name anymore: free it. */ - free (name); + /* Free the un-expanded name. */ + free ((char*)d->name); /* Parse the prerequisites and enter them into the file database. */ - new = enter_prereqs (split_prereqs (p), d->stem); + new = split_prereqs (p); /* If there were no prereqs here (blank!) then throw this one out. */ if (new == 0) { *dp = d->next; + changed_dep = 1; free_dep (d); d = *dp; continue; } /* Add newly parsed prerequisites. */ + fstem = d->stem; next = d->next; + changed_dep = 1; + free_dep (d); *dp = new; - for (dp = &new->next, d = new->next; d != 0; dp = &d->next, d = d->next) - ; + for (dp = &new, d = new; d != 0; dp = &d->next, d = d->next) + { + d->file = lookup_file (d->name); + if (d->file == 0) + d->file = enter_file (d->name); + d->name = 0; + d->stem = fstem; + if (!fstem) + /* This file is explicitly mentioned as a prereq. */ + d->file->is_explicit = 1; + } *dp = next; d = *dp; } + + /* Shuffle mode assumes '->next' and '->shuf' links both traverse the same + dependencies (in different sequences). Regenerate '->shuf' so we don't + refer to stale data. */ + if (changed_dep) + shuffle_deps_recursive (f->deps); } /* Add extra prereqs to the file in question. */ @@ -608,10 +718,18 @@ snap_file (const void *item, void *arg) if (!second_expansion) f->updating = 0; - /* If .SECONDARY is set with no deps, mark all targets as intermediate. */ - if (all_secondary) + /* More specific setting has priority. */ + + /* If .SECONDARY is set with no deps, mark all targets as intermediate, + unless the target is a prereq of .NOTINTERMEDIATE. */ + if (all_secondary && !f->notintermediate) f->intermediate = 1; + /* If .NOTINTERMEDIATE is set with no deps, mark all targets as + notintermediate, unless the target is a prereq of .INTERMEDIATE. */ + if (no_intermediates && !f->intermediate && !f->secondary) + f->notintermediate = 1; + /* If .EXTRA_PREREQS is set, add them as ignored by automatic variables. */ if (f->variables) prereqs = expand_extra_prereqs (lookup_variable_in_set (STRING_SIZE_TUPLE(".EXTRA_PREREQS"), f->variables->set)); @@ -642,10 +760,7 @@ snap_file (const void *item, void *arg) } } -/* For each dependency of each file, make the 'struct dep' point - at the appropriate 'struct file' (which may have to be created). - - Also mark the files depended on by .PRECIOUS, .PHONY, .SILENT, +/* Mark the files depended on by .PRECIOUS, .PHONY, .SILENT, and various other special targets. */ void @@ -659,37 +774,6 @@ snap_deps (void) longer define new targets. */ snapped_deps = 1; - /* Perform second expansion and enter each dependency name as a file. We - must use hash_dump() here because within these loops we likely add new - files to the table, possibly causing an in-situ table expansion. - - We only need to do this if second_expansion has been defined; if it - hasn't then all deps were expanded as the makefile was read in. If we - ever change make to be able to unset .SECONDARY_EXPANSION this will have - to change. */ - - if (second_expansion) - { - struct file **file_slot_0 = (struct file **) hash_dump (&files, 0, 0); - struct file **file_end = file_slot_0 + files.ht_fill; - struct file **file_slot; - const char *suffixes; - - /* Expand .SUFFIXES: its prerequisites are used for $$* calc. */ - f = lookup_file (".SUFFIXES"); - suffixes = f ? f->name : 0; - for (; f != 0; f = f->prev) - expand_deps (f); - - /* For every target that's not .SUFFIXES, expand its prerequisites. */ - - for (file_slot = file_slot_0; file_slot < file_end; file_slot++) - for (f = *file_slot; f != 0; f = f->prev) - if (f->name != suffixes) - expand_deps (f); - free (file_slot_0); - } - /* Now manage all the special targets. */ for (f = lookup_file (".PRECIOUS"); f != 0; f = f->prev) @@ -713,11 +797,32 @@ snap_deps (void) f2->mtime_before_update = NONEXISTENT_MTIME; } + for (f = lookup_file (".NOTINTERMEDIATE"); f != 0; f = f->prev) + /* Mark .NOTINTERMEDIATE deps as notintermediate files. */ + if (f->deps) + for (d = f->deps; d != 0; d = d->next) + for (f2 = d->file; f2 != 0; f2 = f2->prev) + f2->notintermediate = 1; + /* .NOTINTERMEDIATE with no deps marks all files as notintermediate. */ + else + no_intermediates = 1; + + /* The same file cannot be both .INTERMEDIATE and .NOTINTERMEDIATE. + However, it is possible for a file to be .INTERMEDIATE and also match a + .NOTINTERMEDIATE pattern. In that case, the intermediate file has + priority over the notintermediate pattern. This priority is enforced by + pattern_search. */ + for (f = lookup_file (".INTERMEDIATE"); f != 0; f = f->prev) /* Mark .INTERMEDIATE deps as intermediate files. */ for (d = f->deps; d != 0; d = d->next) for (f2 = d->file; f2 != 0; f2 = f2->prev) - f2->intermediate = 1; + if (f2->notintermediate) + OS (fatal, NILF, + _("%s cannot be both .NOTINTERMEDIATE and .INTERMEDIATE"), + f2->name); + else + f2->intermediate = 1; /* .INTERMEDIATE with no deps does nothing. Marking all files as intermediates is useless since the goal targets would be deleted after they are built. */ @@ -727,11 +832,20 @@ snap_deps (void) if (f->deps) for (d = f->deps; d != 0; d = d->next) for (f2 = d->file; f2 != 0; f2 = f2->prev) + if (f2->notintermediate) + OS (fatal, NILF, + _("%s cannot be both .NOTINTERMEDIATE and .SECONDARY"), + f2->name); + else f2->intermediate = f2->secondary = 1; /* .SECONDARY with no deps listed marks *all* files that way. */ else all_secondary = 1; + if (no_intermediates && all_secondary) + O (fatal, NILF, + _(".NOTINTERMEDIATE and .SECONDARY are mutually exclusive")); + f = lookup_file (".EXPORT_ALL_VARIABLES"); if (f != 0 && f->is_target) export_all_variables = 1; @@ -760,7 +874,19 @@ snap_deps (void) f = lookup_file (".NOTPARALLEL"); if (f != 0 && f->is_target) - not_parallel = 1; + { + struct dep *d2; + + if (!f->deps) + not_parallel = 1; + else + /* Set a wait point between every prerequisite of each target. */ + for (d = f->deps; d != NULL; d = d->next) + for (f2 = d->file; f2 != NULL; f2 = f2->prev) + if (f2->deps) + for (d2 = f2->deps->next; d2 != NULL; d2 = d2->next) + d2->wait_here = 1; + } { struct dep *prereqs = expand_extra_prereqs (lookup_variable (STRING_SIZE_TUPLE(".EXTRA_PREREQS"))); @@ -812,7 +938,7 @@ file_timestamp_cons (const char *fname, time_t stamp, long int ns) char buf[FILE_TIMESTAMP_PRINT_LEN_BOUND + 1]; const char *f = fname ? fname : _("Current time"); ts = s <= OLD_MTIME ? ORDINARY_MTIME_MIN : ORDINARY_MTIME_MAX; - file_timestamp_sprintf (buf, sizeof(buf), ts); + file_timestamp_sprintf (buf, ts); OSS (error, NILF, _("%s: Timestamp out of range; substituting %s"), f, buf); } @@ -832,6 +958,8 @@ file_timestamp_now (int *resolution) /* Don't bother with high-resolution clocks if file timestamps have only one-second resolution. The code below should work, but it's not worth the hassle of debugging it on hosts where it fails. */ +#if FILE_TIMESTAMP_HI_RES +# if HAVE_CLOCK_GETTIME && defined CLOCK_REALTIME { struct timespec timespec; if (clock_gettime (CLOCK_REALTIME, ×pec) == 0) @@ -842,6 +970,8 @@ file_timestamp_now (int *resolution) goto got_time; } } +# endif +# if HAVE_GETTIMEOFDAY { struct timeval timeval; if (gettimeofday (&timeval, 0) == 0) @@ -852,12 +982,16 @@ file_timestamp_now (int *resolution) goto got_time; } } +# endif +#endif r = 1000000000; s = time ((time_t *) 0); ns = 0; +#if FILE_TIMESTAMP_HI_RES got_time: +#endif *resolution = r; return file_timestamp_cons (0, s, ns); } @@ -865,37 +999,30 @@ file_timestamp_now (int *resolution) /* Place into the buffer P a printable representation of the file timestamp TS. */ void -file_timestamp_sprintf (char *p, int n, FILE_TIMESTAMP ts) +file_timestamp_sprintf (char *p, FILE_TIMESTAMP ts) { - /* - * [jart] patch weakness upstream because buffer can probably overflow - * if integer timestamp is irreguular - */ - int m; time_t t = FILE_TIMESTAMP_S (ts); struct tm *tm = localtime (&t); if (tm) - snprintf (p, n, "%04d-%02d-%02d %02d:%02d:%02d", - tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + { + intmax_t year = tm->tm_year; + sprintf (p, "%04" PRIdMAX "-%02d-%02d %02d:%02d:%02d", + year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + } else if (t < 0) - snprintf (p, n, "%ld", (long) t); + sprintf (p, "%" PRIdMAX, (intmax_t) t); else - snprintf (p, n, "%lu", (unsigned long) t); - m = strlen (p); - p += m; - n -= m; - if (n <= 0) return; + sprintf (p, "%" PRIuMAX, (uintmax_t) t); + p += strlen (p); /* Append nanoseconds as a fraction, but remove trailing zeros. We don't know the actual timestamp resolution, since clock_getres applies only to local times, whereas this timestamp might come from a remote filesystem. So removing trailing zeros is the best guess that we can do. */ - snprintf (p, n, ".%09d", FILE_TIMESTAMP_NS (ts)); - m = strlen (p) - 1; - p += m; - n += m; + sprintf (p, ".%09d", FILE_TIMESTAMP_NS (ts)); + p += strlen (p) - 1; while (*p == '0') p--; p += *p != '.'; @@ -913,17 +1040,17 @@ print_prereqs (const struct dep *deps) /* Print all normal dependencies; note any order-only deps. */ for (; deps != 0; deps = deps->next) if (! deps->ignore_mtime) - printf (" %s", dep_name (deps)); + printf (" %s%s", deps->wait_here ? ".WAIT " : "", dep_name (deps)); else if (! ood) ood = deps; /* Print order-only deps, if we have any. */ if (ood) { - printf (" | %s", dep_name (ood)); + printf (" | %s%s", ood->wait_here ? ".WAIT " : "", dep_name (ood)); for (ood = ood->next; ood != 0; ood = ood->next) if (ood->ignore_mtime) - printf (" %s", dep_name (ood)); + printf (" %s%s", ood->wait_here ? ".WAIT " : "", dep_name (ood)); } putchar ('\n'); @@ -977,6 +1104,10 @@ print_file (const void *item) printf (_("# Implicit/static pattern stem: '%s'\n"), f->stem); if (f->intermediate) puts (_("# File is an intermediate prerequisite.")); + if (f->notintermediate) + puts (_("# File is a prerequisite of .NOTINTERMEDIATE.")); + if (f->secondary) + puts (_("# File is secondary (prerequisite of .SECONDARY).")); if (f->also_make != 0) { const struct dep *d; @@ -994,7 +1125,7 @@ print_file (const void *item) else { char buf[FILE_TIMESTAMP_PRINT_LEN_BOUND + 1]; - file_timestamp_sprintf (buf, sizeof(buf), f->last_mtime); + file_timestamp_sprintf (buf, f->last_mtime); printf (_("# Last modified %s\n"), buf); } puts (f->updated @@ -1124,8 +1255,7 @@ build_target_list (char *value) p = &value[off]; } - memcpy (p, f->name, l); - p += l; + p = mempcpy (p, f->name, l); *(p++) = ' '; } *(p-1) = '\0'; @@ -1139,8 +1269,7 @@ build_target_list (char *value) void init_hash_files (void) { - // [jart] increased from 1000 - hash_init (&files, 32768, file_hash_1, file_hash_2, file_hash_cmp); + hash_init (&files, 1000, file_hash_1, file_hash_2, file_hash_cmp); } /* EOF */ diff --git a/third_party/make/filedef.h b/third_party/make/filedef.h index aab75773c..94abcff59 100644 --- a/third_party/make/filedef.h +++ b/third_party/make/filedef.h @@ -1,5 +1,5 @@ /* Definition of target file data structures for GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,13 +12,14 @@ 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 . */ +this program. If not, see . */ + /* Structure that represents the info on one file that the makefile says how to make. All of these are chained together through 'next'. */ -#include "third_party/make/hash.h" +#include "hash.h" struct commands; struct dep; @@ -62,8 +63,6 @@ struct file FILE_TIMESTAMP last_mtime; /* File's modtime, if already known. */ FILE_TIMESTAMP mtime_before_update; /* File's modtime before any updating has been performed. */ - FILE_TIMESTAMP touched; /* Set if file was created in order for - Landlock LSM to sandbox it. */ unsigned int considered; /* equal to 'considered' if file has been considered on current scan of goal chain */ int command_flags; /* Flags OR'd in for cmds; see commands.h. */ @@ -85,6 +84,7 @@ struct file unsigned int builtin:1; /* True if the file is a builtin rule. */ unsigned int precious:1; /* Non-0 means don't delete file on quit */ unsigned int loaded:1; /* True if the file is a loaded object. */ + unsigned int unloaded:1; /* True if this loaded object was unloaded. */ unsigned int low_resolution_time:1; /* Nonzero if this file's time stamp has only one-second resolution. */ unsigned int tried_implicit:1; /* Nonzero if have searched @@ -97,8 +97,11 @@ struct file unsigned int phony:1; /* Nonzero if this is a phony file i.e., a prerequisite of .PHONY. */ unsigned int intermediate:1;/* Nonzero if this is an intermediate file. */ + unsigned int is_explicit:1; /* Nonzero if explicitly mentioned. */ unsigned int secondary:1; /* Nonzero means remove_intermediates should not delete it. */ + unsigned int notintermediate:1; /* Nonzero means a file is a prereq to + .NOTINTERMEDIATE. */ unsigned int dontcare:1; /* Nonzero if no complaint is to be made if this target cannot be remade. */ unsigned int ignore_vpath:1;/* Nonzero if we threw out VPATH name. */ @@ -106,6 +109,10 @@ struct file pattern-specific variables. */ unsigned int no_diag:1; /* True if the file failed to update and no diagnostics has been issued (dontcare). */ + unsigned int was_shuffled:1; /* Did we already shuffle 'deps'? used when + --shuffle passes through the graph. */ + unsigned int snapped:1; /* True if the deps of this file have been + secondary expanded. */ }; @@ -116,6 +123,7 @@ struct file *lookup_file (const char *name); struct file *enter_file (const char *name); struct dep *split_prereqs (char *prereqstr); struct dep *enter_prereqs (struct dep *prereqs, const char *stem); +void expand_deps (struct file *f); struct dep *expand_extra_prereqs (const struct variable *extra); void remove_intermediates (int sig); void snap_deps (void); @@ -165,14 +173,14 @@ int stemlen_compare (const void *v1, const void *v2); add 4 to allow for any 4-digit epoch year (e.g. 1970); add 25 to allow for "-MM-DD HH:MM:SS.NNNNNNNNN". */ #define FLOOR_LOG2_SECONDS_PER_YEAR 24 -#define FILE_TIMESTAMP_PRINT_LEN_BOUND /* 62 */ \ +#define FILE_TIMESTAMP_PRINT_LEN_BOUND \ (((sizeof (FILE_TIMESTAMP) * CHAR_BIT - 1 - FLOOR_LOG2_SECONDS_PER_YEAR) \ * 302 / 1000) \ + 1 + 1 + 4 + 25) FILE_TIMESTAMP file_timestamp_cons (char const *, time_t, long int); FILE_TIMESTAMP file_timestamp_now (int *); -void file_timestamp_sprintf (char *, int, FILE_TIMESTAMP ); +void file_timestamp_sprintf (char *p, FILE_TIMESTAMP ts); /* Return the mtime of file F (a struct file *), caching it. The value is NONEXISTENT_MTIME if the file does not exist. */ @@ -204,6 +212,8 @@ FILE_TIMESTAMP f_mtime (struct file *file, int search); << FILE_TIMESTAMP_LO_BITS) \ + ORDINARY_MTIME_MIN + FILE_TIMESTAMPS_PER_S - 1) +#define is_ordinary_mtime(_t) ((_t) >= ORDINARY_MTIME_MIN && (_t) <= ORDINARY_MTIME_MAX) + /* Modtime value to use for 'infinitely new'. We used to get the current time from the system and use that whenever we wanted 'new'. But that causes trouble when the machine running make and the machine holding a file have diff --git a/third_party/make/filename.h b/third_party/make/filename.h index 6a9533982..a2400a9df 100644 --- a/third_party/make/filename.h +++ b/third_party/make/filename.h @@ -1,33 +1,95 @@ /* Basic filename support macros. - Copyright (C) 2001-2004, 2007-2020 Free Software Foundation, Inc. + Copyright (C) 2001-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. - This program is distributed in the hope that it will be useful, + The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 . */ + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* From Paul Eggert and Jim Meyering. */ #ifndef _FILENAME_H #define _FILENAME_H +#include + #ifdef __cplusplus extern "C" { #endif -/* Pathname support. - ISSLASH(C) tests whether C is a directory separator character. - IS_ABSOLUTE_PATH(P) tests whether P is an absolute path. If it is not, - it may be concatenated to a directory pathname. - IS_PATH_WITH_DIR(P) tests whether P contains a directory specification. +/* Filename support. + ISSLASH(C) tests whether C is a directory separator + character. + HAS_DEVICE(Filename) tests whether Filename contains a device + specification. + FILE_SYSTEM_PREFIX_LEN(Filename) length of the device specification + at the beginning of Filename, + index of the part consisting of + alternating components and slashes. + FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE + 1 when a non-empty device specification + can be followed by an empty or relative + part, + 0 when a non-empty device specification + must be followed by a slash, + 0 when device specification don't exist. + IS_ABSOLUTE_FILE_NAME(Filename) + tests whether Filename is independent of + any notion of "current directory". + IS_RELATIVE_FILE_NAME(Filename) + tests whether Filename may be concatenated + to a directory filename. + Note: On native Windows, OS/2, DOS, "c:" is neither an absolute nor a + relative file name! + IS_FILE_NAME_WITH_DIR(Filename) tests whether Filename contains a device + or directory specification. */ +#if defined _WIN32 || defined __CYGWIN__ \ + || defined __EMX__ || defined __MSDOS__ || defined __DJGPP__ + /* Native Windows, Cygwin, OS/2, DOS */ +# define ISSLASH(C) ((C) == '/' || (C) == '\\') + /* Internal macro: Tests whether a character is a drive letter. */ +# define _IS_DRIVE_LETTER(C) \ + (((C) >= 'A' && (C) <= 'Z') || ((C) >= 'a' && (C) <= 'z')) + /* Help the compiler optimizing it. This assumes ASCII. */ +# undef _IS_DRIVE_LETTER +# define _IS_DRIVE_LETTER(C) \ + (((unsigned int) (C) | ('a' - 'A')) - 'a' <= 'z' - 'a') +# define HAS_DEVICE(Filename) \ + (_IS_DRIVE_LETTER ((Filename)[0]) && (Filename)[1] == ':') +# define FILE_SYSTEM_PREFIX_LEN(Filename) (HAS_DEVICE (Filename) ? 2 : 0) +# ifdef __CYGWIN__ +# define FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE 0 +# else + /* On native Windows, OS/2, DOS, the system has the notion of a + "current directory" on each drive. */ +# define FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE 1 +# endif +# if FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE +# define IS_ABSOLUTE_FILE_NAME(Filename) \ + ISSLASH ((Filename)[FILE_SYSTEM_PREFIX_LEN (Filename)]) +# else +# define IS_ABSOLUTE_FILE_NAME(Filename) \ + (ISSLASH ((Filename)[0]) || HAS_DEVICE (Filename)) +# endif +# define IS_RELATIVE_FILE_NAME(Filename) \ + (! (ISSLASH ((Filename)[0]) || HAS_DEVICE (Filename))) +# define IS_FILE_NAME_WITH_DIR(Filename) \ + (strchr ((Filename), '/') != NULL || strchr ((Filename), '\\') != NULL \ + || HAS_DEVICE (Filename)) +#else + /* Unix */ # define ISSLASH(C) ((C) == '/') # define HAS_DEVICE(Filename) ((void) (Filename), 0) # define FILE_SYSTEM_PREFIX_LEN(Filename) ((void) (Filename), 0) @@ -35,6 +97,12 @@ extern "C" { # define IS_ABSOLUTE_FILE_NAME(Filename) ISSLASH ((Filename)[0]) # define IS_RELATIVE_FILE_NAME(Filename) (! ISSLASH ((Filename)[0])) # define IS_FILE_NAME_WITH_DIR(Filename) (strchr ((Filename), '/') != NULL) +#endif + +/* Deprecated macros. For backward compatibility with old users of the + 'filename' module. */ +#define IS_ABSOLUTE_PATH IS_ABSOLUTE_FILE_NAME +#define IS_PATH_WITH_DIR IS_FILE_NAME_WITH_DIR #ifdef __cplusplus diff --git a/third_party/make/findprog-in.c b/third_party/make/findprog-in.c index 4ae85ef10..f5f9fc1a7 100644 --- a/third_party/make/findprog-in.c +++ b/third_party/make/findprog-in.c @@ -1,37 +1,34 @@ /* Locating a program in a given path. - Copyright (C) 2001-2004, 2006-2020 Free Software Foundation, Inc. + Copyright (C) 2001-2004, 2006-2023 Free Software Foundation, Inc. Written by Bruno Haible , 2001, 2019. - 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 file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. - This program is distributed in the hope that it will be useful, + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + GNU Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ -#include "libc/errno.h" -#include "libc/str/str.h" -#include "libc/mem/mem.h" -#include "third_party/make/filename.h" -#include "libc/calls/struct/stat.h" -#include "libc/sysv/consts/s.h" -#include "third_party/make/config.h" +#include "config.h" /* Specification. */ -#include "third_party/make/findprog.h" -#include "libc/sysv/consts/ok.h" +#include "findprog.h" +#include +#include +#include +#include +#include -#include "third_party/make/filename.h" -#include "third_party/make/concat-filename.h" -#include "third_party/make/xalloc.h" +#include "filename.h" +#include "concat-filename.h" #if (defined _WIN32 && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__ /* Native Windows, OS/2, DOS */ diff --git a/third_party/make/findprog.h b/third_party/make/findprog.h index 60f432530..6223394a4 100644 --- a/third_party/make/findprog.h +++ b/third_party/make/findprog.h @@ -1,18 +1,18 @@ /* Locating a program in PATH. - Copyright (C) 2001-2003, 2009-2020 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2009-2023 Free Software Foundation, Inc. Written by Bruno Haible , 2001. - 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 file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. - This program is distributed in the hope that it will be useful, + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + GNU Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef _FINDPROG_H diff --git a/third_party/make/function.c b/third_party/make/function.c index 5fe386045..f12d5d7c1 100644 --- a/third_party/make/function.c +++ b/third_party/make/function.c @@ -1,5 +1,5 @@ /* Builtin function expansion for GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,20 +12,17 @@ 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 . */ +this program. If not, see . */ + +#include "makeint.h" +#include "filedef.h" +#include "variable.h" +#include "dep.h" +#include "job.h" +#include "os.h" +#include "commands.h" +#include "debug.h" -#include "third_party/make/makeint.inc" -/**/ -#include "third_party/make/filedef.h" -#include "third_party/make/variable.h" -#include "third_party/make/dep.h" -#include "third_party/make/job.h" -#include "third_party/make/os.h" -#include "third_party/make/commands.h" -#include "libc/mem/critbit0.h" -#include "libc/log/rop.internal.h" -#include "libc/runtime/runtime.h" -#include "third_party/make/debug.h" struct function_table_entry { @@ -39,6 +36,7 @@ struct function_table_entry unsigned char maximum_args; unsigned int expand_args:1; unsigned int alloc_fn:1; + unsigned int adds_command:1; }; static unsigned long @@ -464,7 +462,6 @@ func_origin (char *o, char **argv, const char *funcname UNUSED) else switch (v->origin) { - default: case o_invalid: abort (); break; @@ -523,7 +520,24 @@ func_notdir_suffix (char *o, char **argv, const char *funcname) int is_suffix = funcname[0] == 's'; int is_notdir = !is_suffix; int stop = MAP_DIRSEP | (is_suffix ? MAP_DOT : 0); +#ifdef VMS + /* For VMS list_iterator points to a comma separated list. To use the common + [find_]next_token, create a local copy and replace the commas with + spaces. Obviously, there is a problem if there is a ',' in the VMS filename + (can only happen on ODS5), the same problem as with spaces in filenames, + which seems to be present in make on all platforms. */ + char *vms_list_iterator = alloca(strlen(list_iterator) + 1); + int i; + for (i = 0; list_iterator[i]; i++) + if (list_iterator[i] == ',') + vms_list_iterator[i] = ' '; + else + vms_list_iterator[i] = list_iterator[i]; + vms_list_iterator[i] = list_iterator[i]; + while ((p2 = find_next_token((const char**) &vms_list_iterator, &len)) != 0) +#else while ((p2 = find_next_token (&list_iterator, &len)) != 0) +#endif { const char *p = p2 + len - 1; @@ -538,12 +552,26 @@ func_notdir_suffix (char *o, char **argv, const char *funcname) continue; o = variable_buffer_output (o, p, len - (p - p2)); } +#ifdef HAVE_DOS_PATHS + /* Handle the case of "d:foo/bar". */ + else if (is_notdir && p2[0] && p2[1] == ':') + { + p = p2 + 2; + o = variable_buffer_output (o, p, len - (p - p2)); + } +#endif else if (is_notdir) o = variable_buffer_output (o, p2, len); if (is_notdir || p >= p2) { +#ifdef VMS + if (vms_comma_separator) + o = variable_buffer_output (o, ",", 1); + else +#endif o = variable_buffer_output (o, " ", 1); + doneany = 1; } } @@ -568,7 +596,20 @@ func_basename_dir (char *o, char **argv, const char *funcname) int is_basename = funcname[0] == 'b'; int is_dir = !is_basename; int stop = MAP_DIRSEP | (is_basename ? MAP_DOT : 0) | MAP_NUL; +#ifdef VMS + /* As in func_notdir_suffix ... */ + char *vms_p3 = alloca (strlen(p3) + 1); + int i; + for (i = 0; p3[i]; i++) + if (p3[i] == ',') + vms_p3[i] = ' '; + else + vms_p3[i] = p3[i]; + vms_p3[i] = p3[i]; + while ((p2 = find_next_token((const char**) &vms_p3, &len)) != 0) +#else while ((p2 = find_next_token (&p3, &len)) != 0) +#endif { const char *p = p2 + len - 1; while (p >= p2 && ! STOP_SET (*p, stop)) @@ -578,12 +619,37 @@ func_basename_dir (char *o, char **argv, const char *funcname) o = variable_buffer_output (o, p2, ++p - p2); else if (p >= p2 && (*p == '.')) o = variable_buffer_output (o, p2, p - p2); +#ifdef HAVE_DOS_PATHS + /* Handle the "d:foobar" case */ + else if (p2[0] && p2[1] == ':' && is_dir) + o = variable_buffer_output (o, p2, 2); +#endif else if (is_dir) - o = variable_buffer_output (o, "./", 2); +#ifdef VMS + { + extern int vms_report_unix_paths; + if (vms_report_unix_paths) + o = variable_buffer_output (o, "./", 2); + else + o = variable_buffer_output (o, "[]", 2); + } +#else +#ifndef _AMIGA + o = variable_buffer_output (o, "./", 2); +#else + ; /* Just a nop... */ +#endif /* AMIGA */ +#endif /* !VMS */ else /* The entire name is the basename. */ o = variable_buffer_output (o, p2, len); - o = variable_buffer_output (o, " ", 1); + +#ifdef VMS + if (vms_comma_separator) + o = variable_buffer_output (o, ",", 1); + else +#endif + o = variable_buffer_output (o, " ", 1); doneany = 1; } @@ -668,14 +734,14 @@ func_lastword (char *o, char **argv, const char *funcname UNUSED) static char * func_words (char *o, char **argv, const char *funcname UNUSED) { - int i = 0; + unsigned int i = 0; const char *word_iterator = argv[0]; - char buf[20]; + char buf[INTSTR_LENGTH]; while (find_next_token (&word_iterator, NULL) != 0) ++i; - sprintf (buf, "%d", i); + sprintf (buf, "%u", i); o = variable_buffer_output (o, buf, strlen (buf)); return o; @@ -696,35 +762,39 @@ strip_whitespace (const char **begpp, const char **endpp) return (char *)*begpp; } -static void -check_numeric (const char *s, const char *msg) +static long long +parse_numeric (const char *s, const char *msg) { - const char *end = s + strlen (s) - 1; const char *beg = s; - strip_whitespace (&s, &end); + const char *end = s + strlen (s) - 1; + char *endp; + long long num; + strip_whitespace (&beg, &end); - for (; s <= end; ++s) - if (!ISDIGIT (*s)) /* ISDIGIT only evals its arg once: see makeint.h. */ - break; + if (beg > end) + OS (fatal, *expanding_var, _("%s: empty value"), msg); - if (s <= end || end - beg < 0) - OSS (fatal, *expanding_var, "%s: '%s'", msg, beg); + errno = 0; + num = strtoll (beg, &endp, 10); + if (errno == ERANGE) + OSS (fatal, *expanding_var, _("%s: '%s' out of range"), msg, s); + else if (endp == beg || endp <= end) + /* Empty or non-numeric input */ + OSS (fatal, *expanding_var, "%s: '%s'", msg, s); + + return num; } - - static char * func_word (char *o, char **argv, const char *funcname UNUSED) { const char *end_p; const char *p; - int i; + long long i; - /* Check the first argument. */ - check_numeric (argv[0], _("non-numeric first argument to 'word' function")); - i = atoi (argv[0]); - - if (i == 0) + i = parse_numeric (argv[0], + _("invalid first argument to 'word' function")); + if (i < 1) O (fatal, *expanding_var, _("first argument to 'word' function must be greater than 0")); @@ -742,20 +812,20 @@ func_word (char *o, char **argv, const char *funcname UNUSED) static char * func_wordlist (char *o, char **argv, const char *funcname UNUSED) { - int start, count; + char buf[INTSTR_LENGTH + 1]; + long long start, stop, count; + const char* badfirst = _("invalid first argument to 'wordlist' function"); + const char* badsecond = _("invalid second argument to 'wordlist' function"); - /* Check the arguments. */ - check_numeric (argv[0], - _("non-numeric first argument to 'wordlist' function")); - check_numeric (argv[1], - _("non-numeric second argument to 'wordlist' function")); - - start = atoi (argv[0]); + start = parse_numeric (argv[0], badfirst); if (start < 1) - ON (fatal, *expanding_var, - "invalid first argument to 'wordlist' function: '%d'", start); + OSS (fatal, *expanding_var, "%s: '%s'", badfirst, make_lltoa (start, buf)); - count = atoi (argv[1]) - start + 1; + stop = parse_numeric (argv[1], badsecond); + if (stop < 0) + OSS (fatal, *expanding_var, "%s: '%s'", badsecond, make_lltoa (stop, buf)); + + count = stop - start + 1; if (count > 0) { @@ -838,9 +908,58 @@ func_foreach (char *o, char **argv, const char *funcname UNUSED) return o; } +static char * +func_let (char *o, char **argv, const char *funcname UNUSED) +{ + /* expand only the first two. */ + char *varnames = expand_argument (argv[0], NULL); + char *list = expand_argument (argv[1], NULL); + const char *body = argv[2]; + + const char *vp; + const char *vp_next = varnames; + const char *list_iterator = list; + char *p; + size_t len; + size_t vlen; + + push_new_variable_scope (); + + /* loop through LIST for all but the last VARNAME */ + vp = find_next_token (&vp_next, &vlen); + NEXT_TOKEN (vp_next); + while (*vp_next != '\0') + { + p = find_next_token (&list_iterator, &len); + if (*list_iterator != '\0') + { + ++list_iterator; + p[len] = '\0'; + } + define_variable (vp, vlen, p ? p : "", o_automatic, 0); + + vp = find_next_token (&vp_next, &vlen); + NEXT_TOKEN (vp_next); + } + + /* set the last VARNAME to the remainder of LIST */ + if (vp) + define_variable (vp, vlen, next_token (list_iterator), o_automatic, 0); + + /* Expand the body in the context of the arguments, adding the result to + the variable buffer. */ + + o = variable_expand_string (o, body, SIZE_MAX); + + pop_variable_scope (); + free (varnames); + free (list); + + return o + strlen (o); +} + struct a_word { - struct a_word *next; struct a_word *chain; char *str; size_t length; @@ -862,16 +981,17 @@ a_word_hash_2 (const void *key) static int a_word_hash_cmp (const void *x, const void *y) { - int result = (int) ((struct a_word const *) x)->length - ((struct a_word const *) y)->length; - if (result) - return result; - return_STRING_COMPARE (((struct a_word const *) x)->str, - ((struct a_word const *) y)->str); + const struct a_word *ax = x; + const struct a_word *ay = y; + + if (ax->length != ay->length) + return ax->length > ay->length ? 1 : -1; + + return_STRING_N_COMPARE (ax->str, ay->str, ax->length); } struct a_pattern { - struct a_pattern *next; char *str; char *percent; size_t length; @@ -880,78 +1000,84 @@ struct a_pattern static char * func_filter_filterout (char *o, char **argv, const char *funcname) { - struct a_word *wordhead; - struct a_word **wordtail; + struct a_word *words; + struct a_word *word_end; struct a_word *wp; - struct a_pattern *pathead; - struct a_pattern **pattail; + struct a_pattern *patterns; + struct a_pattern *pat_end; struct a_pattern *pp; + unsigned long pat_count = 0, word_count = 0; struct hash_table a_word_table; int is_filter = funcname[CSTRLEN ("filter")] == '\0'; - const char *pat_iterator = argv[0]; - const char *word_iterator = argv[1]; + const char *cp; int literals = 0; - int words = 0; int hashing = 0; char *p; size_t len; + int doneany = 0; - /* Chop ARGV[0] up into patterns to match against the words. - We don't need to preserve it because our caller frees all the - argument memory anyway. */ + /* Find the number of words and get memory for them. */ + cp = argv[1]; + while ((p = find_next_token (&cp, NULL)) != 0) + ++word_count; - pattail = &pathead; - while ((p = find_next_token (&pat_iterator, &len)) != 0) + if (!word_count) + return o; + + words = xcalloc (word_count * sizeof (struct a_word)); + word_end = words + word_count; + + /* Find the number of patterns and get memory for them. */ + cp = argv[0]; + while ((p = find_next_token (&cp, NULL)) != 0) + ++pat_count; + + patterns = xcalloc (pat_count * sizeof (struct a_pattern)); + pat_end = patterns + pat_count; + + /* Chop argv[0] up into patterns to match against the words. */ + + cp = argv[0]; + pp = patterns; + while ((p = find_next_token (&cp, &len)) != 0) { - struct a_pattern *pat = alloca (sizeof (struct a_pattern)); + if (*cp != '\0') + ++cp; - *pattail = pat; - pattail = &pat->next; - - if (*pat_iterator != '\0') - ++pat_iterator; - - pat->str = p; p[len] = '\0'; - pat->percent = find_percent (p); - if (pat->percent == 0) + pp->str = p; + pp->percent = find_percent (p); + if (pp->percent == 0) literals++; - /* find_percent() might shorten the string so LEN is wrong. */ - pat->length = strlen (pat->str); + pp->length = strlen (pp->str); + + ++pp; } - *pattail = 0; /* Chop ARGV[1] up into words to match against the patterns. */ - wordtail = &wordhead; - while ((p = find_next_token (&word_iterator, &len)) != 0) + cp = argv[1]; + wp = words; + while ((p = find_next_token (&cp, &len)) != 0) { - struct a_word *word = alloca (sizeof (struct a_word)); - - *wordtail = word; - wordtail = &word->next; - - if (*word_iterator != '\0') - ++word_iterator; + if (*cp != '\0') + ++cp; p[len] = '\0'; - word->str = p; - word->length = len; - word->matched = 0; - word->chain = 0; - words++; + wp->str = p; + wp->length = len; + ++wp; } - *wordtail = 0; /* Only use a hash table if arg list lengths justifies the cost. */ - hashing = (literals >= 2 && (literals * words) >= 10); + hashing = (literals > 1 && (literals * word_count) >= 10); if (hashing) { - hash_init (&a_word_table, words, a_word_hash_1, a_word_hash_2, + hash_init (&a_word_table, word_count, a_word_hash_1, a_word_hash_2, a_word_hash_cmp); - for (wp = wordhead; wp != 0; wp = wp->next) + for (wp = words; wp < word_end; ++wp) { struct a_word *owp = hash_insert (&a_word_table, wp); if (owp) @@ -959,51 +1085,49 @@ func_filter_filterout (char *o, char **argv, const char *funcname) } } - if (words) + /* Run each pattern through the words, killing words. */ + for (pp = patterns; pp < pat_end; ++pp) { - int doneany = 0; - - /* Run each pattern through the words, killing words. */ - for (pp = pathead; pp != 0; pp = pp->next) + if (pp->percent) + for (wp = words; wp < word_end; ++wp) + wp->matched |= pattern_matches (pp->str, pp->percent, wp->str); + else if (hashing) { - if (pp->percent) - for (wp = wordhead; wp != 0; wp = wp->next) - wp->matched |= pattern_matches (pp->str, pp->percent, wp->str); - else if (hashing) + struct a_word a_word_key; + a_word_key.str = pp->str; + a_word_key.length = pp->length; + wp = hash_find_item (&a_word_table, &a_word_key); + while (wp) { - struct a_word a_word_key; - a_word_key.str = pp->str; - a_word_key.length = pp->length; - wp = hash_find_item (&a_word_table, &a_word_key); - while (wp) - { - wp->matched |= 1; - wp = wp->chain; - } + wp->matched |= 1; + wp = wp->chain; } - else - for (wp = wordhead; wp != 0; wp = wp->next) - wp->matched |= (wp->length == pp->length - && strneq (pp->str, wp->str, wp->length)); } - - /* Output the words that matched (or didn't, for filter-out). */ - for (wp = wordhead; wp != 0; wp = wp->next) - if (is_filter ? wp->matched : !wp->matched) - { - o = variable_buffer_output (o, wp->str, strlen (wp->str)); - o = variable_buffer_output (o, " ", 1); - doneany = 1; - } - - if (doneany) - /* Kill the last space. */ - --o; + else + for (wp = words; wp < word_end; ++wp) + wp->matched |= (wp->length == pp->length + && memcmp (pp->str, wp->str, wp->length) == 0); } + /* Output the words that matched (or didn't, for filter-out). */ + for (wp = words; wp < word_end; ++wp) + if (is_filter ? wp->matched : !wp->matched) + { + o = variable_buffer_output (o, wp->str, strlen (wp->str)); + o = variable_buffer_output (o, " ", 1); + doneany = 1; + } + + if (doneany) + /* Kill the last space. */ + --o; + if (hashing) hash_free (&a_word_table, 0); + free (patterns); + free (words); + return o; } @@ -1043,41 +1167,25 @@ func_strip (char *o, char **argv, const char *funcname UNUSED) static char * func_error (char *o, char **argv, const char *funcname) { - char **argvp; - char *msg, *p; - size_t len; - - /* The arguments will be broken on commas. Rather than create yet - another special case where function arguments aren't broken up, - just create a format string that puts them back together. */ - for (len=0, argvp=argv; *argvp != 0; ++argvp) - len += strlen (*argvp) + 2; - - p = msg = alloca (len + 1); - msg[0] = '\0'; - - for (argvp=argv; argvp[1] != 0; ++argvp) - { - strcpy (p, *argvp); - p += strlen (*argvp); - *(p++) = ','; - *(p++) = ' '; - } - strcpy (p, *argvp); - switch (*funcname) { case 'e': - OS (fatal, reading_file, "%s", msg); + OS (fatal, reading_file, "%s", argv[0]); case 'w': - OS (error, reading_file, "%s", msg); + OS (error, reading_file, "%s", argv[0]); break; case 'i': - outputs (0, msg); - outputs (0, "\n"); - break; + { + size_t len = strlen (argv[0]); + char *msg = alloca (len + 2); + memcpy (msg, argv[0], len); + msg[len] = '\n'; + msg[len + 1] = '\0'; + outputs (0, msg); + break; + } default: OS (fatal, *expanding_var, "Internal error: func_error: '%s'", funcname); @@ -1133,7 +1241,7 @@ func_sort (char *o, char **argv, const char *funcname UNUSED) { len = strlen (words[i]); if (i == wordi - 1 || strlen (words[i + 1]) != len - || strcmp (words[i], words[i + 1])) + || memcmp (words[i], words[i + 1], len)) { o = variable_buffer_output (o, words[i], len); o = variable_buffer_output (o, " ", 1); @@ -1150,42 +1258,112 @@ func_sort (char *o, char **argv, const char *funcname UNUSED) } /* - chop argv[0] into words, and remove duplicates. - */ -static char * -func_uniq (char *o, char **argv, const char *funcname UNUSED) + Traverse NUMBER consisting of optional leading white space, optional + sign, digits, and optional trailing white space. + If number is not of the proper form, diagnose with MSG. Otherwise, + return the address of of the first character after NUMBER, store + into *SIGN an integer consistent with the number's sign (-1, 0, or 1) + and store into *NUMSTART the address of NUMBER's first nonzero digit + (if NUMBER contains only zero digits, store the address of the first + character after NUMBER). +*/ +static const char * +parse_textint (const char *number, const char *msg, + int *sign, const char **numstart) { - char *p; - size_t len; - int mutated; - bool once = false; - const char *s = argv[0]; - struct critbit0 t = {0}; + const char *after_sign, *after_number; + const char *p = next_token (number); + int negative = *p == '-'; + int nonzero; - while ((p = find_next_token (&s, &len))) + if (*p == '\0') + OS (fatal, *expanding_var, _("%s: empty value"), msg); + + p += negative || *p == '+'; + after_sign = p; + + while (*p == '0') + p++; + *numstart = p; + + while (ISDIGIT (*p)) + ++p; + after_number = p; + nonzero = *numstart != after_number; + *sign = negative ? -nonzero : nonzero; + + /* Check for extra non-whitespace stuff after the value. */ + if (after_number == after_sign || *next_token (p) != '\0') + OSS (fatal, *expanding_var, "%s: '%s'", msg, number); + + return after_number; +} + + +/* + $(intcmp lhs,rhs[,lt-part[,eq-part[,gt-part]]]) + + LHS and RHS must be integer values (leading/trailing whitespace is ignored). + If none of LT-PART, EQ-PART, or GT-PART are given then the function expands + to empty if LHS and RHS are not equal, or the numeric value if they are equal. + LT-PART is evaluated when LHS is strictly less than RHS, EQ-PART is evaluated + when LHS is equal to RHS, and GT-part is evaluated when LHS is strictly + greater than RHS. + If GT-PART is not provided, it defaults to EQ-PART. When neither EQ-PART + nor GT-PART are provided, the function expands to empty if LHS is not + strictly less than RHS. +*/ + +static char * +func_intcmp (char *o, char **argv, const char *funcname UNUSED) +{ + int lsign, rsign; + const char *lnum, *rnum; + char *lhs_str = expand_argument (argv[0], NULL); + char *rhs_str = expand_argument (argv[1], NULL); + const char *llim = parse_textint (lhs_str, _("non-numeric first argument to 'intcmp' function"), &lsign, &lnum); + const char *rlim = parse_textint (rhs_str, _("non-numeric second argument to 'intcmp' function"), &rsign, &rnum); + ptrdiff_t llen = llim - lnum; + ptrdiff_t rlen = rlim - rnum; + int cmp = lsign - rsign; + + if (cmp == 0) { - ++s; - p[len] = 0; - RETURN_ON_ERROR ((mutated = critbit0_insert (&t, p))); - if (mutated) - { - if (once) - o = variable_buffer_output (o, " ", 1); - else - once = true; - o = variable_buffer_output (o, p, len); - } + cmp = (llen > rlen) - (llen < rlen); + if (cmp == 0) + cmp = memcmp (lnum, rnum, llen); } - critbit0_clear (&t); + argv += 2; + + /* Handle the special case where there are only two arguments. */ + if (!*argv && cmp == 0) + { + if (lsign < 0) + o = variable_buffer_output (o, "-", 1); + o = variable_buffer_output(o, lnum - !lsign, llen + !lsign); + } + + free (lhs_str); + free (rhs_str); + + if (*argv && cmp >= 0) + { + ++argv; + if (cmp > 0 && *argv && *(argv + 1)) + ++argv; + } + + if (*argv) + { + char *expansion = expand_argument (*argv, NULL); + + o = variable_buffer_output (o, expansion, strlen (expansion)); + + free (expansion); + } return o; - -OnError: - critbit0_clear (&t); - OSS (error, NILF, "%s: function failed: %s", - "uniq", strerror (errno)); - exit (1); } /* @@ -1346,8 +1524,12 @@ func_and (char *o, char **argv, const char *funcname UNUSED) static char * func_wildcard (char *o, char **argv, const char *funcname UNUSED) { +#ifdef _AMIGA + o = wildcard_expansion (argv[0], o); +#else char *p = string_glob (argv[0]); o = variable_buffer_output (o, p, strlen (p)); +#endif return o; } @@ -1429,7 +1611,7 @@ static int shell_function_completed; void shell_completed (int exit_code, int exit_sig) { - char buf[256]; + char buf[INTSTR_LENGTH]; shell_function_pid = 0; if (exit_sig == 0 && exit_code == 127) @@ -1444,42 +1626,240 @@ shell_completed (int exit_code, int exit_sig) define_variable_cname (".SHELLSTATUS", buf, o_override, 0); } +#ifdef WINDOWS32 +/*untested*/ + + +int +windows32_openpipe (int *pipedes, int errfd, pid_t *pid_p, char **command_argv, char **envp) +{ + SECURITY_ATTRIBUTES saAttr; + HANDLE hIn = INVALID_HANDLE_VALUE; + HANDLE hErr = INVALID_HANDLE_VALUE; + HANDLE hChildOutRd; + HANDLE hChildOutWr; + HANDLE hProcess, tmpIn, tmpErr; + DWORD e; + + /* Set status for return. */ + pipedes[0] = pipedes[1] = -1; + *pid_p = (pid_t)-1; + + saAttr.nLength = sizeof (SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + /* Standard handles returned by GetStdHandle can be NULL or + INVALID_HANDLE_VALUE if the parent process closed them. If that + happens, we open the null device and pass its handle to + process_begin below as the corresponding handle to inherit. */ + tmpIn = GetStdHandle (STD_INPUT_HANDLE); + if (DuplicateHandle (GetCurrentProcess (), tmpIn, + GetCurrentProcess (), &hIn, + 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE) + { + e = GetLastError (); + if (e == ERROR_INVALID_HANDLE) + { + tmpIn = CreateFile ("NUL", GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (tmpIn != INVALID_HANDLE_VALUE + && DuplicateHandle (GetCurrentProcess (), tmpIn, + GetCurrentProcess (), &hIn, + 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE) + CloseHandle (tmpIn); + } + if (hIn == INVALID_HANDLE_VALUE) + { + ON (error, NILF, + _("windows32_openpipe: DuplicateHandle(In) failed (e=%lu)\n"), e); + return -1; + } + } + tmpErr = (HANDLE)_get_osfhandle (errfd); + if (DuplicateHandle (GetCurrentProcess (), tmpErr, + GetCurrentProcess (), &hErr, + 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE) + { + e = GetLastError (); + if (e == ERROR_INVALID_HANDLE) + { + tmpErr = CreateFile ("NUL", GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (tmpErr != INVALID_HANDLE_VALUE + && DuplicateHandle (GetCurrentProcess (), tmpErr, + GetCurrentProcess (), &hErr, + 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE) + CloseHandle (tmpErr); + } + if (hErr == INVALID_HANDLE_VALUE) + { + ON (error, NILF, + _("windows32_openpipe: DuplicateHandle(Err) failed (e=%lu)\n"), e); + return -1; + } + } + + if (! CreatePipe (&hChildOutRd, &hChildOutWr, &saAttr, 0)) + { + ON (error, NILF, _("CreatePipe() failed (e=%lu)\n"), GetLastError()); + return -1; + } + + hProcess = process_init_fd (hIn, hChildOutWr, hErr); + + if (!hProcess) + { + O (error, NILF, _("windows32_openpipe(): process_init_fd() failed\n")); + return -1; + } + + if (! process_begin (hProcess, command_argv, envp, command_argv[0], NULL)) + { + /* register process for wait */ + process_register (hProcess); + + /* set the pid for returning to caller */ + *pid_p = (pid_t) hProcess; + + /* set up to read data from child */ + pipedes[0] = _open_osfhandle ((intptr_t) hChildOutRd, O_RDONLY); + + /* this will be closed almost right away */ + pipedes[1] = _open_osfhandle ((intptr_t) hChildOutWr, O_APPEND); + return 0; + } + else + { + /* reap/cleanup the failed process */ + process_cleanup (hProcess); + + /* close handles which were duplicated, they weren't used */ + if (hIn != INVALID_HANDLE_VALUE) + CloseHandle (hIn); + if (hErr != INVALID_HANDLE_VALUE) + CloseHandle (hErr); + + /* close pipe handles, they won't be used */ + CloseHandle (hChildOutRd); + CloseHandle (hChildOutWr); + + return -1; + } +} +#endif + + +#ifdef __MSDOS__ +FILE * +msdos_openpipe (int* pipedes, int *pidp, char *text) +{ + FILE *fpipe=0; + /* MSDOS can't fork, but it has 'popen'. */ + struct variable *sh = lookup_variable ("SHELL", 5); + int e; + extern int dos_command_running, dos_status; + + /* Make sure not to bother processing an empty line. */ + NEXT_TOKEN (text); + if (*text == '\0') + return 0; + + if (sh) + { + char buf[PATH_MAX + 7]; + /* This makes sure $SHELL value is used by $(shell), even + though the target environment is not passed to it. */ + sprintf (buf, "SHELL=%s", sh->value); + putenv (buf); + } + + e = errno; + errno = 0; + dos_command_running = 1; + dos_status = 0; + /* If dos_status becomes non-zero, it means the child process + was interrupted by a signal, like SIGINT or SIGQUIT. See + fatal_error_signal in commands.c. */ + fpipe = popen (text, "rt"); + dos_command_running = 0; + if (!fpipe || dos_status) + { + pipedes[0] = -1; + *pidp = -1; + if (dos_status) + errno = EINTR; + else if (errno == 0) + errno = ENOMEM; + if (fpipe) + pclose (fpipe); + shell_completed (127, 0); + } + else + { + pipedes[0] = fileno (fpipe); + *pidp = 42; /* Yes, the Meaning of Life, the Universe, and Everything! */ + errno = e; + } + return fpipe; +} +#endif /* Do shell spawning, with the naughty bits for different OSes. */ +#ifdef VMS + +/* VMS can't do $(shell ...) */ + char * func_shell_base (char *o, char **argv, int trim_newlines) { + fprintf (stderr, "This platform does not support shell\n"); + die (MAKE_TROUBLE); + return NULL; +} + +#define func_shell 0 + +#else +#ifndef _AMIGA +char * +func_shell_base (char *o, char **argv, int trim_newlines) +{ + struct childbase child = {0}; char *batch_filename = NULL; int errfd; +#ifdef __MSDOS__ + FILE *fpipe; +#endif char **command_argv = NULL; - char **envp; int pipedes[2]; pid_t pid; +#ifndef __MSDOS__ +#ifdef WINDOWS32 + /* Reset just_print_flag. This is needed on Windows when batch files + are used to run the commands, because we normally refrain from + creating batch files under -n. */ + int j_p_f = just_print_flag; + just_print_flag = 0; +#endif + /* Construct the argument list. */ command_argv = construct_command_argv (argv[0], NULL, NULL, 0, &batch_filename); if (command_argv == 0) { +#ifdef WINDOWS32 + just_print_flag = j_p_f; +#endif return o; } - - /* Using a target environment for 'shell' loses in cases like: - export var = $(shell echo foobie) - bad := $(var) - because target_environment hits a loop trying to expand $(var) to put it - in the environment. This is even more confusing when 'var' was not - explicitly exported, but just appeared in the calling environment. - - See Savannah bug #10593. - - envp = target_environment (NULL); - */ - - envp = environ; +#endif /* !__MSDOS__ */ /* Set up the output in case the shell writes something. */ output_start (); @@ -1487,6 +1867,32 @@ func_shell_base (char *o, char **argv, int trim_newlines) errfd = (output_context && output_context->err >= 0 ? output_context->err : FD_STDERR); + child.environment = target_environment (NULL, 0); + +#if defined(__MSDOS__) + fpipe = msdos_openpipe (pipedes, &pid, argv[0]); + if (pipedes[0] < 0) + { + OS (error, reading_file, "pipe: %s", strerror (errno)); + pid = -1; + goto done; + } + +#elif defined(WINDOWS32) + windows32_openpipe (pipedes, errfd, &pid, command_argv, child.environment); + /* Restore the value of just_print_flag. */ + just_print_flag = j_p_f; + + if (pipedes[0] < 0) + { + /* Open of the pipe failed, mark as failed execution. */ + shell_completed (127, 0); + OS (error, reading_file, "pipe: %s", strerror (errno)); + pid = -1; + goto done; + } + +#else if (pipe (pipedes) < 0) { OS (error, reading_file, "pipe: %s", strerror (errno)); @@ -1498,24 +1904,18 @@ func_shell_base (char *o, char **argv, int trim_newlines) fd_noinherit (pipedes[1]); fd_noinherit (pipedes[0]); - { - struct childbase child; - child.cmd_name = NULL; - child.output.syncout = 1; - child.output.out = pipedes[1]; - child.output.err = errfd; - child.environment = envp; + child.output.syncout = 1; + child.output.out = pipedes[1]; + child.output.err = errfd; - pid = child_execute_job (&child, 1, command_argv, false); - - free (child.cmd_name); - } + pid = child_execute_job (&child, 1, command_argv); if (pid < 0) { shell_completed (127, 0); goto done; } +#endif { char *buffer; @@ -1524,6 +1924,7 @@ func_shell_base (char *o, char **argv, int trim_newlines) /* Record the PID for reap_children. */ shell_function_pid = pid; +#ifndef __MSDOS__ shell_function_completed = 0; /* Close the write side of the pipe. We test for -1, since @@ -1531,6 +1932,7 @@ func_shell_base (char *o, char **argv, int trim_newlines) libraries barf when 'close' is called with -1. */ if (pipedes[1] >= 0) close (pipedes[1]); +#endif /* Set up and read from the pipe. */ @@ -1553,7 +1955,15 @@ func_shell_base (char *o, char **argv, int trim_newlines) buffer[i] = '\0'; /* Close the read side of the pipe. */ +#ifdef __MSDOS__ + if (fpipe) + { + int st = pclose (fpipe); + shell_completed (st, 0); + } +#else (void) close (pipedes[0]); +#endif /* Loop until child_handler or reap_children() sets shell_function_completed to the status of our child shell. */ @@ -1569,24 +1979,10 @@ func_shell_base (char *o, char **argv, int trim_newlines) } shell_function_pid = 0; - /* shell_completed() will set shell_function_completed to 1 when the - child dies normally, or to -1 if it dies with status 127, which is - most likely an exec fail. */ - - if (shell_function_completed == -1) - { - /* This likely means that the execvp failed, so we should just - write the error message in the pipe from the child. */ - fputs (buffer, stderr); - fflush (stderr); - } - else - { - /* The child finished normally. Replace all newlines in its output - with spaces, and put that in the variable output buffer. */ - fold_newlines (buffer, &i, trim_newlines); - o = variable_buffer_output (o, buffer, i); - } + /* Replace all newlines in the command's output with spaces, and put that + in the variable output buffer. */ + fold_newlines (buffer, &i, trim_newlines); + o = variable_buffer_output (o, buffer, i); free (buffer); } @@ -1599,14 +1995,105 @@ func_shell_base (char *o, char **argv, int trim_newlines) free (command_argv); } + free_childbase (&child); + return o; } +#else /* _AMIGA */ + +/* Do the Amiga version of func_shell. */ + +char * +func_shell_base (char *o, char **argv, int trim_newlines) +{ + /* Amiga can't fork nor spawn, but I can start a program with + redirection of my choice. However, this means that we + don't have an opportunity to reopen stdout to trap it. Thus, + we save our own stdout onto a new descriptor and dup a temp + file's descriptor onto our stdout temporarily. After we + spawn the shell program, we dup our own stdout back to the + stdout descriptor. The buffer reading is the same as above, + except that we're now reading from a file. */ + +#include +#include + + BPTR child_stdout; + char tmp_output[FILENAME_MAX]; + size_t maxlen = 200, i; + int cc; + char * buffer, * ptr; + char ** aptr; + size_t len = 0; + char* batch_filename = NULL; + + /* Construct the argument list. */ + command_argv = construct_command_argv (argv[0], NULL, NULL, 0, + &batch_filename); + if (command_argv == 0) + return o; + + /* Note the mktemp() is a security hole, but this only runs on Amiga. + Ideally we would use get_tmpfile(), but this uses a special Open(), not + fopen(), and I'm not familiar enough with the code to mess with it. */ + strcpy (tmp_output, "t:MakeshXXXXXXXX"); + mktemp (tmp_output); + child_stdout = Open (tmp_output, MODE_NEWFILE); + + for (aptr=command_argv; *aptr; aptr++) + len += strlen (*aptr) + 1; + + buffer = xmalloc (len + 1); + ptr = buffer; + + for (aptr=command_argv; *aptr; aptr++) + { + strcpy (ptr, *aptr); + ptr += strlen (ptr) + 1; + *(ptr++) = ' '; + *ptr = '\0'; + } + + ptr[-1] = '\n'; + + Execute (buffer, NULL, child_stdout); + free (buffer); + + Close (child_stdout); + + child_stdout = Open (tmp_output, MODE_OLDFILE); + + buffer = xmalloc (maxlen); + i = 0; + do + { + if (i == maxlen) + { + maxlen += 512; + buffer = xrealloc (buffer, maxlen + 1); + } + + cc = Read (child_stdout, &buffer[i], maxlen - i); + if (cc > 0) + i += cc; + } while (cc > 0); + + Close (child_stdout); + + fold_newlines (buffer, &i, trim_newlines); + o = variable_buffer_output (o, buffer, i); + free (buffer); + return o; +} +#endif /* _AMIGA */ + static char * func_shell (char *o, char **argv, const char *funcname UNUSED) { return func_shell_base (o, argv, 1); } +#endif /* !VMS */ #ifdef EXPERIMENTAL @@ -1621,6 +2108,7 @@ func_eq (char *o, char **argv, char *funcname UNUSED) return o; } + /* string-boolean not operator. */ @@ -1637,8 +2125,17 @@ func_not (char *o, char **argv, char *funcname UNUSED) #endif -#define IS_ABSOLUTE(n) (n[0] == '/') -#define ROOT_LEN 1 +#ifdef HAVE_DOS_PATHS +# ifdef __CYGWIN__ +# define IS_ABSOLUTE(n) ((n[0] && n[1] == ':') || ISDIRSEP (n[0])) +# else +# define IS_ABSOLUTE(n) (n[0] && n[1] == ':') +# endif +# define ROOT_LEN 3 +#else +# define IS_ABSOLUTE(n) (n[0] == '/') +# define ROOT_LEN 1 +#endif /* Return the absolute name of file NAME which does not contain any '.', '..' components nor any repeated path separators ('/'). */ @@ -1662,15 +2159,52 @@ abspath (const char *name, char *apath) return NULL; strcpy (apath, starting_directory); + +#ifdef HAVE_DOS_PATHS + if (ISDIRSEP (name[0])) + { + if (ISDIRSEP (name[1])) + { + /* A UNC. Don't prepend a drive letter. */ + apath[0] = name[0]; + apath[1] = name[1]; + root_len = 2; + } + /* We have /foo, an absolute file name except for the drive + letter. Assume the missing drive letter is the current + drive, which we can get if we remove from starting_directory + everything past the root directory. */ + apath[root_len] = '\0'; + } +#endif + dest = strchr (apath, '\0'); } else { +#if defined(__CYGWIN__) && defined(HAVE_DOS_PATHS) + if (ISDIRSEP (name[0])) + root_len = 1; +#endif memcpy (apath, name, root_len); apath[root_len] = '\0'; dest = apath + root_len; /* Get past the root, since we already copied it. */ name += root_len; +#ifdef HAVE_DOS_PATHS + if (! ISDIRSEP (apath[root_len - 1])) + { + /* Convert d:foo into d:./foo and increase root_len. */ + apath[2] = '.'; + apath[3] = '/'; + dest++; + root_len++; + /* strncpy above copied one character too many. */ + name--; + } + else + apath[root_len - 1] = '/'; /* make sure it's a forward slash */ +#endif } for (start = end = name; *start != '\0'; start = end) @@ -1678,7 +2212,7 @@ abspath (const char *name, char *apath) size_t len; /* Skip sequence of multiple path-separators. */ - while (STOP_SET (*start, MAP_DIRSEP)) + while (ISDIRSEP (*start)) ++start; /* Find end of path component. */ @@ -1695,25 +2229,24 @@ abspath (const char *name, char *apath) { /* Back up to previous component, ignore if at root already. */ if (dest > apath + root_len) - for (--dest; ! STOP_SET (dest[-1], MAP_DIRSEP); --dest) + for (--dest; ! ISDIRSEP (dest[-1]); --dest) ; } else { - if (! STOP_SET (dest[-1], MAP_DIRSEP)) + if (! ISDIRSEP (dest[-1])) *dest++ = '/'; if (dest + len >= apath_limit) return NULL; - dest = memcpy (dest, start, len); - dest += len; + dest = mempcpy (dest, start, len); *dest = '\0'; } } /* Unless it is root strip trailing separator. */ - if (dest > apath + root_len && STOP_SET (dest[-1], MAP_DIRSEP)) + if (dest > apath + root_len && ISDIRSEP (dest[-1])) --dest; *dest = '\0'; @@ -1786,6 +2319,10 @@ func_file (char *o, char **argv, const char *funcname UNUSED) if (fn[0] == '>') { + size_t len; + const char *end; + const char *start; + char *nm; FILE *fp; const char *mode = "w"; @@ -1796,14 +2333,26 @@ func_file (char *o, char **argv, const char *funcname UNUSED) mode = "a"; ++fn; } - NEXT_TOKEN (fn); - if (fn[0] == '\0') + start = next_token (fn); + + if (start[0] == '\0') O (fatal, *expanding_var, _("file: missing filename")); - ENULLLOOP (fp, fopen (fn, mode)); + end = end_of_token (start); + len = end - start; + nm = alloca (len + 1); + memcpy (nm, start, len); + nm[len] = '\0'; + + ENULLLOOP (fp, fopen (nm, mode)); if (fp == NULL) - OSS (fatal, reading_file, _("open: %s: %s"), fn, strerror (errno)); + OSS (fatal, reading_file, _("open: %s: %s"), nm, strerror (errno)); + + /* We've changed the contents of a directory, possibly. + Another option would be to look up the directory we changed and reset + its counter to 0. */ + ++command_count; if (argv[1]) { @@ -1811,30 +2360,44 @@ func_file (char *o, char **argv, const char *funcname UNUSED) int nl = l == 0 || argv[1][l-1] != '\n'; if (fputs (argv[1], fp) == EOF || (nl && fputc ('\n', fp) == EOF)) - OSS (fatal, reading_file, _("write: %s: %s"), fn, strerror (errno)); + OSS (fatal, reading_file, _("write: %s: %s"), nm, strerror (errno)); } if (fclose (fp)) - OSS (fatal, reading_file, _("close: %s: %s"), fn, strerror (errno)); + OSS (fatal, reading_file, _("close: %s: %s"), nm, strerror (errno)); } else if (fn[0] == '<') { - char *preo = o; + size_t n = 0; + size_t len; + const char *end; + const char *start; + char *nm; FILE *fp; - ++fn; - NEXT_TOKEN (fn); - if (fn[0] == '\0') + start = next_token (fn + 1); + + if (start[0] == '\0') O (fatal, *expanding_var, _("file: missing filename")); if (argv[1]) O (fatal, *expanding_var, _("file: too many arguments")); - ENULLLOOP (fp, fopen (fn, "r")); + end = end_of_token (start); + len = end - start; + nm = alloca (len + 1); + memcpy (nm, start, len); + nm[len] = '\0'; + + ENULLLOOP (fp, fopen (nm, "r")); if (fp == NULL) { if (errno == ENOENT) - return o; - OSS (fatal, reading_file, _("open: %s: %s"), fn, strerror (errno)); + { + DB (DB_VERBOSE, (_("file: Failed to open '%s': %s\n"), + nm, strerror (errno))); + return o; + } + OSS (fatal, reading_file, _("open: %s: %s"), nm, strerror (errno)); } while (1) @@ -1842,21 +2405,22 @@ func_file (char *o, char **argv, const char *funcname UNUSED) char buf[1024]; size_t l = fread (buf, 1, sizeof (buf), fp); if (l > 0) - o = variable_buffer_output (o, buf, l); - + { + o = variable_buffer_output (o, buf, l); + n += l; + } if (ferror (fp)) if (errno != EINTR) - OSS (fatal, reading_file, _("read: %s: %s"), fn, strerror (errno)); + OSS (fatal, reading_file, _("read: %s: %s"), nm, strerror (errno)); if (feof (fp)) break; } if (fclose (fp)) - OSS (fatal, reading_file, _("close: %s: %s"), fn, strerror (errno)); + OSS (fatal, reading_file, _("close: %s: %s"), nm, strerror (errno)); /* Remove trailing newline. */ - if (o > preo && o[-1] == '\n') - if (--o > preo && o[-1] == '\r') - --o; + if (n && o[-1] == '\n') + o -= 1 + (n > 1 && o[-2] == '\r'); } else OS (fatal, *expanding_var, _("file: invalid file operation: %s"), fn); @@ -1909,12 +2473,13 @@ func_abspath (char *o, char **argv, const char *funcname UNUSED) comma-separated values are treated as arguments. EXPAND_ARGS means that all arguments should be expanded before invocation. - Functions that do namespace tricks (foreach) don't automatically expand. */ + Functions that do namespace tricks (foreach, let) don't automatically + expand. */ static char *func_call (char *o, char **argv, const char *funcname); #define FT_ENTRY(_name, _min, _max, _exp, _func) \ - { { (_func) }, STRING_SIZE_TUPLE(_name), (_min), (_max), (_exp), 0 } + { { (_func) }, STRING_SIZE_TUPLE(_name), (_min), (_max), (_exp), 0, 0 } static struct function_table_entry function_table_init[] = { @@ -1945,17 +2510,18 @@ static struct function_table_entry function_table_init[] = FT_ENTRY ("words", 0, 1, 1, func_words), FT_ENTRY ("origin", 0, 1, 1, func_origin), FT_ENTRY ("foreach", 3, 3, 0, func_foreach), + FT_ENTRY ("let", 3, 3, 0, func_let), FT_ENTRY ("call", 1, 0, 1, func_call), FT_ENTRY ("info", 0, 1, 1, func_error), FT_ENTRY ("error", 0, 1, 1, func_error), FT_ENTRY ("warning", 0, 1, 1, func_error), + FT_ENTRY ("intcmp", 2, 5, 0, func_intcmp), FT_ENTRY ("if", 2, 3, 0, func_if), FT_ENTRY ("or", 1, 0, 0, func_or), FT_ENTRY ("and", 1, 0, 0, func_and), FT_ENTRY ("value", 0, 1, 1, func_value), FT_ENTRY ("eval", 0, 1, 1, func_eval), FT_ENTRY ("file", 1, 2, 1, func_file), - FT_ENTRY ("uniq", 0, 1, 1, func_uniq), #ifdef EXPERIMENTAL FT_ENTRY ("eq", 2, 2, 1, func_eq), FT_ENTRY ("not", 0, 1, 1, func_not), @@ -1968,14 +2534,14 @@ static struct function_table_entry function_table_init[] = /* These must come after the definition of function_table. */ static char * -expand_builtin_function (char *o, int argc, char **argv, +expand_builtin_function (char *o, unsigned int argc, char **argv, const struct function_table_entry *entry_p) { char *p; - if (argc < (int)entry_p->minimum_args) + if (argc < entry_p->minimum_args) fatal (*expanding_var, strlen (entry_p->name), - _("insufficient number of arguments (%d) to function '%s'"), + _("insufficient number of arguments (%u) to function '%s'"), argc, entry_p->name); /* I suppose technically some function could do something with no arguments, @@ -1989,6 +2555,9 @@ expand_builtin_function (char *o, int argc, char **argv, OS (fatal, *expanding_var, _("unimplemented on this platform: function '%s'"), entry_p->name); + if (entry_p->adds_command) + ++command_count; + if (!entry_p->alloc_fn) return entry_p->fptr.func_ptr (o, argv, entry_p->name); @@ -2021,7 +2590,7 @@ handle_function (char **op, const char **stringp) int count = 0; char *abeg = NULL; char **argv, **argvp; - int nargs; + unsigned int nargs; beg = *stringp + 1; @@ -2092,9 +2661,8 @@ handle_function (char **op, const char **stringp) char *p, *aend; abeg = xmalloc (len+1); - memcpy (abeg, beg, len); - abeg[len] = '\0'; - aend = abeg + len; + aend = mempcpy (abeg, beg, len); + *aend = '\0'; for (p=abeg, nargs=0; p <= aend; ++argvp) { @@ -2134,11 +2702,11 @@ handle_function (char **op, const char **stringp) static char * func_call (char *o, char **argv, const char *funcname UNUSED) { - static int max_args = 0; + static unsigned int max_args = 0; char *fname; char *body; size_t flen; - int i; + unsigned int i; int saved_args; const struct function_table_entry *entry_p; struct variable *v; @@ -2187,9 +2755,9 @@ func_call (char *o, char **argv, const char *funcname UNUSED) for (i=0; *argv; ++i, ++argv) { - char num[11]; + char num[INTSTR_LENGTH]; - sprintf (num, "%d", i); + sprintf (num, "%u", i); define_variable (num, strlen (num), *argv, o_automatic, 0); } @@ -2200,9 +2768,9 @@ func_call (char *o, char **argv, const char *funcname UNUSED) for (; i < max_args; ++i) { - char num[11]; + char num[INTSTR_LENGTH]; - sprintf (num, "%d", i); + sprintf (num, "%u", i); define_variable (num, strlen (num), "", o_automatic, 0); } @@ -2250,15 +2818,18 @@ define_new_function (const floc *flocp, const char *name, _("Invalid maximum argument count (%u) for function %s"), max, name); ent = xmalloc (sizeof (struct function_table_entry)); - ent->name = name; + ent->name = strcache_add (name); ent->len = (unsigned char) len; ent->minimum_args = (unsigned char) min; ent->maximum_args = (unsigned char) max; ent->expand_args = ANY_SET(flags, GMK_FUNC_NOEXPAND) ? 0 : 1; ent->alloc_fn = 1; + /* We don't know what this function will do. */ + ent->adds_command = 1; ent->fptr.alloc_func_ptr = func; - hash_insert (&function_table, ent); + ent = hash_insert (&function_table, ent); + free (ent); } void diff --git a/third_party/make/getopt.c b/third_party/make/getopt.c index cd8994e33..7b4202bce 100644 --- a/third_party/make/getopt.c +++ b/third_party/make/getopt.c @@ -3,7 +3,7 @@ NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to drepper@gnu.org before changing it! -Copyright (C) 1987-2020 Free Software Foundation, Inc. +Copyright (C) 1987-2023 Free Software Foundation, Inc. NOTE: The canonical source of this file is maintained with the GNU C Library. Bugs can be reported to bug-glibc@gnu.org. @@ -18,10 +18,7 @@ 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 . */ - -#include "libc/stdio/stdio.h" -#include "libc/str/str.h" +this program. If not, see . */ /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ @@ -30,9 +27,18 @@ this program. If not, see . */ #endif #ifdef HAVE_CONFIG_H -#include "third_party/make/config.h" +#include "config.h" #endif -#pragma GCC diagnostic ignored "-Wredundant-decls" + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +# ifndef const +# define const +# endif +#endif + +#include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C @@ -44,6 +50,7 @@ this program. If not, see . */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +# include # if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION # define ELIDE_CODE # endif @@ -51,9 +58,26 @@ this program. If not, see . */ #ifndef ELIDE_CODE + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +# include +# include +#endif /* GNU C library. */ + +#ifdef VMS +# include +# if HAVE_STRING_H - 0 +# include +# endif +#endif + /* This is for other GNU distributions with internationalized messages. When compiling libc, the _ macro is predefined. */ -#include "third_party/make/gettext.h" +#include "gettext.h" #define _(msgid) gettext (msgid) @@ -71,7 +95,7 @@ this program. If not, see . */ GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ -#include "third_party/make/getopt.h" +#include "getopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, @@ -164,9 +188,16 @@ static char *posixly_correct; because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ +# include # define my_index strchr #else +# if HAVE_STRING_H +# include +# else +# include +# endif + /* Avoid depending on library functions or files whose names are inconsistent. */ @@ -405,6 +436,10 @@ _getopt_initialize (int argc, char *const *argv, const char *optstring) nonoption_flags_len = 0; #endif + /* Make the compiler happy. */ + (void)argc; + (void)argv; + return optstring; } @@ -645,18 +680,19 @@ _getopt_internal (int argc, char *const *argv, const char *optstring, optarg = nameend + 1; else { - if (opterr) { - if (argv[optind - 1][1] == '-') - /* --option */ - fprintf (stderr, - _("%s: option '--%s' doesn't allow an argument\n"), - argv[0], pfound->name); - else - /* +option or -option */ - fprintf (stderr, - _("%s: option '%c%s' doesn't allow an argument\n"), - argv[0], argv[optind - 1][0], pfound->name); - } + if (opterr) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option '--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option '%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); + } nextchar += strlen (nextchar); optopt = pfound->val; diff --git a/third_party/make/getopt.h b/third_party/make/getopt.h index a0a58d8f9..df18ceeb9 100644 --- a/third_party/make/getopt.h +++ b/third_party/make/getopt.h @@ -1,5 +1,5 @@ /* Declarations for getopt. -Copyright (C) 1989-2020 Free Software Foundation, Inc. +Copyright (C) 1989-2023 Free Software Foundation, Inc. NOTE: The canonical source of this file is maintained with the GNU C Library. Bugs can be reported to bug-glibc@gnu.org. @@ -14,8 +14,7 @@ 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 . */ - +this program. If not, see . */ #ifndef _GETOPT_H #define _GETOPT_H 1 @@ -128,10 +127,4 @@ extern int _getopt_internal (); } #endif -#else -extern int _getopt_internal (int argc, char *const *argv, - const char *shortopts, - const struct option *longopts, int *longind, - int long_only); - #endif /* getopt.h */ diff --git a/third_party/make/getopt1.c b/third_party/make/getopt1.c index 59f57e700..a103aceeb 100644 --- a/third_party/make/getopt1.c +++ b/third_party/make/getopt1.c @@ -1,5 +1,5 @@ /* getopt_long and getopt_long_only entry points for GNU getopt. -Copyright (C) 1987-1994, 1996-2020 Free Software Foundation, Inc. +Copyright (C) 1987-1994, 1996-2023 Free Software Foundation, Inc. NOTE: The canonical source of this file is maintained with the GNU C Library. Bugs can be reported to bug-glibc@gnu.org. @@ -14,14 +14,24 @@ 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 . */ - -#include "third_party/make/getopt.h" - +this program. If not, see . */ + #ifdef HAVE_CONFIG_H -#include "third_party/make/config.h" +#include "config.h" #endif +#include "getopt.h" + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling @@ -32,6 +42,7 @@ this program. If not, see . */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +#include #if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION #define ELIDE_CODE #endif @@ -39,6 +50,17 @@ this program. If not, see . */ #ifndef ELIDE_CODE + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#endif + +#ifndef NULL +#define NULL 0 +#endif + int getopt_long (int argc, char *const *argv, const char *options, const struct option *long_options, int *opt_index) @@ -63,6 +85,8 @@ getopt_long_only (int argc, char *const *argv, const char *options, #ifdef TEST +#include + int main (int argc, char **argv) { diff --git a/third_party/make/getprogname.c b/third_party/make/getprogname.c deleted file mode 100644 index 209160423..000000000 --- a/third_party/make/getprogname.c +++ /dev/null @@ -1,34 +0,0 @@ -/* Program name management. - Copyright (C) 2016-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -#include "third_party/make/config.h" -#include "third_party/make/getprogname.h" -#include "libc/intrin/safemacros.internal.h" -#include "libc/errno.h" -#include "third_party/make/dirname.h" - -char const * -getprogname (void) -{ - return firstnonnull(program_invocation_short_name, "unknown"); -} - -/* - * Hey Emacs! - * Local Variables: - * coding: utf-8 - * End: - */ diff --git a/third_party/make/getprogname.h b/third_party/make/getprogname.h deleted file mode 100644 index ff899585b..000000000 --- a/third_party/make/getprogname.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Program name management. - Copyright (C) 2016-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -#ifndef _GL_GETPROGNAME_H -#define _GL_GETPROGNAME_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Return the base name of the executing program. - On native Windows this will usually end in ".exe" or ".EXE". */ -#ifndef HAVE_GETPROGNAME -extern char const *getprogname(void) -#ifdef HAVE_DECL_PROGRAM_INVOCATION_NAME - _GL_ATTRIBUTE_PURE -#endif - ; -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/third_party/make/gettext.h b/third_party/make/gettext.h index 38ffc10bc..949d0a17f 100644 --- a/third_party/make/gettext.h +++ b/third_party/make/gettext.h @@ -1,99 +1,50 @@ /* Convenience header for conditional use of GNU . - Copyright (C) 1995-1998, 2000-2002, 2004-2006, 2009-2020 Free Software - Foundation, Inc. +Copyright (C) 1995-2023 Free Software Foundation, Inc. +This file is part of GNU Make. - 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, or (at your option) - any later version. +GNU Make 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. +GNU Make 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 . */ +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ #ifndef _LIBGETTEXT_H #define _LIBGETTEXT_H 1 -#include "libc/str/str.h" -/* NLS can be disabled through the configure --disable-nls option - or through "#define ENABLE NLS 0" before including this file. */ -#if defined ENABLE_NLS && ENABLE_NLS +/* NLS can be disabled through the configure --disable-nls option. */ +#if ENABLE_NLS /* Get declarations of GNU message catalog functions. */ - -/* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by - the gettext() and ngettext() macros. This is an alternative to calling - textdomain(), and is useful for libraries. */ -# ifdef DEFAULT_TEXT_DOMAIN -# undef gettext -# define gettext(Msgid) \ - dgettext (DEFAULT_TEXT_DOMAIN, Msgid) -# undef ngettext -# define ngettext(Msgid1, Msgid2, N) \ - dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N) -# endif +# include #else -/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which - chokes if dcgettext is defined as a macro. So include it now, to make - and also including would fail on SunOS 4, whereas - is OK. */ -#if defined(__sun) -#endif - -/* Many header files from the libstdc++ coming with g++ 3.3 or newer include - , which chokes if dcgettext is defined as a macro. So include - it now, to make later inclusions of a NOP. */ -#if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3) -# if (__GLIBC__ >= 2 && !defined __UCLIBC__) || _GLIBCXX_HAVE_LIBINTL_H -# endif -#endif - /* Disabled NLS. The casts to 'const char *' serve the purpose of producing warnings for invalid uses of the value returned from these functions. On pre-ANSI systems without 'const', the config.h file is supposed to contain "#define const". */ -# undef gettext # define gettext(Msgid) ((const char *) (Msgid)) -# undef dgettext -# define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid)) -# undef dcgettext -# define dcgettext(Domainname, Msgid, Category) \ - ((void) (Category), dgettext (Domainname, Msgid)) -# undef ngettext +# define dgettext(Domainname, Msgid) ((const char *) (Msgid)) +# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid)) # define ngettext(Msgid1, Msgid2, N) \ - ((N) == 1 \ - ? ((void) (Msgid2), (const char *) (Msgid1)) \ - : ((void) (Msgid1), (const char *) (Msgid2))) -# undef dngettext + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) # define dngettext(Domainname, Msgid1, Msgid2, N) \ - ((void) (Domainname), ngettext (Msgid1, Msgid2, N)) -# undef dcngettext + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) # define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ - ((void) (Category), dngettext (Domainname, Msgid1, Msgid2, N)) -# undef textdomain + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) # define textdomain(Domainname) ((const char *) (Domainname)) -# undef bindtextdomain -# define bindtextdomain(Domainname, Dirname) \ - ((void) (Domainname), (const char *) (Dirname)) -# undef bind_textdomain_codeset -# define bind_textdomain_codeset(Domainname, Codeset) \ - ((void) (Domainname), (const char *) (Codeset)) +# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) +# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset)) #endif -/* Prefer gnulib's setlocale override over libintl's setlocale override. */ -#ifdef GNULIB_defined_setlocale -# undef setlocale -# define setlocale rpl_setlocale -#endif - /* A pseudo function call that serves as a marker for the automated extraction of messages, but does not call gettext(). The run-time translation is done at a different place in the code. @@ -103,192 +54,4 @@ initializer for static 'char[]' or 'const char[]' variables. */ #define gettext_noop(String) String -/* The separator between msgctxt and msgid in a .mo file. */ -#define GETTEXT_CONTEXT_GLUE "\004" - -/* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a - MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be - short and rarely need to change. - The letter 'p' stands for 'particular' or 'special'. */ -#ifdef DEFAULT_TEXT_DOMAIN -# define pgettext(Msgctxt, Msgid) \ - pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) -#else -# define pgettext(Msgctxt, Msgid) \ - pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) -#endif -#define dpgettext(Domainname, Msgctxt, Msgid) \ - pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) -#define dcpgettext(Domainname, Msgctxt, Msgid, Category) \ - pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category) -#ifdef DEFAULT_TEXT_DOMAIN -# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ - npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) -#else -# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ - npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) -#endif -#define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ - npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) -#define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \ - npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, Category) - -#ifdef __GNUC__ -__inline -#else -#ifdef __cplusplus -inline -#endif -#endif -static const char * -pgettext_aux (const char *domain, - const char *msg_ctxt_id, const char *msgid, - int category) -{ - const char *translation = dcgettext (domain, msg_ctxt_id, category); - if (translation == msg_ctxt_id) - return msgid; - else - return translation; -} - -#ifdef __GNUC__ -__inline -#else -#ifdef __cplusplus -inline -#endif -#endif -static const char * -npgettext_aux (const char *domain, - const char *msg_ctxt_id, const char *msgid, - const char *msgid_plural, unsigned long int n, - int category) -{ - const char *translation = - dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); - if (translation == msg_ctxt_id || translation == msgid_plural) - return (n == 1 ? msgid : msgid_plural); - else - return translation; -} - -/* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID - can be arbitrary expressions. But for string literals these macros are - less efficient than those above. */ - - -/* GNULIB_NO_VLA can be defined to disable use of VLAs even if supported. - This relates to the -Wvla and -Wvla-larger-than warnings, enabled in - the default GCC many warnings set. This allows programs to disable use - of VLAs, which may be unintended, or may be awkward to support portably, - or may have security implications due to non-deterministic stack usage. */ - -#if (!defined GNULIB_NO_VLA \ - && (((__GNUC__ >= 3 || __GNUG__ >= 2) && !defined __STRICT_ANSI__) \ - /* || (__STDC_VERSION__ == 199901L && !defined __HP_cc) - || (__STDC_VERSION__ >= 201112L && !defined __STDC_NO_VLA__) */ )) -# define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 1 -#else -# define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 0 -#endif - -#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS -#endif - -#define pgettext_expr(Msgctxt, Msgid) \ - dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES) -#define dpgettext_expr(Domainname, Msgctxt, Msgid) \ - dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES) - -#ifdef __GNUC__ -__inline -#else -#ifdef __cplusplus -inline -#endif -#endif -static const char * -dcpgettext_expr (const char *domain, - const char *msgctxt, const char *msgid, - int category) -{ - size_t msgctxt_len = strlen (msgctxt) + 1; - size_t msgid_len = strlen (msgid) + 1; - const char *translation; -#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS - char msg_ctxt_id[msgctxt_len + msgid_len]; -#else - char buf[1024]; - char *msg_ctxt_id = - (msgctxt_len + msgid_len <= sizeof (buf) - ? buf - : (char *) malloc (msgctxt_len + msgid_len)); - if (msg_ctxt_id != NULL) -#endif - { - int found_translation; - memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); - msg_ctxt_id[msgctxt_len - 1] = '\004'; - memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); - translation = dcgettext (domain, msg_ctxt_id, category); - found_translation = (translation != msg_ctxt_id); -#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS - if (msg_ctxt_id != buf) - free (msg_ctxt_id); -#endif - if (found_translation) - return translation; - } - return msgid; -} - -#define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \ - dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) -#define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ - dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) - -#ifdef __GNUC__ -__inline -#else -#ifdef __cplusplus -inline -#endif -#endif -static const char * -dcnpgettext_expr (const char *domain, - const char *msgctxt, const char *msgid, - const char *msgid_plural, unsigned long int n, - int category) -{ - size_t msgctxt_len = strlen (msgctxt) + 1; - size_t msgid_len = strlen (msgid) + 1; - const char *translation; -#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS - char msg_ctxt_id[msgctxt_len + msgid_len]; -#else - char buf[1024]; - char *msg_ctxt_id = - (msgctxt_len + msgid_len <= sizeof (buf) - ? buf - : (char *) malloc (msgctxt_len + msgid_len)); - if (msg_ctxt_id != NULL) -#endif - { - int found_translation; - memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); - msg_ctxt_id[msgctxt_len - 1] = '\004'; - memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); - translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); - found_translation = !(translation == msg_ctxt_id || translation == msgid_plural); -#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS - if (msg_ctxt_id != buf) - free (msg_ctxt_id); -#endif - if (found_translation) - return translation; - } - return (n == 1 ? msgid : msgid_plural); -} - #endif /* _LIBGETTEXT_H */ diff --git a/third_party/make/glob.c b/third_party/make/glob.c new file mode 100644 index 000000000..020671a6a --- /dev/null +++ b/third_party/make/glob.c @@ -0,0 +1,1318 @@ +/* Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +2023 Free Software Foundation, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public License +along with this library; see the file COPYING.LIB. If not, write to the Free +Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA. */ + +/* AIX requires this to be the first thing in the file. */ +#if defined _AIX && !defined __GNUC__ + #pragma alloca +#endif + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +/* Enable GNU extensions in glob.h. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif + +#include +#include +#include + +/* Outcomment the following line for production quality code. */ +/* #define NDEBUG 1 */ +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GLOB_INTERFACE_VERSION 1 +#if defined _LIBC +# define ELIDE_CODE +#elif defined __GNU_LIBRARY__ && __GNU_LIBRARY__ > 1 +# include +# if _GNU_GLOB_INTERFACE_VERSION == GLOB_INTERFACE_VERSION +# define ELIDE_CODE +# endif +#endif + +#ifndef ELIDE_CODE + +#if defined STDC_HEADERS || defined __GNU_LIBRARY__ +# include +#endif + +#if defined HAVE_UNISTD_H +# include +# ifndef POSIX +# ifdef _POSIX_VERSION +# define POSIX +# endif +# endif +#endif + +#if !defined _AMIGA && !defined VMS && !defined WINDOWS32 +# include +#endif + +#if !defined __GNU_LIBRARY__ && !defined STDC_HEADERS +extern int errno; +#endif +#ifndef __set_errno +# define __set_errno(val) errno = (val) +#endif + +#if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__ +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# ifdef HAVE_SYS_NDIR_H +# include +# endif +# ifdef HAVE_SYS_DIR_H +# include +# endif +# ifdef HAVE_NDIR_H +# include +# endif +#endif + +/* In GNU systems, defines this macro for us. */ +#ifdef _D_NAMLEN +# undef NAMLEN +# define NAMLEN(d) _D_NAMLEN(d) +#endif + +/* When used in the GNU libc the symbol _DIRENT_HAVE_D_TYPE is available + if the `d_type' member for `struct dirent' is available. */ +#if defined(_DIRENT_HAVE_D_TYPE) || defined(HAVE_STRUCT_DIRENT_D_TYPE) +# define HAVE_D_TYPE 1 +#endif + + +#if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__ +/* Posix does not require that the d_ino field be present, and some + systems do not provide it. */ +# define REAL_DIR_ENTRY(dp) 1 +#else +# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0) +#endif /* POSIX */ + +#include +#include + +#if !defined HAVE_STRCOLL +# define strcoll strcmp +#endif + +#if !defined HAVE_MEMPCPY && __GLIBC__ - 0 == 2 && __GLIBC_MINOR__ >= 1 +# define HAVE_MEMPCPY 1 +# undef mempcpy +# define mempcpy(Dest, Src, Len) __mempcpy (Dest, Src, Len) +#endif + +#if !defined __alloca && !defined __GNU_LIBRARY__ + +# ifdef __GNUC__ +# undef alloca +# define alloca(n) __builtin_alloca (n) +# else /* Not GCC. */ +# ifdef HAVE_ALLOCA_H +# include +# else /* Not HAVE_ALLOCA_H. */ +# ifndef _AIX +# ifdef WINDOWS32 +# include +# else +extern char *alloca (); +# endif /* WINDOWS32 */ +# endif /* Not _AIX. */ +# endif /* sparc or HAVE_ALLOCA_H. */ +# endif /* GCC. */ +#endif + +#ifndef __GNU_LIBRARY__ +# ifdef STAT_MACROS_BROKEN +# undef S_ISDIR +# endif +# ifndef S_ISDIR +# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +# endif +#endif + +/* Some system header files erroneously define these. + We want our own definitions from to take precedence. */ +#ifndef __GNU_LIBRARY__ +# undef FNM_PATHNAME +# undef FNM_NOESCAPE +# undef FNM_PERIOD +#endif +#include + +/* Some system header files erroneously define these. + We want our own definitions from to take precedence. */ +#ifndef __GNU_LIBRARY__ +# undef GLOB_ERR +# undef GLOB_MARK +# undef GLOB_NOSORT +# undef GLOB_DOOFFS +# undef GLOB_NOCHECK +# undef GLOB_APPEND +# undef GLOB_NOESCAPE +# undef GLOB_PERIOD +#endif +#include "glob.h" + +#if !defined __alloca +# define __alloca alloca +#endif + +#ifdef HAVE_GETLOGIN_R +extern int getlogin_r (char *, size_t); +#else +extern char *getlogin (void); +#endif + +static +#if __GNUC__ - 0 >= 2 +inline +#endif +const char *next_brace_sub (const char *begin); +static int glob_in_dir (const char *pattern, const char *directory, + int flags, + int (*errfunc) (const char *, int), + glob_t *pglob); +static int prefix_array (const char *prefix, char **array, size_t n); +static int collated_compare (const void *, const void *); + +#if !defined NO_GLOB_PATTERN_P +int __glob_pattern_p (const char *pattern, int quote); +#endif + +/* Find the end of the sub-pattern in a brace expression. We define + this as an inline function if the compiler permits. */ +static +#if __GNUC__ - 0 >= 2 +inline +#endif +const char * +next_brace_sub (const char *begin) +{ + unsigned int depth = 0; + const char *cp = begin; + + while (1) + { + if (depth == 0) + { + if (*cp != ',' && *cp != '}' && *cp != '\0') + { + if (*cp == '{') + ++depth; + ++cp; + continue; + } + } + else + { + while (*cp != '\0' && (*cp != '}' || depth > 0)) + { + if (*cp == '}') + --depth; + ++cp; + } + if (*cp == '\0') + /* An incorrectly terminated brace expression. */ + return NULL; + + continue; + } + break; + } + + return cp; +} + +/* Do glob searching for PATTERN, placing results in PGLOB. + The bits defined above may be set in FLAGS. + If a directory cannot be opened or read and ERRFUNC is not nil, + it is called with the pathname that caused the error, and the + `errno' value from the failing call; if it returns non-zero + `glob' returns GLOB_ABORTED; if it returns zero, the error is ignored. + If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned. + Otherwise, `glob' returns zero. */ +int +glob (const char *pattern, int flags, + int (*errfunc) (const char *, int), glob_t *pglob) +{ + const char *filename; + const char *dirname; + size_t dirlen; + int status; + size_t oldcount; + + if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0) + { + __set_errno (EINVAL); + return -1; + } + + /* POSIX requires all slashes to be matched. This means that with + a trailing slash we must match only directories. */ + if (pattern[0] && pattern[strlen (pattern) - 1] == '/') + flags |= GLOB_ONLYDIR; + + if (flags & GLOB_BRACE) + { + const char *begin = strchr (pattern, '{'); + if (begin != NULL) + { + /* Allocate working buffer large enough for our work. Note that + we have at least an opening and closing brace. */ + size_t firstc; + char *alt_start; + const char *p; + const char *next; + const char *rest; + size_t rest_len; +#ifdef __GNUC__ + char onealt[strlen (pattern) - 1]; +#else + char *onealt = (char *) malloc (strlen (pattern) - 1); + if (onealt == NULL) + { + if (!(flags & GLOB_APPEND)) + globfree (pglob); + return GLOB_NOSPACE; + } +#endif + + /* We know the prefix for all sub-patterns. */ +#ifdef HAVE_MEMPCPY + alt_start = mempcpy (onealt, pattern, begin - pattern); +#else + memcpy (onealt, pattern, begin - pattern); + alt_start = &onealt[begin - pattern]; +#endif + + /* Find the first sub-pattern and at the same time find the + rest after the closing brace. */ + next = next_brace_sub (begin + 1); + if (next == NULL) + { + /* It is an illegal expression. */ +#ifndef __GNUC__ + free (onealt); +#endif + return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob); + } + + /* Now find the end of the whole brace expression. */ + rest = next; + while (*rest != '}') + { + rest = next_brace_sub (rest + 1); + if (rest == NULL) + { + /* It is an illegal expression. */ +#ifndef __GNUC__ + free (onealt); +#endif + return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob); + } + } + /* Please note that we now can be sure the brace expression + is well-formed. */ + rest_len = strlen (++rest) + 1; + + /* We have a brace expression. BEGIN points to the opening {, + NEXT points past the terminator of the first element, and END + points past the final }. We will accumulate result names from + recursive runs for each brace alternative in the buffer using + GLOB_APPEND. */ + + if (!(flags & GLOB_APPEND)) + { + /* This call is to set a new vector, so clear out the + vector so we can append to it. */ + pglob->gl_pathc = 0; + pglob->gl_pathv = NULL; + } + firstc = pglob->gl_pathc; + + p = begin + 1; + while (1) + { + int result; + + /* Construct the new glob expression. */ +#ifdef HAVE_MEMPCPY + mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len); +#else + memcpy (alt_start, p, next - p); + memcpy (&alt_start[next - p], rest, rest_len); +#endif + + result = glob (onealt, + ((flags & ~(GLOB_NOCHECK|GLOB_NOMAGIC)) + | GLOB_APPEND), errfunc, pglob); + + /* If we got an error, return it. */ + if (result && result != GLOB_NOMATCH) + { +#ifndef __GNUC__ + free (onealt); +#endif + if (!(flags & GLOB_APPEND)) + globfree (pglob); + return result; + } + + if (*next == '}') + /* We saw the last entry. */ + break; + + p = next + 1; + next = next_brace_sub (p); + assert (next != NULL); + } + +#ifndef __GNUC__ + free (onealt); +#endif + + if (pglob->gl_pathc != firstc) + /* We found some entries. */ + return 0; + else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) + return GLOB_NOMATCH; + } + } + + /* Find the filename. */ + filename = strrchr (pattern, '/'); +#if defined __MSDOS__ || defined WINDOWS32 + /* The case of "d:pattern". Since `:' is not allowed in + file names, we can safely assume that wherever it + happens in pattern, it signals the filename part. This + is so we could some day support patterns like "[a-z]:foo". */ + if (filename == NULL) + filename = strchr (pattern, ':'); +#endif /* __MSDOS__ || WINDOWS32 */ + if (filename == NULL) + { + /* This can mean two things: a simple name or "~name". The later + case is nothing but a notation for a directory. */ + if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~') + { + dirname = pattern; + dirlen = strlen (pattern); + + /* Set FILENAME to NULL as a special flag. This is ugly but + other solutions would require much more code. We test for + this special case below. */ + filename = NULL; + } + else + { + filename = pattern; +#ifdef _AMIGA + dirname = ""; +#else + dirname = "."; +#endif + dirlen = 0; + } + } + else if (filename == pattern) + { + /* "/pattern". */ + dirname = "/"; + dirlen = 1; + ++filename; + } + else + { + char *newp; + dirlen = filename - pattern; +#if defined __MSDOS__ || defined WINDOWS32 + if (*filename == ':' + || (filename > pattern + 1 && filename[-1] == ':')) + { + char *drive_spec; + + ++dirlen; + drive_spec = (char *) __alloca (dirlen + 1); +#ifdef HAVE_MEMPCPY + *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0'; +#else + memcpy (drive_spec, pattern, dirlen); + drive_spec[dirlen] = '\0'; +#endif + /* For now, disallow wildcards in the drive spec, to + prevent infinite recursion in glob. */ + if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE))) + return GLOB_NOMATCH; + /* If this is "d:pattern", we need to copy `:' to DIRNAME + as well. If it's "d:/pattern", don't remove the slash + from "d:/", since "d:" and "d:/" are not the same.*/ + } +#endif + newp = (char *) __alloca (dirlen + 1); +#ifdef HAVE_MEMPCPY + *((char *) mempcpy (newp, pattern, dirlen)) = '\0'; +#else + memcpy (newp, pattern, dirlen); + newp[dirlen] = '\0'; +#endif + dirname = newp; + ++filename; + + if (filename[0] == '\0' +#if defined __MSDOS__ || defined WINDOWS32 + && dirname[dirlen - 1] != ':' + && (dirlen < 3 || dirname[dirlen - 2] != ':' + || dirname[dirlen - 1] != '/') +#endif + && dirlen > 1) + /* "pattern/". Expand "pattern", appending slashes. */ + { + int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob); + if (val == 0) + pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK) + | (flags & GLOB_MARK)); + return val; + } + } + + if (!(flags & GLOB_APPEND)) + { + pglob->gl_pathc = 0; + pglob->gl_pathv = NULL; + } + + oldcount = pglob->gl_pathc; + +#ifndef VMS + if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~') + { + if (dirname[1] == '\0' || dirname[1] == '/') + { + /* Look up home directory. */ +#ifdef VMS +/* This isn't obvious, RTLs of DECC and VAXC know about "HOME" */ + const char *home_dir = getenv ("SYS$LOGIN"); +#else + const char *home_dir = getenv ("HOME"); +#endif +# ifdef _AMIGA + if (home_dir == NULL || home_dir[0] == '\0') + home_dir = "SYS:"; +# else +# ifdef WINDOWS32 + if (home_dir == NULL || home_dir[0] == '\0') + home_dir = "c:/users/default"; /* poor default */ +# else +# ifdef VMS +/* Again, this isn't obvious, if "HOME" isn't known "SYS$LOGIN" should be set */ + if (home_dir == NULL || home_dir[0] == '\0') + home_dir = "SYS$DISK:[]"; +# else + if (home_dir == NULL || home_dir[0] == '\0') + { + int success; + char *name; +# if defined HAVE_GETLOGIN_R + size_t buflen = sysconf (_SC_LOGIN_NAME_MAX) + 1; + + if (buflen == 0) + /* `sysconf' does not support _SC_LOGIN_NAME_MAX. Try + a moderate value. */ + buflen = 20; + name = (char *) __alloca (buflen); + + success = getlogin_r (name, buflen) >= 0; +# else + success = (name = getlogin ()) != NULL; +# endif + if (success) + { + struct passwd *p; +# if defined HAVE_GETPWNAM_R + size_t pwbuflen = sysconf (_SC_GETPW_R_SIZE_MAX); + char *pwtmpbuf; + struct passwd pwbuf; + int save = errno; + + if (pwbuflen == -1) + /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX. + Try a moderate value. */ + pwbuflen = 1024; + pwtmpbuf = (char *) __alloca (pwbuflen); + + while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p) + != 0) + { + if (errno != ERANGE) + { + p = NULL; + break; + } + pwbuflen *= 2; + pwtmpbuf = (char *) __alloca (pwbuflen); + __set_errno (save); + } +# else + p = getpwnam (name); +# endif + if (p != NULL) + home_dir = p->pw_dir; + } + } + if (home_dir == NULL || home_dir[0] == '\0') + { + if (flags & GLOB_TILDE_CHECK) + return GLOB_NOMATCH; + else + home_dir = "~"; /* No luck. */ + } +# endif /* VMS */ +# endif /* WINDOWS32 */ +# endif + /* Now construct the full directory. */ + if (dirname[1] == '\0') + dirname = home_dir; + else + { + char *newp; + size_t home_len = strlen (home_dir); + newp = (char *) __alloca (home_len + dirlen); +# ifdef HAVE_MEMPCPY + mempcpy (mempcpy (newp, home_dir, home_len), + &dirname[1], dirlen); +# else + memcpy (newp, home_dir, home_len); + memcpy (&newp[home_len], &dirname[1], dirlen); +# endif + dirname = newp; + } + } +# if !defined _AMIGA && !defined WINDOWS32 && !defined VMS + else + { + char *end_name = strchr (dirname, '/'); + const char *user_name; + const char *home_dir; + + if (end_name == NULL) + user_name = dirname + 1; + else + { + char *newp; + newp = (char *) __alloca (end_name - dirname); +# ifdef HAVE_MEMPCPY + *((char *) mempcpy (newp, dirname + 1, end_name - dirname)) + = '\0'; +# else + memcpy (newp, dirname + 1, end_name - dirname); + newp[end_name - dirname - 1] = '\0'; +# endif + user_name = newp; + } + + /* Look up specific user's home directory. */ + { + struct passwd *p; +# if defined HAVE_GETPWNAM_R + size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX); + char *pwtmpbuf; + struct passwd pwbuf; + int save = errno; + + if (buflen == -1) + /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX. Try a + moderate value. */ + buflen = 1024; + pwtmpbuf = (char *) __alloca (buflen); + + while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0) + { + if (errno != ERANGE) + { + p = NULL; + break; + } + buflen *= 2; + pwtmpbuf = __alloca (buflen); + __set_errno (save); + } +# else + p = getpwnam (user_name); +# endif + if (p != NULL) + home_dir = p->pw_dir; + else + home_dir = NULL; + } + /* If we found a home directory use this. */ + if (home_dir != NULL) + { + char *newp; + size_t home_len = strlen (home_dir); + size_t rest_len = end_name == NULL ? 0 : strlen (end_name); + newp = (char *) __alloca (home_len + rest_len + 1); +# ifdef HAVE_MEMPCPY + *((char *) mempcpy (mempcpy (newp, home_dir, home_len), + end_name, rest_len)) = '\0'; +# else + memcpy (newp, home_dir, home_len); + memcpy (&newp[home_len], end_name, rest_len); + newp[home_len + rest_len] = '\0'; +# endif + dirname = newp; + } + else + if (flags & GLOB_TILDE_CHECK) + /* We have to regard it as an error if we cannot find the + home directory. */ + return GLOB_NOMATCH; + } +# endif /* Not Amiga && not WINDOWS32 && not VMS. */ + } +#endif /* Not VMS. */ + + /* Now test whether we looked for "~" or "~NAME". In this case we + can give the answer now. */ + if (filename == NULL) + { + struct stat st; + + /* Return the directory if we don't check for error or if it exists. */ + if ((flags & GLOB_NOCHECK) + || (((flags & GLOB_ALTDIRFUNC) + ? (*pglob->gl_stat) (dirname, &st) + : stat (dirname, &st)) == 0 + && S_ISDIR (st.st_mode))) + { + pglob->gl_pathv + = (char **) realloc (pglob->gl_pathv, + (pglob->gl_pathc + + ((flags & GLOB_DOOFFS) ? + pglob->gl_offs : 0) + + 1 + 1) * + sizeof (char *)); + if (pglob->gl_pathv == NULL) + return GLOB_NOSPACE; + + if (flags & GLOB_DOOFFS) + while (pglob->gl_pathc < pglob->gl_offs) + pglob->gl_pathv[pglob->gl_pathc++] = NULL; + +#if defined HAVE_STRDUP + pglob->gl_pathv[pglob->gl_pathc] = strdup (dirname); +#else + { + size_t len = strlen (dirname) + 1; + char *dircopy = malloc (len); + if (dircopy != NULL) + pglob->gl_pathv[pglob->gl_pathc] = memcpy (dircopy, dirname, + len); + } +#endif + if (pglob->gl_pathv[pglob->gl_pathc] == NULL) + { + free (pglob->gl_pathv); + return GLOB_NOSPACE; + } + pglob->gl_pathv[++pglob->gl_pathc] = NULL; + pglob->gl_flags = flags; + + return 0; + } + + /* Not found. */ + return GLOB_NOMATCH; + } + + if (__glob_pattern_p (dirname, !(flags & GLOB_NOESCAPE))) + { + /* The directory name contains metacharacters, so we + have to glob for the directory, and then glob for + the pattern in each directory found. */ + glob_t dirs; + size_t i; + + status = glob (dirname, + ((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE)) + | GLOB_NOSORT | GLOB_ONLYDIR), + errfunc, &dirs); + if (status != 0) + return status; + + /* We have successfully globbed the preceding directory name. + For each name we found, call glob_in_dir on it and FILENAME, + appending the results to PGLOB. */ + for (i = 0; i < dirs.gl_pathc; ++i) + { + size_t old_pathc; + +#ifdef SHELL + { + /* Make globbing interruptible in the bash shell. */ + extern int interrupt_state; + + if (interrupt_state) + { + globfree (&dirs); + globfree (&files); + return GLOB_ABORTED; + } + } +#endif /* SHELL. */ + + old_pathc = pglob->gl_pathc; + status = glob_in_dir (filename, dirs.gl_pathv[i], + ((flags | GLOB_APPEND) + & ~(GLOB_NOCHECK | GLOB_ERR)), + errfunc, pglob); + if (status == GLOB_NOMATCH) + /* No matches in this directory. Try the next. */ + continue; + + if (status != 0) + { + globfree (&dirs); + globfree (pglob); + return status; + } + + /* Stick the directory on the front of each name. */ + if (prefix_array (dirs.gl_pathv[i], + &pglob->gl_pathv[old_pathc], + pglob->gl_pathc - old_pathc)) + { + globfree (&dirs); + globfree (pglob); + return GLOB_NOSPACE; + } + } + + flags |= GLOB_MAGCHAR; + + /* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls. + But if we have not found any matching entry and thie GLOB_NOCHECK + flag was set we must return the list consisting of the disrectory + names followed by the filename. */ + if (pglob->gl_pathc == oldcount) + { + /* No matches. */ + if (flags & GLOB_NOCHECK) + { + size_t filename_len = strlen (filename) + 1; + char **new_pathv; + struct stat st; + + /* This is an pessimistic guess about the size. */ + pglob->gl_pathv + = (char **) realloc (pglob->gl_pathv, + (pglob->gl_pathc + + ((flags & GLOB_DOOFFS) ? + pglob->gl_offs : 0) + + dirs.gl_pathc + 1) * + sizeof (char *)); + if (pglob->gl_pathv == NULL) + { + globfree (&dirs); + return GLOB_NOSPACE; + } + + if (flags & GLOB_DOOFFS) + while (pglob->gl_pathc < pglob->gl_offs) + pglob->gl_pathv[pglob->gl_pathc++] = NULL; + + for (i = 0; i < dirs.gl_pathc; ++i) + { + const char *dir = dirs.gl_pathv[i]; + size_t dir_len = strlen (dir); + + /* First check whether this really is a directory. */ + if (((flags & GLOB_ALTDIRFUNC) + ? (*pglob->gl_stat) (dir, &st) : stat (dir, &st)) != 0 + || !S_ISDIR (st.st_mode)) + /* No directory, ignore this entry. */ + continue; + + pglob->gl_pathv[pglob->gl_pathc] = malloc (dir_len + 1 + + filename_len); + if (pglob->gl_pathv[pglob->gl_pathc] == NULL) + { + globfree (&dirs); + globfree (pglob); + return GLOB_NOSPACE; + } + +#ifdef HAVE_MEMPCPY + mempcpy (mempcpy (mempcpy (pglob->gl_pathv[pglob->gl_pathc], + dir, dir_len), + "/", 1), + filename, filename_len); +#else + memcpy (pglob->gl_pathv[pglob->gl_pathc], dir, dir_len); + pglob->gl_pathv[pglob->gl_pathc][dir_len] = '/'; + memcpy (&pglob->gl_pathv[pglob->gl_pathc][dir_len + 1], + filename, filename_len); +#endif + ++pglob->gl_pathc; + } + + pglob->gl_pathv[pglob->gl_pathc] = NULL; + pglob->gl_flags = flags; + + /* Now we know how large the gl_pathv vector must be. */ + new_pathv = (char **) realloc (pglob->gl_pathv, + ((pglob->gl_pathc + 1) + * sizeof (char *))); + if (new_pathv != NULL) + pglob->gl_pathv = new_pathv; + } + else + return GLOB_NOMATCH; + } + + globfree (&dirs); + } + else + { + status = glob_in_dir (filename, dirname, flags, errfunc, pglob); + if (status != 0) + return status; + + if (dirlen > 0) + { + /* Stick the directory on the front of each name. */ + size_t ignore = oldcount; + + if ((flags & GLOB_DOOFFS) && ignore < pglob->gl_offs) + ignore = pglob->gl_offs; + + if (prefix_array (dirname, + &pglob->gl_pathv[ignore], + pglob->gl_pathc - ignore)) + { + globfree (pglob); + return GLOB_NOSPACE; + } + } + } + + if (flags & GLOB_MARK) + { + /* Append slashes to directory names. */ + size_t i; + struct stat st; + for (i = oldcount; i < pglob->gl_pathc; ++i) + if (((flags & GLOB_ALTDIRFUNC) + ? (*pglob->gl_stat) (pglob->gl_pathv[i], &st) + : stat (pglob->gl_pathv[i], &st)) == 0 + && S_ISDIR (st.st_mode)) + { + size_t len = strlen (pglob->gl_pathv[i]) + 2; + char *new = realloc (pglob->gl_pathv[i], len); + if (new == NULL) + { + globfree (pglob); + return GLOB_NOSPACE; + } + strcpy (&new[len - 2], "/"); + pglob->gl_pathv[i] = new; + } + } + + if (!(flags & GLOB_NOSORT)) + { + /* Sort the vector. */ + size_t non_sort = oldcount; + + if ((flags & GLOB_DOOFFS) && pglob->gl_offs > oldcount) + non_sort = pglob->gl_offs; + + qsort ((void *) &pglob->gl_pathv[non_sort], + pglob->gl_pathc - non_sort, + sizeof (char *), collated_compare); + } + + return 0; +} + + +/* Free storage allocated in PGLOB by a previous `glob' call. */ +void +globfree (glob_t *pglob) +{ + if (pglob->gl_pathv != NULL) + { + size_t i; + for (i = 0; i < pglob->gl_pathc; ++i) + if (pglob->gl_pathv[i] != NULL) + free (pglob->gl_pathv[i]); + free (pglob->gl_pathv); + } +} + + +/* Do a collated comparison of A and B. */ +static int +collated_compare (const void *a, const void *b) +{ + const char *const s1 = *(const char *const * const) a; + const char *const s2 = *(const char *const * const) b; + + if (s1 == s2) + return 0; + if (s1 == NULL) + return 1; + if (s2 == NULL) + return -1; + return strcoll (s1, s2); +} + + +/* Prepend DIRNAME to each of N members of ARRAY, replacing ARRAY's + elements in place. Return nonzero if out of memory, zero if successful. + A slash is inserted between DIRNAME and each elt of ARRAY, + unless DIRNAME is just "/". Each old element of ARRAY is freed. */ +static int +prefix_array (const char *dirname, char **array, size_t n) +{ + size_t i; + size_t dirlen = strlen (dirname); +#if defined __MSDOS__ || defined WINDOWS32 + char sep_char = '/'; +# define DIRSEP_CHAR sep_char +#else +# define DIRSEP_CHAR '/' +#endif + + if (dirlen == 1 && dirname[0] == '/') + /* DIRNAME is just "/", so normal prepending would get us "//foo". + We want "/foo" instead, so don't prepend any chars from DIRNAME. */ + dirlen = 0; +#if defined __MSDOS__ || defined WINDOWS32 + else if (dirlen > 1) + { + if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':') + /* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */ + --dirlen; + else if (dirname[dirlen - 1] == ':') + { + /* DIRNAME is "d:". Use `:' instead of `/'. */ + --dirlen; + sep_char = ':'; + } + } +#endif + + for (i = 0; i < n; ++i) + { + size_t eltlen = strlen (array[i]) + 1; + char *new = (char *) malloc (dirlen + 1 + eltlen); + if (new == NULL) + { + while (i > 0) + free (array[--i]); + return 1; + } + +#ifdef HAVE_MEMPCPY + { + char *endp = (char *) mempcpy (new, dirname, dirlen); + *endp++ = DIRSEP_CHAR; + mempcpy (endp, array[i], eltlen); + } +#else + memcpy (new, dirname, dirlen); + new[dirlen] = DIRSEP_CHAR; + memcpy (&new[dirlen + 1], array[i], eltlen); +#endif + free (array[i]); + array[i] = new; + } + + return 0; +} + + +/* We must not compile this function twice. */ +#if !defined NO_GLOB_PATTERN_P +/* Return nonzero if PATTERN contains any metacharacters. + Metacharacters can be quoted with backslashes if QUOTE is nonzero. */ +int +__glob_pattern_p (const char *pattern, int quote) +{ + const char *p; + int open = 0; + + for (p = pattern; *p != '\0'; ++p) + switch (*p) + { + case '?': + case '*': + return 1; + + case '\\': + if (quote && p[1] != '\0') + ++p; + break; + + case '[': + open = 1; + break; + + case ']': + if (open) + return 1; + break; + } + + return 0; +} +#endif + + +/* Like `glob', but PATTERN is a final pathname component, + and matches are searched for in DIRECTORY. + The GLOB_NOSORT bit in FLAGS is ignored. No sorting is ever done. + The GLOB_APPEND flag is assumed to be set (always appends). */ +static int +glob_in_dir (const char *pattern, const char *directory, int flags, + int (*errfunc) (const char *, int), glob_t *pglob) +{ + void *stream = NULL; + + struct globlink + { + struct globlink *next; + char *name; + }; + struct globlink *names = NULL; + size_t nfound; + int meta; + int save; + +#ifdef VMS + if (*directory == 0) + directory = "[]"; +#endif + meta = __glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE)); + if (meta == 0) + { + if (flags & (GLOB_NOCHECK|GLOB_NOMAGIC)) + /* We need not do any tests. The PATTERN contains no meta + characters and we must not return an error therefore the + result will always contain exactly one name. */ + flags |= GLOB_NOCHECK; + else + { + /* Since we use the normal file functions we can also use stat() + to verify the file is there. */ + struct stat st; + size_t patlen = strlen (pattern); + size_t dirlen = strlen (directory); + char *fullname = (char *) __alloca (dirlen + 1 + patlen + 1); + +# ifdef HAVE_MEMPCPY + mempcpy (mempcpy (mempcpy (fullname, directory, dirlen), + "/", 1), + pattern, patlen + 1); +# else + memcpy (fullname, directory, dirlen); + fullname[dirlen] = '/'; + memcpy (&fullname[dirlen + 1], pattern, patlen + 1); +# endif + if (((flags & GLOB_ALTDIRFUNC) + ? (*pglob->gl_stat) (fullname, &st) + : stat (fullname, &st)) == 0) + /* We found this file to be existing. Now tell the rest + of the function to copy this name into the result. */ + flags |= GLOB_NOCHECK; + } + + nfound = 0; + } + else + { + if (pattern[0] == '\0') + { + /* This is a special case for matching directories like in + "*a/". */ + names = (struct globlink *) __alloca (sizeof (struct globlink)); + names->name = (char *) malloc (1); + if (names->name == NULL) + goto memory_error; + names->name[0] = '\0'; + names->next = NULL; + nfound = 1; + meta = 0; + } + else + { + stream = ((flags & GLOB_ALTDIRFUNC) + ? (*pglob->gl_opendir) (directory) + : (void *) opendir (directory)); + if (stream == NULL) + { + if (errno != ENOTDIR + && ((errfunc != NULL && (*errfunc) (directory, errno)) + || (flags & GLOB_ERR))) + return GLOB_ABORTED; + nfound = 0; + meta = 0; + } + else + { + int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) + | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) +#if defined HAVE_CASE_INSENSITIVE_FS + | FNM_CASEFOLD +#endif + ); + nfound = 0; + flags |= GLOB_MAGCHAR; + + while (1) + { + const char *name; + size_t len; + struct dirent *d = ((flags & GLOB_ALTDIRFUNC) + ? (*pglob->gl_readdir) (stream) + : readdir ((DIR *) stream)); + if (d == NULL) + break; + if (! REAL_DIR_ENTRY (d)) + continue; + +#ifdef HAVE_D_TYPE + /* If we shall match only directories use the information + provided by the dirent call if possible. */ + if ((flags & GLOB_ONLYDIR) + && d->d_type != DT_UNKNOWN && d->d_type != DT_DIR && d->d_type != DT_LNK) + continue; +#endif + + name = d->d_name; + + if (fnmatch (pattern, name, fnm_flags) == 0) + { + struct globlink *new = (struct globlink *) + __alloca (sizeof (struct globlink)); + len = NAMLEN (d); + new->name = (char *) malloc (len + 1); + if (new->name == NULL) + goto memory_error; +#ifdef HAVE_MEMPCPY + *((char *) mempcpy (new->name, name, len)) = '\0'; +#else + memcpy (new->name, name, len); + new->name[len] = '\0'; +#endif + new->next = names; + names = new; + ++nfound; + } + } + } + } + } + + if (nfound == 0 && (flags & GLOB_NOCHECK)) + { + size_t len = strlen (pattern); + nfound = 1; + names = (struct globlink *) __alloca (sizeof (struct globlink)); + names->next = NULL; + names->name = (char *) malloc (len + 1); + if (names->name == NULL) + goto memory_error; +#ifdef HAVE_MEMPCPY + *((char *) mempcpy (names->name, pattern, len)) = '\0'; +#else + memcpy (names->name, pattern, len); + names->name[len] = '\0'; +#endif + } + + if (nfound != 0) + { + pglob->gl_pathv + = (char **) realloc (pglob->gl_pathv, + (pglob->gl_pathc + + ((flags & GLOB_DOOFFS) ? pglob->gl_offs : 0) + + nfound + 1) * + sizeof (char *)); + if (pglob->gl_pathv == NULL) + goto memory_error; + + if (flags & GLOB_DOOFFS) + while (pglob->gl_pathc < pglob->gl_offs) + pglob->gl_pathv[pglob->gl_pathc++] = NULL; + + for (; names != NULL; names = names->next) + pglob->gl_pathv[pglob->gl_pathc++] = names->name; + pglob->gl_pathv[pglob->gl_pathc] = NULL; + + pglob->gl_flags = flags; + } + + save = errno; + if (stream != NULL) + { + if (flags & GLOB_ALTDIRFUNC) + (*pglob->gl_closedir) (stream); + else + closedir ((DIR *) stream); + } + __set_errno (save); + + return nfound == 0 ? GLOB_NOMATCH : 0; + + memory_error: + { + save = errno; + if (flags & GLOB_ALTDIRFUNC) + (*pglob->gl_closedir) (stream); + else + closedir ((DIR *) stream); + __set_errno (save); + } + while (names != NULL) + { + if (names->name != NULL) + free (names->name); + names = names->next; + } + return GLOB_NOSPACE; +} + +#endif /* Not ELIDE_CODE. */ diff --git a/third_party/make/glob.h b/third_party/make/glob.h new file mode 100644 index 000000000..971f290b6 --- /dev/null +++ b/third_party/make/glob.h @@ -0,0 +1,163 @@ +/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ +/* Copyright (C) 1991, 1992, 1995, 1996, 1997, 1998, 2023 Free Software +Foundation, Inc. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public License +along with this library; see the file COPYING.LIB. If not, write to the Free +Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA. */ + +#ifndef _GLOB_H +#define _GLOB_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Bits set in the FLAGS argument to `glob'. */ +#define GLOB_ERR (1 << 0)/* Return on read errors. */ +#define GLOB_MARK (1 << 1)/* Append a slash to each name. */ +#define GLOB_NOSORT (1 << 2)/* Don't sort the names. */ +#define GLOB_DOOFFS (1 << 3)/* Insert PGLOB->gl_offs NULLs. */ +#define GLOB_NOCHECK (1 << 4)/* If nothing matches, return the pattern. */ +#define GLOB_APPEND (1 << 5)/* Append to results of a previous call. */ +#define GLOB_NOESCAPE (1 << 6)/* Backslashes don't quote metacharacters. */ +#define GLOB_PERIOD (1 << 7)/* Leading `.' can be matched by metachars. */ + +#if (!defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _BSD_SOURCE \ + || defined _GNU_SOURCE) +# define GLOB_MAGCHAR (1 << 8)/* Set in gl_flags if any metachars seen. */ +# define GLOB_ALTDIRFUNC (1 << 9)/* Use gl_opendir et al functions. */ +# define GLOB_BRACE (1 << 10)/* Expand "{a,b}" to "a" "b". */ +# define GLOB_NOMAGIC (1 << 11)/* If no magic chars, return the pattern. */ +# define GLOB_TILDE (1 << 12)/* Expand ~user and ~ to home directories. */ +# define GLOB_ONLYDIR (1 << 13)/* Match only directories. */ +# define GLOB_TILDE_CHECK (1 << 14)/* Like GLOB_TILDE but return an error + if the user name is not available. */ +# define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \ + GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \ + GLOB_PERIOD|GLOB_ALTDIRFUNC|GLOB_BRACE| \ + GLOB_NOMAGIC|GLOB_TILDE|GLOB_ONLYDIR|GLOB_TILDE_CHECK) +#else +# define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \ + GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \ + GLOB_PERIOD) +#endif + +/* Error returns from `glob'. */ +#define GLOB_NOSPACE 1 /* Ran out of memory. */ +#define GLOB_ABORTED 2 /* Read error. */ +#define GLOB_NOMATCH 3 /* No matches found. */ +#define GLOB_NOSYS 4 /* Not implemented. */ +#ifdef _GNU_SOURCE +/* Previous versions of this file defined GLOB_ABEND instead of + GLOB_ABORTED. Provide a compatibility definition here. */ +# define GLOB_ABEND GLOB_ABORTED +#endif + +/* Structure describing a globbing run. */ +#if !defined _AMIGA && !defined VMS /* Buggy compiler. */ +struct stat; +#endif +typedef struct + { + size_t gl_pathc; /* Count of paths matched by the pattern. */ + char **gl_pathv; /* List of matched pathnames. */ + size_t gl_offs; /* Slots to reserve in `gl_pathv'. */ + int gl_flags; /* Set to FLAGS, maybe | GLOB_MAGCHAR. */ + + /* If the GLOB_ALTDIRFUNC flag is set, the following functions + are used instead of the normal file access functions. */ + void (*gl_closedir) (void *); + struct dirent *(*gl_readdir) (void *); + void * (*gl_opendir) (const char *); + int (*gl_lstat) (const char *, struct stat *); +#if defined(VMS) && defined(__DECC) && !defined(_POSIX_C_SOURCE) + int (*gl_stat) (const char *, struct stat *, ...); +#else + int (*gl_stat) (const char *, struct stat *); +#endif + } glob_t; + +#ifdef _LARGEFILE64_SOURCE +struct stat64; +typedef struct + { + size_t gl_pathc; + char **gl_pathv; + size_t gl_offs; + int gl_flags; + + /* If the GLOB_ALTDIRFUNC flag is set, the following functions + are used instead of the normal file access functions. */ + void (*gl_closedir) (void *); + struct dirent64 *(*gl_readdir) (void *); + void * (*gl_opendir) (const char *); + int (*gl_lstat) (const char *, struct stat64 *); + int (*gl_stat) (const char *, struct stat64 *); + } glob64_t; +#endif + +#if _FILE_OFFSET_BITS == 64 && __GNUC__ < 2 +# define glob glob64 +# define globfree globfree64 +#else +# ifdef _LARGEFILE64_SOURCE +extern int glob64 (const char *pattern, int flags, + int (*errfunc) (const char *, int), + glob64_t *pglob); + +extern void globfree64 (glob64_t *pglob); +# endif +#endif + +/* Do glob searching for PATTERN, placing results in PGLOB. + The bits defined above may be set in FLAGS. + If a directory cannot be opened or read and ERRFUNC is not nil, + it is called with the pathname that caused the error, and the + `errno' value from the failing call; if it returns non-zero + `glob' returns GLOB_ABEND; if it returns zero, the error is ignored. + If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned. + Otherwise, `glob' returns zero. */ +#if _FILE_OFFSET_BITS != 64 || __GNUC__ < 2 +extern int glob (const char *pattern, int flags, + int (*errfunc) (const char *, int), + glob_t *pglob); + +/* Free storage allocated in PGLOB by a previous `glob' call. */ +extern void globfree (glob_t *pglob); +#else +extern int glob (const char *pattern, int flags, + int (*errfunc) (const char *, int), + glob_t *pglob) __asm__ ("glob64"); + +extern void globfree (glob_t *pglob) __asm__ ("globfree64"); +#endif + + +#ifdef _GNU_SOURCE +/* Return nonzero if PATTERN contains any metacharacters. + Metacharacters can be quoted with backslashes if QUOTE is nonzero. + + This function is not part of the interface specified by POSIX.2 + but several programs want to use it. */ +extern int glob_pattern_p (const char *pattern, int quote); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* glob.h */ diff --git a/third_party/make/gnumake.h b/third_party/make/gnumake.h index fe0f7f309..b437db75e 100644 --- a/third_party/make/gnumake.h +++ b/third_party/make/gnumake.h @@ -1,7 +1,7 @@ /* External interfaces usable by dynamic objects loaded into GNU Make. --THIS API IS A "TECHNOLOGY PREVIEW" ONLY. IT IS NOT A STABLE INTERFACE-- -Copyright (C) 2013-2020 Free Software Foundation, Inc. +Copyright (C) 2013-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -14,7 +14,7 @@ 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 . */ +this program. If not, see . */ #ifndef _GNUMAKE_H_ #define _GNUMAKE_H_ @@ -41,23 +41,23 @@ typedef char *(*gmk_func_ptr)(const char *nm, unsigned int argc, char **argv); /* Free memory returned by the gmk_expand() function. */ GMK_EXPORT void gmk_free (char *str); -/* Allocate memory in GNU make's context. */ +/* Allocate memory in GNU Make's context. */ GMK_EXPORT char *gmk_alloc (unsigned int len); /* Run $(eval ...) on the provided string BUFFER. */ GMK_EXPORT void gmk_eval (const char *buffer, const gmk_floc *floc); -/* Run GNU make expansion on the provided string STR. +/* Run GNU Make expansion on the provided string STR. Returns an allocated buffer that the caller must free with gmk_free(). */ GMK_EXPORT char *gmk_expand (const char *str); -/* Register a new GNU make function NAME (maximum of 255 chars long). +/* Register a new GNU Make function NAME (maximum of 255 chars long). When the function is expanded in the makefile, FUNC will be invoked with the appropriate arguments. The return value of FUNC must be either NULL, in which case it expands to the empty string, or a pointer to the result of the expansion in a string - created by gmk_alloc(). GNU make will free the memory when it's done. + created by gmk_alloc(). GNU Make will free the memory when it's done. MIN_ARGS is the minimum number of arguments the function requires. MAX_ARGS is the maximum number of arguments (or 0 if there's no maximum). diff --git a/third_party/make/guile.c b/third_party/make/guile.c index 18b526624..303dbeae3 100644 --- a/third_party/make/guile.c +++ b/third_party/make/guile.c @@ -1,5 +1,5 @@ /* GNU Guile interface for GNU Make. -Copyright (C) 2011-2020 Free Software Foundation, Inc. +Copyright (C) 2011-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,12 +12,148 @@ 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 . */ +this program. If not, see . */ -#include "third_party/make/makeint.inc" +#include "makeint.h" + +#ifdef HAVE_GUILE + +#include "gnumake.h" + +#include "debug.h" +#include "filedef.h" +#include "dep.h" +#include "variable.h" + +#include + +/* Pre-2.0 versions of Guile don't have a typedef for gsubr function types. */ +#if SCM_MAJOR_VERSION < 2 +# define GSUBR_TYPE SCM (*) () +/* Guile 1.x doesn't really support i18n. */ +# define EVAL_STRING(_s) scm_c_eval_string (_s) +#else +# define GSUBR_TYPE scm_t_subr +# define EVAL_STRING(_s) scm_eval_string (scm_from_utf8_string (_s)) +#endif + +static SCM make_mod = SCM_EOL; +static SCM obj_to_str = SCM_EOL; + +/* Convert an SCM object into a string. */ +static char * +cvt_scm_to_str (SCM obj) +{ + return scm_to_locale_string (scm_call_1 (obj_to_str, obj)); +} + +/* Perform the GNU Make expansion function. */ +static SCM +guile_expand_wrapper (SCM obj) +{ + char *str = cvt_scm_to_str (obj); + SCM ret; + char *res; + + DB (DB_BASIC, (_("guile: Expanding '%s'\n"), str)); + res = gmk_expand (str); + ret = scm_from_locale_string (res); + + free (str); + free (res); + + return ret; +} + +/* Perform the GNU Make eval function. */ +static SCM +guile_eval_wrapper (SCM obj) +{ + char *str = cvt_scm_to_str (obj); + + DB (DB_BASIC, (_("guile: Evaluating '%s'\n"), str)); + gmk_eval (str, 0); + + return SCM_BOOL_F; +} + +/* Invoked by scm_c_define_module(), in the context of the GNU Make module. */ +static void +guile_define_module (void *data UNUSED) +{ +/* Ingest the predefined Guile module for GNU Make. */ + //#include "gmk-default.h" + + /* Register a subr for GNU Make's eval capability. */ + scm_c_define_gsubr ("gmk-expand", 1, 0, 0, (GSUBR_TYPE) guile_expand_wrapper); + + /* Register a subr for GNU Make's eval capability. */ + scm_c_define_gsubr ("gmk-eval", 1, 0, 0, (GSUBR_TYPE) guile_eval_wrapper); + + /* Define the rest of the module. */ + scm_c_eval_string (GUILE_module_defn); +} + +/* Initialize the GNU Make Guile module. */ +static void * +guile_init (void *arg UNUSED) +{ + /* Define the module. */ + make_mod = scm_c_define_module ("gnu make", guile_define_module, NULL); + + /* Get a reference to the object-to-string translator, for later. */ + obj_to_str = scm_variable_ref (scm_c_module_lookup (make_mod, "obj-to-str")); + + /* Import the GNU Make module exports into the generic space. */ + scm_c_eval_string ("(use-modules (gnu make))"); + + return NULL; +} + +static void * +internal_guile_eval (void *arg) +{ + return cvt_scm_to_str (EVAL_STRING (arg)); +} + +/* This is the function registered with make */ +static char * +func_guile (const char *funcname UNUSED, unsigned int argc UNUSED, char **argv) +{ + static int init = 0; + + if (! init) + { + /* Initialize the Guile interpreter. */ + scm_with_guile (guile_init, NULL); + init = 1; + } + + if (argv[0] && argv[0][0] != '\0') + return scm_with_guile (internal_guile_eval, argv[0]); + + return NULL; +} + +/* ----- Public interface ----- */ + +/* We could send the flocp to define_new_function(), but since guile is + "kind of" built-in, that didn't seem so useful. */ +int +guile_gmake_setup (const floc *flocp UNUSED) +{ + /* Create a make function "guile". */ + gmk_add_function ("guile", func_guile, 0, 1, GMK_FUNC_DEFAULT); + + return 1; +} + +#else int guile_gmake_setup (const floc *flocp UNUSED) { return 1; } + +#endif diff --git a/third_party/make/hash.c b/third_party/make/hash.c index 0012dcdcc..d1652f84b 100644 --- a/third_party/make/hash.c +++ b/third_party/make/hash.c @@ -12,20 +12,13 @@ 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 . */ +this program. If not, see . */ -#include "third_party/make/makeint.inc" -/**/ -#include "libc/assert.h" -#include "libc/intrin/bsr.h" -#include "libc/intrin/likely.h" -#include "libc/log/check.h" -#include "libc/runtime/runtime.h" -#include "libc/x/x.h" -#include "libc/serialize.h" -#include "third_party/make/hash.h" +#include "makeint.h" +#include "hash.h" +#include -#define CALLOC(t, n) ((t *) xcalloc (1, sizeof (t) * (n))) +#define CALLOC(t, n) ((t *) xcalloc (sizeof (t) * (n))) #define MALLOC(t, n) ((t *) xmalloc (sizeof (t) * (n))) #define REALLOC(o, t, n) ((t *) xrealloc ((o), sizeof (t) * (n))) #define CLONE(o, t, n) ((t *) memcpy (MALLOC (t, (n)), (o), sizeof (t) * (n))) @@ -51,11 +44,11 @@ hash_init (struct hash_table *ht, unsigned long size, { ht->ht_size = round_up_2 (size); ht->ht_empty_slots = ht->ht_size; - ht->ht_vec = (void**) CALLOC (struct token *, ht->ht_size); + ht->ht_vec = CALLOC (void *, ht->ht_size); if (ht->ht_vec == 0) { fprintf (stderr, _("can't allocate %lu bytes for hash table: memory exhausted"), - ht->ht_size * (unsigned long) sizeof (struct token *)); + ht->ht_size * (unsigned long) sizeof (void *)); exit (MAKE_TROUBLE); } @@ -267,7 +260,7 @@ hash_rehash (struct hash_table *ht) ht->ht_capacity = ht->ht_size - (ht->ht_size >> 4); } ht->ht_rehashes++; - ht->ht_vec = (void **) CALLOC (struct token *, ht->ht_size); + ht->ht_vec = CALLOC (void *, ht->ht_size); for (ovp = old_vec; ovp < &old_vec[old_ht_size]; ovp++) { @@ -322,8 +315,18 @@ hash_dump (struct hash_table *ht, void **vector_0, qsort_cmp_t compare) static unsigned long round_up_2 (unsigned long n) { - if (UNLIKELY(!n)) return 1; - return 2ul << _bsrl(n); + n |= (n >> 1); + n |= (n >> 2); + n |= (n >> 4); + n |= (n >> 8); + n |= (n >> 16); + +#if !defined(HAVE_LIMITS_H) || ULONG_MAX > 4294967295 + /* We only need this on systems where unsigned long is >32 bits. */ + n |= (n >> 32); +#endif + + return n + 1; } #define rol32(v, n) \ @@ -358,7 +361,7 @@ round_up_2 (unsigned long n) #define sum_get_unaligned_32(r, p) \ do { \ unsigned int val; \ - memcpy(&val, (p), 4); \ + memcpy (&val, (p), 4); \ r += val; \ } while(0); @@ -409,17 +412,39 @@ jhash(unsigned const char *k, int length) #define UINTSZ sizeof (unsigned int) +#ifdef WORDS_BIGENDIAN +/* The ifs are ordered from the first byte in memory to the last. + Help the compiler optimize by using static memcpy length. */ +#define sum_up_to_nul(r, p, plen, flag) \ + do { \ + unsigned int val = 0; \ + size_t pn = (plen); \ + if (pn >= UINTSZ) \ + memcpy (&val, (p), UINTSZ); \ + else \ + memcpy (&val, (p), pn); \ + if ((val & 0xFF000000) == 0) \ + flag = 1; \ + else if ((val & 0xFF0000) == 0) \ + r += val & ~0xFFFF, flag = 1; \ + else if ((val & 0xFF00) == 0) \ + r += val & ~0xFF, flag = 1; \ + else \ + r += val, flag = (val & 0xFF) == 0; \ + } while (0) +#else /* First detect the presence of zeroes. If there is none, we can sum the 4 bytes directly. Otherwise, the ifs are ordered as in the - big endian case, from the first byte in memory to the last. */ + big endian case, from the first byte in memory to the last. + Help the compiler optimize by using static memcpy length. */ #define sum_up_to_nul(r, p, plen, flag) \ do { \ unsigned int val = 0; \ size_t pn = (plen); \ if (pn >= UINTSZ) \ - memcpy(&val, (p), UINTSZ); \ + memcpy (&val, (p), UINTSZ); \ else \ - memcpy(&val, (p), pn); \ + memcpy (&val, (p), pn); \ flag = ((val - 0x01010101) & ~val) & 0x80808080; \ if (!flag) \ r += val; \ @@ -433,6 +458,7 @@ jhash(unsigned const char *k, int length) r += val; \ } \ } while (0) +#endif unsigned int jhash_string(unsigned const char *k) @@ -445,35 +471,27 @@ jhash_string(unsigned const char *k) /* Set up the internal state */ a = b = c = JHASH_INITVAL; - for (; klen > 12; k += 12, klen -= 12) - { - a += READ32LE (k + 0); - b += READ32LE (k + 4); - c += READ32LE (k + 8); - jhash_mix (a, b, c); - } - /* All but the last block: affect some 32 bits of (a,b,c) */ for (;;) { sum_up_to_nul(a, k, klen, have_nul); if (have_nul) break; k += UINTSZ; - DCHECK (klen >= UINTSZ); + assert (klen >= UINTSZ); klen -= UINTSZ; sum_up_to_nul(b, k, klen, have_nul); if (have_nul) break; k += UINTSZ; - DCHECK (klen >= UINTSZ); + assert (klen >= UINTSZ); klen -= UINTSZ; sum_up_to_nul(c, k, klen, have_nul); if (have_nul) break; k += UINTSZ; - DCHECK (klen >= UINTSZ); + assert (klen >= UINTSZ); klen -= UINTSZ; jhash_mix(a, b, c); } diff --git a/third_party/make/hash.h b/third_party/make/hash.h index 52222cb2d..deaceab6b 100644 --- a/third_party/make/hash.h +++ b/third_party/make/hash.h @@ -12,11 +12,14 @@ 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 . */ +this program. If not, see . */ #ifndef _hash_h_ #define _hash_h_ +#include +#include + #if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32 # if !defined __GLIBC__ || !defined __P # undef __P @@ -53,9 +56,9 @@ struct hash_table typedef int (*qsort_cmp_t) __P((void const *, void const *)); void hash_init __P((struct hash_table *ht, unsigned long size, - hash_func_t hash_1, hash_func_t hash_2, hash_cmp_func_t hash_cmp)); + hash_func_t hash_1, hash_func_t hash_2, hash_cmp_func_t hash_cmp)); void hash_load __P((struct hash_table *ht, void *item_table, - unsigned long cardinality, unsigned long size)); + unsigned long cardinality, unsigned long size)); void **hash_find_slot __P((struct hash_table *ht, void const *key)); void *hash_find_item __P((struct hash_table *ht, void const *key)); void *hash_insert __P((struct hash_table *ht, const void *item)); @@ -151,7 +154,7 @@ extern void *hash_deleted_item; #define ISTRING_HASH_1(KEY, RESULT) do { \ unsigned char const *_key_ = (unsigned char const *) (KEY) - 1; \ while (*++_key_) \ - (RESULT) += ((isupper (*_key_) ? tolower (*_key_) : *_key_) << (_key_[1] & 0xf)); \ + (RESULT) += (tolower (*_key_) << (_key_[1] & 0xf)); \ } while (0) #define return_ISTRING_HASH_1(KEY) do { \ unsigned long _result_ = 0; \ @@ -162,7 +165,7 @@ extern void *hash_deleted_item; #define ISTRING_HASH_2(KEY, RESULT) do { \ unsigned char const *_key_ = (unsigned char const *) (KEY) - 1; \ while (*++_key_) \ - (RESULT) += ((isupper (*_key_) ? tolower (*_key_) : *_key_) << (_key_[1] & 0x7)); \ + (RESULT) += (tolower (*_key_) << (_key_[1] & 0x7)); \ } while (0) #define return_ISTRING_HASH_2(KEY) do { \ unsigned long _result_ = 0; \ diff --git a/third_party/make/implicit.c b/third_party/make/implicit.c index 6538da3b4..5fa309449 100644 --- a/third_party/make/implicit.c +++ b/third_party/make/implicit.c @@ -1,5 +1,5 @@ /* Implicit rule searching for GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,19 +12,22 @@ 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 . */ +this program. If not, see . */ -#include "third_party/make/makeint.inc" -#include "third_party/make/filedef.h" -#include "third_party/make/rule.h" -#include "third_party/make/dep.h" -#include "third_party/make/debug.h" -#include "third_party/make/variable.h" -#include "third_party/make/job.h" /* struct child, used inside commands.h */ -#include "third_party/make/commands.h" /* set_file_variables */ +#include "makeint.h" +#include "filedef.h" +#include "rule.h" +#include "dep.h" +#include "debug.h" +#include "variable.h" +#include "job.h" /* struct child, used inside commands.h */ +#include "commands.h" /* set_file_variables */ +#include "shuffle.h" +#include static int pattern_search (struct file *file, int archive, - unsigned int depth, unsigned int recursions); + unsigned int depth, unsigned int recursions, + int allow_compat_rules); /* For a FILE which has no commands specified, try to figure out some from the implicit pattern rules. @@ -42,7 +45,7 @@ try_implicit_rule (struct file *file, unsigned int depth) (the archive search omits the archive name), it is more specific and should come first. */ - if (pattern_search (file, 0, depth, 0)) + if (pattern_search (file, 0, depth, 0, 0)) return 1; #ifndef NO_ARCHIVES @@ -52,8 +55,11 @@ try_implicit_rule (struct file *file, unsigned int depth) { DBF (DB_IMPLICIT, _("Looking for archive-member implicit rule for '%s'.\n")); - if (pattern_search (file, 1, depth, 0)) + if (pattern_search (file, 1, depth, 0, 0)) return 1; + DBS (DB_IMPLICIT, + (_("No archive-member implicit rule found for '%s'.\n"), + file->name)); } #endif @@ -153,6 +159,8 @@ struct patdeps struct file *file; unsigned int ignore_mtime : 1; unsigned int ignore_automatic_vars : 1; + unsigned int is_explicit : 1; + unsigned int wait_here : 1; }; /* This structure stores information about pattern rules that we need @@ -200,7 +208,8 @@ stemlen_compare (const void *v1, const void *v2) static int pattern_search (struct file *file, int archive, - unsigned int depth, unsigned int recursions) + unsigned int depth, unsigned int recursions, + int allow_compat_rules) { /* Filename we are searching for a rule for. */ const char *filename = archive ? strchr (file->name, '(') : file->name; @@ -223,7 +232,11 @@ pattern_search (struct file *file, int archive, /* Names of possible dependencies are constructed in this buffer. We may replace % by $(*F) for second expansion, increasing the length. */ - char *depname = alloca (namelen + max_pattern_dep_length + 4); + size_t deplen = namelen + max_pattern_dep_length + 4; + char *depname = alloca (deplen); +#ifndef NDEBUG + char *dend = depname + deplen; +#endif /* The start and length of the stem of FILENAME for the current rule. */ const char *stem = 0; @@ -251,6 +264,7 @@ pattern_search (struct file *file, int archive, int specific_rule_matched = 0; unsigned int ri; /* uninit checks OK */ + int found_compat_rule = 0; struct rule *rule; char *pathdir = NULL; @@ -258,6 +272,8 @@ pattern_search (struct file *file, int archive, PATH_VAR (stem_str); /* @@ Need to get rid of stem, stemlen, etc. */ + ++depth; + #ifndef NO_ARCHIVES if (archive || ar_name (filename)) lastslash = 0; @@ -268,6 +284,14 @@ pattern_search (struct file *file, int archive, but not counting any slash at the end. (foo/bar/ counts as bar/ in directory foo/, not empty in directory foo/bar/.) */ lastslash = memrchr (filename, '/', namelen - 1); +#ifdef VMS + if (lastslash == NULL) + lastslash = strrchr (filename, ']'); + if (lastslash == NULL) + lastslash = strrchr (filename, '>'); + if (lastslash == NULL) + lastslash = strrchr (filename, ':'); +#endif #ifdef HAVE_DOS_PATHS /* Handle backslashes (possibly mixed with forward slashes) and the case of "d:file". */ @@ -300,7 +324,9 @@ pattern_search (struct file *file, int archive, don't use it here. */ if (rule->in_use) { - DBS (DB_IMPLICIT, (_("Avoiding implicit rule recursion.\n"))); + DBS (DB_IMPLICIT, + (_("Avoiding implicit rule recursion for rule '%s'.\n"), + get_rule_defn (rule))); continue; } @@ -331,7 +357,11 @@ pattern_search (struct file *file, int archive, check_lastslash = 0; if (lastslash) { +#ifdef VMS + check_lastslash = strpbrk (target, "/]>:") == NULL; +#else check_lastslash = strchr (target, '/') == 0; +#endif #ifdef HAVE_DOS_PATHS /* Didn't find it yet: check for DOS-type directories. */ if (check_lastslash) @@ -419,6 +449,8 @@ pattern_search (struct file *file, int archive, for (intermed_ok = 0; intermed_ok < 2; ++intermed_ok) { pat = deplist; + if (intermed_ok) + DBS (DB_IMPLICIT, (_("Trying harder.\n"))); /* Try each pattern rule till we find one that applies. If it does, expand its dependencies (as substituted) and chain them in DEPS. */ @@ -467,6 +499,10 @@ pattern_search (struct file *file, int archive, } } + DBS (DB_IMPLICIT, + (_("Trying pattern rule '%s' with stem '%.*s'.\n"), + get_rule_defn (rule), (int) stemlen, stem)); + if (stemlen + (check_lastslash ? pathlen : 0) > GET_PATH_MAX) { DBS (DB_IMPLICIT, (_("Stem too long: '%s%.*s'.\n"), @@ -475,9 +511,6 @@ pattern_search (struct file *file, int archive, continue; } - DBS (DB_IMPLICIT, (_("Trying pattern rule with stem '%.*s'.\n"), - (int) stemlen, stem)); - if (!check_lastslash) { memcpy (stem_str, stem, stemlen); @@ -496,10 +529,6 @@ pattern_search (struct file *file, int archive, if (rule->deps == 0) break; - /* Temporary assign STEM to file->stem (needed to set file - variables below). */ - file->stem = stem_str; - /* Mark this rule as in use so a recursive pattern_search won't try to use it. */ rule->in_use = 1; @@ -514,7 +543,6 @@ pattern_search (struct file *file, int archive, while (1) { struct dep *dl, *d; - char *p; /* If we're out of name to parse, start the next prereq. */ if (! nptr) @@ -528,32 +556,33 @@ pattern_search (struct file *file, int archive, /* If we don't need a second expansion, just replace the %. */ if (! dep->need_2nd_expansion) { - p = strchr (nptr, '%'); - if (p == 0) + char *p; + int is_explicit = 1; + const char *cp = strchr (nptr, '%'); + if (cp == 0) strcpy (depname, nptr); else { char *o = depname; if (check_lastslash) - { - memcpy (o, filename, pathlen); - o += pathlen; - } - memcpy (o, nptr, p - nptr); - o += p - nptr; - memcpy (o, stem, stemlen); - o += stemlen; - strcpy (o, p + 1); + o = mempcpy (o, filename, pathlen); + o = mempcpy (o, nptr, cp - nptr); + o = mempcpy (o, stem, stemlen); + strcpy (o, cp + 1); + is_explicit = 0; } /* Parse the expanded string. It might have wildcards. */ p = depname; - dl = PARSE_FILE_SEQ (&p, struct dep, MAP_NUL, NULL, PARSEFS_ONEWORD); + dl = PARSE_FILE_SEQ (&p, struct dep, MAP_NUL, NULL, + PARSEFS_ONEWORD|PARSEFS_WAIT); for (d = dl; d != NULL; d = d->next) { ++deps_found; d->ignore_mtime = dep->ignore_mtime; d->ignore_automatic_vars = dep->ignore_automatic_vars; + d->wait_here |= dep->wait_here; + d->is_explicit = is_explicit; } /* We've used up this dep, so next time get a new one. */ @@ -573,17 +602,22 @@ pattern_search (struct file *file, int archive, { int add_dir = 0; size_t len; + const char *end; struct dep **dptr; + int is_explicit; + const char *cp; + char *p; nptr = get_next_word (nptr, &len); if (nptr == 0) continue; + end = nptr + len; - /* See this is a transition to order-only prereqs. */ + /* See if this is a transition to order-only prereqs. */ if (! order_only && len == 1 && nptr[0] == '|') { order_only = 1; - nptr += len; + nptr = end; continue; } @@ -598,49 +632,76 @@ pattern_search (struct file *file, int archive, (since $* and $(*F) are simple variables) there won't be additional re-expansion of the stem. */ - p = lindex (nptr, nptr + len, '%'); - if (p == 0) + cp = lindex (nptr, end, '%'); + if (cp == 0) { memcpy (depname, nptr, len); depname[len] = '\0'; + is_explicit = 1; } else { - size_t i = p - nptr; + /* Go through all % between NPTR and END. + Copy contents of [NPTR, END) to depname, with the + first % after NPTR and then each first % after white + space replaced with $* or $(*F). depname has enough + room to substitute each % with $(*F). */ char *o = depname; - memcpy (o, nptr, i); - o += i; - if (check_lastslash) + + is_explicit = 0; + for (;;) { - add_dir = 1; - memcpy (o, "$(*F)", 5); - o += 5; + size_t i = cp - nptr; + assert (o + i < dend); + o = mempcpy (o, nptr, i); + if (check_lastslash) + { + add_dir = 1; + assert (o + 5 < dend); + o = mempcpy (o, "$(*F)", 5); + } + else + { + assert (o + 2 < dend); + o = mempcpy (o, "$*", 2); + } + assert (o < dend); + ++cp; + assert (cp <= end); + nptr = cp; + if (nptr == end) + break; + + /* Skip the rest of this word then find the next %. + No need to worry about order-only, or nested + functions: NPTR went though get_next_word. */ + while (cp < end && ! END_OF_TOKEN (*cp)) + ++cp; + cp = lindex (cp, end, '%'); + if (cp == 0) + break; } - else - { - memcpy (o, "$*", 2); - o += 2; - } - memcpy (o, p + 1, len - i - 1); - o[len - i - 1] = '\0'; + len = end - nptr; + memcpy (o, nptr, len); + o[len] = '\0'; } /* Set up for the next word. */ - nptr += len; + nptr = end; /* Initialize and set file variables if we haven't already done so. */ if (!file_vars_initialized) { initialize_file_variables (file, 0); - set_file_variables (file); + set_file_variables (file, stem_str); file_vars_initialized = 1; } /* Update the stem value in $* for this rule. */ else if (!file_variables_set) { define_variable_for_file ( - "*", 1, file->stem, o_automatic, 0, file); + "*", 1, stem_str, o_automatic, 0, file); file_variables_set = 1; } @@ -654,7 +715,8 @@ pattern_search (struct file *file, int archive, /* Parse the expanded string. */ struct dep *dp = PARSE_FILE_SEQ (&p, struct dep, order_only ? MAP_NUL : MAP_PIPE, - add_dir ? pathdir : NULL, PARSEFS_NONE); + add_dir ? pathdir : NULL, + PARSEFS_WAIT); *dptr = dp; for (d = dp; d != NULL; d = d->next) @@ -662,6 +724,7 @@ pattern_search (struct file *file, int archive, ++deps_found; if (order_only) d->ignore_mtime = 1; + d->is_explicit = is_explicit; dptr = &d->next; } @@ -692,8 +755,10 @@ pattern_search (struct file *file, int archive, /* Go through the nameseq and handle each as a prereq name. */ for (d = dl; d != 0; d = d->next) { - struct dep *expl_d; + struct file *df; int is_rule = d->name == dep_name (dep); + int explicit = 0; + struct dep *dp = 0; if (file_impossible_p (d->name)) { @@ -702,9 +767,11 @@ pattern_search (struct file *file, int archive, second pass either since we know that will fail. */ DBS (DB_IMPLICIT, (is_rule - ? _("Rejecting impossible rule prerequisite '%s'.\n") - : _("Rejecting impossible implicit prerequisite '%s'.\n"), - d->name)); + ? _("Rejecting rule '%s' due to impossible rule" + " prerequisite '%s'.\n") + : _("Rejecting rule '%s' due to impossible implicit" + " prerequisite '%s'.\n"), + get_rule_defn (rule), d->name)); tryrules[ri].rule = 0; failed = 1; @@ -714,41 +781,86 @@ pattern_search (struct file *file, int archive, memset (pat, '\0', sizeof (struct patdeps)); pat->ignore_mtime = d->ignore_mtime; pat->ignore_automatic_vars = d->ignore_automatic_vars; + pat->wait_here = d->wait_here; + pat->is_explicit = d->is_explicit; DBS (DB_IMPLICIT, (is_rule ? _("Trying rule prerequisite '%s'.\n") : _("Trying implicit prerequisite '%s'.\n"), d->name)); - /* If this prereq is also explicitly mentioned for FILE, - skip all tests below since it must be built no matter - which implicit rule we choose. */ + df = lookup_file (d->name); - for (expl_d = file->deps; expl_d != 0; expl_d = expl_d->next) - if (streq (dep_name (expl_d), d->name)) - break; - if (expl_d != 0) + if (df && df->is_explicit) + pat->is_explicit = 1; + + /* If we found a file for the dep, set its intermediate flag. + df->is_explicit is set when the dep file is mentioned + explicitly on some other rule. d->is_explicit is set when + the dep file is mentioned explicitly on this rule. E.g.: + %.x : %.y ; ... + then: + one.x: + one.y: # df->is_explicit + vs. + one.x: one.y # d->is_explicit + */ + if (df && !df->is_explicit && !d->is_explicit) + df->intermediate = 1; + + /* If the pattern prereq is also explicitly mentioned for + FILE, skip all tests below since it must be built no + matter which implicit rule we choose. */ + if (df && df->is_target) + /* This prerequisite is mentioned explicitly as a target of + some rule. */ + explicit = 1; + else + for (dp = file->deps; dp != 0; dp = dp->next) + if (streq (d->name, dep_name (dp))) + break; + + /* If dp is set, this prerequisite is mentioned explicitly as + a prerequisite of the current target. */ + + if (explicit || dp) { (pat++)->name = d->name; + DBS (DB_IMPLICIT, (_("'%s' ought to exist.\n"), d->name)); continue; } - /* The DEP->changed flag says that this dependency resides - in a nonexistent directory. So we normally can skip - looking for the file. However, if CHECK_LASTSLASH is - set, then the dependency file we are actually looking for - is in a different directory (the one gotten by prepending - FILENAME's directory), so it might actually exist. */ - - /* @@ dep->changed check is disabled. */ - if (lookup_file (d->name) != 0 - /*|| ((!dep->changed || check_lastslash) && */ - || file_exists_p (d->name)) + if (file_exists_p (d->name)) { (pat++)->name = d->name; + DBS (DB_IMPLICIT, (_("Found '%s'.\n"), d->name)); continue; } + if (df && allow_compat_rules) + { + (pat++)->name = d->name; + DBS (DB_IMPLICIT, + (_("Using compatibility rule '%s' due to '%s'.\n"), + get_rule_defn (rule), d->name)); + continue; + } + + if (df) + { + /* This prerequisite is mentioned explicitly as a + prerequisite on some rule, but it is not a + prerequisite of the current target. Therefore, this + prerequisite does not qualify as ought-to-exist. Keep + note of this rule and continue the search. If a more + suitable rule is not found, then use this rule. */ + DBS (DB_IMPLICIT, + (_("Prerequisite '%s' of rule '%s' does not qualify" + " as ought to exist.\n"), + d->name, get_rule_defn (rule))); + found_compat_rule = 1; + } + /* This code, given FILENAME = "lib/foo.o", dependency name "lib/foo.c", and VPATH=src, searches for "src/lib/foo.c". */ @@ -757,7 +869,7 @@ pattern_search (struct file *file, int archive, if (vname) { DBS (DB_IMPLICIT, - (_("Found prerequisite '%s' as VPATH '%s'\n"), + (_("Found prerequisite '%s' as VPATH '%s'.\n"), d->name, vname)); (pat++)->name = d->name; continue; @@ -765,13 +877,15 @@ pattern_search (struct file *file, int archive, } /* We could not find the file in any place we should look. - Try to make this dependency as an intermediate file, but + Look for an implicit rule to make this dependency, but only on the second pass. */ if (intermed_ok) { DBS (DB_IMPLICIT, - (_("Looking for a rule with intermediate file '%s'.\n"), + (d->is_explicit || (df && df->is_explicit) + ? _("Looking for a rule with explicit file '%s'.\n") + : _("Looking for a rule with intermediate file '%s'.\n"), d->name)); if (int_file == 0) @@ -781,8 +895,9 @@ pattern_search (struct file *file, int archive, if (pattern_search (int_file, 0, - depth + 1, - recursions + 1)) + depth, + recursions + 1, + allow_compat_rules)) { pat->pattern = int_file->name; int_file->name = d->name; @@ -799,11 +914,24 @@ pattern_search (struct file *file, int archive, free_variable_set (int_file->variables); if (int_file->pat_variables) free_variable_set (int_file->pat_variables); - file_impossible (d->name); + + /* Keep prerequisites explicitly mentioned on unrelated + rules as "possible" to let compatibility search find + such prerequisites. */ + if (df == 0) + file_impossible (d->name); } /* A dependency of this rule does not exist. Therefore, this rule fails. */ + if (intermed_ok) + DBS (DB_IMPLICIT, + (_("Rejecting rule '%s' " + "due to impossible prerequisite '%s'.\n"), + get_rule_defn (rule), d->name)); + else + DBS (DB_IMPLICIT, (_("Not found '%s'.\n"), d->name)); + failed = 1; break; } @@ -815,10 +943,6 @@ pattern_search (struct file *file, int archive, break; } - /* Reset the stem in FILE. */ - - file->stem = 0; - /* This rule is no longer 'in use' for recursive searches. */ rule->in_use = 0; @@ -870,24 +994,24 @@ pattern_search (struct file *file, int archive, struct file *imf = pat->file; struct file *f = lookup_file (imf->name); - /* We don't want to delete an intermediate file that happened - to be a prerequisite of some (other) target. Mark it as - secondary. We don't want it to be precious as that disables - DELETE_ON_ERROR etc. */ - if (f != 0) - f->secondary = 1; - else + if (!f) f = enter_file (imf->name); f->deps = imf->deps; f->cmds = imf->cmds; f->stem = imf->stem; - f->variables = imf->variables; + /* Setting target specific variables for a file causes the file to be + entered to the database as a prerequisite. Implicit search then + treats this file as explicitly mentioned. Preserve target specific + variables of this file. */ + merge_variable_set_lists(&f->variables, imf->variables); f->pat_variables = imf->pat_variables; f->pat_searched = imf->pat_searched; f->also_make = imf->also_make; f->is_target = 1; - f->intermediate = 1; + f->is_explicit |= imf->is_explicit || pat->is_explicit; + f->notintermediate |= imf->notintermediate || no_intermediates; + f->intermediate |= !f->is_explicit && !f->notintermediate; f->tried_implicit = 1; imf = lookup_file (pat->pattern); @@ -904,7 +1028,9 @@ pattern_search (struct file *file, int archive, dep = alloc_dep (); dep->ignore_mtime = pat->ignore_mtime; + dep->is_explicit = pat->is_explicit; dep->ignore_automatic_vars = pat->ignore_automatic_vars; + dep->wait_here = pat->wait_here; s = strcache_add (pat->name); if (recursions) dep->name = s; @@ -930,8 +1056,14 @@ pattern_search (struct file *file, int archive, dep->next = file->deps; file->deps = dep; + + /* The file changed its dependencies; schedule the shuffle. */ + file->was_shuffled = 0; } + if (!file->was_shuffled) + shuffle_deps_recursive (file->deps); + if (!tryrules[foundrule].checked_lastslash) { /* Always allocate new storage, since STEM might be on the stack for an @@ -953,11 +1085,16 @@ pattern_search (struct file *file, int archive, file->cmds = rule->cmds; file->is_target = 1; - /* Set precious flag. */ + /* Set precious and notintermediate flags. */ { struct file *f = lookup_file (rule->targets[tryrules[foundrule].matches]); - if (f && f->precious) - file->precious = 1; + if (f) + { + if (f->precious) + file->precious = 1; + if (f->notintermediate || no_intermediates) + file->notintermediate = 1; + } } /* If this rule builds other targets, too, put the others into FILE's @@ -973,11 +1110,9 @@ pattern_search (struct file *file, int archive, struct dep *new = alloc_dep (); /* GKM FIMXE: handle '|' here too */ - memcpy (p, rule->targets[ri], - rule->suffixes[ri] - rule->targets[ri] - 1); - p += rule->suffixes[ri] - rule->targets[ri] - 1; - memcpy (p, file->stem, fullstemlen); - p += fullstemlen; + p = mempcpy (p, rule->targets[ri], + rule->suffixes[ri] - rule->targets[ri] - 1); + p = mempcpy (p, file->stem, fullstemlen); memcpy (p, rule->suffixes[ri], rule->lens[ri] - (rule->suffixes[ri] - rule->targets[ri])+1); new->name = strcache_add (nm); @@ -986,8 +1121,13 @@ pattern_search (struct file *file, int archive, /* Set precious flag. */ f = lookup_file (rule->targets[ri]); - if (f && f->precious) - new->file->precious = 1; + if (f) + { + if (f->precious) + new->file->precious = 1; + if (f->notintermediate || no_intermediates) + new->file->notintermediate = 1; + } /* Set the is_target flag so that this file is not treated as intermediate by the pattern rule search algorithm and @@ -1001,5 +1141,23 @@ pattern_search (struct file *file, int archive, free (tryrules); free (deplist); - return rule != 0; + --depth; + + if (rule) + { + DBS (DB_IMPLICIT, (_("Found implicit rule '%s' for '%s'.\n"), + get_rule_defn (rule), filename)); + return 1; + } + + if (found_compat_rule) + { + DBS (DB_IMPLICIT, (_("Searching for a compatibility rule for '%s'.\n"), + filename)); + assert (allow_compat_rules == 0); + return pattern_search (file, archive, depth, recursions, 1); + } + + DBS (DB_IMPLICIT, (_("No implicit rule found for '%s'.\n"), filename)); + return 0; } diff --git a/third_party/make/intprops.h b/third_party/make/intprops.h deleted file mode 100644 index 283282c54..000000000 --- a/third_party/make/intprops.h +++ /dev/null @@ -1,583 +0,0 @@ -/* intprops.h -- properties of integer types - - Copyright (C) 2001-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -/* Written by Paul Eggert. */ - -#ifndef _GL_INTPROPS_H -#define _GL_INTPROPS_H - - -/* Return a value with the common real type of E and V and the value of V. - Do not evaluate E. */ -#define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v)) - -/* Act like _GL_INT_CONVERT (E, -V) but work around a bug in IRIX 6.5 cc; see - . */ -#define _GL_INT_NEGATE_CONVERT(e, v) ((1 ? 0 : (e)) - (v)) - -/* The extra casts in the following macros work around compiler bugs, - e.g., in Cray C 5.0.3.0. */ - -/* True if the arithmetic type T is an integer type. bool counts as - an integer. */ -#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1) - -/* True if the real type T is signed. */ -#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) - -/* Return 1 if the real expression E, after promotion, has a - signed or floating type. Do not evaluate E. */ -#define EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0) - - -/* Minimum and maximum values for integer types and expressions. */ - -/* The width in bits of the integer type or expression T. - Do not evaluate T. - Padding bits are not supported; this is checked at compile-time below. */ -#define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT) - -/* The maximum and minimum values for the integer type T. */ -#define TYPE_MINIMUM(t) ((t) ~ TYPE_MAXIMUM (t)) -#define TYPE_MAXIMUM(t) \ - ((t) (! TYPE_SIGNED (t) \ - ? (t) -1 \ - : ((((t) 1 << (TYPE_WIDTH (t) - 2)) - 1) * 2 + 1))) - -/* The maximum and minimum values for the type of the expression E, - after integer promotion. E is not evaluated. */ -#define _GL_INT_MINIMUM(e) \ - (EXPR_SIGNED (e) \ - ? ~ _GL_SIGNED_INT_MAXIMUM (e) \ - : _GL_INT_CONVERT (e, 0)) -#define _GL_INT_MAXIMUM(e) \ - (EXPR_SIGNED (e) \ - ? _GL_SIGNED_INT_MAXIMUM (e) \ - : _GL_INT_NEGATE_CONVERT (e, 1)) -#define _GL_SIGNED_INT_MAXIMUM(e) \ - (((_GL_INT_CONVERT (e, 1) << (TYPE_WIDTH ((e) + 0) - 2)) - 1) * 2 + 1) - -/* Work around OpenVMS incompatibility with C99. */ -#if !defined LLONG_MAX && defined __INT64_MAX -# define LLONG_MAX __INT64_MAX -# define LLONG_MIN __INT64_MIN -#endif - -/* This include file assumes that signed types are two's complement without - padding bits; the above macros have undefined behavior otherwise. - If this is a problem for you, please let us know how to fix it for your host. - This assumption is tested by the intprops-tests module. */ - -/* Does the __typeof__ keyword work? This could be done by - 'configure', but for now it's easier to do it by hand. */ -#if (2 <= __GNUC__ \ - || (1210 <= __IBMC__ && defined __IBM__TYPEOF__) \ - || (0x5110 <= __SUNPRO_C && !__STDC__)) -# define _GL_HAVE___TYPEOF__ 1 -#else -# define _GL_HAVE___TYPEOF__ 0 -#endif - -/* Return 1 if the integer type or expression T might be signed. Return 0 - if it is definitely unsigned. This macro does not evaluate its argument, - and expands to an integer constant expression. */ -#if _GL_HAVE___TYPEOF__ -# define _GL_SIGNED_TYPE_OR_EXPR(t) TYPE_SIGNED (__typeof__ (t)) -#else -# define _GL_SIGNED_TYPE_OR_EXPR(t) 1 -#endif - -/* Bound on length of the string representing an unsigned integer - value representable in B bits. log10 (2.0) < 146/485. The - smallest value of B where this bound is not tight is 2621. */ -#define INT_BITS_STRLEN_BOUND(b) (((b) * 146 + 484) / 485) - -/* Bound on length of the string representing an integer type or expression T. - Subtract 1 for the sign bit if T is signed, and then add 1 more for - a minus sign if needed. - - Because _GL_SIGNED_TYPE_OR_EXPR sometimes returns 1 when its argument is - unsigned, this macro may overestimate the true bound by one byte when - applied to unsigned types of size 2, 4, 16, ... bytes. */ -#define INT_STRLEN_BOUND(t) \ - (INT_BITS_STRLEN_BOUND (TYPE_WIDTH (t) - _GL_SIGNED_TYPE_OR_EXPR (t)) \ - + _GL_SIGNED_TYPE_OR_EXPR (t)) - -/* Bound on buffer size needed to represent an integer type or expression T, - including the terminating null. */ -#define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1) - - -/* Range overflow checks. - - The INT__RANGE_OVERFLOW macros return 1 if the corresponding C - operators might not yield numerically correct answers due to - arithmetic overflow. They do not rely on undefined or - implementation-defined behavior. Their implementations are simple - and straightforward, but they are a bit harder to use than the - INT__OVERFLOW macros described below. - - Example usage: - - long int i = ...; - long int j = ...; - if (INT_MULTIPLY_RANGE_OVERFLOW (i, j, LONG_MIN, LONG_MAX)) - printf ("multiply would overflow"); - else - printf ("product is %ld", i * j); - - Restrictions on *_RANGE_OVERFLOW macros: - - These macros do not check for all possible numerical problems or - undefined or unspecified behavior: they do not check for division - by zero, for bad shift counts, or for shifting negative numbers. - - These macros may evaluate their arguments zero or multiple times, - so the arguments should not have side effects. The arithmetic - arguments (including the MIN and MAX arguments) must be of the same - integer type after the usual arithmetic conversions, and the type - must have minimum value MIN and maximum MAX. Unsigned types should - use a zero MIN of the proper type. - - These macros are tuned for constant MIN and MAX. For commutative - operations such as A + B, they are also tuned for constant B. */ - -/* Return 1 if A + B would overflow in [MIN,MAX] arithmetic. - See above for restrictions. */ -#define INT_ADD_RANGE_OVERFLOW(a, b, min, max) \ - ((b) < 0 \ - ? (a) < (min) - (b) \ - : (max) - (b) < (a)) - -/* Return 1 if A - B would overflow in [MIN,MAX] arithmetic. - See above for restrictions. */ -#define INT_SUBTRACT_RANGE_OVERFLOW(a, b, min, max) \ - ((b) < 0 \ - ? (max) + (b) < (a) \ - : (a) < (min) + (b)) - -/* Return 1 if - A would overflow in [MIN,MAX] arithmetic. - See above for restrictions. */ -#define INT_NEGATE_RANGE_OVERFLOW(a, min, max) \ - ((min) < 0 \ - ? (a) < - (max) \ - : 0 < (a)) - -/* Return 1 if A * B would overflow in [MIN,MAX] arithmetic. - See above for restrictions. Avoid && and || as they tickle - bugs in Sun C 5.11 2010/08/13 and other compilers; see - . */ -#define INT_MULTIPLY_RANGE_OVERFLOW(a, b, min, max) \ - ((b) < 0 \ - ? ((a) < 0 \ - ? (a) < (max) / (b) \ - : (b) == -1 \ - ? 0 \ - : (min) / (b) < (a)) \ - : (b) == 0 \ - ? 0 \ - : ((a) < 0 \ - ? (a) < (min) / (b) \ - : (max) / (b) < (a))) - -/* Return 1 if A / B would overflow in [MIN,MAX] arithmetic. - See above for restrictions. Do not check for division by zero. */ -#define INT_DIVIDE_RANGE_OVERFLOW(a, b, min, max) \ - ((min) < 0 && (b) == -1 && (a) < - (max)) - -/* Return 1 if A % B would overflow in [MIN,MAX] arithmetic. - See above for restrictions. Do not check for division by zero. - Mathematically, % should never overflow, but on x86-like hosts - INT_MIN % -1 traps, and the C standard permits this, so treat this - as an overflow too. */ -#define INT_REMAINDER_RANGE_OVERFLOW(a, b, min, max) \ - INT_DIVIDE_RANGE_OVERFLOW (a, b, min, max) - -/* Return 1 if A << B would overflow in [MIN,MAX] arithmetic. - See above for restrictions. Here, MIN and MAX are for A only, and B need - not be of the same type as the other arguments. The C standard says that - behavior is undefined for shifts unless 0 <= B < wordwidth, and that when - A is negative then A << B has undefined behavior and A >> B has - implementation-defined behavior, but do not check these other - restrictions. */ -#define INT_LEFT_SHIFT_RANGE_OVERFLOW(a, b, min, max) \ - ((a) < 0 \ - ? (a) < (min) >> (b) \ - : (max) >> (b) < (a)) - -/* True if __builtin_add_overflow (A, B, P) and __builtin_sub_overflow - (A, B, P) work when P is non-null. */ -#if 5 <= __GNUC__ && !defined __ICC -# define _GL_HAS_BUILTIN_ADD_OVERFLOW 1 -#elif defined __has_builtin -# define _GL_HAS_BUILTIN_ADD_OVERFLOW __has_builtin (__builtin_add_overflow) -#else -# define _GL_HAS_BUILTIN_ADD_OVERFLOW 0 -#endif - -/* True if __builtin_mul_overflow (A, B, P) works when P is non-null. */ -#ifdef __clang__ -/* Work around Clang bug . */ -# define _GL_HAS_BUILTIN_MUL_OVERFLOW 0 -#else -# define _GL_HAS_BUILTIN_MUL_OVERFLOW _GL_HAS_BUILTIN_ADD_OVERFLOW -#endif - -/* True if __builtin_add_overflow_p (A, B, C) works, and similarly for - __builtin_mul_overflow_p and __builtin_mul_overflow_p. */ -#define _GL_HAS_BUILTIN_OVERFLOW_P (7 <= __GNUC__) - -/* The _GL*_OVERFLOW macros have the same restrictions as the - *_RANGE_OVERFLOW macros, except that they do not assume that operands - (e.g., A and B) have the same type as MIN and MAX. Instead, they assume - that the result (e.g., A + B) has that type. */ -#if _GL_HAS_BUILTIN_OVERFLOW_P -# define _GL_ADD_OVERFLOW(a, b, min, max) \ - __builtin_add_overflow_p (a, b, (__typeof__ ((a) + (b))) 0) -# define _GL_SUBTRACT_OVERFLOW(a, b, min, max) \ - __builtin_sub_overflow_p (a, b, (__typeof__ ((a) - (b))) 0) -# define _GL_MULTIPLY_OVERFLOW(a, b, min, max) \ - __builtin_mul_overflow_p (a, b, (__typeof__ ((a) * (b))) 0) -#else -# define _GL_ADD_OVERFLOW(a, b, min, max) \ - ((min) < 0 ? INT_ADD_RANGE_OVERFLOW (a, b, min, max) \ - : (a) < 0 ? (b) <= (a) + (b) \ - : (b) < 0 ? (a) <= (a) + (b) \ - : (a) + (b) < (b)) -# define _GL_SUBTRACT_OVERFLOW(a, b, min, max) \ - ((min) < 0 ? INT_SUBTRACT_RANGE_OVERFLOW (a, b, min, max) \ - : (a) < 0 ? 1 \ - : (b) < 0 ? (a) - (b) <= (a) \ - : (a) < (b)) -# define _GL_MULTIPLY_OVERFLOW(a, b, min, max) \ - (((min) == 0 && (((a) < 0 && 0 < (b)) || ((b) < 0 && 0 < (a)))) \ - || INT_MULTIPLY_RANGE_OVERFLOW (a, b, min, max)) -#endif -#define _GL_DIVIDE_OVERFLOW(a, b, min, max) \ - ((min) < 0 ? (b) == _GL_INT_NEGATE_CONVERT (min, 1) && (a) < - (max) \ - : (a) < 0 ? (b) <= (a) + (b) - 1 \ - : (b) < 0 && (a) + (b) <= (a)) -#define _GL_REMAINDER_OVERFLOW(a, b, min, max) \ - ((min) < 0 ? (b) == _GL_INT_NEGATE_CONVERT (min, 1) && (a) < - (max) \ - : (a) < 0 ? (a) % (b) != ((max) - (b) + 1) % (b) \ - : (b) < 0 && ! _GL_UNSIGNED_NEG_MULTIPLE (a, b, max)) - -/* Return a nonzero value if A is a mathematical multiple of B, where - A is unsigned, B is negative, and MAX is the maximum value of A's - type. A's type must be the same as (A % B)'s type. Normally (A % - -B == 0) suffices, but things get tricky if -B would overflow. */ -#define _GL_UNSIGNED_NEG_MULTIPLE(a, b, max) \ - (((b) < -_GL_SIGNED_INT_MAXIMUM (b) \ - ? (_GL_SIGNED_INT_MAXIMUM (b) == (max) \ - ? (a) \ - : (a) % (_GL_INT_CONVERT (a, _GL_SIGNED_INT_MAXIMUM (b)) + 1)) \ - : (a) % - (b)) \ - == 0) - -/* Check for integer overflow, and report low order bits of answer. - - The INT__OVERFLOW macros return 1 if the corresponding C operators - might not yield numerically correct answers due to arithmetic overflow. - The INT__WRAPV macros compute the low-order bits of the sum, - difference, and product of two C integers, and return 1 if these - low-order bits are not numerically correct. - These macros work correctly on all known practical hosts, and do not rely - on undefined behavior due to signed arithmetic overflow. - - Example usage, assuming A and B are long int: - - if (INT_MULTIPLY_OVERFLOW (a, b)) - printf ("result would overflow\n"); - else - printf ("result is %ld (no overflow)\n", a * b); - - Example usage with WRAPV flavor: - - long int result; - bool overflow = INT_MULTIPLY_WRAPV (a, b, &result); - printf ("result is %ld (%s)\n", result, - overflow ? "after overflow" : "no overflow"); - - Restrictions on these macros: - - These macros do not check for all possible numerical problems or - undefined or unspecified behavior: they do not check for division - by zero, for bad shift counts, or for shifting negative numbers. - - These macros may evaluate their arguments zero or multiple times, so the - arguments should not have side effects. - - The WRAPV macros are not constant expressions. They support only - +, binary -, and *. Because the WRAPV macros convert the result, - they report overflow in different circumstances than the OVERFLOW - macros do. - - These macros are tuned for their last input argument being a constant. - - Return 1 if the integer expressions A * B, A - B, -A, A * B, A / B, - A % B, and A << B would overflow, respectively. */ - -#define INT_ADD_OVERFLOW(a, b) \ - _GL_BINARY_OP_OVERFLOW (a, b, _GL_ADD_OVERFLOW) -#define INT_SUBTRACT_OVERFLOW(a, b) \ - _GL_BINARY_OP_OVERFLOW (a, b, _GL_SUBTRACT_OVERFLOW) -#if _GL_HAS_BUILTIN_OVERFLOW_P -# define INT_NEGATE_OVERFLOW(a) INT_SUBTRACT_OVERFLOW (0, a) -#else -# define INT_NEGATE_OVERFLOW(a) \ - INT_NEGATE_RANGE_OVERFLOW (a, _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a)) -#endif -#define INT_MULTIPLY_OVERFLOW(a, b) \ - _GL_BINARY_OP_OVERFLOW (a, b, _GL_MULTIPLY_OVERFLOW) -#define INT_DIVIDE_OVERFLOW(a, b) \ - _GL_BINARY_OP_OVERFLOW (a, b, _GL_DIVIDE_OVERFLOW) -#define INT_REMAINDER_OVERFLOW(a, b) \ - _GL_BINARY_OP_OVERFLOW (a, b, _GL_REMAINDER_OVERFLOW) -#define INT_LEFT_SHIFT_OVERFLOW(a, b) \ - INT_LEFT_SHIFT_RANGE_OVERFLOW (a, b, \ - _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a)) - -/* Return 1 if the expression A B would overflow, - where OP_RESULT_OVERFLOW (A, B, MIN, MAX) does the actual test, - assuming MIN and MAX are the minimum and maximum for the result type. - Arguments should be free of side effects. */ -#define _GL_BINARY_OP_OVERFLOW(a, b, op_result_overflow) \ - op_result_overflow (a, b, \ - _GL_INT_MINIMUM (_GL_INT_CONVERT (a, b)), \ - _GL_INT_MAXIMUM (_GL_INT_CONVERT (a, b))) - -/* Store the low-order bits of A + B, A - B, A * B, respectively, into *R. - Return 1 if the result overflows. See above for restrictions. */ -#if _GL_HAS_BUILTIN_ADD_OVERFLOW -# define INT_ADD_WRAPV(a, b, r) __builtin_add_overflow (a, b, r) -# define INT_SUBTRACT_WRAPV(a, b, r) __builtin_sub_overflow (a, b, r) -#else -# define INT_ADD_WRAPV(a, b, r) \ - _GL_INT_OP_WRAPV (a, b, r, +, _GL_INT_ADD_RANGE_OVERFLOW) -# define INT_SUBTRACT_WRAPV(a, b, r) \ - _GL_INT_OP_WRAPV (a, b, r, -, _GL_INT_SUBTRACT_RANGE_OVERFLOW) -#endif -#if _GL_HAS_BUILTIN_MUL_OVERFLOW -# if (9 < __GNUC__ + (3 <= __GNUC_MINOR__) \ - || (__GNUC__ == 8 && 4 <= __GNUC_MINOR__)) -# define INT_MULTIPLY_WRAPV(a, b, r) __builtin_mul_overflow (a, b, r) -# else - /* Work around GCC bug 91450. */ -# define INT_MULTIPLY_WRAPV(a, b, r) \ - ((!_GL_SIGNED_TYPE_OR_EXPR (*(r)) && EXPR_SIGNED (a) && EXPR_SIGNED (b) \ - && _GL_INT_MULTIPLY_RANGE_OVERFLOW (a, b, 0, (__typeof__ (*(r))) -1)) \ - ? ((void) __builtin_mul_overflow (a, b, r), 1) \ - : __builtin_mul_overflow (a, b, r)) -# endif -#else -# define INT_MULTIPLY_WRAPV(a, b, r) \ - _GL_INT_OP_WRAPV (a, b, r, *, _GL_INT_MULTIPLY_RANGE_OVERFLOW) -#endif - -/* Nonzero if this compiler has GCC bug 68193 or Clang bug 25390. See: - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68193 - https://llvm.org/bugs/show_bug.cgi?id=25390 - For now, assume all versions of GCC-like compilers generate bogus - warnings for _Generic. This matters only for compilers that - lack relevant builtins. */ -#if __GNUC__ -# define _GL__GENERIC_BOGUS 1 -#else -# define _GL__GENERIC_BOGUS 0 -#endif - -/* Store the low-order bits of A B into *R, where OP specifies - the operation and OVERFLOW the overflow predicate. Return 1 if the - result overflows. See above for restrictions. */ -#if 201112 <= __STDC_VERSION__ && !_GL__GENERIC_BOGUS -# define _GL_INT_OP_WRAPV(a, b, r, op, overflow) \ - (_Generic \ - (*(r), \ - signed char: \ - _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ - signed char, SCHAR_MIN, SCHAR_MAX), \ - unsigned char: \ - _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ - unsigned char, 0, UCHAR_MAX), \ - short int: \ - _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ - short int, SHRT_MIN, SHRT_MAX), \ - unsigned short int: \ - _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ - unsigned short int, 0, USHRT_MAX), \ - int: \ - _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ - int, INT_MIN, INT_MAX), \ - unsigned int: \ - _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ - unsigned int, 0, UINT_MAX), \ - long int: \ - _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ - long int, LONG_MIN, LONG_MAX), \ - unsigned long int: \ - _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ - unsigned long int, 0, ULONG_MAX), \ - long long int: \ - _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \ - long long int, LLONG_MIN, LLONG_MAX), \ - unsigned long long int: \ - _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \ - unsigned long long int, 0, ULLONG_MAX))) -#else -/* Store the low-order bits of A B into *R, where OP specifies - the operation and OVERFLOW the overflow predicate. If *R is - signed, its type is ST with bounds SMIN..SMAX; otherwise its type - is UT with bounds U..UMAX. ST and UT are narrower than int. - Return 1 if the result overflows. See above for restrictions. */ -# if _GL_HAVE___TYPEOF__ -# define _GL_INT_OP_WRAPV_SMALLISH(a,b,r,op,overflow,st,smin,smax,ut,umax) \ - (TYPE_SIGNED (__typeof__ (*(r))) \ - ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, st, smin, smax) \ - : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, ut, 0, umax)) -# else -# define _GL_INT_OP_WRAPV_SMALLISH(a,b,r,op,overflow,st,smin,smax,ut,umax) \ - (overflow (a, b, smin, smax) \ - ? (overflow (a, b, 0, umax) \ - ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st), 1) \ - : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st)) < 0) \ - : (overflow (a, b, 0, umax) \ - ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st)) >= 0 \ - : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st), 0))) -# endif - -# define _GL_INT_OP_WRAPV(a, b, r, op, overflow) \ - (sizeof *(r) == sizeof (signed char) \ - ? _GL_INT_OP_WRAPV_SMALLISH (a, b, r, op, overflow, \ - signed char, SCHAR_MIN, SCHAR_MAX, \ - unsigned char, UCHAR_MAX) \ - : sizeof *(r) == sizeof (short int) \ - ? _GL_INT_OP_WRAPV_SMALLISH (a, b, r, op, overflow, \ - short int, SHRT_MIN, SHRT_MAX, \ - unsigned short int, USHRT_MAX) \ - : sizeof *(r) == sizeof (int) \ - ? (EXPR_SIGNED (*(r)) \ - ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ - int, INT_MIN, INT_MAX) \ - : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ - unsigned int, 0, UINT_MAX)) \ - : _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow)) -# ifdef LLONG_MAX -# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \ - (sizeof *(r) == sizeof (long int) \ - ? (EXPR_SIGNED (*(r)) \ - ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ - long int, LONG_MIN, LONG_MAX) \ - : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ - unsigned long int, 0, ULONG_MAX)) \ - : (EXPR_SIGNED (*(r)) \ - ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \ - long long int, LLONG_MIN, LLONG_MAX) \ - : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \ - unsigned long long int, 0, ULLONG_MAX))) -# else -# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \ - (EXPR_SIGNED (*(r)) \ - ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ - long int, LONG_MIN, LONG_MAX) \ - : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ - unsigned long int, 0, ULONG_MAX)) -# endif -#endif - -/* Store the low-order bits of A B into *R, where the operation - is given by OP. Use the unsigned type UT for calculation to avoid - overflow problems. *R's type is T, with extrema TMIN and TMAX. - T must be a signed integer type. Return 1 if the result overflows. */ -#define _GL_INT_OP_CALC(a, b, r, op, overflow, ut, t, tmin, tmax) \ - (overflow (a, b, tmin, tmax) \ - ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 1) \ - : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 0)) - -/* Return the low-order bits of A B, where the operation is given - by OP. Use the unsigned type UT for calculation to avoid undefined - behavior on signed integer overflow, and convert the result to type T. - UT is at least as wide as T and is no narrower than unsigned int, - T is two's complement, and there is no padding or trap representations. - Assume that converting UT to T yields the low-order bits, as is - done in all known two's-complement C compilers. E.g., see: - https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html - - According to the C standard, converting UT to T yields an - implementation-defined result or signal for values outside T's - range. However, code that works around this theoretical problem - runs afoul of a compiler bug in Oracle Studio 12.3 x86. See: - https://lists.gnu.org/r/bug-gnulib/2017-04/msg00049.html - As the compiler bug is real, don't try to work around the - theoretical problem. */ - -#define _GL_INT_OP_WRAPV_VIA_UNSIGNED(a, b, op, ut, t) \ - ((t) ((ut) (a) op (ut) (b))) - -/* Return true if the numeric values A + B, A - B, A * B fall outside - the range TMIN..TMAX. Arguments should be integer expressions - without side effects. TMIN should be signed and nonpositive. - TMAX should be positive, and should be signed unless TMIN is zero. */ -#define _GL_INT_ADD_RANGE_OVERFLOW(a, b, tmin, tmax) \ - ((b) < 0 \ - ? (((tmin) \ - ? ((EXPR_SIGNED (_GL_INT_CONVERT (a, (tmin) - (b))) || (b) < (tmin)) \ - && (a) < (tmin) - (b)) \ - : (a) <= -1 - (b)) \ - || ((EXPR_SIGNED (a) ? 0 <= (a) : (tmax) < (a)) && (tmax) < (a) + (b))) \ - : (a) < 0 \ - ? (((tmin) \ - ? ((EXPR_SIGNED (_GL_INT_CONVERT (b, (tmin) - (a))) || (a) < (tmin)) \ - && (b) < (tmin) - (a)) \ - : (b) <= -1 - (a)) \ - || ((EXPR_SIGNED (_GL_INT_CONVERT (a, b)) || (tmax) < (b)) \ - && (tmax) < (a) + (b))) \ - : (tmax) < (b) || (tmax) - (b) < (a)) -#define _GL_INT_SUBTRACT_RANGE_OVERFLOW(a, b, tmin, tmax) \ - (((a) < 0) == ((b) < 0) \ - ? ((a) < (b) \ - ? !(tmin) || -1 - (tmin) < (b) - (a) - 1 \ - : (tmax) < (a) - (b)) \ - : (a) < 0 \ - ? ((!EXPR_SIGNED (_GL_INT_CONVERT ((a) - (tmin), b)) && (a) - (tmin) < 0) \ - || (a) - (tmin) < (b)) \ - : ((! (EXPR_SIGNED (_GL_INT_CONVERT (tmax, b)) \ - && EXPR_SIGNED (_GL_INT_CONVERT ((tmax) + (b), a))) \ - && (tmax) <= -1 - (b)) \ - || (tmax) + (b) < (a))) -#define _GL_INT_MULTIPLY_RANGE_OVERFLOW(a, b, tmin, tmax) \ - ((b) < 0 \ - ? ((a) < 0 \ - ? (EXPR_SIGNED (_GL_INT_CONVERT (tmax, b)) \ - ? (a) < (tmax) / (b) \ - : ((INT_NEGATE_OVERFLOW (b) \ - ? _GL_INT_CONVERT (b, tmax) >> (TYPE_WIDTH (b) - 1) \ - : (tmax) / -(b)) \ - <= -1 - (a))) \ - : INT_NEGATE_OVERFLOW (_GL_INT_CONVERT (b, tmin)) && (b) == -1 \ - ? (EXPR_SIGNED (a) \ - ? 0 < (a) + (tmin) \ - : 0 < (a) && -1 - (tmin) < (a) - 1) \ - : (tmin) / (b) < (a)) \ - : (b) == 0 \ - ? 0 \ - : ((a) < 0 \ - ? (INT_NEGATE_OVERFLOW (_GL_INT_CONVERT (a, tmin)) && (a) == -1 \ - ? (EXPR_SIGNED (b) ? 0 < (b) + (tmin) : -1 - (tmin) < (b) - 1) \ - : (tmin) / (a) < (b)) \ - : (tmax) / (b) < (a))) - -#endif /* _GL_INTPROPS_H */ diff --git a/third_party/make/job.c b/third_party/make/job.c index a9e1ff1c1..8f73533cd 100644 --- a/third_party/make/job.c +++ b/third_party/make/job.c @@ -1,5 +1,5 @@ /* Job execution and handling for GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,77 +12,192 @@ 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 . */ +this program. If not, see . */ -#include "third_party/make/makeint.inc" -/**/ -#include "third_party/make/debug.h" -#include "third_party/make/filedef.h" -#include "third_party/make/job.h" -/**/ -#include "libc/assert.h" -#include "libc/calls/calls.h" -#include "libc/calls/pledge.h" -#include "libc/calls/pledge.internal.h" -#include "libc/calls/struct/bpf.internal.h" -#include "libc/calls/struct/filter.internal.h" -#include "libc/calls/struct/seccomp.internal.h" -#include "libc/calls/struct/sysinfo.h" -#include "libc/calls/struct/timeval.h" -#include "libc/dce.h" -#include "libc/elf/def.h" -#include "libc/elf/elf.h" -#include "libc/elf/struct/ehdr.h" -#include "libc/elf/struct/phdr.h" -#include "libc/fmt/conv.h" -#include "libc/fmt/itoa.h" -#include "libc/fmt/libgen.h" -#include "libc/intrin/promises.internal.h" -#include "libc/intrin/safemacros.internal.h" -#include "libc/log/backtrace.internal.h" -#include "libc/log/log.h" -#include "libc/log/rop.internal.h" -#include "libc/macros.internal.h" -#include "libc/math.h" -#include "libc/nexgen32e/kcpuids.h" -#include "libc/proc/posix_spawn.h" -#include "libc/runtime/runtime.h" -#include "libc/sock/sock.h" -#include "libc/str/str.h" -#include "libc/sysv/consts/audit.h" -#include "libc/sysv/consts/map.h" -#include "libc/sysv/consts/nrlinux.h" -#include "libc/sysv/consts/o.h" -#include "libc/sysv/consts/pr.h" -#include "libc/sysv/consts/prot.h" -#include "libc/sysv/consts/rlimit.h" -#include "libc/sysv/consts/sig.h" -#include "libc/sysv/errfuns.h" -#include "libc/time/time.h" -#include "libc/x/x.h" -#include "third_party/make/commands.h" -#include "third_party/make/dep.h" -#include "third_party/make/findprog.h" -#include "third_party/make/os.h" -#include "libc/serialize.h" -#include "third_party/make/variable.h" +#include "makeint.h" -#define USE_POSIX_SPAWN (!IsLinux() && !IsOpenbsd()) -#define HAVE_POSIX_SPAWNATTR_SETSIGMASK +#include +#include +#include "job.h" +#include "debug.h" +#include "filedef.h" +#include "commands.h" +#include "variable.h" +#include "os.h" +#include "dep.h" +#include "shuffle.h" + +/* Default shell to use. */ #ifdef WINDOWS32 +# include + const char *default_shell = "sh.exe"; int no_default_sh_exe = 1; int batch_mode_shell = 1; HANDLE main_thread; -#else + +#elif defined (_AMIGA) + +const char *default_shell = ""; +extern int MyExecute (char **); +int batch_mode_shell = 0; + +#elif defined (__MSDOS__) + +/* The default shell is a pointer so we can change it if Makefile + says so. It is without an explicit path so we get a chance + to search the $PATH for it (since MSDOS doesn't have standard + directories we could trust). */ +const char *default_shell = "command.com"; +int batch_mode_shell = 0; + +#elif defined (__EMX__) + const char *default_shell = "/bin/sh"; int batch_mode_shell = 0; + +#elif defined (VMS) + +# include +# include +const char *default_shell = ""; +int batch_mode_shell = 0; + +#define strsignal vms_strsignal +char * vms_strsignal (int status); + +#ifndef C_FACILITY_NO +# define C_FACILITY_NO 0x350000 +#endif +#ifndef VMS_POSIX_EXIT_MASK +# define VMS_POSIX_EXIT_MASK (C_FACILITY_NO | 0xA000) #endif -#define WAIT_NOHANG(status) waitpid (-1, (status), WNOHANG) +#else -#define WAIT_T int +const char *default_shell = "/bin/sh"; +int batch_mode_shell = 0; + +#endif + +#ifdef __MSDOS__ +# include +static int execute_by_shell; +static int dos_pid = 123; +int dos_status; +int dos_command_running; +#endif /* __MSDOS__ */ + +#ifdef _AMIGA +# include +static int amiga_pid = 123; +static int amiga_status; +static char amiga_bname[32]; +static int amiga_batch_file; +#endif /* Amiga. */ + +#ifdef VMS +# ifndef __GNUC__ +# include +# endif +# include +# include +static void vmsWaitForChildren (int *); +#endif + +#ifdef __EMX__ +# include +#endif + +#if defined (HAVE_FCNTL_H) +# include +#endif + +#if defined (HAVE_SYS_WAIT_H) || defined (HAVE_UNION_WAIT) +# include +#endif + +#ifdef HAVE_WAITPID +# define WAIT_NOHANG(status) waitpid (-1, (status), WNOHANG) +#else /* Don't have waitpid. */ +# ifdef HAVE_WAIT3 +# ifndef wait3 +extern int wait3 (); +# endif +# define WAIT_NOHANG(status) wait3 ((status), WNOHANG, (struct rusage *) 0) +# endif /* Have wait3. */ +#endif /* Have waitpid. */ + +#ifdef USE_POSIX_SPAWN +# include +# include "findprog.h" +#endif + +#if !defined (wait) && !defined (POSIX) +int wait (); +#endif + +#ifndef HAVE_UNION_WAIT + +# define WAIT_T int + +# ifndef WTERMSIG +# define WTERMSIG(x) ((x) & 0x7f) +# endif +# ifndef WCOREDUMP +# define WCOREDUMP(x) ((x) & 0x80) +# endif +# ifndef WEXITSTATUS +# define WEXITSTATUS(x) (((x) >> 8) & 0xff) +# endif +# ifndef WIFSIGNALED +# define WIFSIGNALED(x) (WTERMSIG (x) != 0) +# endif +# ifndef WIFEXITED +# define WIFEXITED(x) (WTERMSIG (x) == 0) +# endif + +#else /* Have 'union wait'. */ + +# define WAIT_T union wait +# ifndef WTERMSIG +# define WTERMSIG(x) ((x).w_termsig) +# endif +# ifndef WCOREDUMP +# define WCOREDUMP(x) ((x).w_coredump) +# endif +# ifndef WEXITSTATUS +# define WEXITSTATUS(x) ((x).w_retcode) +# endif +# ifndef WIFSIGNALED +# define WIFSIGNALED(x) (WTERMSIG(x) != 0) +# endif +# ifndef WIFEXITED +# define WIFEXITED(x) (WTERMSIG(x) == 0) +# endif + +#endif /* Don't have 'union wait'. */ + +#if !defined(HAVE_UNISTD_H) && !defined(WINDOWS32) +int dup2 (); +int execve (); +void _exit (); +# ifndef VMS +int geteuid (); +int getegid (); +int setgid (); +int getgid (); +# endif +#endif + +#if HAVE_SYS_LOADAVG_H +# include +#endif + +#if HAVE_DECL_GETLOADAVG == 0 +int getloadavg (double loadavg[], int nelem); +#endif /* Different systems have different requirements for pid_t. Plus we have to support gettext string translation... Argh. */ @@ -90,7 +205,13 @@ static const char * pid2str (pid_t pid) { static char pidstring[100]; +#if defined(WINDOWS32) && (__GNUC__ > 3 || _MSC_VER > 1300) + /* %Id is only needed for 64-builds, which were not supported by + older versions of Windows compilers. */ + sprintf (pidstring, "%Id", pid); +#else sprintf (pidstring, "%lu", (unsigned long) pid); +#endif return pidstring; } @@ -148,7 +269,7 @@ create_batch_file (char const *base, int unixy, int *fd) { const char *const ext = unixy ? "sh" : "bat"; const char *error_string = NULL; - char temp_path[MAXPATHLEN]; /* need to know its length */ + char temp_path[MAX_PATH+1]; /* need to know its length */ unsigned path_size = GetTempPath (sizeof temp_path, temp_path); int path_is_dot = 0; /* The following variable is static so we won't try to reuse a name @@ -243,7 +364,7 @@ create_batch_file (char const *base, int unixy, int *fd) *fd = -1; if (error_string == NULL) - error_string = _("Cannot create a temporary file\n"); + error_string = _("Cannot create a temporary file"); O (fatal, NILF, error_string); /* not reached */ @@ -251,29 +372,28 @@ create_batch_file (char const *base, int unixy, int *fd) } #endif /* WINDOWS32 */ -/* determines whether path looks to be a Bourne-like shell. */ +#ifdef __EMX__ +/* returns whether path is assumed to be a unix like shell. */ int -is_bourne_compatible_shell (const char *path) +_is_unixy_shell (const char *path) { - /* List of known POSIX (or POSIX-ish) shells. */ - static const char *unix_shells[] = { - "build/bootstrap/cocmd.com", - "false", - "dash", - "sh", - "bash", - "ksh", - "rksh", - "zsh", - "ash", - "dash", + /* list of non unix shells */ + const char *known_os2shells[] = { + "cmd.exe", + "cmd", + "4os2.exe", + "4os2", + "4dos.exe", + "4dos", + "command.com", + "command", NULL }; - const char **s; /* find the rightmost '/' or '\\' */ const char *name = strrchr (path, '/'); - char *p = strrchr (path, '\\'); + const char *p = strrchr (path, '\\'); + unsigned i; if (name && p) /* take the max */ name = (name > p) ? name : p; @@ -282,18 +402,54 @@ is_bourne_compatible_shell (const char *path) else if (!name) /* name and p must be 0 */ name = path; - if (*name == '/' || *name == '\\') - ++name; + if (ISDIRSEP (*name)) + name++; + + i = 0; + while (known_os2shells[i] != NULL) + { + if (strcasecmp (name, known_os2shells[i]) == 0) + return 0; /* not a unix shell */ + i++; + } + + /* in doubt assume a unix like shell */ + return 1; +} +#endif /* __EMX__ */ + +/* determines whether path looks to be a Bourne-like shell. */ +int +is_bourne_compatible_shell (const char *path) +{ + /* List of known POSIX (or POSIX-ish) shells. */ + static const char *unix_shells[] = { + "sh", + "bash", + "dash", + "ksh", + "rksh", + "zsh", + "ash", + NULL + }; + const char **s; + + /* find the last directory separator, or the beginning of the string. */ + const char *cp = path + strlen (path); + + while (cp > path && !ISDIRSEP (cp[-1])) + --cp; /* this should be able to deal with extensions on Windows-like systems */ for (s = unix_shells; *s != NULL; ++s) { #if defined(WINDOWS32) || defined(__MSDOS__) size_t len = strlen (*s); - if ((strlen (name) >= len && STOP_SET (name[len], MAP_DOT|MAP_NUL)) - && strncasecmp (name, *s, len) == 0) + if ((strlen (cp) >= len && STOP_SET (cp[len], MAP_DOT|MAP_NUL)) + && strncasecmp (cp, *s, len) == 0) #else - if (strcmp (name, *s) == 0) + if (strcmp (cp, *s) == 0) #endif return 1; /* a known unix-style shell */ } @@ -302,6 +458,7 @@ is_bourne_compatible_shell (const char *path) return 0; } +#ifdef POSIX extern sigset_t fatal_signal_set; static void @@ -324,6 +481,39 @@ unblock_all_sigs () sigprocmask (SIG_SETMASK, &empty, (sigset_t *) 0); } +#elif defined(HAVE_SIGSETMASK) + +extern int fatal_signal_mask; + +static void +block_sigs () +{ + sigblock (fatal_signal_mask); +} + +static void +unblock_sigs () +{ + sigsetmask (siggetmask () & ~fatal_signal_mask); +} + +void +unblock_all_sigs () +{ + sigsetmask (0); +} + +#else + +#define block_sigs() +#define unblock_sigs() + +void +unblock_all_sigs () +{ +} + +#endif /* Write an error message describing the exit status given in EXIT_CODE, EXIT_SIG, and COREDUMP, for the target TARGET_NAME. @@ -339,6 +529,7 @@ child_error (struct child *child, const struct file *f = child->file; const floc *flocp = &f->cmds->fileinfo; const char *nm; + const char *smode; size_t l; if (ignored && run_silent) @@ -364,187 +555,35 @@ child_error (struct child *child, l = strlen (pre) + strlen (nm) + strlen (f->name) + strlen (post); + smode = shuffle_get_mode (); + if (smode) + { +#define SHUFFLE_PREFIX " shuffle=" + char *a = alloca (CSTRLEN(SHUFFLE_PREFIX) + strlen (smode) + 1); + sprintf (a, SHUFFLE_PREFIX "%s", smode); + smode = a; + l += strlen (smode); +#undef SHUFFLE_PREFIX + } + OUTPUT_SET (&child->output); show_goal_error (); if (exit_sig == 0) - error (NILF, l + INTSTR_LENGTH, - _("%s[%s: %s] Error %d%s"), pre, nm, f->name, exit_code, post); + error (NILF, l + INTSTR_LENGTH, _("%s[%s: %s] Error %d%s%s"), + pre, nm, f->name, exit_code, post, smode ? smode : ""); else { const char *s = strsignal (exit_sig); - error (NILF, l + strlen (s) + strlen (dump), - "%s[%s: %s] %s%s%s", pre, nm, f->name, s, dump, post); + error (NILF, l + strlen (s) + strlen (dump), "%s[%s: %s] %s%s%s%s", + pre, nm, f->name, s, dump, post, smode ? smode : ""); } OUTPUT_UNSET (); } -/* [jart] manage temporary directories per rule */ - -bool -parse_bool (const char *s) -{ - while (isspace (*s)) - ++s; - if (isdigit (*s)) - return !! atoi (s); - return _startswithi (s, "true"); -} - -const char * -get_target_variable (const char *name, - size_t length, - struct file *file, - const char *dflt) -{ - const struct variable *var; - if ((file && - ((var = lookup_variable_in_set (name, length, - file->variables->set)) || - (file->pat_variables && - (var = lookup_variable_in_set (name, length, - file->pat_variables->set))))) || - (var = lookup_variable (name, length))) - return variable_expand (var->value); - else - return dflt; -} - -char * -get_tmpdir (struct file *file) -{ - const char *tmpdir; - tmpdir = get_target_variable (STRING_SIZE_TUPLE ("TMPDIR"), file, 0); - if (!tmpdir) tmpdir = __get_tmpdir(); - return strdup (tmpdir); -} - -char * -new_tmpdir (const char *tmp, struct file *file) -{ - char *tmpdir; - const char *s; - int c, e, i, j; - char cwd[PATH_MAX]; - char path[PATH_MAX]; - - /* create temporary directory in tmp */ - i = 0; - - /* ensure tmpdir will be absolute */ - if (tmp[0] != '/') - { - if (getcwd(cwd, sizeof(cwd))) - { - for (j = 0; cwd[j]; ++j) - if (i < PATH_MAX) - path[i++] = cwd[j]; - if (i && path[i - 1] != '/') - if (i < PATH_MAX) - path[i++] = '/'; - } - else - DB (DB_JOBS, (_("Failed to get current directory\n"))); - } - - /* copy old tmpdir */ - for (j = 0; tmp[j]; ++j) - if (i < PATH_MAX) - path[i++] = tmp[j]; - - /* append slash */ - if (i && path[i - 1] != '/') - if (i < PATH_MAX) - path[i++] = '/'; - - /* append target name safely */ - for (j = 0; (c = file->name[j]); ++j) - { - if (isalnum(c)) - c = tolower(c); - else - c = '_'; - if (i < PATH_MAX) - path[i++] = c; - } - - /* copy random template */ - s = ".XXXXXX"; - for (j = 0; s[j]; ++j) - if (i < PATH_MAX) - path[i++] = s[j]; - - /* add nul terminator */ - if (i + 11 < PATH_MAX) - path[i] = 0; - else - { - DB (DB_JOBS, (_("Creating TMPDIR in %s for %s is too long\n"), - tmp, file->name)); - return 0; - } - - /* create temp directory with random data */ - e = errno; - if (!(tmpdir = mkdtemp (path)) && errno == ENOENT) - { - /* create parent directories if necessary */ - char *dir; - errno = e; - dir = xstrdup (path); - if (!makedirs (dirname (dir), 0700)) - tmpdir = mkdtemp (path); - free (dir); - } - - /* returned string must be free'd */ - if (tmpdir) - { - tmpdir = xstrdup (tmpdir); - DB (DB_JOBS, (_("Created TMPDIR %s\n"), path)); - } - else - DB (DB_JOBS, (_("Creating TMPDIR %s failed %s\n"), - path, strerror (errno))); - - return tmpdir; -} - -bool -get_file_timestamp (struct file *file) -{ - int e; - struct stat st; - EINTRLOOP (e, stat (file->name, &st)); - if (e == 0) - return FILE_TIMESTAMP_STAT_MODTIME (file->name, st); - else - return NONEXISTENT_MTIME; -} - -void -delete_tmpdir (struct child *c) -{ - if (!c->tmpdir) return; - - DB (DB_JOBS, (_("Deleting TMPDIR %s\n"), c->tmpdir)); - - if (!isdirectory (c->tmpdir)) - DB (DB_JOBS, (_("Warning TMPDIR %s doesn't exist\n"), c->tmpdir)); - - errno = 0; - if (rmrf (c->tmpdir)) - DB (DB_JOBS, (_("Deleting TMPDIR %s failed %s\n"), - c->tmpdir, strerror(errno))); - - free (c->tmpdir); - c->tmpdir = 0; -} - - /* Handle a dead child. This handler may or may not ever be installed. If we're using the jobserver feature without pselect(), we need it. @@ -558,11 +597,17 @@ delete_tmpdir (struct child *c) static unsigned int dead_children = 0; -RETSIGTYPE +void child_handler (int sig UNUSED) { ++dead_children; + jobserver_signal (); + +#ifdef __EMX__ + /* The signal handler must called only once! */ + signal (SIGCHLD, SIG_DFL); +#endif } extern pid_t shell_function_pid; @@ -577,10 +622,18 @@ extern pid_t shell_function_pid; void reap_children (int block, int err) { +#ifndef WINDOWS32 WAIT_T status; +#endif /* Initially, assume we have some. */ int reap_more = 1; +#ifdef WAIT_NOHANG +# define REAP_MORE reap_more +#else +# define REAP_MORE dead_children +#endif + /* As long as: We have at least one child outstanding OR a shell function in progress, @@ -590,7 +643,7 @@ reap_children (int block, int err) we'll keep reaping children. */ while ((children != 0 || shell_function_pid != 0) - && (block || reap_more)) + && (block || REAP_MORE)) { unsigned int remote = 0; pid_t pid; @@ -653,6 +706,9 @@ reap_children (int block, int err) DB (DB_JOBS, (_("Live child %p (%s) PID %s %s\n"), c, c->file->name, pid2str (c->pid), c->remote ? _(" (remote)") : "")); +#ifdef VMS + break; +#endif } /* First, check for remote children. */ @@ -667,18 +723,34 @@ reap_children (int block, int err) else if (pid < 0) { /* A remote status command failed miserably. Punt. */ - remote_status_lose: pfatal_with_name ("remote_status"); } else { /* No remote children. Check for local children. */ +#if !defined(__MSDOS__) && !defined(_AMIGA) && !defined(WINDOWS32) if (any_local) { +#ifdef VMS + /* Todo: This needs more untangling multi-process support */ + /* Just do single child process support now */ + vmsWaitForChildren (&status); + pid = c->pid; + + /* VMS failure status can not be fully translated */ + status = $VMS_STATUS_SUCCESS (c->cstatus) ? 0 : (1 << 8); + + /* A Posix failure can be exactly translated */ + if ((c->cstatus & VMS_POSIX_EXIT_MASK) == VMS_POSIX_EXIT_MASK) + status = (c->cstatus >> 3 & 255) << 8; +#else +#ifdef WAIT_NOHANG if (!block) pid = WAIT_NOHANG (&status); else +#endif EINTRLOOP (pid, wait (&status)); +#endif /* !VMS */ } else pid = 0; @@ -706,17 +778,107 @@ reap_children (int block, int err) /* Now try a blocking wait for a remote child. */ pid = remote_status (&exit_code, &exit_sig, &coredump, 1); if (pid < 0) - goto remote_status_lose; - else if (pid == 0) + pfatal_with_name ("remote_status"); + + if (pid == 0) /* No remote children either. Finally give up. */ break; /* We got a remote child. */ remote = 1; } +#endif /* !__MSDOS__, !Amiga, !WINDOWS32. */ +#ifdef __MSDOS__ + /* Life is very different on MSDOS. */ + pid = dos_pid - 1; + status = dos_status; + exit_code = WEXITSTATUS (status); + if (exit_code == 0xff) + exit_code = -1; + exit_sig = WIFSIGNALED (status) ? WTERMSIG (status) : 0; + coredump = 0; +#endif /* __MSDOS__ */ +#ifdef _AMIGA + /* Same on Amiga */ + pid = amiga_pid - 1; + status = amiga_status; + exit_code = amiga_status; + exit_sig = 0; + coredump = 0; +#endif /* _AMIGA */ +#ifdef WINDOWS32 + { + HANDLE hPID; + HANDLE hcTID, hcPID; + DWORD dwWaitStatus = 0; + exit_code = 0; + exit_sig = 0; + coredump = 0; + + /* Record the thread ID of the main process, so that we + could suspend it in the signal handler. */ + if (!main_thread) + { + hcTID = GetCurrentThread (); + hcPID = GetCurrentProcess (); + if (!DuplicateHandle (hcPID, hcTID, hcPID, &main_thread, 0, + FALSE, DUPLICATE_SAME_ACCESS)) + { + DWORD e = GetLastError (); + fprintf (stderr, + "Determine main thread ID (Error %ld: %s)\n", + e, map_windows32_error_to_string (e)); + } + else + DB (DB_VERBOSE, ("Main thread handle = %p\n", main_thread)); + } + + /* wait for anything to finish */ + hPID = process_wait_for_any (block, &dwWaitStatus); + if (hPID) + { + /* was an error found on this process? */ + int werr = process_last_err (hPID); + + /* get exit data */ + exit_code = process_exit_code (hPID); + + /* the extra tests of exit_code are here to prevent + map_windows32_error_to_string from calling 'fatal', + which will then call reap_children again */ + if (werr && exit_code > 0 && exit_code < WSABASEERR) + fprintf (stderr, "make (e=%d): %s\n", exit_code, + map_windows32_error_to_string (exit_code)); + + /* signal */ + exit_sig = process_signal (hPID); + + /* cleanup process */ + process_cleanup (hPID); + + coredump = 0; + } + else if (dwWaitStatus == WAIT_FAILED) + { + /* The WaitForMultipleObjects() failed miserably. Punt. */ + pfatal_with_name ("WaitForMultipleObjects"); + } + else if (dwWaitStatus == WAIT_TIMEOUT) + { + /* No child processes are finished. Give up waiting. */ + reap_more = 0; + break; + } + + pid = (pid_t) hPID; + } +#endif /* WINDOWS32 */ } + /* Some child finished: increment the command count. */ + ++command_count; + /* Check if this is the child of the 'shell' function. */ if (!remote && pid == shell_function_pid) { @@ -746,6 +908,35 @@ reap_children (int block, int err) process_child: +#if defined(USE_POSIX_SPAWN) + /* Some versions of posix_spawn() do not detect errors such as command + not found until after they fork. In that case they will exit with a + code of 127. Try to detect that and provide a useful error message. + Otherwise we'll just show the error below, as normal. */ + if (exit_sig == 0 && exit_code == 127 && c->cmd_name) + { + const char *e = NULL; + struct stat st; + int r; + + /* There are various ways that this will show a different error than + fork/exec. To really get the right error we'd have to fall back + to fork/exec but I don't want to bother with that. Just do the + best we can. */ + + EINTRLOOP(r, stat (c->cmd_name, &st)); + if (r < 0) + e = strerror (errno); + else if (S_ISDIR(st.st_mode) || !(st.st_mode & S_IXUSR)) + e = strerror (EACCES); + else if (st.st_size == 0) + e = strerror (ENOEXEC); + + if (e) + OSS(error, NILF, "%s: %s", c->cmd_name, e); + } +#endif + /* Determine the failure status: 0 for success, 1 for updating target in question mode, 2 for anything else. */ if (exit_sig == 0 && exit_code == 0) @@ -795,16 +986,7 @@ reap_children (int block, int err) delete_on_error = f != 0 && f->is_target; } if (exit_sig != 0 || delete_on_error) - { - delete_child_targets (c); - delete_tmpdir (c); - } - else if (c->file->touched && - c->file->touched != get_file_timestamp (c->file)) - /* If file was created just so it could be sandboxed, then - delete that file even if .DELETE_ON_ERROR isn't used, - but only if the command hasn't modified it. */ - unlink (c->file->name); + delete_child_targets (c); } else { @@ -828,12 +1010,10 @@ reap_children (int block, int err) } else { -#ifndef NO_OUTPUT_SYNC /* If we're sync'ing per line, write the previous line's output before starting the next one. */ if (output_sync == OUTPUT_SYNC_LINE) output_dump (&c->output); -#endif /* Check again whether to start remotely. Whether or not we want to changes over time. Also, start_remote_job may need state set up @@ -852,28 +1032,20 @@ reap_children (int block, int err) } if (c->file->update_status != us_success) - { - /* We failed to start the commands. */ - delete_child_targets (c); - delete_tmpdir (c); - } + /* We failed to start the commands. */ + delete_child_targets (c); } else - { - /* There are no more commands. We got through them all - without an unignored error. Now the target has been - successfully updated. */ - c->file->update_status = us_success; - delete_tmpdir (c); - } + /* There are no more commands. We got through them all + without an unignored error. Now the target has been + successfully updated. */ + c->file->update_status = us_success; } /* When we get here, all the commands for c->file are finished. */ -#ifndef NO_OUTPUT_SYNC /* Synchronize any remaining parallel output. */ output_dump (&c->output); -#endif /* At this point c->file->update_status is success or failed. But c->file->command_state is still cs_running if all the commands @@ -929,13 +1101,27 @@ reap_children (int block, int err) /* Free the storage allocated for CHILD. */ +void +free_childbase (struct childbase *child) +{ + if (child->environment != 0) + { + char **ep = child->environment; + while (*ep != 0) + free (*ep++); + free (child->environment); + } + + free (child->cmd_name); +} + static void free_child (struct child *child) { output_close (&child->output); if (!jobserver_tokens) - ONS (fatal, NILF, "INTERNAL: Freeing child %p (%s) but no tokens left!\n", + ONS (fatal, NILF, "INTERNAL: Freeing child %p (%s) but no tokens left", child, child->file->name); /* If we're using the jobserver and this child is not the only outstanding @@ -961,16 +1147,8 @@ free_child (struct child *child) free (child->command_lines); } - if (child->environment != 0) - { - char **ep = child->environment; - while (*ep != 0) - free (*ep++); - free (child->environment); - } + free_childbase ((struct childbase*)child); - free (child->tmpdir); - free (child->cmd_name); free (child); } @@ -987,8 +1165,13 @@ start_job_command (struct child *child) { int flags; char *p; +#ifdef VMS +# define FREE_ARGV(_a) + char *argv; +#else # define FREE_ARGV(_a) do{ if (_a) { free ((_a)[0]); free (_a); } }while(0) char **argv; +#endif /* If we have a completely empty commandset, stop now. */ if (!child->command_ptr) @@ -1000,7 +1183,7 @@ start_job_command (struct child *child) | child->file->cmds->lines_flags[child->command_line - 1]); p = child->command_ptr; - child->noerror = ((flags & COMMANDS_NOERROR) != 0); + child->noerror = ANY_SET (flags, COMMANDS_NOERROR); while (*p != '\0') { @@ -1016,7 +1199,7 @@ start_job_command (struct child *child) ++p; } - child->recursive = ((flags & COMMANDS_RECURSE) != 0); + child->recursive = ANY_SET (flags, COMMANDS_RECURSE); /* Update the file's command flags with any new ones we found. We only keep the COMMANDS_RECURSE setting. Even this isn't 100% correct; we are @@ -1045,9 +1228,49 @@ start_job_command (struct child *child) /* Figure out an argument list from this command line. */ { char *end = 0; +#ifdef VMS + /* Skip any leading whitespace */ + while (*p) + { + if (!ISSPACE (*p)) + { + if (*p != '\\') + break; + if ((p[1] != '\n') && (p[1] != 'n') && (p[1] != 't')) + break; + } + p++; + } + + argv = p; + /* Please note, for VMS argv is a string (not an array of strings) which + contains the complete command line, which for multi-line variables + still includes the newlines. So detect newlines and set 'end' (which + is used for child->command_ptr) instead of (re-)writing + construct_command_argv */ + if (!one_shell) + { + char *s = p; + int instring = 0; + while (*s) + { + if (*s == '"') + instring = !instring; + else if (*s == '\\' && !instring && *(s+1) != 0) + s++; + else if (*s == '\n' && !instring) + { + end = s; + break; + } + ++s; + } + } +#else argv = construct_command_argv (p, &end, child->file, child->file->cmds->lines_flags[child->command_line - 1], &child->sh_batch_file); +#endif if (end == NULL) child->command_ptr = NULL; else @@ -1061,15 +1284,23 @@ start_job_command (struct child *child) command line, or 'succeeded' otherwise. The exit status of 1 tells the user that -q is saying 'something to do'; the exit status for a random error is 2. */ - if (argv != 0 && question_flag && !(flags & COMMANDS_RECURSE)) + if (argv != 0 && question_flag && NONE_SET (flags, COMMANDS_RECURSE)) { FREE_ARGV (argv); +#ifdef VMS + /* On VMS, argv[0] can be a null string here */ + if (argv[0] != 0) + { +#endif child->file->update_status = us_question; notice_finished_file (child->file); return; +#ifdef VMS + } +#endif } - if (touch_flag && !(flags & COMMANDS_RECURSE)) + if (touch_flag && NONE_SET (flags, COMMANDS_RECURSE)) { /* Go on to the next command. It might be the recursive one. We construct ARGV only to find the end of the command line. */ @@ -1080,6 +1311,9 @@ start_job_command (struct child *child) if (argv == 0) { next_command: +#ifdef __MSDOS__ + execute_by_shell = 0; /* in case construct_command_argv sets it */ +#endif /* This line has no commands. Go to the next. */ if (job_next_command (child)) start_job_command (child); @@ -1100,20 +1334,18 @@ start_job_command (struct child *child) in SYNC_RECURSE mode or this command is not recursive. We'll also check output_sync separately below in case it changes due to error. */ child->output.syncout = output_sync && (output_sync == OUTPUT_SYNC_RECURSE - || !(flags & COMMANDS_RECURSE)); + || NONE_SET (flags, COMMANDS_RECURSE)); OUTPUT_SET (&child->output); -#ifndef NO_OUTPUT_SYNC if (! child->output.syncout) /* We don't want to sync this command: to avoid misordered output ensure any already-synced content is written. */ output_dump (&child->output); -#endif /* Print the command if appropriate. */ - if (just_print_flag || trace_flag - || (!(flags & COMMANDS_SILENT) && !run_silent)) + if (just_print_flag || ISDB (DB_PRINT) + || (NONE_SET (flags, COMMANDS_SILENT) && !run_silent)) OS (message, 0, "%s", p); /* Tell update_goal_chain that a command has been started on behalf of @@ -1131,8 +1363,13 @@ start_job_command (struct child *child) performed some action (makes a difference as to what messages are printed, etc. */ +#if !defined(VMS) && !defined(_AMIGA) if ( +#if defined __MSDOS__ || defined (__EMX__) + unixy_shell /* the test is complicated and we already did it */ +#else (argv[0] && is_bourne_compatible_shell (argv[0])) +#endif && (argv[1] && argv[1][0] == '-' && ((argv[1][1] == 'c' && argv[1][2] == '\0') @@ -1144,10 +1381,11 @@ start_job_command (struct child *child) FREE_ARGV (argv); goto next_command; } +#endif /* !VMS && !_AMIGA */ /* If -n was given, recurse to get the next line in the sequence. */ - if (just_print_flag && !(flags & COMMANDS_RECURSE)) + if (just_print_flag && NONE_SET (flags, COMMANDS_RECURSE)) { FREE_ARGV (argv); goto next_command; @@ -1171,10 +1409,22 @@ start_job_command (struct child *child) child->deleted = 0; - /* Set up the environment for the child. */ +#ifndef _AMIGA + /* Set up the environment for the child. + It's a slight inaccuracy to set the environment for recursive make even + for command lines that aren't recursive, but I don't want to have to + recompute the target environment for each command. Better would be to + keep a separate entry for MAKEFLAGS in the environment so it could be + replaced on its own. For now just set it for all lines. + */ if (child->environment == 0) - child->environment = target_environment (child->file); + child->environment = target_environment (child->file, + child->file->cmds->any_recurse); +#endif +#if !defined(__MSDOS__) && !defined(_AMIGA) && !defined(WINDOWS32) + +#ifndef VMS /* start_waiting_job has set CHILD->remote if we can start a remote job. */ if (child->remote) { @@ -1198,20 +1448,143 @@ start_job_command (struct child *child) } } else +#endif /* !VMS */ { /* Fork the child process. */ - char **parent_environ; run_local: block_sigs (); + child->remote = 0; - parent_environ = environ; - jobserver_pre_child (flags & COMMANDS_RECURSE); + +#ifdef VMS + child->pid = child_execute_job ((struct childbase *)child, 1, argv); + +#else + + jobserver_pre_child (ANY_SET (flags, COMMANDS_RECURSE)); + child->pid = child_execute_job ((struct childbase *)child, - child->good_stdin, argv, true); - environ = parent_environ; /* Restore value child may have clobbered. */ - jobserver_post_child (flags & COMMANDS_RECURSE); + child->good_stdin, argv); + + jobserver_post_child (ANY_SET (flags, COMMANDS_RECURSE)); + +#endif /* !VMS */ } +#else /* __MSDOS__ or Amiga or WINDOWS32 */ +#ifdef __MSDOS__ + { + int proc_return; + + block_sigs (); + dos_status = 0; + + /* We call 'system' to do the job of the SHELL, since stock DOS + shell is too dumb. Our 'system' knows how to handle long + command lines even if pipes/redirection is needed; it will only + call COMMAND.COM when its internal commands are used. */ + if (execute_by_shell) + { + char *cmdline = argv[0]; + /* We don't have a way to pass environment to 'system', + so we need to save and restore ours, sigh... */ + char **parent_env = environ; + + environ = child->environment; + + /* If we have a *real* shell, tell 'system' to call + it to do everything for us. */ + if (unixy_shell) + { + /* A *real* shell on MSDOS may not support long + command lines the DJGPP way, so we must use 'system'. */ + cmdline = argv[2]; /* get past "shell -c" */ + } + + dos_command_running = 1; + proc_return = system (cmdline); + environ = parent_env; + execute_by_shell = 0; /* for the next time */ + } + else + { + dos_command_running = 1; + proc_return = spawnvpe (P_WAIT, argv[0], argv, child->environment); + } + + /* Need to unblock signals before turning off + dos_command_running, so that child's signals + will be treated as such (see fatal_error_signal). */ + unblock_sigs (); + dos_command_running = 0; + + /* If the child got a signal, dos_status has its + high 8 bits set, so be careful not to alter them. */ + if (proc_return == -1) + dos_status |= 0xff; + else + dos_status |= (proc_return & 0xff); + ++dead_children; + child->pid = dos_pid++; + } +#endif /* __MSDOS__ */ +#ifdef _AMIGA + amiga_status = MyExecute (argv); + + ++dead_children; + child->pid = amiga_pid++; + if (amiga_batch_file) + { + amiga_batch_file = 0; + DeleteFile (amiga_bname); /* Ignore errors. */ + } +#endif /* Amiga */ +#ifdef WINDOWS32 + { + HANDLE hPID; + char* arg0; + int outfd = -1; + int errfd = -1; + + /* make UNC paths safe for CreateProcess -- backslash format */ + arg0 = argv[0]; + if (arg0 && arg0[0] == '/' && arg0[1] == '/') + for ( ; arg0 && *arg0; arg0++) + if (*arg0 == '/') + *arg0 = '\\'; + + /* make sure CreateProcess() has Path it needs */ + sync_Path_environment (); + + /* Divert child output if output_sync in use. */ + if (child->output.syncout) + { + if (child->output.out >= 0) + outfd = child->output.out; + if (child->output.err >= 0) + errfd = child->output.err; + } + + hPID = process_easy (argv, child->environment, outfd, errfd); + + if (hPID != INVALID_HANDLE_VALUE) + child->pid = (pid_t) hPID; + else + { + int i; + unblock_sigs (); + fprintf (stderr, + _("process_easy() failed to launch process (e=%ld)\n"), + process_last_err (hPID)); + for (i = 0; argv[i]; i++) + fprintf (stderr, "%s ", argv[i]); + fprintf (stderr, _("\nCounted %d args in failed launch\n"), i); + child->pid = -1; + } + } +#endif /* WINDOWS32 */ +#endif /* __MSDOS__ or Amiga or WINDOWS32 */ + /* Bump the number of jobs started in this second. */ if (child->pid >= 0) ++job_counter; @@ -1303,12 +1676,10 @@ start_waiting_job (struct child *c) void new_job (struct file *file) { - struct commands *cmds = file->cmds; - struct variable *var; struct child *c; - unsigned int i; char **lines; + unsigned int i; /* Let any previously decided-upon jobs that are waiting for the load to go down start before this new one. */ @@ -1323,21 +1694,12 @@ new_job (struct file *file) /* Start the command sequence, record it in a new 'struct child', and add that to the chain. */ - c = xcalloc (1, sizeof (struct child)); + c = xcalloc (sizeof (struct child)); output_init (&c->output); c->file = file; c->sh_batch_file = NULL; - /* [jart] manage temporary directories per rule */ - if ((c->tmpdir = get_tmpdir (file)) && - (c->tmpdir = new_tmpdir (c->tmpdir, file))) - { - var = define_variable_for_file ("TMPDIR", 6, c->tmpdir, - o_override, 0, file); - var->export = v_export; - } - /* Cache dontcare flag because file->dontcare can be changed once we return. Check dontcare inheritance mechanism for details. */ c->dontcare = file->dontcare; @@ -1504,7 +1866,7 @@ new_job (struct file *file) /* There must be at least one child already, or we have no business waiting for a token. */ if (!children) - O (fatal, NILF, "INTERNAL: no children as we go to sleep on read\n"); + O (fatal, NILF, "INTERNAL: no children as we go to sleep on read"); /* Get a token. */ got_token = jobserver_acquire (waiting_jobs != NULL); @@ -1523,9 +1885,8 @@ new_job (struct file *file) /* Trace the build. Use message here so that changes to working directories are logged. */ - if (trace_flag) + if (ISDB (DB_WHY)) { - char *newer = allocated_variable_expand_for_file ("$?", c->file); const char *nm; if (! cmds->fileinfo.filenm) @@ -1537,14 +1898,51 @@ new_job (struct file *file) nm = n; } - if (newer[0] == '\0') + if (c->file->phony) + OSS (message, 0, _("%s: update target '%s' due to: target is .PHONY"), + nm, c->file->name); + else if (c->file->last_mtime == NONEXISTENT_MTIME) OSS (message, 0, - _("%s: target '%s' does not exist"), nm, c->file->name); + _("%s: update target '%s' due to: target does not exist"), + nm, c->file->name); else - OSSS (message, 0, - _("%s: update target '%s' due to: %s"), nm, c->file->name, newer); + { + char *newer = allocated_variable_expand_for_file ("$?", c->file); + if (newer[0] != '\0') + { + OSSS (message, 0, _("%s: update target '%s' due to: %s"), + nm, c->file->name, newer); + free (newer); + } + else + { + /* One or more files didn't exist, and didn't get created. */ + size_t len = 0; + struct dep *d; - free (newer); + for (d = c->file->deps; d != NULL; d = d->next) + if (d->file->last_mtime == NONEXISTENT_MTIME) + len += strlen (d->file->name) + 1; + + if (!len) + OSS (message, 0, + _("%s: update target '%s' due to: unknown reasons"), + nm, c->file->name); + else + { + char *cp = newer = alloca (len); + for (d = c->file->deps; d != NULL; d = d->next) + if (d->file->last_mtime == NONEXISTENT_MTIME) + { + if (cp > newer) + *(cp++) = ' '; + cp = stpcpy (cp, d->file->name); + } + OSSS (message, 0, _("%s: update target '%s' due to: %s"), + nm, c->file->name, newer); + } + } + } } /* The job is now primed. Start it running. @@ -1590,12 +1988,13 @@ job_next_command (struct child *child) On systems which provide /proc/loadavg (e.g., Linux), we use an idea provided by Sven C. Dack : retrieve the current number - of processes the kernel is running and, if it's greater than the requested - load we don't allow another job to start. We allow a job to start with - equal processes since one of those will be for make itself, which will then - pause waiting for jobs to clear. + of runnable processes, if it's greater than the requested load we don't + allow another job to start. We allow a job to start with equal processes + since one of those will be for make itself, which will then pause waiting + for jobs to clear. - Otherwise, we obtain the system load average and compare that. + If /proc/loadavg is not available for some reason, we obtain the system + load average and compare that. The system load average is only recomputed once every N (N>=1) seconds. However, a very parallel make can easily start tens or even hundreds of @@ -1643,25 +2042,89 @@ job_next_command (struct child *child) static int load_too_high (void) { +#if defined(__MSDOS__) || defined(VMS) || defined(_AMIGA) || defined(__riscos__) + return 1; +#else static double last_sec; static time_t last_now; + static int proc_fd = -2; - /* This is disabled by default for now, because it will behave badly if the - user gives a value > the number of cores; in that situation the load will - never be exceeded, this function always returns false, and we'll start - all the jobs. Also, it's not quite right to limit jobs to the number of - cores not busy since a job takes some time to start etc. Maybe that's - OK, I'm not sure exactly how to handle that, but for sure we need to - clamp this value at the number of cores before this can be enabled. - */ double load, guess; time_t now; +#ifdef WINDOWS32 + /* sub_proc.c is limited in the number of objects it can wait for. */ + if (process_table_full ()) + return 1; +#endif + if (max_load_average < 0) return 0; + /* If we haven't tried to open /proc/loadavg, try now. */ +#define LOADAVG "/proc/loadavg" + if (proc_fd == -2) + { + EINTRLOOP (proc_fd, open (LOADAVG, O_RDONLY)); + if (proc_fd < 0) + DB (DB_JOBS, ("Using system load detection method.\n")); + else + { + DB (DB_JOBS, ("Using " LOADAVG " load detection method.\n")); + fd_noinherit (proc_fd); + } + } + + /* Try to read /proc/loadavg if we managed to open it. */ + if (proc_fd >= 0) + { + int r; + + EINTRLOOP (r, lseek (proc_fd, 0, SEEK_SET)); + if (r >= 0) + { +#define PROC_LOADAVG_SIZE 64 + char avg[PROC_LOADAVG_SIZE+1]; + + EINTRLOOP (r, read (proc_fd, avg, PROC_LOADAVG_SIZE)); + if (r >= 0) + { + const char *p; + + /* The syntax of /proc/loadavg is: + <1m> <5m> <15m> / + The load is considered too high if there are more jobs + running than the requested average. */ + + avg[r] = '\0'; + p = strchr (avg, ' '); + if (p) + p = strchr (p+1, ' '); + if (p) + p = strchr (p+1, ' '); + + if (p && ISDIGIT(p[1])) + { + unsigned int cnt = make_toui (p+1, NULL); + DB (DB_JOBS, ("Running: system = %u / make = %u (max requested = %f)\n", + cnt, job_slots_used, max_load_average)); + return (double)cnt > max_load_average; + } + + DB (DB_JOBS, ("Failed to parse " LOADAVG ": %s\n", avg)); + } + } + + /* If we got here, something went wrong. Give up on this method. */ + if (r < 0) + DB (DB_JOBS, ("Failed to read " LOADAVG ": %s\n", strerror (errno))); + + close (proc_fd); + proc_fd = -1; + } + /* Find the real system load average. */ - make_access (); + errno = 0; if (getloadavg (&load, 1) != 1) { static int lossage = -1; @@ -1678,7 +2141,6 @@ load_too_high (void) lossage = errno; load = 0; } - user_access (); /* If we're in a new second zero the counter and correct the backlog value. Only keep the backlog for one extra second; after that it's 0. */ @@ -1701,6 +2163,7 @@ load_too_high (void) guess, load, max_load_average)); return guess >= max_load_average; +#endif } /* Start jobs that are waiting for the load to be lower. */ @@ -1730,160 +2193,125 @@ start_waiting_jobs (void) return; } +#ifndef WINDOWS32 -bool -get_perm_prefix (const char *path, char out_perm[5], const char **out_path) +/* EMX: Start a child process. This function returns the new pid. */ +# if defined __EMX__ +pid_t +child_execute_job (struct childbase *child, int good_stdin, char **argv) { - int c, n; - for (n = 0;;) - switch ((c = *path++)) { - case 'r': - case 'w': - case 'c': - case 'x': - out_perm[n++] = c; - out_perm[n] = 0; - break; - case ':': - if (n) + pid_t pid; + int fdin = good_stdin ? FD_STDIN : get_bad_stdin (); + int fdout = FD_STDOUT; + int fderr = FD_STDERR; + int save_fdin = -1; + int save_fdout = -1; + int save_fderr = -1; + + /* Divert child output if we want to capture output. */ + if (child->output.syncout) + { + if (child->output.out >= 0) + fdout = child->output.out; + if (child->output.err >= 0) + fderr = child->output.err; + } + + /* For each FD which needs to be redirected first make a dup of the standard + FD to save and mark it close on exec so our child won't see it. Then + dup2() the standard FD to the redirect FD, and also mark the redirect FD + as close on exec. */ + if (fdin != FD_STDIN) + { + save_fdin = dup (FD_STDIN); + if (save_fdin < 0) + O (fatal, NILF, _("no more file handles: could not duplicate stdin")); + fd_noinherit (save_fdin); + + dup2 (fdin, FD_STDIN); + fd_noinherit (fdin); + } + + if (fdout != FD_STDOUT) + { + save_fdout = dup (FD_STDOUT); + if (save_fdout < 0) + O (fatal, NILF, + _("no more file handles: could not duplicate stdout")); + fd_noinherit (save_fdout); + + dup2 (fdout, FD_STDOUT); + fd_noinherit (fdout); + } + + if (fderr != FD_STDERR) + { + if (fderr != fdout) { - *out_path = path; - return true; + save_fderr = dup (FD_STDERR); + if (save_fderr < 0) + O (fatal, NILF, + _("no more file handles: could not duplicate stderr")); + fd_noinherit (save_fderr); } + + dup2 (fderr, FD_STDERR); + fd_noinherit (fderr); + } + + /* Run the command. */ + pid = exec_command (argv, child->environment); + + /* Restore stdout/stdin/stderr of the parent and close temporary FDs. */ + if (save_fdin >= 0) + { + if (dup2 (save_fdin, FD_STDIN) != FD_STDIN) + O (fatal, NILF, _("Could not restore stdin")); else - return false; - default: - return false; + close (save_fdin); } -} -/* Adds path to sandbox, returning true if found. */ -int -Unveil (const char *path, const char *perm) -{ - int e; - char *fp[2]; - char permprefix[5]; - - /* if path is like `rwcx:o/tmp` then `rwcx` will override perm */ - if (path && get_perm_prefix (path, permprefix, &path)) - perm = permprefix; - - fp[0] = 0; - fp[1] = 0; - if (path && path[0] == '~' && - (fp[1] = tilde_expand ((fp[0] = xstrdup (path))))) - path = fp[1]; - - DB (DB_JOBS, (_("Unveiling %s with permissions %s\n"), path, perm)); - - e = errno; - if (unveil (path, perm) != -1) + if (save_fdout >= 0) { - free(fp[0]); - free(fp[1]); - return 0; + if (dup2 (save_fdout, FD_STDOUT) != FD_STDOUT) + O (fatal, NILF, _("Could not restore stdout")); + else + close (save_fdout); } - /* path not found isn't really much of an error */ - if (errno == ENOENT) + if (save_fderr >= 0) { - free(fp[0]); - free(fp[1]); - errno = e; - return 0; + if (dup2 (save_fderr, FD_STDERR) != FD_STDERR) + O (fatal, NILF, _("Could not restore stderr")); + else + close (save_fderr); } - /* otherwise fail */ - OSS (error, NILF, "%s: unveil() failed %s", path, strerror (errno)); - free(fp[0]); - free(fp[1]); - return -1; + if (pid < 0) + OSS (error, NILF, "%s: %s", argv[0], strerror (errno)); + + return pid; } -int -unveil_variable (const struct variable *var) -{ - char *val, *tok, *state, *start; - if (!var) return 0; - start = val = xstrdup (variable_expand (var->value)); - while ((tok = strtok_r (start, " \t\r\n", &state))) - { - RETURN_ON_ERROR (Unveil (tok, "r")); - start = 0; - } - free(val); - return 0; - OnError: - return -1; -} - -static int -get_base_cpu_freq_mhz (void) -{ - return KCPUIDS(16H, EAX) & 0x7fff; -} - -int -set_limit (int r, long lo, long hi) -{ - struct rlimit old; - struct rlimit lim = {lo, hi}; - if (!setrlimit (r, &lim)) - return 0; - if (getrlimit (r, &old)) - return -1; - lim.rlim_cur = MIN (lim.rlim_cur, old.rlim_max); - lim.rlim_max = MIN (lim.rlim_max, old.rlim_max); - return setrlimit (r, &lim); -} - -static int -set_cpu_limit (int secs) -{ - int mhz, lim; - if (secs <= 0) return 0; - if (!(mhz = get_base_cpu_freq_mhz())) return eopnotsupp(); - lim = ceil(3100. / mhz * secs); - return set_limit (RLIMIT_CPU, lim, lim + 1); -} - -static struct sysinfo g_sysinfo; - -__attribute__((__constructor__)) static void -get_sysinfo (void) -{ - int e = errno; - sysinfo (&g_sysinfo); - errno = e; -} - -static bool internet; -static char *promises; +#elif !defined (_AMIGA) && !defined (__MSDOS__) && !defined (VMS) /* POSIX: Create a child process executing the command in ARGV. Returns the PID or -1. */ pid_t -child_execute_job (struct childbase *child, - int good_stdin, - char **argv, - bool is_build_rule) +child_execute_job (struct childbase *child, int good_stdin, char **argv) { const int fdin = good_stdin ? FD_STDIN : get_bad_stdin (); - struct dep *d; - bool strict; - bool sandboxed; - bool unsandboxed; - struct child *c; - unsigned long ipromises; - char pathbuf[PATH_MAX]; - char outpathbuf[PATH_MAX]; int fdout = FD_STDOUT; int fderr = FD_STDERR; - const char *s; - pid_t pid; - int e, r; + pid_t pid = -1; + int r; +#if defined(USE_POSIX_SPAWN) + char *cmd; + posix_spawnattr_t attr; + posix_spawn_file_actions_t fa; + short flags = 0; +#endif /* Divert child output if we want to capture it. */ if (child->output.syncout) @@ -1894,11 +2322,42 @@ child_execute_job (struct childbase *child, fderr = child->output.err; } - if (USE_POSIX_SPAWN) { - char *cmd; - posix_spawnattr_t attr; - posix_spawn_file_actions_t fa; - short flags = 0; +#if !defined(USE_POSIX_SPAWN) + + { + /* The child may clobber environ so remember ours and restore it. */ + char **parent_env = environ; + pid = vfork (); + if (pid != 0) + { + environ = parent_env; + return pid; + } + } + + /* We are the child. */ + unblock_all_sigs (); + +#ifdef SET_STACK_SIZE + /* Reset limits, if necessary. */ + if (stack_limit.rlim_cur) + setrlimit (RLIMIT_STACK, &stack_limit); +#endif + + /* For any redirected FD, dup2() it to the standard FD. + They are all marked close-on-exec already. */ + if (fdin >= 0 && fdin != FD_STDIN) + EINTRLOOP (r, dup2 (fdin, FD_STDIN)); + if (fdout != FD_STDOUT) + EINTRLOOP (r, dup2 (fdout, FD_STDOUT)); + if (fderr != FD_STDERR) + EINTRLOOP (r, dup2 (fderr, FD_STDERR)); + + /* Run the command. */ + exec_command (argv, child->environment); + _exit (127); + +#else /* USE_POSIX_SPAWN */ if ((r = posix_spawnattr_init (&attr)) != 0) goto done; @@ -1909,14 +2368,6 @@ child_execute_job (struct childbase *child, goto done; } - // [jart] use setrlimit on posix_spawn - // TODO(jart): support landlock make rlimit variables - if (stack_limit.rlim_cur && RLIMIT_STACK < RLIM_NLIMITS) - { - posix_spawnattr_setrlimit (&attr, RLIMIT_STACK, &stack_limit); - flags |= POSIX_SPAWN_SETRLIMIT; - } - /* Unblock all signals. */ #ifdef HAVE_POSIX_SPAWNATTR_SETSIGMASK { @@ -2034,515 +2485,223 @@ child_execute_job (struct childbase *child, if (r != 0) pid = -1; +#endif /* USE_POSIX_SPAWN */ + if (pid < 0) OSS (error, NILF, "%s: %s", argv[0], strerror (r)); return pid; - - } // USE_POSIX_SPAWN - - pid = fork(); - if (pid != 0) - return pid; - - /* We are the child. */ - unblock_all_sigs (); - - /* Reset limits, if necessary. */ - if (stack_limit.rlim_cur) - setrlimit (RLIMIT_STACK, &stack_limit); - - /* Tell build rules apart from $(shell foo). */ - if (is_build_rule) { - c = (struct child *)child; - } else { - c = 0; - } - - if (c) - { - strict = parse_bool (get_target_variable - (STRING_SIZE_TUPLE (".STRICT"), - c->file, "0")); - internet = !strict || - parse_bool (get_target_variable - (STRING_SIZE_TUPLE (".INTERNET"), - c->file, "0")); - unsandboxed = !strict || - parse_bool (get_target_variable - (STRING_SIZE_TUPLE (".UNSANDBOXED"), - c->file, "0")); - } - else - { - strict = false; - internet = true; - unsandboxed = true; - } - - sandboxed = !unsandboxed; - - if (sandboxed) - { - const char *ps; - ps = emptytonull (get_target_variable - (STRING_SIZE_TUPLE (".PLEDGE"), - c ? c->file : 0, 0)); - promises = ps ? xstrdup (ps) : 0; - if (ParsePromises (promises, &ipromises, 0)) - { - OSS (error, NILF, "%s: invalid .PLEDGE string: %s", - argv[0], strerror (errno)); - _Exit (127); - } - } - else - { - promises = NULL; - ipromises = 0; - } - - DB (DB_JOBS, - (_("Executing %s for %s%s%s%s\n"), - argv[0], c ? c->file->name : "$(shell)", - sandboxed ? " with sandboxing" : " without sandboxing", - strict ? " in .STRICT mode" : "", - internet ? " with internet access" : "")); - -#ifdef __x86_64__ - /* [jart] Set cpu seconds quota. */ - if (RLIMIT_CPU < RLIM_NLIMITS && - (s = get_target_variable (STRING_SIZE_TUPLE (".CPU"), - c ? c->file : 0, 0))) - { - int secs; - secs = atoi (s); - if (!set_cpu_limit (secs)) - DB (DB_JOBS, (_("Set cpu limit of %d seconds\n"), secs)); - else - DB (DB_JOBS, (_("Failed to set CPU limit: %s\n"), strerror (errno))); - } -#endif /* __x86_64__ */ - - /* [jart] Set virtual memory quota. */ - if (RLIMIT_AS < RLIM_NLIMITS && - (s = get_target_variable (STRING_SIZE_TUPLE (".MEMORY"), - c ? c->file : 0, 0))) - { - long bytes; - char buf[16]; - errno = 0; - if (!strchr (s, '%')) - bytes = sizetol (s, 1024); - else - bytes = strtod (s, 0) / 100. * g_sysinfo.totalram; - if (bytes > 0) - { - if (!set_limit (RLIMIT_AS, bytes, bytes)) - DB (DB_JOBS, (_("Set virtual memory limit of %sb\n"), - (sizefmt (buf, bytes, 1024), buf))); - else - DB (DB_JOBS, (_("Failed to set virtual memory: %s\n"), - strerror (errno))); - } - else if (errno) - { - OSS (error, NILF, "%s: .MEMORY invalid: %s", - argv[0], strerror (errno)); - _Exit (127); - } - } - - /* [jart] Set resident memory quota. */ - if (RLIMIT_RSS < RLIM_NLIMITS && - (s = get_target_variable (STRING_SIZE_TUPLE (".RSS"), - c ? c->file : 0, 0))) - { - long bytes; - char buf[16]; - errno = 0; - if (!strchr (s, '%')) - bytes = sizetol (s, 1024); - else - bytes = strtod (s, 0) / 100. * g_sysinfo.totalram; - if (bytes > 0) - { - if (!set_limit (RLIMIT_RSS, bytes, bytes)) - DB (DB_JOBS, (_("Set resident memory limit of %sb\n"), - (sizefmt (buf, bytes, 1024), buf))); - else - DB (DB_JOBS, (_("Failed to set resident memory: %s\n"), - strerror (errno))); - } - else if (errno) - { - OSS (error, NILF, "%s: .RSS invalid: %s", - argv[0], strerror (errno)); - _Exit (127); - } - } - - /* [jart] Set file size limit. */ - if (RLIMIT_FSIZE < RLIM_NLIMITS && - (s = get_target_variable (STRING_SIZE_TUPLE (".FSIZE"), - c ? c->file : 0, 0))) - { - long bytes; - char buf[16]; - errno = 0; - if ((bytes = sizetol (s, 1000)) > 0) - { - if (!set_limit (RLIMIT_FSIZE, bytes, bytes * 1.5)) - DB (DB_JOBS, (_("Set file size limit of %sb\n"), - (sizefmt (buf, bytes, 1000), buf))); - else - DB (DB_JOBS, (_("Failed to set file size limit: %s\n"), - strerror (errno))); - } - else if (errno) - { - OSS (error, NILF, "%s: .FSIZE invalid: %s", - argv[0], strerror (errno)); - _Exit (127); - } - } - - /* [jart] Set core dump limit. */ - if (RLIMIT_CORE < RLIM_NLIMITS && - (s = get_target_variable (STRING_SIZE_TUPLE (".MAXCORE"), - c ? c->file : 0, 0))) - { - long bytes; - char buf[16]; - errno = 0; - if ((bytes = sizetol (s, 1000)) > 0) - { - if (!set_limit (RLIMIT_CORE, bytes, bytes)) - DB (DB_JOBS, (_("Set core dump limit of %sb\n"), - (sizefmt (buf, bytes, 1000), buf))); - else - DB (DB_JOBS, (_("Failed to set core dump limit: %s\n"), - strerror (errno))); - } - else if (errno) - { - OSS (error, NILF, "%s: .MAXCORE invalid: %s", - argv[0], strerror (errno)); - _Exit (127); - } - } - - /* [jart] Set process limit. */ - if (RLIMIT_NPROC < RLIM_NLIMITS && - (s = get_target_variable (STRING_SIZE_TUPLE (".NPROC"), - c ? c->file : 0, 0))) - { - int procs; - if ((procs = atoi (s)) > 0) - { - if (!set_limit (RLIMIT_NPROC, - procs + g_sysinfo.procs, - procs + g_sysinfo.procs)) - DB (DB_JOBS, (_("Set process limit to %d + %d preexisting\n"), - procs, g_sysinfo.procs)); - else - DB (DB_JOBS, (_("Failed to set process limit: %s\n"), - strerror (errno))); - } - } - - /* [jart] Set file descriptor limit. */ - if (RLIMIT_NOFILE < RLIM_NLIMITS && - (s = get_target_variable (STRING_SIZE_TUPLE (".NOFILE"), - c ? c->file : 0, 0))) - { - int fds; - if ((fds = atoi (s)) > 0) - { - if (!set_limit (RLIMIT_NOFILE, fds, fds)) - DB (DB_JOBS, (_("Set file descriptor limit to %d\n"), fds)); - else - DB (DB_JOBS, (_("Failed to set process limit: %s\n"), - strerror (errno))); - } - } - - /* [jart] Resolve command into executable path. */ - if (!strict || !sandboxed) - { - if ((s = commandv (argv[0], pathbuf, sizeof (pathbuf)))) - argv[0] = (char *)s; - else - { - OSS (error, NILF, "%s: command not found on $PATH: %s", - argv[0], strerror (errno)); - _Exit (127); - } - } - - /* [jart] Sandbox build rule commands based on prerequisites. */ - if (c) - { - errno = 0; - if (sandboxed) - { - /* - * permit launching actually portable executables - * - * we assume launching make.com already did the expensive - * work of extracting the ape loader program, via /bin/sh - * and we won't need to do that again, since sys_execve() - * will pass ape binaries directly to the ape loader, but - * only if the ape loader exists on a well-known path. - */ - e = errno; - DB (DB_JOBS, (_("Unveiling %s with permissions %s\n"), - "/usr/bin/ape", "rx")); - if (unveil ("/usr/bin/ape", "rx") == -1) - { - char *s, *t; - errno = e; - if ((s = getenv ("TMPDIR"))) - { - t = xjoinpaths (s, ".ape"); - RETURN_ON_ERROR (Unveil (t, "rx")); - free (t); - } - if ((s = getenv ("HOME"))) - { - t = xjoinpaths (s, ".ape"); - RETURN_ON_ERROR (Unveil (t, "rx")); - free (t); - } - } - - /* Unveil executable. */ - RETURN_ON_ERROR (Unveil (argv[0], "rx")); - - /* Unveil temporary directory. */ - if (c->tmpdir) - RETURN_ON_ERROR (Unveil (c->tmpdir, "rwcx")); - - /* Unveil .PLEDGE = vminfo. */ - if (promises && (~ipromises & (1ul << PROMISE_VMINFO))) - { - RETURN_ON_ERROR (Unveil ("/proc/stat", "r")); - RETURN_ON_ERROR (Unveil ("/proc/meminfo", "r")); - RETURN_ON_ERROR (Unveil ("/proc/cpuinfo", "r")); - RETURN_ON_ERROR (Unveil ("/proc/diskstats", "r")); - RETURN_ON_ERROR (Unveil ("/proc/self/maps", "r")); - RETURN_ON_ERROR (Unveil ("/sys/devices/system/cpu", "r")); - } - - /* Unveil .PLEDGE = tty. */ - if (promises && (~ipromises & (1ul << PROMISE_TTY))) - { - RETURN_ON_ERROR (Unveil (ttyname(0), "rw")); - RETURN_ON_ERROR (Unveil ("/dev/tty", "rw")); - RETURN_ON_ERROR (Unveil ("/dev/console", "rw")); - RETURN_ON_ERROR (Unveil ("/etc/terminfo", "r")); - RETURN_ON_ERROR (Unveil ("/usr/lib/terminfo", "r")); - RETURN_ON_ERROR (Unveil ("/usr/share/terminfo", "r")); - } - - /* Unveil .PLEDGE = dns. */ - if (promises && (~ipromises & (1ul << PROMISE_DNS))) - { - RETURN_ON_ERROR (Unveil ("/etc/hosts", "r")); - RETURN_ON_ERROR (Unveil ("/etc/hostname", "r")); - RETURN_ON_ERROR (Unveil ("/etc/services", "r")); - RETURN_ON_ERROR (Unveil ("/etc/protocols", "r")); - RETURN_ON_ERROR (Unveil ("/etc/resolv.conf", "r")); - } - - /* Unveil .PLEDGE = inet. */ - if (promises && (~ipromises & (1ul << PROMISE_INET))) - RETURN_ON_ERROR (Unveil ("/etc/ssl/certs/ca-certificates.crt", "r")); - - /* Unveil .PLEDGE = rpath. */ - if (promises && (~ipromises & (1ul << PROMISE_RPATH))) - RETURN_ON_ERROR (Unveil ("/proc/filesystems", "r")); - - /* - * unveils target output file - * - * landlock operates per inode so it can't whitelist missing - * paths. so we create the output file manually, and prevent - * creation so that it can't be deleted by the command which - * must truncate when writing its output. - */ - if (!c->file->phony && - strlen(c->file->name) < PATH_MAX) - { - int fd, err; - if (c->file->last_mtime == NONEXISTENT_MTIME) - { - strcpy (outpathbuf, c->file->name); - err = errno; - if (makedirs (dirname (outpathbuf), 0777) == -1) - errno = err; - fd = open (c->file->name, O_RDWR | O_CREAT, 0777); - if (fd != -1) - close (fd); - else if (errno == EEXIST) - errno = err; - else - { - OSS (error, NILF, "%s: touch target failed %s", - c->file->name, strerror (errno)); - _Exit (127); - } - c->file->touched = get_file_timestamp (c->file); - } - DB (DB_JOBS, (_("Unveiling %s with permissions %s\n"), - c->file->name, "rwx")); - if (unveil (c->file->name, "rwx") && errno != ENOSYS) - { - OSS (error, NILF, "%s: unveil target failed %s", - c->file->name, strerror (errno)); - _Exit (127); - } - } - - /* - * unveil target prerequisites - * - * directories get special treatment: - * - * - libc/nt - * shall unveil everything beneath dir - * - * - libc/nt/ - * no sandboxing due to trailing slash - * intended to be timestamp check only - */ - for (d = c->file->deps; d; d = d->next) - { - size_t n; - n = strlen (d->file->name); - if (n && d->file->name[n - 1] == '/') - continue; - RETURN_ON_ERROR (Unveil (d->file->name, "rx")); - if (n > 4 && READ32LE(d->file->name + n - 4) == READ32LE(".com")) - { - char *s = xstrcat (d->file->name, ".dbg"); - RETURN_ON_ERROR (Unveil (s, "rx")); - free (s); - } - } - - /* unveil explicit .UNVEIL entries */ - RETURN_ON_ERROR - (unveil_variable - (lookup_variable - (STRING_SIZE_TUPLE (".UNVEIL")))); - RETURN_ON_ERROR - (unveil_variable - (lookup_variable_in_set - (STRING_SIZE_TUPLE (".UNVEIL"), - c->file->variables->set))); - if (c->file->pat_variables) - RETURN_ON_ERROR - (unveil_variable - (lookup_variable_in_set - (STRING_SIZE_TUPLE (".UNVEIL"), - c->file->pat_variables->set))); - - /* commit sandbox */ - RETURN_ON_ERROR (Unveil (0, 0)); - } - } - - /* For any redirected FD, dup2() it to the standard FD. - They are all marked close-on-exec already. */ - if (fdin >= 0 && fdin != FD_STDIN) - EINTRLOOP (r, dup2 (fdin, FD_STDIN)); - if (fdout != FD_STDOUT) - EINTRLOOP (r, dup2 (fdout, FD_STDOUT)); - if (fderr != FD_STDERR) - EINTRLOOP (r, dup2 (fderr, FD_STDERR)); - - /* Run the command. */ - exec_command (argv, child->environment); - - OnError: - _Exit (127); } - +#endif /* !AMIGA && !__MSDOS__ && !VMS */ +#endif /* !WINDOWS32 */ +#ifndef _AMIGA /* Replace the current process with one running the command in ARGV, with environment ENVP. This function does not return. */ -void + +pid_t exec_command (char **argv, char **envp) { - /* Be the user, permanently. */ - child_access (); +#ifdef VMS + /* to work around a problem with signals and execve: ignore them */ +#ifdef SIGCHLD + signal (SIGCHLD,SIG_IGN); +#endif + /* Run the program. */ + execve (argv[0], argv, envp); + OSS (error, NILF, "%s: %s", argv[0], strerror (errno)); + _exit (EXIT_FAILURE); +#else +#ifdef WINDOWS32 + HANDLE hPID; + HANDLE hWaitPID; + int exit_code = EXIT_FAILURE; - /* Restrict system calls. */ - if (promises) + /* make sure CreateProcess() has Path it needs */ + sync_Path_environment (); + + /* launch command */ + hPID = process_easy (argv, envp, -1, -1); + + /* make sure launch ok */ + if (hPID == INVALID_HANDLE_VALUE) { - __pledge_mode = PLEDGE_PENALTY_RETURN_EPERM; - DB (DB_JOBS, (_("Pledging %s\n"), promises)); - promises = xstrcat (promises, " prot_exec exec"); - if (pledge (promises, promises)) + int i; + fprintf (stderr, _("process_easy() failed to launch process (e=%ld)\n"), + process_last_err (hPID)); + for (i = 0; argv[i]; i++) + fprintf (stderr, "%s ", argv[i]); + fprintf (stderr, _("\nCounted %d args in failed launch\n"), i); + exit (EXIT_FAILURE); + } + + /* wait and reap last child */ + hWaitPID = process_wait_for_any (1, 0); + while (hWaitPID) + { + /* was an error found on this process? */ + int err = process_last_err (hWaitPID); + + /* get exit data */ + exit_code = process_exit_code (hWaitPID); + + if (err) + fprintf (stderr, "make (e=%d, rc=%d): %s\n", + err, exit_code, map_windows32_error_to_string (err)); + + /* cleanup process */ + process_cleanup (hWaitPID); + + /* expect to find only last pid, warn about other pids reaped */ + if (hWaitPID == hPID) + break; + else { - OSS (error, NILF, "pledge(%s) failed: %s", - promises, strerror (errno)); - _Exit (127); + char *pidstr = xstrdup (pid2str ((pid_t)hWaitPID)); + + fprintf (stderr, + _("make reaped child pid %s, still waiting for pid %s\n"), + pidstr, pid2str ((pid_t)hPID)); + free (pidstr); } } + /* Use the child's exit code as our exit code */ + exit (exit_code); + +#else /* !WINDOWS32 */ + + pid_t pid = -1; + +# ifdef __EMX__ /* Run the program. */ + pid = spawnvpe (P_NOWAIT, argv[0], argv, envp); + if (pid >= 0) + return pid; + + /* the file might have a strange shell extension */ + if (errno == ENOENT) + errno = ENOEXEC; + +# elif MK_OS_ZOS + /* In z/OS we can't set environ in ASCII mode. */ + environ = envp; + execvpe(argv[0], argv, envp); + +# else + + /* Run the program. Don't use execvpe() as we want the search for argv[0] + to use the new PATH, but execvpe() searches before resetting PATH. */ environ = envp; execvp (argv[0], argv); - if(errno == ENOENT) - OSS (error, NILF, "%s: command doesn't exist: %s", - argv[0], strerror (errno)); - else if(errno == ENOEXEC) - { - /* The file was not a program. Try it as a shell script. */ - const char *shell; - char **new_argv; - int argc; - int i=1; +# endif /* !__EMX__ */ - shell = getenv ("SHELL"); - if (shell == 0) - shell = default_shell; - - argc = 1; - while (argv[argc] != 0) - ++argc; - - new_argv = alloca ((1 + argc + 1) * sizeof (char *)); - new_argv[0] = (char *)shell; - - new_argv[i] = argv[0]; - while (argc > 0) + switch (errno) { - new_argv[i + argc] = argv[argc]; - --argc; + case ENOENT: + OSS (error, NILF, "%s: %s", argv[0], strerror (errno)); + break; + case ENOEXEC: + { + /* The file was not a program. Try it as a shell script. */ + const char *shell; + char **new_argv; + int argc; + int i=1; + +# ifdef __EMX__ + /* Do not use $SHELL from the environment */ + struct variable *p = lookup_variable ("SHELL", 5); + if (p) + shell = p->value; + else + shell = 0; +# else + shell = getenv ("SHELL"); +# endif + if (shell == 0) + shell = default_shell; + + argc = 1; + while (argv[argc] != 0) + ++argc; + +# ifdef __EMX__ + if (!unixy_shell) + ++argc; +# endif + + new_argv = alloca ((1 + argc + 1) * sizeof (char *)); + new_argv[0] = (char *)shell; + +# ifdef __EMX__ + if (!unixy_shell) + { + new_argv[1] = (char *)"/c"; + ++i; + --argc; + } +# endif + + new_argv[i] = argv[0]; + while (argc > 0) + { + new_argv[i + argc] = argv[argc]; + --argc; + } + +# ifdef __EMX__ + pid = spawnvpe (P_NOWAIT, shell, new_argv, envp); + if (pid >= 0) + break; +# elif MK_OS_ZOS + /* In z/OS we can't set environ in ASCII mode. */ + execvpe(shell, new_argv, envp); +# else + execvp (shell, new_argv); +# endif + OSS (error, NILF, "%s: %s", new_argv[0], strerror (errno)); + break; + } + +# ifdef __EMX__ + case EINVAL: + /* this nasty error was driving me nuts :-( */ + O (error, NILF, _("spawnvpe: environment space might be exhausted")); + /* FALLTHROUGH */ +# endif + + default: + OSS (error, NILF, "%s: %s", argv[0], strerror (errno)); + break; } - execvp (shell, new_argv); - OSS (error, NILF, "%s: execvp shell failed: %s", - new_argv[0], strerror (errno)); - } - - OSS (error, NILF, "%s: execv failed: %s", - argv[0], strerror (errno)); - - _Exit (127); + return pid; +#endif /* !WINDOWS32 */ +#endif /* !VMS */ +} +#else /* On Amiga */ +void +exec_command (char **argv) +{ + MyExecute (argv); } +void clean_tmp (void) +{ + DeleteFile (amiga_bname); +} + +#endif /* On Amiga */ +#ifndef VMS /* Figure out the argument list necessary to run LINE as a command. Try to avoid using a shell. This routine handles only ' quoting, and " quoting when no backslash, $ or ' characters are seen in the quotes. Starting quotes may be escaped with a backslash. If any of the characters in - sh_chars is seen, or any of the builtin commands listed in sh_cmds - is the first word of a line, the shell is used. + sh_chars is seen, or any of the builtin commands listed in sh_cmds is the + first word of a line, the shell is used. If RESTP is not NULL, *RESTP is set to point to the first newline in LINE. If *RESTP is NULL, newlines will be ignored. @@ -2550,16 +2709,128 @@ exec_command (char **argv, char **envp) SHELL is the shell to use, or nil to use the default shell. IFS is the value of $IFS, or nil (meaning the default). - FLAGS is the value of lines_flags for this command line. It is - used in the WINDOWS32 port to check whether + or $(MAKE) were found - in this command line, in which case the effect of just_print_flag - is overridden. */ + FLAGS is the value of lines_flags for this command line. It is used in the + WINDOWS32 port to check whether + or $(MAKE) were found in this command + line, in which case the effect of just_print_flag is overridden. + + The returned value is either NULL if the line was empty, or else a pointer + to an array of strings. The fist pointer points to the memory used by all + the strings, so to free you free the 0'th element then the returned pointer + (see the FREE_ARGV macro). */ static char ** construct_command_argv_internal (char *line, char **restp, const char *shell, const char *shellflags, const char *ifs, int flags, char **batch_filename UNUSED) { +#ifdef __MSDOS__ + /* MSDOS supports both the stock DOS shell and ports of Unixy shells. + We call 'system' for anything that requires ''slow'' processing, + because DOS shells are too dumb. When $SHELL points to a real + (unix-style) shell, 'system' just calls it to do everything. When + $SHELL points to a DOS shell, 'system' does most of the work + internally, calling the shell only for its internal commands. + However, it looks on the $PATH first, so you can e.g. have an + external command named 'mkdir'. + + Since we call 'system', certain characters and commands below are + actually not specific to COMMAND.COM, but to the DJGPP implementation + of 'system'. In particular: + + The shell wildcard characters are in DOS_CHARS because they will + not be expanded if we call the child via 'spawnXX'. + + The ';' is in DOS_CHARS, because our 'system' knows how to run + multiple commands on a single line. + + DOS_CHARS also include characters special to 4DOS/NDOS, so we + won't have to tell one from another and have one more set of + commands and special characters. */ + static const char *sh_chars_dos = "*?[];|<>%^&()"; + static const char *sh_cmds_dos[] = + { "break", "call", "cd", "chcp", "chdir", "cls", "copy", "ctty", "date", + "del", "dir", "echo", "erase", "exit", "for", "goto", "if", "md", + "mkdir", "path", "pause", "prompt", "rd", "rmdir", "rem", "ren", + "rename", "set", "shift", "time", "type", "ver", "verify", "vol", ":", + 0 }; + + static const char *sh_chars_sh = "#;\"*?[]&|<>(){}$`^"; + static const char *sh_cmds_sh[] = + { "cd", "echo", "eval", "exec", "exit", "login", "logout", "set", "umask", + "wait", "while", "for", "case", "if", ":", ".", "break", "continue", + "export", "read", "readonly", "shift", "times", "trap", "switch", + "unset", "ulimit", "command", 0 }; + + const char *sh_chars; + const char **sh_cmds; + +#elif defined (__EMX__) + static const char *sh_chars_dos = "*?[];|<>%^&()"; + static const char *sh_cmds_dos[] = + { "break", "call", "cd", "chcp", "chdir", "cls", "copy", "ctty", "date", + "del", "dir", "echo", "erase", "exit", "for", "goto", "if", "md", + "mkdir", "path", "pause", "prompt", "rd", "rmdir", "rem", "ren", + "rename", "set", "shift", "time", "type", "ver", "verify", "vol", ":", + 0 }; + + static const char *sh_chars_os2 = "*?[];|<>%^()\"'&"; + static const char *sh_cmds_os2[] = + { "call", "cd", "chcp", "chdir", "cls", "copy", "date", "del", "detach", + "dir", "echo", "endlocal", "erase", "exit", "for", "goto", "if", "keys", + "md", "mkdir", "move", "path", "pause", "prompt", "rd", "rem", "ren", + "rename", "rmdir", "set", "setlocal", "shift", "start", "time", "type", + "ver", "verify", "vol", ":", 0 }; + + static const char *sh_chars_sh = "#;\"*?[]&|<>(){}$`^~'"; + static const char *sh_cmds_sh[] = + { "echo", "cd", "eval", "exec", "exit", "login", "logout", "set", "umask", + "wait", "while", "for", "case", "if", ":", ".", "break", "continue", + "export", "read", "readonly", "shift", "times", "trap", "switch", + "unset", "command", 0 }; + + const char *sh_chars; + const char **sh_cmds; + +#elif defined (_AMIGA) + static const char *sh_chars = "#;\"|<>()?*$`"; + static const char *sh_cmds[] = + { "cd", "eval", "if", "delete", "echo", "copy", "rename", "set", "setenv", + "date", "makedir", "skip", "else", "endif", "path", "prompt", "unset", + "unsetenv", "version", "command", 0 }; + +#elif defined (WINDOWS32) + /* We used to have a double quote (") in sh_chars_dos[] below, but + that caused any command line with quoted file names be run + through a temporary batch file, which introduces command-line + limit of 4K characters imposed by cmd.exe. Since CreateProcess + can handle quoted file names just fine, removing the quote lifts + the limit from a very frequent use case, because using quoted + file names is commonplace on MS-Windows. */ + static const char *sh_chars_dos = "|&<>"; + static const char *sh_cmds_dos[] = + { "assoc", "break", "call", "cd", "chcp", "chdir", "cls", "color", "copy", + "ctty", "date", "del", "dir", "echo", "echo.", "endlocal", "erase", + "exit", "for", "ftype", "goto", "if", "if", "md", "mkdir", "move", + "path", "pause", "prompt", "rd", "rem", "ren", "rename", "rmdir", + "set", "setlocal", "shift", "time", "title", "type", "ver", "verify", + "vol", ":", 0 }; + + static const char *sh_chars_sh = "#;\"*?[]&|<>(){}$`^"; + static const char *sh_cmds_sh[] = + { "cd", "eval", "exec", "exit", "login", "logout", "set", "umask", "wait", + "while", "for", "case", "if", ":", ".", "break", "continue", "export", + "read", "readonly", "shift", "times", "trap", "switch", "test", "command", +#ifdef BATCH_MODE_ONLY_SHELL + "echo", +#endif + 0 }; + + const char *sh_chars; + const char **sh_cmds; +#elif defined(__riscos__) + static const char *sh_chars = ""; + static const char *sh_cmds[] = { 0 }; +#else /* must be UNIX-ish */ static const char *sh_chars = "#;\"*?[]&|<>(){}$`^~!"; static const char *sh_cmds[] = { ".", ":", "alias", "bg", "break", "case", "cd", "command", "continue", @@ -2567,6 +2838,15 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, "if", "jobs", "login", "logout", "read", "readonly", "return", "set", "shift", "test", "times", "trap", "type", "ulimit", "umask", "unalias", "unset", "wait", "while", 0 }; + +# ifdef HAVE_DOS_PATHS + /* This is required if the MSYS/Cygwin ports (which do not define + WINDOWS32) are compiled with HAVE_DOS_PATHS defined, which uses + sh_chars_sh directly (see below). The value must be identical + to that of sh_chars immediately above. */ + static const char *sh_chars_sh = "#;\"*?[]&|<>(){}$`^~!"; +# endif /* HAVE_DOS_PATHS */ +#endif size_t i; char *p; #ifndef NDEBUG @@ -2578,6 +2858,20 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, int instring, word_has_equals, seen_nonequals, last_argument_was_empty; char **new_argv = 0; char *argstr = 0; +#ifdef WINDOWS32 + int slow_flag = 0; + + if (!unixy_shell) + { + sh_cmds = sh_cmds_dos; + sh_chars = sh_chars_dos; + } + else + { + sh_cmds = sh_cmds_sh; + sh_chars = sh_chars_sh; + } +#endif /* WINDOWS32 */ if (restp != NULL) *restp = NULL; @@ -2589,30 +2883,71 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, return 0; if (shellflags == 0) - shellflags = posix_pedantic ? "-ec" : "-c"; + shellflags = posix_pedantic && NONE_SET (flags, COMMANDS_NOERROR) ? "-ec" : "-c"; /* See if it is safe to parse commands internally. */ if (shell == 0) shell = default_shell; - +#ifdef WINDOWS32 + else if (strcmp (shell, default_shell)) + { + char *s1 = _fullpath (NULL, shell, 0); + char *s2 = _fullpath (NULL, default_shell, 0); + + slow_flag = strcmp ((s1 ? s1 : ""), (s2 ? s2 : "")); + + free (s1); + free (s2); + } + if (slow_flag) + goto slow; +#else /* not WINDOWS32 */ +#if defined (__MSDOS__) || defined (__EMX__) + else if (strcasecmp (shell, default_shell)) + { + extern int _is_unixy_shell (const char *_path); + + DB (DB_BASIC, (_("$SHELL changed (was '%s', now '%s')\n"), + default_shell, shell)); + unixy_shell = _is_unixy_shell (shell); + /* we must allocate a copy of shell: construct_command_argv() will free + * shell after this function returns. */ + default_shell = xstrdup (shell); + } + if (unixy_shell) + { + sh_chars = sh_chars_sh; + sh_cmds = sh_cmds_sh; + } + else + { + sh_chars = sh_chars_dos; + sh_cmds = sh_cmds_dos; +# ifdef __EMX__ + if (_osmode == OS2_MODE) + { + sh_chars = sh_chars_os2; + sh_cmds = sh_cmds_os2; + } +# endif + } +#else /* !__MSDOS__ */ /* [jart] remove code that forces slow path if not using /bin/sh */ /* else if (strcmp (shell, default_shell)) */ /* goto slow; */ +#endif /* !__MSDOS__ && !__EMX__ */ +#endif /* not WINDOWS32 */ if (ifs) for (cap = ifs; *cap != '\0'; ++cap) - if (*cap != ' ' && *cap != '\t' && *cap != '\n') { - // kprintf("slow because whitespace\n"); + if (*cap != ' ' && *cap != '\t' && *cap != '\n') goto slow; - } if (shellflags) if (shellflags[0] != '-' || ((shellflags[1] != 'c' || shellflags[2] != '\0') - && (shellflags[1] != 'e' || shellflags[2] != 'c' || shellflags[3] != '\0'))) { - // kprintf("slow because shell flags\n"); + && (shellflags[1] != 'e' || shellflags[2] != 'c' || shellflags[3] != '\0'))) goto slow; - } i = strlen (line) + 1; @@ -2630,7 +2965,7 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, instring = word_has_equals = seen_nonequals = last_argument_was_empty = 0; for (p = line; *p != '\0'; ++p) { - // assert (ap <= end); + assert (ap <= end); if (instring) { @@ -2671,21 +3006,31 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, If we see any of those, punt. But on MSDOS, if we use COMMAND.COM, double and single quotes have the same effect. */ - else if (instring == '"' && strchr ("\\$`", *p) != 0 && unixy_shell) { - // kprintf("slow because backslash\n"); + else if (instring == '"' && strchr ("\\$`", *p) != 0 && unixy_shell) goto slow; - } else +#ifdef WINDOWS32 + /* Quoted wildcard characters must be passed quoted to the + command, so give up the fast route. */ + else if (instring == '"' && strchr ("*?", *p) != 0 && !unixy_shell) + goto slow; + else if (instring == '"' && strncmp (p, "\\\"", 2) == 0) + *ap++ = *++p; +#endif + else *ap++ = *p; } - else if (strchr (sh_chars, *p) != 0) { + else if (strchr (sh_chars, *p) != 0) /* Not inside a string, but it's a special char. */ - // kprintf("slow because %#c found in %#s\n", *p, line); goto slow; - } else if (one_shell && *p == '\n') { + else if (one_shell && *p == '\n') /* In .ONESHELL mode \n is a separator like ; or && */ - // kprintf("slow because oneshell thing\n"); goto slow; - } else +#ifdef __MSDOS__ + else if (*p == '.' && p[1] == '.' && p[2] == '.' && p[3] != '.') + /* '...' is a wildcard in DJGPP. */ + goto slow; +#endif + else /* Not a special char. */ switch (*p) { @@ -2694,10 +3039,8 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, first word with no equals sign in it. This is not the case with sh -k, but we never get here when using nonstandard shell flags. */ - if (! seen_nonequals && unixy_shell) { - // kprintf("slow because nonequals\n"); + if (! seen_nonequals && unixy_shell) goto slow; - } word_has_equals = 1; *ap++ = '='; break; @@ -2716,8 +3059,41 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, while (ISBLANK (p[1])) ++p; } +#ifdef WINDOWS32 + /* Backslash before whitespace is not special if our shell + is not Unixy. */ + else if (ISSPACE (p[1]) && !unixy_shell) + { + *ap++ = *p; + break; + } +#endif else if (p[1] != '\0') { +#ifdef HAVE_DOS_PATHS + /* Only remove backslashes before characters special to Unixy + shells. All other backslashes are copied verbatim, since + they are probably DOS-style directory separators. This + still leaves a small window for problems, but at least it + should work for the vast majority of naive users. */ + +#ifdef __MSDOS__ + /* A dot is only special as part of the "..." + wildcard. */ + if (strneq (p + 1, ".\\.\\.", 5)) + { + *ap++ = '.'; + *ap++ = '.'; + p += 4; + } + else +#endif + if (p[1] != '\\' && p[1] != '\'' && !ISSPACE (p[1]) + && strchr (sh_chars_sh, p[1]) == 0) + /* back up one notch, to copy the backslash */ + --p; +#endif /* HAVE_DOS_PATHS */ + /* Copy and skip the following char. */ *ap++ = *++p; } @@ -2751,12 +3127,10 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, /* Update SEEN_NONEQUALS, which tells us if every word heretofore has contained an '='. */ seen_nonequals |= ! word_has_equals; - if (word_has_equals && ! seen_nonequals) { + if (word_has_equals && ! seen_nonequals) /* An '=' in a word before the first word without one is magical. */ - // kprintf("slow because word equals\n"); goto slow; - } word_has_equals = 0; /* Prepare for the next word. */ /* If this argument is the command name, @@ -2767,10 +3141,14 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, int j; for (j = 0; sh_cmds[j] != 0; ++j) { - if (streq (sh_cmds[j], new_argv[0])) { - // kprintf("slow because builtin shell commands\n"); + if (streq (sh_cmds[j], new_argv[0])) goto slow; - } +#if defined(__EMX__) || defined(WINDOWS32) + /* Non-Unix shells are case insensitive. */ + if (!unixy_shell + && strcasecmp (sh_cmds[j], new_argv[0]) == 0) + goto slow; +#endif } } @@ -2786,11 +3164,9 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, } end_of_line: - if (instring) { + if (instring) /* Let the shell deal with an unterminated quote. */ - // kprintf("slow because unterminated quote\n"); goto slow; - } /* Terminate the last argument and the argument list. */ @@ -2803,10 +3179,8 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, { int j; for (j = 0; sh_cmds[j] != 0; ++j) - if (streq (sh_cmds[j], new_argv[0])) { - // kprintf("slow because sh_cmds\n"); + if (streq (sh_cmds[j], new_argv[0])) goto slow; - } } if (new_argv[0] == 0) @@ -2829,6 +3203,55 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, free (new_argv); } +#ifdef __MSDOS__ + execute_by_shell = 1; /* actually, call 'system' if shell isn't unixy */ +#endif + +#ifdef _AMIGA + { + char *ptr; + char *buffer; + char *dptr; + + buffer = xmalloc (strlen (line)+1); + + ptr = line; + for (dptr=buffer; *ptr; ) + { + if (*ptr == '\\' && ptr[1] == '\n') + ptr += 2; + else if (*ptr == '@') /* Kludge: multiline commands */ + { + ptr += 2; + *dptr++ = '\n'; + } + else + *dptr++ = *ptr++; + } + *dptr = 0; + + new_argv = xmalloc (2 * sizeof (char *)); + new_argv[0] = buffer; + new_argv[1] = 0; + } +#else /* Not Amiga */ +#ifdef WINDOWS32 + /* + * Not eating this whitespace caused things like + * + * sh -c "\n" + * + * which gave the shell fits. I think we have to eat + * whitespace here, but this code should be considered + * suspicious if things start failing.... + */ + + /* Make sure not to bother processing an empty line. */ + NEXT_TOKEN (line); + if (*line == '\0') + return 0; +#endif /* WINDOWS32 */ + { /* SHELL may be a multi-word command. Construct a command line "$(SHELL) $(.SHELLFLAGS) LINE", with all special chars in LINE escaped. @@ -2839,6 +3262,20 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, size_t shell_len = strlen (shell); size_t line_len = strlen (line); size_t sflags_len = shellflags ? strlen (shellflags) : 0; +#ifdef WINDOWS32 + char *command_ptr = NULL; /* used for batch_mode_shell mode */ +#endif + +# ifdef __EMX__ /* is this necessary? */ + if (!unixy_shell && shellflags) + { + size_t len = strlen (shellflags); + char *shflags = alloca (len + 1); + memcpy (shflags, shellflags, len + 1); + shflags[0] = '/'; /* "/c" */ + shellflags = shflags; + } +# endif /* In .ONESHELL mode we are allowed to throw the entire current recipe string at a single shell and trust that the user @@ -2856,7 +3293,16 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, /* Remove and ignore interior prefix chars [@+-] because they're meaningless given a single shell. */ - if (is_bourne_compatible_shell (shell)) +#if defined __MSDOS__ || defined (__EMX__) + if (unixy_shell) /* the test is complicated and we already did it */ +#else + if (is_bourne_compatible_shell (shell) +#ifdef WINDOWS32 + /* If we didn't find any sh.exe, don't behave is if we did! */ + && !no_default_sh_exe +#endif + ) +#endif { const char *f = line; char *t = line; @@ -2891,27 +3337,119 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, } *t = '\0'; } +#ifdef WINDOWS32 + else /* non-Posix shell (cmd.exe etc.) */ + { + const char *f = line; + char *t = line; + char *tstart = t; + int temp_fd; + FILE* batch = NULL; + int id = GetCurrentProcessId (); + PATH_VAR(fbuf); + + /* Generate a file name for the temporary batch file. */ + sprintf (fbuf, "make%d", id); + *batch_filename = create_batch_file (fbuf, 0, &temp_fd); + DB (DB_JOBS, (_("Creating temporary batch file %s\n"), + *batch_filename)); + + /* Create a FILE object for the batch file, and write to it the + commands to be executed. Put the batch file in TEXT mode. */ + _setmode (temp_fd, _O_TEXT); + batch = _fdopen (temp_fd, "wt"); + fputs ("@echo off\n", batch); + DB (DB_JOBS, (_("Batch file contents:\n\t@echo off\n"))); + + /* Copy the recipe, removing and ignoring interior prefix chars + [@+-]: they're meaningless in .ONESHELL mode. */ + while (*f != '\0') + { + /* This is the start of a new recipe line. Skip whitespace + and prefix characters but not newlines. */ + while (ISBLANK (*f) || *f == '-' || *f == '@' || *f == '+') + ++f; + + /* Copy until we get to the next logical recipe line. */ + while (*f != '\0') + { + /* Remove the escaped newlines in the command, and the + blanks that follow them. Windows shells cannot handle + escaped newlines. */ + if (*f == '\\' && f[1] == '\n') + { + f += 2; + while (ISBLANK (*f)) + ++f; + } + *(t++) = *(f++); + /* On an unescaped newline, we're done with this + line. */ + if (f[-1] == '\n') + break; + } + /* Write another line into the batch file. */ + if (t > tstart) + { + char c = *t; + *t = '\0'; + fputs (tstart, batch); + DB (DB_JOBS, ("\t%s", tstart)); + tstart = t; + *t = c; + } + } + DB (DB_JOBS, ("\n")); + fclose (batch); + + /* Create an argv list for the shell command line that + will run the batch file. */ + new_argv = xmalloc (2 * sizeof (char *)); + new_argv[0] = xstrdup (*batch_filename); + new_argv[1] = NULL; + return new_argv; + } +#endif /* WINDOWS32 */ /* Create an argv list for the shell command line. */ { - int n = 0; + int n = 1; + char *nextp; new_argv = xmalloc ((4 + sflags_len/2) * sizeof (char *)); - new_argv[n++] = xstrdup (shell); + + nextp = new_argv[0] = xmalloc (shell_len + sflags_len + line_len + 3); + nextp = mempcpy (nextp, shell, shell_len + 1); /* Chop up the shellflags (if any) and assign them. */ if (! shellflags) - new_argv[n++] = xstrdup (""); + { + new_argv[n++] = nextp; + *(nextp++) = '\0'; + } else { - const char *s = shellflags; - char *t; - size_t len; - while ((t = find_next_token (&s, &len)) != 0) - new_argv[n++] = xstrndup (t, len); + /* Parse shellflags using construct_command_argv_internal to + handle quotes. */ + char **argv; + char *f = alloca (sflags_len + 1); + memcpy (f, shellflags, sflags_len + 1); + argv = construct_command_argv_internal (f, 0, 0, 0, 0, flags, 0); + if (argv) + { + char **a; + for (a = argv; *a; ++a) + { + new_argv[n++] = nextp; + nextp = stpcpy (nextp, *a) + 1; + } + free (argv[0]); + free (argv); + } } /* Set the command to invoke. */ - new_argv[n++] = line; + new_argv[n++] = nextp; + memcpy(nextp, line, line_len + 1); new_argv[n++] = NULL; } return new_argv; @@ -2932,9 +3470,10 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, } *(ap++) = ' '; if (shellflags) - memcpy (ap, shellflags, sflags_len); - ap += sflags_len; - *(ap++) = ' '; + { + ap = mempcpy (ap, shellflags, sflags_len); + *(ap++) = ' '; + } #ifdef WINDOWS32 command_ptr = ap; #endif @@ -2975,6 +3514,14 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, || ISSPACE (*p) || strchr (sh_chars, *p) != 0)) *ap++ = '\\'; +#ifdef __MSDOS__ + else if (unixy_shell && strneq (p, "...", 3)) + { + /* The case of '...' wildcard again. */ + ap = stpcpy (ap, "\\.\\.\\"); + p += 2; + } +#endif *ap++ = *p; } if (ap == new_line + shell_len + sflags_len + 2) @@ -2987,9 +3534,9 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, #ifdef WINDOWS32 /* Some shells do not work well when invoked as 'sh -c xxx' to run a - command line (e.g. Cygnus GNUWIN32 sh.exe on WIN32 systems). In these + command line (e.g. Cygnus GNUWIN32 sh.exe on W32 systems). In these cases, run commands via a script file. */ - if (just_print_flag && !(flags & COMMANDS_RECURSE)) + if (just_print_flag && NONE_SET (flags, COMMANDS_RECURSE)) { /* Need to allocate new_argv, although it's unused, because start_job_command will want to free it and its 0'th element. */ @@ -3039,18 +3586,106 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, } else #endif /* WINDOWS32 */ + if (unixy_shell) new_argv = construct_command_argv_internal (new_line, 0, 0, 0, 0, flags, 0); + +#ifdef __EMX__ + else if (!unixy_shell) + { + /* new_line is local, must not be freed therefore + We use line here instead of new_line because we run the shell + manually. */ + char *q = new_line; + line_len = strlen (line); + p = new_line; + memcpy (new_line, line, line_len + 1); + /* Replace all backslash-newline combination and also following tabs. + Important: stop at the first '\n' because that's what the loop above + did. The next line starting at restp[0] will be executed during the + next call of this function. */ + while (*q != '\0' && *q != '\n') + { + if (q[0] == '\\' && q[1] == '\n') + q += 2; /* remove '\\' and '\n' */ + else + *p++ = *q++; + } + *p = '\0'; + +# ifndef NO_CMD_DEFAULT + if (strnicmp (new_line, "echo", 4) == 0 + && (new_line[4] == ' ' || new_line[4] == '\t')) + { + /* the builtin echo command: handle it separately */ + size_t echo_len = line_len - 5; + char *echo_line = new_line + 5; + + /* special case: echo 'x="y"' + cmd works this way: a string is printed as is, i.e., no quotes + are removed. But autoconf uses a command like echo 'x="y"' to + determine whether make works. autoconf expects the output x="y" + so we will do exactly that. + Note: if we do not allow cmd to be the default shell + we do not need this kind of voodoo */ + if (echo_line[0] == '\'' + && echo_line[echo_len - 1] == '\'' + && strncmp (echo_line + 1, "ac_maketemp=", + strlen ("ac_maketemp=")) == 0) + { + /* remove the enclosing quotes */ + memmove (echo_line, echo_line + 1, echo_len - 2); + echo_line[echo_len - 2] = '\0'; + } + } +# endif + + { + /* Let the shell decide what to do. Put the command line into the + 2nd command line argument and hope for the best ;-) */ + size_t sh_len = strlen (shell); + + /* exactly 3 arguments + NULL */ + new_argv = xmalloc (4 * sizeof (char *)); + /* Exactly strlen(shell) + strlen("/c") + strlen(line) + 3 times + the trailing '\0' */ + new_argv[0] = xmalloc (sh_len + line_len + 5); + memcpy (new_argv[0], shell, sh_len + 1); + new_argv[1] = new_argv[0] + sh_len + 1; + memcpy (new_argv[1], "/c", 3); + new_argv[2] = new_argv[1] + 3; + memcpy (new_argv[2], new_line, line_len + 1); + new_argv[3] = NULL; + } + } +#elif defined(__MSDOS__) + else + { + /* With MSDOS shells, we must construct the command line here + instead of recursively calling ourselves, because we + cannot backslash-escape the special characters (see above). */ + new_argv = xmalloc (sizeof (char *)); + line_len = strlen (new_line) - shell_len - sflags_len - 2; + new_argv[0] = xmalloc (line_len + 1); + strncpy (new_argv[0], + new_line + shell_len + sflags_len + 2, line_len); + new_argv[0][line_len] = '\0'; + } +#else else fatal (NILF, CSTRLEN (__FILE__) + INTSTR_LENGTH, _("%s (line %d) Bad shell context (!unixy && !batch_mode_shell)\n"), __FILE__, __LINE__); +#endif + free (new_line); } +#endif /* ! AMIGA */ return new_argv; } +#endif /* !VMS */ /* Figure out the argument list necessary to run LINE as a command. Try to avoid using a shell. This routine handles only ' quoting, and " quoting @@ -3073,6 +3708,7 @@ construct_command_argv (char *line, char **restp, struct file *file, char **argv; { + struct variable *var; /* Turn off --warn-undefined-variables while we expand SHELL and IFS. */ int save = warn_undefined_variables_flag; warn_undefined_variables_flag = 0; @@ -3089,7 +3725,59 @@ construct_command_argv (char *line, char **restp, struct file *file, strcpy (shell, p); } #endif - shellflags = allocated_variable_expand_for_file ("$(.SHELLFLAGS)", file); +#ifdef __EMX__ + { + static const char *unixroot = NULL; + static const char *last_shell = ""; + static int init = 0; + if (init == 0) + { + unixroot = getenv ("UNIXROOT"); + /* unixroot must be NULL or not empty */ + if (unixroot && unixroot[0] == '\0') unixroot = NULL; + init = 1; + } + + /* if we have an unixroot drive and if shell is not default_shell + (which means it's either cmd.exe or the test has already been + performed) and if shell is an absolute path without drive letter, + try whether it exists e.g.: if "/bin/sh" does not exist use + "$UNIXROOT/bin/sh" instead. */ + if (unixroot && shell && ISDIRSEP (shell[0]) && !streq (shell, last_shell)) + { + /* trying a new shell, check whether it exists */ + size_t size = strlen (shell); + char *buf = xmalloc (size + 7); + memcpy (buf, shell, size); + memcpy (buf + size, ".exe", 5); /* including the trailing '\0' */ + if (access (shell, F_OK) != 0 && access (buf, F_OK) != 0) + { + /* try the same for the unixroot drive */ + memmove (buf + 2, buf, size + 5); + buf[0] = unixroot[0]; + buf[1] = unixroot[1]; + if (access (buf, F_OK) == 0) + /* we have found a shell! */ + /* free(shell); */ + shell = buf; + else + free (buf); + } + else + free (buf); + } + } +#endif /* __EMX__ */ + + var = lookup_variable_for_file (STRING_SIZE_TUPLE (".SHELLFLAGS"), file); + if (!var) + shellflags = xstrdup (""); + else if (posix_pedantic && var->origin == o_default) + /* In POSIX mode we default to -ec, unless we're ignoring errors. */ + shellflags = xstrdup (ANY_SET (cmd_flags, COMMANDS_NOERROR) ? "-c" : "-ec"); + else + shellflags = allocated_variable_expand_for_file (var->value, file); + ifs = allocated_variable_expand_for_file ("$(IFS)", file); warn_undefined_variables_flag = save; @@ -3104,3 +3792,24 @@ construct_command_argv (char *line, char **restp, struct file *file, return argv; } + +#if !defined(HAVE_DUP2) && !defined(_AMIGA) +int +dup2 (int old, int new) +{ + int fd; + + (void) close (new); + EINTRLOOP (fd, dup (old)); + if (fd != new) + { + (void) close (fd); + errno = EMFILE; + return -1; + } + + return fd; +} +#endif /* !HAVE_DUP2 && !_AMIGA */ + +/* On VMS systems, include special VMS functions. */ diff --git a/third_party/make/job.h b/third_party/make/job.h index 41236962a..00fac9984 100644 --- a/third_party/make/job.h +++ b/third_party/make/job.h @@ -1,5 +1,5 @@ /* Definitions for managing subprocesses in GNU Make. -Copyright (C) 1992-2020 Free Software Foundation, Inc. +Copyright (C) 1992-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,16 +12,24 @@ 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 . */ +this program. If not, see . */ -#include "third_party/make/output.h" +#include "output.h" /* Structure describing a running or dead child process. */ +#ifdef VMS +#define VMSCHILD \ + char *comname; /* Temporary command file name */ \ + int efn; /* Completion event flag number */ \ + int cstatus; /* Completion status */ \ + int vms_launch_status; /* non-zero if lib$spawn, etc failed */ +#else #define VMSCHILD +#endif #define CHILDBASE \ - char *cmd_name; /* Alloced copy of command run. */ \ + char *cmd_name; /* Allocated copy of command run. */ \ char **environment; /* Environment for commands. */ \ VMSCHILD \ struct output output /* Output for this child. */ @@ -40,7 +48,6 @@ struct child struct file *file; /* File being remade. */ - char *tmpdir; /* Temporary directory */ char *sh_batch_file; /* Script file for shell commands */ char **command_lines; /* Array of variable-expanded cmd lines. */ char *command_ptr; /* Ptr into command_lines[command_line]. */ @@ -61,28 +68,25 @@ struct child extern struct child *children; /* A signal handler for SIGCHLD, if needed. */ -RETSIGTYPE child_handler (int sig); +void child_handler (int sig); int is_bourne_compatible_shell(const char *path); void new_job (struct file *file); void reap_children (int block, int err); void start_waiting_jobs (void); +void free_childbase (struct childbase* child); char **construct_command_argv (char *line, char **restp, struct file *file, int cmd_flags, char** batch_file); -pid_t child_execute_job (struct childbase *, int, char **, bool); +pid_t child_execute_job (struct childbase *child, int good_stdin, char **argv); #ifdef _AMIGA void exec_command (char **argv) NORETURN; -#elif defined(__EMX__) -int exec_command (char **argv, char **envp); #else -void exec_command (char **argv, char **envp) NORETURN; +pid_t exec_command (char **argv, char **envp); #endif void unblock_all_sigs (void); extern unsigned int job_slots_used; extern unsigned int jobserver_tokens; - -void delete_tmpdir (struct child *); diff --git a/third_party/make/load.c b/third_party/make/load.c index facf5bfa7..0f8d18604 100644 --- a/third_party/make/load.c +++ b/third_party/make/load.c @@ -1,5 +1,5 @@ /* Loading dynamic objects for GNU Make. -Copyright (C) 2012-2020 Free Software Foundation, Inc. +Copyright (C) 2012-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,22 +12,251 @@ 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 . */ +this program. If not, see . */ -#include "third_party/make/makeint.inc" +#include "makeint.h" + +#if MAKE_LOAD + +#include +#include +#include +#include +#include + +#define SYMBOL_EXTENSION "_gmk_setup" + +#include "debug.h" +#include "filedef.h" +#include "variable.h" + +/* Tru64 V4.0 does not have this flag */ +#ifndef RTLD_GLOBAL +# define RTLD_GLOBAL 0 +#endif + +struct load_list + { + struct load_list *next; + const char *name; + void *dlp; + }; + +static struct load_list *loaded_syms = NULL; + +static load_func_t +load_object (const floc *flocp, int noerror, const char *ldname, + const char *symname) +{ + static void *global_dl = NULL; + load_func_t symp; + + if (! global_dl) + { + global_dl = dlopen (NULL, RTLD_NOW|RTLD_GLOBAL); + if (! global_dl) + { + const char *err = dlerror (); + OS (fatal, flocp, _("Failed to open global symbol table: %s"), err); + } + } + + symp = (load_func_t) dlsym (global_dl, symname); + if (! symp) + { + struct load_list *new; + void *dlp = NULL; + + /* If the path has no "/", try the current directory first. */ + if (! strchr (ldname, '/') +#ifdef HAVE_DOS_PATHS + && ! strchr (ldname, '\\') +#endif + ) + dlp = dlopen (concat (2, "./", ldname), RTLD_LAZY|RTLD_GLOBAL); + + /* If we haven't opened it yet, try the default search path. */ + if (! dlp) + dlp = dlopen (ldname, RTLD_LAZY|RTLD_GLOBAL); + + /* Still no? Then fail. */ + if (! dlp) + { + const char *err = dlerror (); + if (noerror) + DB (DB_BASIC, ("%s\n", err)); + else + OS (error, flocp, "%s", err); + return NULL; + } + + DB (DB_VERBOSE, (_("Loaded shared object %s\n"), ldname)); + + /* Assert that the GPL license symbol is defined. */ + symp = (load_func_t) dlsym (dlp, "plugin_is_GPL_compatible"); + if (! symp) + OS (fatal, flocp, + _("Loaded object %s is not declared to be GPL compatible"), + ldname); + + symp = (load_func_t) dlsym (dlp, symname); + if (! symp) + { + const char *err = dlerror (); + OSSS (fatal, flocp, _("Failed to load symbol %s from %s: %s"), + symname, ldname, err); + } + + /* Add this symbol to a trivial lookup table. This is not efficient but + it's highly unlikely we'll be loading lots of objects, and we only + need it to look them up on unload, if we rebuild them. */ + new = xmalloc (sizeof (struct load_list)); + new->name = xstrdup (ldname); + new->dlp = dlp; + new->next = loaded_syms; + loaded_syms = new; + } + + return symp; +} int -load_file (const floc *flocp, const char **ldname UNUSED, int noerror) +load_file (const floc *flocp, struct file *file, int noerror) +{ + const char *ldname = file->name; + size_t nmlen = strlen (ldname); + char *new = alloca (nmlen + CSTRLEN (SYMBOL_EXTENSION) + 1); + char *symname = NULL; + const char *fp; + int r; + load_func_t symp; + + /* Break the input into an object file name and a symbol name. If no symbol + name was provided, compute one from the object file name. */ + fp = strchr (ldname, '('); + if (fp) + { + const char *ep; + + /* There's an open paren, so see if there's a close paren: if so use + that as the symbol name. We can't have whitespace: it would have + been chopped up before this function is called. */ + ep = strchr (fp+1, ')'); + if (ep && ep[1] == '\0') + { + size_t l = fp - ldname; + + ++fp; + if (fp == ep) + OS (fatal, flocp, _("Empty symbol name for load: %s"), ldname); + + /* Make a copy of the ldname part. */ + memcpy (new, ldname, l); + new[l] = '\0'; + ldname = new; + nmlen = l; + + /* Make a copy of the symbol name part. */ + symname = new + l + 1; + memcpy (symname, fp, ep - fp); + symname[ep - fp] = '\0'; + } + } + + /* Make sure this name is in the string cache. */ + ldname = file->name = strcache_add (ldname); + + /* If this object has been loaded, we're done: return -1 to ensure make does + not rebuild again. If a rebuild is allowed it was set up when this + object was initially loaded. */ + file = lookup_file (ldname); + if (file && file->loaded) + return -1; + + /* If we didn't find a symbol name yet, construct it from the ldname. */ + if (! symname) + { + char *p = new; + + fp = strrchr (ldname, '/'); +#ifdef HAVE_DOS_PATHS + if (fp) + { + const char *fp2 = strchr (fp, '\\'); + + if (fp2 > fp) + fp = fp2; + } + else + fp = strrchr (ldname, '\\'); + /* The (improbable) case of d:foo. */ + if (fp && *fp && fp[1] == ':') + fp++; +#endif + if (!fp) + fp = ldname; + else + ++fp; + while (isalnum ((unsigned char) *fp) || *fp == '_') + *(p++) = *(fp++); + strcpy (p, SYMBOL_EXTENSION); + symname = new; + } + + DB (DB_VERBOSE, (_("Loading symbol %s from %s\n"), symname, ldname)); + + /* Load it! */ + symp = load_object (flocp, noerror, ldname, symname); + if (! symp) + return 0; + + /* Invoke the symbol. */ + r = (*symp) (flocp); + + /* If the load didn't fail, add the file to the .LOADED variable. */ + if (r) + do_variable_definition(flocp, ".LOADED", ldname, o_file, f_append_value, 0); + + return r; +} + +int +unload_file (const char *name) +{ + int rc = 0; + struct load_list *d; + + for (d = loaded_syms; d != NULL; d = d->next) + if (streq (d->name, name) && d->dlp) + { + DB (DB_VERBOSE, (_("Unloading shared object %s\n"), name)); + rc = dlclose (d->dlp); + if (rc) + perror_with_name ("dlclose: ", d->name); + else + d->dlp = NULL; + break; + } + + return rc; +} + +#else + +int +load_file (const floc *flocp, struct file *file UNUSED, int noerror) { if (! noerror) O (fatal, flocp, - _("The 'load' operation is not supported on this platform.")); + _("The 'load' operation is not supported on this platform")); return 0; } -void +int unload_file (const char *name UNUSED) { - O (fatal, NILF, "INTERNAL: Cannot unload when load is not supported!"); + O (fatal, NILF, "INTERNAL: Cannot unload when load is not supported"); } + +#endif /* MAKE_LOAD */ diff --git a/third_party/make/loadapi.c b/third_party/make/loadapi.c index 0d03212f5..06277668e 100644 --- a/third_party/make/loadapi.c +++ b/third_party/make/loadapi.c @@ -1,5 +1,5 @@ /* API for GNU Make dynamic objects. -Copyright (C) 2013-2020 Free Software Foundation, Inc. +Copyright (C) 2013-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,13 +12,13 @@ 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 . */ +this program. If not, see . */ -#include "third_party/make/makeint.inc" +#include "makeint.h" -#include "third_party/make/filedef.h" -#include "third_party/make/variable.h" -#include "third_party/make/dep.h" +#include "filedef.h" +#include "variable.h" +#include "dep.h" /* Allocate a buffer in our context, so we can free it. */ char * diff --git a/third_party/make/main.c b/third_party/make/main.c index bbe688ec9..8a367f766 100644 --- a/third_party/make/main.c +++ b/third_party/make/main.c @@ -1,5 +1,5 @@ /* Argument parsing and main program of GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,82 +12,91 @@ 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 . */ +this program. If not, see . */ -#include "third_party/make/makeint.inc" -/**/ -#include "third_party/make/filedef.h" -#include "third_party/make/os.h" -/**/ -#include "third_party/make/dep.h" -#include "third_party/make/job.h" -#include "third_party/make/variable.h" -/**/ -#include "third_party/make/commands.h" -#include "third_party/make/debug.h" -#include "third_party/make/rule.h" -/**/ -#include "libc/calls/calls.h" -#include "libc/calls/struct/bpf.internal.h" -#include "libc/calls/struct/filter.internal.h" -#include "libc/calls/struct/seccomp.internal.h" -#include "libc/calls/syscall_support-sysv.internal.h" -#include "libc/dce.h" -#include "libc/limits.h" -#include "libc/macros.internal.h" +#include "makeint.h" +#include "config.h" +#include "os.h" +#include "filedef.h" +#include "dep.h" +#include "variable.h" +#include "job.h" +#include "commands.h" +#include "rule.h" +#include "debug.h" +#include "getopt.h" #include "libc/runtime/runtime.h" -#include "libc/runtime/stack.h" -#include "libc/sock/sock.h" -#include "libc/stdio/stdio.h" -#include "libc/sysv/consts/audit.h" -#include "libc/sysv/consts/pr.h" -#include "libc/sysv/consts/sig.h" -#include "third_party/make/getopt.h" +#include "shuffle.h" -STATIC_STACK_SIZE(0x00800000); // 8mb stack +#include +#ifdef HAVE_FCNTL_H +# include +#endif -#define HAVE_WAIT_NOHANG +#ifdef _AMIGA +int __stack = 20000; /* Make sure we have 20K of stack space */ +#endif +#ifdef VMS +int vms_use_mcr_command = 0; +int vms_always_use_cmd_file = 0; +int vms_gnv_shell = 0; +int vms_legacy_behavior = 0; +int vms_comma_separator = 0; +int vms_unix_simulation = 0; +int vms_report_unix_paths = 0; + +/* Evaluates if a VMS environment option is set, only look at first character */ +static int +get_vms_env_flag (const char *name, int default_value) +{ +char * value; +char x; + + value = getenv (name); + if (value == NULL) + return default_value; + + x = toupper (value[0]); + switch (x) + { + case '1': + case 'T': + case 'E': + return 1; + break; + case '0': + case 'F': + case 'D': + return 0; + } +} +#endif + +#if defined HAVE_WAITPID || defined HAVE_WAIT3 +# define HAVE_WAIT_NOHANG +#endif + +#ifndef HAVE_UNISTD_H +int chdir (); +#endif +#ifndef STDC_HEADERS +# ifndef sun /* Sun has an incorrect decl in a header. */ +void exit (int) NORETURN; +# endif +double atof (); +#endif static void clean_jobserver (int status); static void print_data_base (void); static void print_version (void); -static void decode_switches (int argc, const char **argv, int env); -static void decode_env_switches (const char *envar, size_t len); -static struct variable *define_makeflags (int all, int makefile); +static void decode_switches (int argc, const char **argv, + enum variable_origin origin); +static void decode_env_switches (const char *envar, size_t len, + enum variable_origin origin); static char *quote_for_env (char *out, const char *in); static void initialize_global_hash_tables (void); -/* The structure that describes an accepted command switch. */ - -struct command_switch - { - int c; /* The switch character. */ - - enum /* Type of the value. */ - { - flag, /* Turn int flag on. */ - flag_off, /* Turn int flag off. */ - string, /* One string per invocation. */ - strlist, /* One string per switch. */ - filename, /* A string containing a file name. */ - positive_int, /* A positive integer. */ - floating, /* A floating-point number (double). */ - ignore /* Ignored. */ - } type; - - void *value_ptr; /* Pointer to the value-holding variable. */ - - unsigned int env:1; /* Can come from MAKEFLAGS. */ - unsigned int toenv:1; /* Should be put in MAKEFLAGS. */ - unsigned int no_makefile:1; /* Don't propagate when remaking makefiles. */ - - const void *noarg_value; /* Pointer to value used if no arg given. */ - const void *default_value; /* Pointer to default value. */ - - const char *long_name; /* Long option name. */ - }; - /* True if C is a switch value that corresponds to a short option. */ #define short_option(c) ((c) <= CHAR_MAX) @@ -113,6 +122,7 @@ int verify_flag; static int silent_flag; static const int default_silent_flag = 0; +static enum variable_origin silent_origin = o_default; /* Nonzero means either -s was given, or .SILENT-with-no-deps was seen. */ @@ -167,19 +177,15 @@ int no_builtin_variables_flag = 0; int keep_going_flag; static const int default_keep_going_flag = 0; +static enum variable_origin keep_going_origin = o_default; /* Nonzero means check symlink mtimes. */ int check_symlink_flag = 0; -/* Nonzero means print directory before starting and when done (-w). */ - -int print_directory_flag = 0; - -/* Nonzero means ignore print_directory_flag and never print the directory. - This is necessary because print_directory_flag is set implicitly. */ - -int inhibit_print_directory_flag = 0; +static int print_directory_flag = -1; +static const int default_print_directory_flag = -1; +static enum variable_origin print_directory_origin = o_default; /* Nonzero means print version information. */ @@ -191,7 +197,9 @@ static struct stringlist *makefiles = 0; /* Size of the stack when we started. */ +#ifdef SET_STACK_SIZE struct rlimit stack_limit; +#endif /* Number of job slots for parallelism. */ @@ -210,12 +218,19 @@ static const int inf_jobs = 0; /* Authorization for the jobserver. */ -static char *jobserver_auth = NULL; +char *jobserver_auth = NULL; -/* Handle for the mutex used on Windows to synchronize output of our - children under -O. */ +/* Style for the jobserver. */ -char *sync_mutex = NULL; +static char *jobserver_style = NULL; + +/* Shuffle mode for goals and prerequisites. */ + +static char *shuffle_mode = NULL; + +/* Handle for the mutex to synchronize output of our children under -O. */ + +static char *sync_mutex = NULL; /* Maximum load average at which multiple jobs will be run. Negative values mean unlimited, while zero means limit to @@ -230,7 +245,7 @@ static struct stringlist *directories = 0; /* List of include directories given with -I switches. */ -static struct stringlist *include_directories = 0; +static struct stringlist *include_dirs = 0; /* List of files given with -o switches. */ @@ -270,6 +285,18 @@ struct variable shell_var; char cmd_prefix = '\t'; +/* Whether or not .NOTINTERMEDIATE with no prerequisites was given. */ +unsigned int no_intermediates; + +/* Count the number of commands we've invoked, that might change something in + the filesystem. Start with 1 so calloc'd memory never matches. */ + +unsigned long command_count = 1; + +/* Remember the location of the name of the batch file from stdin. */ + +static int stdin_offset = -1; + /* The usage output. We write it this way to make life easier for the translators, especially those trying to translate to right-to-left @@ -307,6 +334,8 @@ static const char *const usage[] = N_("\ -j [N], --jobs[=N] Allow N jobs at once; infinite jobs with no arg.\n"), N_("\ + --jobserver-style=STYLE Select the style of jobserver to use.\n"), + N_("\ -k, --keep-going Keep going when some targets can't be made.\n"), N_("\ -l [N], --load-average[=N], --max-load[=N]\n\ @@ -331,6 +360,9 @@ static const char *const usage[] = N_("\ -R, --no-builtin-variables Disable the built-in variable settings.\n"), N_("\ + --shuffle[={SEED|random|reverse|none}]\n\ + Perform shuffle of prerequisites and goals.\n"), + N_("\ -s, --silent, --quiet Don't echo recipes.\n"), N_("\ --no-silent Echo recipes (disable --silent mode).\n"), @@ -352,68 +384,111 @@ static const char *const usage[] = Consider FILE to be infinitely new.\n"), N_("\ --warn-undefined-variables Warn when an undefined variable is referenced.\n"), - N_("\ - --strace Log system calls.\n"), - N_("\ - --ftrace Log function calls.\n"), NULL }; +/* Nonzero if the "--trace" option was given. */ + +static int trace_flag = 0; + +/* The structure that describes an accepted command switch. */ + +struct command_switch + { + int c; /* The switch character. */ + + enum /* Type of the value. */ + { + flag, /* Turn int flag on. */ + flag_off, /* Turn int flag off. */ + string, /* One string per invocation. */ + strlist, /* One string per switch. */ + filename, /* A string containing a file name. */ + positive_int, /* A positive integer. */ + floating, /* A floating-point number (double). */ + ignore /* Ignored. */ + } type; + + void *value_ptr; /* Pointer to the value-holding variable. */ + + unsigned int env:1; /* Can come from MAKEFLAGS. */ + unsigned int toenv:1; /* Should be put in MAKEFLAGS. */ + unsigned int no_makefile:1; /* Don't propagate when remaking makefiles. */ + unsigned int specified:1; /* Set if the switch was specified somewhere. + Allows switches that are ON by default to + appear in MAKEFLAGS when set explicitly. */ + + const void *noarg_value; /* Pointer to value used if no arg given. */ + const void *default_value; /* Pointer to default value. */ + + const char *long_name; /* Long option name. */ + enum variable_origin *origin; /* Origin of the value. */ + }; + /* The table of command switches. Order matters here: this is the order MAKEFLAGS will be constructed. So be sure all simple flags (single char, no argument) come first. */ -static const struct command_switch switches[] = +#define TEMP_STDIN_OPT (CHAR_MAX+10) + +static struct command_switch switches[] = { - { 'b', ignore, 0, 0, 0, 0, 0, 0, 0 }, - { 'B', flag, &always_make_set, 1, 1, 0, 0, 0, "always-make" }, - { 'd', flag, &debug_flag, 1, 1, 0, 0, 0, 0 }, - { 'e', flag, &env_overrides, 1, 1, 0, 0, 0, "environment-overrides", }, - { 'E', strlist, &eval_strings, 1, 0, 0, 0, 0, "eval" }, - { 'h', flag, &print_usage_flag, 0, 0, 0, 0, 0, "help" }, - { 'i', flag, &ignore_errors_flag, 1, 1, 0, 0, 0, "ignore-errors" }, - { 'k', flag, &keep_going_flag, 1, 1, 0, 0, &default_keep_going_flag, - "keep-going" }, - { 'L', flag, &check_symlink_flag, 1, 1, 0, 0, 0, "check-symlink-times" }, - { 'm', ignore, 0, 0, 0, 0, 0, 0, 0 }, - { 'n', flag, &just_print_flag, 1, 1, 1, 0, 0, "just-print" }, - { 'p', flag, &print_data_base_flag, 1, 1, 0, 0, 0, "print-data-base" }, - { 'q', flag, &question_flag, 1, 1, 1, 0, 0, "question" }, - { 'r', flag, &no_builtin_rules_flag, 1, 1, 0, 0, 0, "no-builtin-rules" }, - { 'R', flag, &no_builtin_variables_flag, 1, 1, 0, 0, 0, - "no-builtin-variables" }, - { 's', flag, &silent_flag, 1, 1, 0, 0, &default_silent_flag, "silent" }, - { 'S', flag_off, &keep_going_flag, 1, 1, 0, 0, &default_keep_going_flag, - "no-keep-going" }, - { 't', flag, &touch_flag, 1, 1, 1, 0, 0, "touch" }, - { 'v', flag, &print_version_flag, 1, 1, 0, 0, 0, "version" }, - { 'w', flag, &print_directory_flag, 1, 1, 0, 0, 0, "print-directory" }, + { 'b', ignore, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 'B', flag, &always_make_set, 1, 1, 0, 0, 0, 0, "always-make", 0 }, + { 'd', flag, &debug_flag, 1, 1, 0, 0, 0, 0, 0, 0 }, + { 'e', flag, &env_overrides, 1, 1, 0, 0, 0, 0, "environment-overrides", 0 }, + { 'E', strlist, &eval_strings, 1, 0, 0, 0, 0, 0, "eval", 0 }, + { 'h', flag, &print_usage_flag, 0, 0, 0, 0, 0, 0, "help", 0 }, + { 'i', flag, &ignore_errors_flag, 1, 1, 0, 0, 0, 0, "ignore-errors", 0 }, + { 'k', flag, &keep_going_flag, 1, 1, 0, 0, 0, &default_keep_going_flag, + "keep-going", &keep_going_origin }, + { 'L', flag, &check_symlink_flag, 1, 1, 0, 0, 0, 0, "check-symlink-times", 0 }, + { 'm', ignore, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 'n', flag, &just_print_flag, 1, 1, 1, 0, 0, 0, "just-print", 0 }, + { 'p', flag, &print_data_base_flag, 1, 1, 0, 0, 0, 0, "print-data-base", 0 }, + { 'q', flag, &question_flag, 1, 1, 1, 0, 0, 0, "question", 0 }, + { 'r', flag, &no_builtin_rules_flag, 1, 1, 0, 0, 0, 0, "no-builtin-rules", 0 }, + { 'R', flag, &no_builtin_variables_flag, 1, 1, 0, 0, 0, 0, + "no-builtin-variables", 0 }, + { 's', flag, &silent_flag, 1, 1, 0, 0, 0, &default_silent_flag, "silent", + &silent_origin }, + { 'S', flag_off, &keep_going_flag, 1, 1, 0, 0, 0, &default_keep_going_flag, + "no-keep-going", &keep_going_origin }, + { 't', flag, &touch_flag, 1, 1, 1, 0, 0, 0, "touch", 0 }, + { 'v', flag, &print_version_flag, 1, 0, 0, 0, 0, 0, "version", 0 }, + { 'w', flag, &print_directory_flag, 1, 1, 0, 0, 0, + &default_print_directory_flag, "print-directory", &print_directory_origin }, /* These options take arguments. */ - { 'C', filename, &directories, 0, 0, 0, 0, 0, "directory" }, - { 'f', filename, &makefiles, 0, 0, 0, 0, 0, "file" }, - { 'I', filename, &include_directories, 1, 1, 0, 0, 0, - "include-dir" }, - { 'j', positive_int, &arg_job_slots, 1, 1, 0, &inf_jobs, &default_job_slots, - "jobs" }, - { 'l', floating, &max_load_average, 1, 1, 0, &default_load_average, - &default_load_average, "load-average" }, - { 'o', filename, &old_files, 0, 0, 0, 0, 0, "old-file" }, - { 'O', string, &output_sync_option, 1, 1, 0, "target", 0, "output-sync" }, - { 'W', filename, &new_files, 0, 0, 0, 0, 0, "what-if" }, + { 'C', filename, &directories, 0, 0, 0, 0, 0, 0, "directory", 0 }, + { 'f', filename, &makefiles, 0, 0, 0, 0, 0, 0, "file", 0 }, + { 'I', filename, &include_dirs, 1, 1, 0, 0, 0, 0, + "include-dir", 0 }, + { 'j', positive_int, &arg_job_slots, 1, 1, 0, 0, &inf_jobs, &default_job_slots, + "jobs", 0 }, + { 'l', floating, &max_load_average, 1, 1, 0, 0, &default_load_average, + &default_load_average, "load-average", 0 }, + { 'o', filename, &old_files, 0, 0, 0, 0, 0, 0, "old-file", 0 }, + { 'O', string, &output_sync_option, 1, 1, 0, 0, "target", 0, "output-sync", 0 }, + { 'W', filename, &new_files, 0, 0, 0, 0, 0, 0, "what-if", 0 }, /* These are long-style options. */ - { CHAR_MAX+1, strlist, &db_flags, 1, 1, 0, "basic", 0, "debug" }, - { CHAR_MAX+2, string, &jobserver_auth, 1, 1, 0, 0, 0, "jobserver-auth" }, - { CHAR_MAX+3, flag, &trace_flag, 1, 1, 0, 0, 0, "trace" }, - { CHAR_MAX+4, flag, &inhibit_print_directory_flag, 1, 1, 0, 0, 0, - "no-print-directory" }, - { CHAR_MAX+5, flag, &warn_undefined_variables_flag, 1, 1, 0, 0, 0, - "warn-undefined-variables" }, - { CHAR_MAX+7, string, &sync_mutex, 1, 1, 0, 0, 0, "sync-mutex" }, - { CHAR_MAX+8, flag_off, &silent_flag, 1, 1, 0, 0, &default_silent_flag, "no-silent" }, - { CHAR_MAX+9, string, &jobserver_auth, 1, 0, 0, 0, 0, "jobserver-fds" }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0 } + { CHAR_MAX+1, strlist, &db_flags, 1, 1, 0, 0, "basic", 0, "debug", 0 }, + { CHAR_MAX+2, string, &jobserver_auth, 1, 1, 0, 0, 0, 0, JOBSERVER_AUTH_OPT, 0 }, + { CHAR_MAX+3, flag, &trace_flag, 1, 1, 0, 0, 0, 0, "trace", 0 }, + { CHAR_MAX+4, flag_off, &print_directory_flag, 1, 1, 0, 0, 0, + &default_print_directory_flag, "no-print-directory", &print_directory_origin }, + { CHAR_MAX+5, flag, &warn_undefined_variables_flag, 1, 1, 0, 0, 0, 0, + "warn-undefined-variables", 0 }, + { CHAR_MAX+7, string, &sync_mutex, 1, 1, 0, 0, 0, 0, "sync-mutex", 0 }, + { CHAR_MAX+8, flag_off, &silent_flag, 1, 1, 0, 0, 0, &default_silent_flag, + "no-silent", &silent_origin }, + { CHAR_MAX+9, string, &jobserver_auth, 1, 0, 0, 0, 0, 0, "jobserver-fds", 0 }, + /* There is special-case handling for this in decode_switches() as well. */ + { TEMP_STDIN_OPT, filename, &makefiles, 0, 0, 0, 0, 0, 0, "temp-stdin", 0 }, + { CHAR_MAX+11, string, &shuffle_mode, 1, 1, 0, 0, "random", 0, "shuffle", 0 }, + { CHAR_MAX+12, string, &jobserver_style, 1, 0, 0, 0, 0, 0, "jobserver-style", 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; /* Secondary long names for options. */ @@ -497,10 +572,6 @@ int one_shell; int output_sync = OUTPUT_SYNC_NONE; -/* Nonzero if the "--trace" option was given. */ - -int trace_flag = 0; - /* Nonzero if we have seen the '.NOTPARALLEL' target. This turns off parallel builds for this invocation of make. */ @@ -513,6 +584,9 @@ int not_parallel; int clock_skew_detected; /* Map of possible stop characters for searching strings. */ +#ifndef UCHAR_MAX +# define UCHAR_MAX 255 +#endif unsigned short stopchar_map[UCHAR_MAX + 1] = {0}; /* If output-sync is enabled we'll collect all the output generated due to @@ -523,9 +597,17 @@ struct output make_sync; /* Mask of signals that are being caught with fatal_error_signal. */ +#if defined(POSIX) sigset_t fatal_signal_set; +#elif defined(HAVE_SIGSETMASK) +int fatal_signal_mask; +#endif -typedef RETSIGTYPE (*bsd_signal_ret_t) (int); +#if !HAVE_DECL_BSD_SIGNAL && !defined bsd_signal +# if !defined HAVE_SIGACTION +# define bsd_signal signal +# else +typedef void (*bsd_signal_ret_t) (int); static bsd_signal_ret_t bsd_signal (int sig, bsd_signal_ret_t func) @@ -539,6 +621,8 @@ bsd_signal (int sig, bsd_signal_ret_t func) return SIG_ERR; return oact.sa_handler; } +# endif +#endif static void initialize_global_hash_tables (void) @@ -579,7 +663,11 @@ initialize_stopchar_map (void) stopchar_map[(int)'\t'] = MAP_BLANK; stopchar_map[(int)'/'] = MAP_DIRSEP; -#if defined(HAVE_DOS_PATHS) +#if defined(VMS) + stopchar_map[(int)':'] |= MAP_DIRSEP; + stopchar_map[(int)']'] |= MAP_DIRSEP; + stopchar_map[(int)'>'] |= MAP_DIRSEP; +#elif defined(HAVE_DOS_PATHS) stopchar_map[(int)'\\'] |= MAP_DIRSEP; #endif @@ -593,6 +681,52 @@ initialize_stopchar_map (void) } } +/* This code is stolen from gnulib. + If/when we abandon the requirement to work with K&R compilers, we can + remove this (and perhaps other parts of GNU Make!) and migrate to using + gnulib directly. + + This is called only through atexit(), which means die() has already been + invoked. So, call exit() here directly. Apparently that works...? +*/ + +/* Close standard output, exiting with status 'exit_failure' on failure. + If a program writes *anything* to stdout, that program should close + stdout and make sure that it succeeds before exiting. Otherwise, + suppose that you go to the extreme of checking the return status + of every function that does an explicit write to stdout. The last + printf can succeed in writing to the internal stream buffer, and yet + the fclose(stdout) could still fail (due e.g., to a disk full error) + when it tries to write out that buffered data. Thus, you would be + left with an incomplete output file and the offending program would + exit successfully. Even calling fflush is not always sufficient, + since some file systems (NFS and CODA) buffer written/flushed data + until an actual close call. + + Besides, it's wasteful to check the return value from every call + that writes to stdout -- just let the internal stream state record + the failure. That's what the ferror test is checking below. + + It's important to detect such failures and exit nonzero because many + tools (most notably 'make' and other build-management systems) depend + on being able to detect failure in other tools via their exit status. */ + +static void +close_stdout (void) +{ + int prev_fail = ferror (stdout); + int fclose_fail = fclose (stdout); + + if (prev_fail || fclose_fail) + { + if (fclose_fail) + perror_with_name (_("write error: stdout"), ""); + else + O (error, NILF, _("write error: stdout")); + exit (MAKE_TROUBLE); + } +} + static const char * expand_command_line_file (const char *name) { @@ -635,11 +769,13 @@ expand_command_line_file (const char *name) /* Toggle -d on receipt of SIGUSR1. */ -static RETSIGTYPE +#ifdef SIGUSR1 +static void debug_signal_handler (int sig UNUSED) { db_level = db_level ? DB_NONE : DB_BASIC; } +#endif static void decode_debug_flags (void) @@ -649,6 +785,9 @@ decode_debug_flags (void) if (debug_flag) db_level = DB_ALL; + if (trace_flag) + db_level |= DB_PRINT | DB_WHY; + if (db_flags) for (pp=db_flags->list; *pp; ++pp) { @@ -676,9 +815,15 @@ decode_debug_flags (void) case 'n': db_level = 0; break; + case 'p': + db_level |= DB_PRINT; + break; case 'v': db_level |= DB_BASIC | DB_VERBOSE; break; + case 'w': + db_level |= DB_WHY; + break; default: OS (fatal, NILF, _("unknown debug level specification '%s'"), p); @@ -725,32 +870,43 @@ decode_output_sync_flags (void) } if (sync_mutex) - RECORD_SYNC_MUTEX (sync_mutex); + osync_parse_mutex (sync_mutex); #endif } -#ifdef WINDOWS32 +/* Print a nice usage method and exit. */ -#ifndef NO_OUTPUT_SYNC - -/* This is called from start_job_command when it detects that - output_sync option is in effect. The handle to the synchronization - mutex is passed, as a string, to sub-makes via the --sync-mutex - command-line argument. */ -void -prepare_mutex_handle_string (sync_handle_t handle) +static void NORETURN +print_usage (int bad) { - if (!sync_mutex) + const char *const *cpp; + FILE *usageto; + + if (print_version_flag) { - /* Prepare the mutex handle string for our children. */ - /* 2 hex digits per byte + 2 characters for "0x" + null. */ - sync_mutex = xmalloc ((2 * sizeof (sync_handle_t)) + 2 + 1); - sprintf (sync_mutex, "0x%Ix", handle); - define_makeflags (1, 0); + print_version (); + fputs ("\n", stdout); } + + usageto = bad ? stderr : stdout; + + fprintf (usageto, _("Usage: %s [options] [target] ...\n"), program); + + for (cpp = usage; *cpp; ++cpp) + fputs (_(*cpp), usageto); + + if (!remote_description || *remote_description == '\0') + fprintf (usageto, _("\nThis program built for %s\n"), make_host); + else + fprintf (usageto, _("\nThis program built for %s (%s)\n"), + make_host, remote_description); + + fprintf (usageto, _("Report bugs to \n")); + + die (bad ? MAKE_FAILURE : MAKE_SUCCESS); } -#endif /* NO_OUTPUT_SYNC */ +#ifdef WINDOWS32 /* * HANDLE runtime exceptions by avoiding a requestor on the GUI. Capture @@ -797,7 +953,7 @@ handle_runtime_exceptions (struct _EXCEPTION_POINTERS *exinfo) /* turn this on if we want to put stuff in the event log too */ #ifdef USE_EVENT_LOG - hEventSource = RegisterEventSource (NULL, u"GNU Make"); + hEventSource = RegisterEventSource (NULL, "GNU Make"); lpszStrings[0] = errmsg; if (hEventSource != NULL) @@ -828,7 +984,7 @@ handle_runtime_exceptions (struct _EXCEPTION_POINTERS *exinfo) } /* - * On WIN32 systems we don't have the luxury of a /bin directory that + * On W32 systems we don't have the luxury of a /bin directory that * is mapped globally to every drive mounted to the system. Since make could * be invoked from any drive, and we don't want to propagate /bin/sh * to every single drive. Allow ourselves a chance to search for @@ -842,7 +998,6 @@ find_and_set_default_shell (const char *token) char *atoken = 0; const char *search_token; const char *tokend; - PATH_VAR(sh_path); extern const char *default_shell; if (!token) @@ -856,18 +1011,15 @@ find_and_set_default_shell (const char *token) "cmd.exe" case-insensitive. */ tokend = search_token + strlen (search_token) - 3; if (((tokend == search_token - || (tokend > search_token - && (tokend[-1] == '/' || tokend[-1] == '\\'))) + || (tokend > search_token && ISDIRSEP (tokend[-1]))) && !strcasecmp (tokend, "cmd")) || ((tokend - 4 == search_token - || (tokend - 4 > search_token - && (tokend[-5] == '/' || tokend[-5] == '\\'))) + || (tokend - 4 > search_token && ISDIRSEP (tokend[-5]))) && !strcasecmp (tokend - 4, "cmd.exe"))) { batch_mode_shell = 1; unixy_shell = 0; - sprintf (sh_path, "%s", search_token); - default_shell = xstrdup (w32ify (sh_path, 0)); + default_shell = xstrdup (w32ify (search_token, 0)); DB (DB_VERBOSE, (_("find_and_set_shell() setting default_shell = %s\n"), default_shell)); sh_found = 1; @@ -881,8 +1033,7 @@ find_and_set_default_shell (const char *token) else if (_access (search_token, 0) == 0) { /* search token path was found */ - sprintf (sh_path, "%s", search_token); - default_shell = xstrdup (w32ify (sh_path, 0)); + default_shell = xstrdup (w32ify (search_token, 0)); DB (DB_VERBOSE, (_("find_and_set_shell() setting default_shell = %s\n"), default_shell)); sh_found = 1; @@ -902,9 +1053,11 @@ find_and_set_default_shell (const char *token) while (ep && *ep) { + PATH_VAR (sh_path); + *ep = '\0'; - sprintf (sh_path, "%s/%s", p, search_token); + snprintf (sh_path, GET_PATH_MAX, "%s/%s", p, search_token); if (_access (sh_path, 0) == 0) { default_shell = xstrdup (w32ify (sh_path, 0)); @@ -926,7 +1079,8 @@ find_and_set_default_shell (const char *token) /* be sure to check last element of Path */ if (p && *p) { - sprintf (sh_path, "%s/%s", p, search_token); + PATH_VAR (sh_path); + snprintf (sh_path, GET_PATH_MAX, "%s/%s", p, search_token); if (_access (sh_path, 0) == 0) { default_shell = xstrdup (w32ify (sh_path, 0)); @@ -959,6 +1113,15 @@ find_and_set_default_shell (const char *token) } #endif /* WINDOWS32 */ +#ifdef __MSDOS__ +static void +msdos_return_to_initial_directory (void) +{ + if (directory_before_chdir) + chdir (directory_before_chdir); +} +#endif /* __MSDOS__ */ + static void reset_jobserver (void) { @@ -967,30 +1130,69 @@ reset_jobserver (void) jobserver_auth = NULL; } +void +temp_stdin_unlink () +{ + /* This function is called from a signal handler. Keep async-signal-safe. + If there is a temp file from reading from stdin, get rid of it. */ + if (stdin_offset >= 0) + { + const char *nm = makefiles->list[stdin_offset]; + int r = 0; + + stdin_offset = -1; + EINTRLOOP(r, unlink (nm)); + if (r < 0 && errno != ENOENT && !handling_fatal_signal) + perror_with_name (_("unlink (temporary file): "), nm); + } +} + +#ifdef MK_OS_ZOS +extern char **environ; +#endif + +#if defined(_AMIGA) || defined(MK_OS_ZOS) +int +main (int argc, char **argv) +#else int main (int argc, char **argv, char **envp) +#endif { - // ShowCrashReports(); + ShowCrashReports (); - static char *stdin_nm = 0; int makefile_status = MAKE_SUCCESS; struct goaldep *read_files; PATH_VAR (current_directory); unsigned int restarts = 0; unsigned int syncing = 0; - int argv_slots; + int argv_slots; /* The jobslot info we got from our parent process. */ +#ifdef WINDOWS32 + const char *unix_path = NULL; + const char *windows32_path = NULL; - // [jart] workaround to prevent make -j fork bomb - default_load_average = __get_cpu_count() * 1.5; - max_load_average = default_load_average; + SetUnhandledExceptionFilter (handle_runtime_exceptions); + + /* start off assuming we have no shell */ + unixy_shell = 0; + no_default_sh_exe = 1; +#endif + + initialize_variable_output (); /* Useful for attaching debuggers, etc. */ SPIN ("main-entry"); +#ifdef HAVE_ATEXIT + if (ANY_SET (check_io_state (), IO_STDOUT_OK)) + atexit (close_stdout); +#endif + output_init (&make_sync); initialize_stopchar_map(); +#ifdef SET_STACK_SIZE /* Get rid of any avoidable limit on stack size. */ { struct rlimit rlim; @@ -1006,6 +1208,7 @@ main (int argc, char **argv, char **envp) else stack_limit.rlim_cur = 0; } +#endif /* Needed for OS/2 */ initialize_main (&argc, &argv); @@ -1015,29 +1218,71 @@ main (int argc, char **argv, char **envp) verify_flag = 1; #endif +#if defined (__MSDOS__) && !defined (_POSIX_SOURCE) + /* Request the most powerful version of 'system', to + make up for the dumb default shell. */ + __system_flags = (__system_redirect + | __system_use_shell + | __system_allow_multiple_cmds + | __system_allow_long_cmds + | __system_handle_null_commands + | __system_emulate_chdir); + +#endif + /* Set up gettext/internationalization support. */ setlocale (LC_ALL, ""); /* The cast to void shuts up compiler warnings on systems that disable NLS. */ - (void)bindtextdomain (PACKAGE, LOCALEDIR); + (void)bindtextdomain (PACKAGE, "/usr/share/locale"); (void)textdomain (PACKAGE); +#ifdef POSIX sigemptyset (&fatal_signal_set); - #define ADD_SIG(sig) sigaddset (&fatal_signal_set, sig) +#else +#ifdef HAVE_SIGSETMASK + fatal_signal_mask = 0; +#define ADD_SIG(sig) fatal_signal_mask |= sigmask (sig) +#else +#define ADD_SIG(sig) (void)sig +#endif +#endif + #define FATAL_SIG(sig) \ if (bsd_signal (sig, fatal_error_signal) == SIG_IGN) \ bsd_signal (sig, SIG_IGN); \ else \ ADD_SIG (sig); +#ifdef SIGHUP FATAL_SIG (SIGHUP); +#endif +#ifdef SIGQUIT FATAL_SIG (SIGQUIT); +#endif +#ifdef SIGPIPE + FATAL_SIG (SIGPIPE); +#endif FATAL_SIG (SIGINT); FATAL_SIG (SIGTERM); + +#ifdef __MSDOS__ + /* Windows 9X delivers FP exceptions in child programs to their + parent! We don't want Make to die when a child divides by zero, + so we work around that lossage by catching SIGFPE. */ + FATAL_SIG (SIGFPE); +#endif + +#ifdef SIGDANGER + FATAL_SIG (SIGDANGER); +#endif +#ifdef SIGXCPU FATAL_SIG (SIGXCPU); +#endif +#ifdef SIGXFSZ FATAL_SIG (SIGXFSZ); - FATAL_SIG (SIGPIPE); /* [jart] handle case of piped into less */ +#endif #undef FATAL_SIG @@ -1077,7 +1322,7 @@ main (int argc, char **argv, char **envp) else { program = start + strlen (start); - while (program > start && ! STOP_SET (program[-1], MAP_DIRSEP)) + while (program > start && ! ISDIRSEP (program[-1])) --program; /* Remove the .exe extension if present. */ @@ -1087,6 +1332,52 @@ main (int argc, char **argv, char **envp) program = xstrndup (program, len - 4); } } +#elif defined(VMS) + set_program_name (argv[0]); + program = program_name; + { + const char *shell; + char pwdbuf[256]; + char *pwd; + shell = getenv ("SHELL"); + if (shell != NULL) + vms_gnv_shell = 1; + + /* Need to know if CRTL set to report UNIX paths. Use getcwd as + it works on all versions of VMS. */ + pwd = getcwd(pwdbuf, 256); + if (pwd[0] == '/') + vms_report_unix_paths = 1; + + vms_use_mcr_command = get_vms_env_flag ("GNV$MAKE_USE_MCR", 0); + + vms_always_use_cmd_file = get_vms_env_flag ("GNV$MAKE_USE_CMD_FILE", 0); + + /* Legacy behavior is on VMS is older behavior that needed to be + changed to be compatible with standard make behavior. + For now only completely disable when running under a Bash shell. + TODO: Update VMS built in recipes and macros to not need this + behavior, at which time the default may change. */ + vms_legacy_behavior = get_vms_env_flag ("GNV$MAKE_OLD_VMS", + !vms_gnv_shell); + + /* VMS was changed to use a comma separator in the past, but that is + incompatible with built in functions that expect space separated + lists. Allow this to be selectively turned off. */ + vms_comma_separator = get_vms_env_flag ("GNV$MAKE_COMMA", + vms_legacy_behavior); + + /* Some Posix shell syntax options are incompatible with VMS syntax. + VMS requires double quotes for strings and escapes quotes + differently. When this option is active, VMS will try + to simulate Posix shell simulations instead of using + VMS DCL behavior. */ + vms_unix_simulation = get_vms_env_flag ("GNV$MAKE_SHELL_SIM", + !vms_legacy_behavior); + + } + if (need_vms_symbol () && !vms_use_mcr_command) + create_foreign_command (program_name, argv[0]); #else program = strrchr (argv[0], '/'); if (program == 0) @@ -1096,14 +1387,19 @@ main (int argc, char **argv, char **envp) #endif } - /* Set up to access user data (files). */ - user_access (); - initialize_global_hash_tables (); + /* Ensure the temp directory is set up: we don't want the first time we use + it to be in a forked process. */ + get_tmpdir (); + /* Figure out where we are. */ +#ifdef WINDOWS32 + if (getcwd_fs (current_directory, GET_PATH_MAX) == 0) +#else if (getcwd (current_directory, GET_PATH_MAX) == 0) +#endif { #ifdef HAVE_GETCWD perror_with_name ("getcwd", ""); @@ -1116,6 +1412,11 @@ main (int argc, char **argv, char **envp) else directory_before_chdir = xstrdup (current_directory); +#ifdef __MSDOS__ + /* Make sure we will return to the initial directory, come what may. */ + atexit (msdos_return_to_initial_directory); +#endif + /* Initialize the special variables. */ define_variable_cname (".VARIABLES", "", o_default, 0)->special = 1; /* define_variable_cname (".TARGETS", "", o_default, 0)->special = 1; */ @@ -1129,12 +1430,16 @@ main (int argc, char **argv, char **envp) { const char *features = "target-specific order-only second-expansion" " else-if shortest-stem undefine oneshell nocomment" - " grouped-target extra-prereqs" + " grouped-target extra-prereqs notintermediate" + " shell-export" #ifndef NO_ARCHIVES " archives" #endif #ifdef MAKE_JOBSERVER " jobserver" +# if JOBSERVER_USE_FIFO + " jobserver-fifo" +# endif #endif #ifndef NO_OUTPUT_SYNC " output-sync" @@ -1142,6 +1447,15 @@ main (int argc, char **argv, char **envp) #ifdef MAKE_SYMLINKS " check-symlink" #endif +#ifdef HAVE_GUILE + " guile" +#endif +#ifdef MAKE_LOAD + " load" +#endif +#ifdef HAVE_DOS_PATHS + " dospaths" +#endif #ifdef MAKE_MAINTAINER_MODE " maintainer" #endif @@ -1157,6 +1471,11 @@ main (int argc, char **argv, char **envp) done before $(MAKE) is figured out so its definitions will not be from the environment. */ +#ifdef MK_OS_ZOS + char **envp = environ; +#endif + +#ifndef _AMIGA { unsigned int i; @@ -1168,7 +1487,7 @@ main (int argc, char **argv, char **envp) enum variable_export export = v_export; size_t len; - while (! STOP_SET (*ep, MAP_EQUALS)) + while (! STOP_SET (*ep, MAP_EQUALS|MAP_NUL)) ++ep; /* If there's no equals sign it's a malformed environment. Ignore. */ @@ -1192,14 +1511,14 @@ main (int argc, char **argv, char **envp) /* If this is MAKE_RESTARTS, check to see if the "already printed the enter statement" flag is set. */ - if (len == 13 && strneq (envp[i], "MAKE_RESTARTS", 13)) + if (len == 13 && memcmp (envp[i], "MAKE_RESTARTS", CSTRLEN ("MAKE_RESTARTS")) == 0) { if (*ep == '-') { OUTPUT_TRACED (); ++ep; } - restarts = (unsigned int) atoi (ep); + restarts = make_toui (ep, NULL); export = v_noexport; } @@ -1209,7 +1528,9 @@ main (int argc, char **argv, char **envp) value of SHELL given to subprocesses. */ if (streq (v->name, "SHELL")) { +#ifndef __MSDOS__ export = v_noexport; +#endif shell_var.name = xstrdup ("SHELL"); shell_var.length = 5; shell_var.value = xstrdup (ep); @@ -1219,21 +1540,56 @@ main (int argc, char **argv, char **envp) } } #ifdef WINDOWS32 - /* If we didn't find a correctly spelled PATH we define PATH as - * either the first misspelled value or an empty string - */ - if (!unix_path) - define_variable_cname ("PATH", windows32_path ? windows32_path : "", - o_env, 1)->export = v_export; + /* If we didn't find a correctly spelled PATH we define PATH as + * either the first misspelled value or an empty string + */ + if (!unix_path) + define_variable_cname ("PATH", windows32_path ? windows32_path : "", + o_env, 1)->export = v_export; +#endif +#else /* For Amiga, read the ENV: device, ignoring all dirs */ + { + BPTR env, file, old; + char buffer[1024]; + int len; + __aligned struct FileInfoBlock fib; + + env = Lock ("ENV:", ACCESS_READ); + if (env) + { + old = CurrentDir (DupLock (env)); + Examine (env, &fib); + + while (ExNext (env, &fib)) + { + if (fib.fib_DirEntryType < 0) /* File */ + { + /* Define an empty variable. It will be filled in + variable_lookup(). Makes startup quite a bit faster. */ + define_variable (fib.fib_FileName, + strlen (fib.fib_FileName), + "", o_env, 1)->export = v_export; + } + } + UnLock (env); + UnLock (CurrentDir (old)); + } + } #endif /* Decode the switches. */ - decode_env_switches (STRING_SIZE_TUPLE ("GNUMAKEFLAGS")); + if (lookup_variable (STRING_SIZE_TUPLE (GNUMAKEFLAGS_NAME))) + { + decode_env_switches (STRING_SIZE_TUPLE (GNUMAKEFLAGS_NAME), o_command); - /* Clear GNUMAKEFLAGS to avoid duplication. */ - define_variable_cname ("GNUMAKEFLAGS", "", o_env, 0); + /* Clear GNUMAKEFLAGS to avoid duplication. */ + define_variable_cname (GNUMAKEFLAGS_NAME, "", o_env, 0); + } - decode_env_switches (STRING_SIZE_TUPLE ("MAKEFLAGS")); + /* Set MAKEFLAGS's origin to command line: in submakes MAKEFLAGS will carry + command line switches. This causes env variable MAKEFLAGS to beat + makefile modifications to MAKEFLAGS. */ + decode_env_switches (STRING_SIZE_TUPLE (MAKEFLAGS_NAME), o_command); #if 0 /* People write things like: @@ -1254,13 +1610,46 @@ main (int argc, char **argv, char **envp) int env_slots = arg_job_slots; arg_job_slots = INVALID_JOB_SLOTS; - decode_switches (argc, (const char **)argv, 0); + decode_switches (argc, (const char **)argv, o_command); argv_slots = arg_job_slots; if (arg_job_slots == INVALID_JOB_SLOTS) arg_job_slots = env_slots; } + if (print_usage_flag) + print_usage (0); + + /* Print version information, and exit. */ + if (print_version_flag) + { + print_version (); + die (MAKE_SUCCESS); + } + + /* Now that we know we'll be running, force stdout to be line-buffered. */ +#ifdef HAVE_SETVBUF + setvbuf (stdout, 0, _IOLBF, BUFSIZ); +#elif HAVE_SETLINEBUF + setlinebuf (stdout); +#endif + + /* Handle shuffle mode argument. */ + if (shuffle_mode) + { + const char *effective_mode; + shuffle_set_mode (shuffle_mode); + + /* Write fixed seed back to argument list to propagate mode and + fixed seed to child $(MAKE) runs. */ + free (shuffle_mode); + effective_mode = shuffle_get_mode (); + if (effective_mode) + shuffle_mode = xstrdup (effective_mode); + else + shuffle_mode = NULL; + } + /* Set a variable specifying whether stdout/stdin is hooked to a TTY. */ #ifdef HAVE_ISATTY if (isatty (fileno (stdout))) @@ -1293,7 +1682,7 @@ main (int argc, char **argv, char **envp) { struct variable *v = lookup_variable (STRING_SIZE_TUPLE (MAKELEVEL_NAME)); if (v && v->value[0] != '\0' && v->value[0] != '-') - makelevel = (unsigned int) atoi (v->value); + makelevel = make_toui (v->value, NULL); else makelevel = 0; } @@ -1301,16 +1690,20 @@ main (int argc, char **argv, char **envp) /* Set always_make_flag if -B was given and we've not restarted already. */ always_make_flag = always_make_set && (restarts == 0); - /* Print version information, and exit. */ - if (print_version_flag) - { - print_version (); - die (MAKE_SUCCESS); - } + /* If -R was given, set -r too (doesn't make sense otherwise!) */ + if (no_builtin_variables_flag) + no_builtin_rules_flag = 1; if (ISDB (DB_BASIC)) - print_version (); + { + print_version (); + /* Flush stdout so the user doesn't have to wait to see the + version information while make thinks about things. */ + fflush (stdout); + } + +#ifndef VMS /* Set the "MAKE_COMMAND" variable to the name we were invoked with. (If it is a relative pathname with a slash, prepend our directory name so the result will run the same program regardless of the current dir. @@ -1327,6 +1720,29 @@ main (int argc, char **argv, char **envp) || strneq (argv[0], "//", 2)) argv[0] = xstrdup (w32ify (argv[0], 1)); #else /* WINDOWS32 */ +#if defined (__MSDOS__) || defined (__EMX__) + if (strchr (argv[0], '\\')) + { + char *p; + + argv[0] = xstrdup (argv[0]); + for (p = argv[0]; *p; p++) + if (*p == '\\') + *p = '/'; + } + /* If argv[0] is not in absolute form, prepend the current + directory. This can happen when Make is invoked by another DJGPP + program that uses a non-absolute name. */ + if (current_directory[0] != '\0' + && argv[0] != 0 + && (argv[0][0] != '/' && (argv[0][0] == '\0' || argv[0][1] != ':')) +# ifdef __EMX__ + /* do not prepend cwd if argv[0] contains no '/', e.g. "make" */ + && (strchr (argv[0], '/') != 0 || strchr (argv[0], '\\') != 0) +# endif + ) + argv[0] = xstrdup (concat (3, current_directory, "/", argv[0])); +#else /* !__MSDOS__ */ if (current_directory[0] != '\0' && argv[0] != 0 && argv[0][0] != '/' && strchr (argv[0], '/') != 0 #ifdef HAVE_DOS_PATHS @@ -1335,11 +1751,74 @@ main (int argc, char **argv, char **envp) #endif ) argv[0] = xstrdup (concat (3, current_directory, "/", argv[0])); +#endif /* !__MSDOS__ */ #endif /* WINDOWS32 */ +#endif /* We may move, but until we do, here we are. */ starting_directory = current_directory; + /* If there were -C flags, move ourselves about. */ + if (directories != 0) + { + unsigned int i; + for (i = 0; directories->list[i] != 0; ++i) + { + const char *dir = directories->list[i]; +#ifdef WINDOWS32 + /* WINDOWS32 chdir() doesn't work if the directory has a trailing '/' + But allow -C/ just in case someone wants that. */ + { + char *p = (char *)dir + strlen (dir) - 1; + while (p > dir && ISDIRSEP (p[0])) + --p; + p[1] = '\0'; + } +#endif + if (chdir (dir) < 0) + pfatal_with_name (dir); + } + } + +#ifdef WINDOWS32 + /* + * THIS BLOCK OF CODE MUST COME AFTER chdir() CALL ABOVE IN ORDER + * TO NOT CONFUSE THE DEPENDENCY CHECKING CODE IN implicit.c. + * + * The functions in dir.c can incorrectly cache information for "." + * before we have changed directory and this can cause file + * lookups to fail because the current directory (.) was pointing + * at the wrong place when it was first evaluated. + */ + no_default_sh_exe = !find_and_set_default_shell (NULL); +#endif /* WINDOWS32 */ + + /* If we chdir'ed, figure out where we are now. */ + if (directories) + { +#ifdef WINDOWS32 + if (getcwd_fs (current_directory, GET_PATH_MAX) == 0) +#else + if (getcwd (current_directory, GET_PATH_MAX) == 0) +#endif + { +#ifdef HAVE_GETCWD + perror_with_name ("getcwd", ""); +#else + OS (error, NILF, "getwd: %s", current_directory); +#endif + starting_directory = 0; + } + else + starting_directory = current_directory; + } + + define_variable_cname ("CURDIR", current_directory, o_file, 0); + + /* Construct the list of include directories to search. + This will check for existence so it must be done after chdir. */ + construct_include_path (include_dirs ? include_dirs->list : NULL); + /* Validate the arg_job_slots configuration before we define MAKEFLAGS so users get an accurate value in their makefiles. At this point arg_job_slots is the argv setting, if there is one, else @@ -1352,10 +1831,8 @@ main (int argc, char **argv, char **envp) { /* There's no -j option on the command line: check authorization. */ if (jobserver_parse_auth (jobserver_auth)) - { - /* Success! Use the jobserver. */ - goto job_setup_complete; - } + /* Success! Use the jobserver. */ + goto job_setup_complete; /* Oops: we have jobserver-auth but it's invalid :(. */ O (error, NILF, _("warning: jobserver unavailable: using -j1. Add '+' to parent make rule.")); @@ -1378,7 +1855,14 @@ main (int argc, char **argv, char **envp) /* The extra indirection through $(MAKE_COMMAND) is done for hysterical raisins. */ +#ifdef VMS + if (vms_use_mcr_command) + define_variable_cname ("MAKE_COMMAND", vms_command (argv[0]), o_default, 0); + else + define_variable_cname ("MAKE_COMMAND", program, o_default, 0); +#else define_variable_cname ("MAKE_COMMAND", argv[0], o_default, 0); +#endif define_variable_cname ("MAKE", "$(MAKE_COMMAND)", o_default, 1); if (command_variables != 0) @@ -1426,83 +1910,12 @@ main (int argc, char **argv, char **envp) allow the user's setting of MAKEOVERRIDES to affect MAKEFLAGS, so a reference to this hidden variable is written instead. */ define_variable_cname ("MAKEOVERRIDES", "${-*-command-variables-*-}", - o_env, 1); - } - - /* If there were -C flags, move ourselves about. */ - if (directories != 0) - { - unsigned int i; - for (i = 0; directories->list[i] != 0; ++i) - { - const char *dir = directories->list[i]; -#ifdef WINDOWS32 - /* WINDOWS32 chdir() doesn't work if the directory has a trailing '/' - But allow -C/ just in case someone wants that. */ - { - char *p = (char *)dir + strlen (dir) - 1; - while (p > dir && (p[0] == '/' || p[0] == '\\')) - --p; - p[1] = '\0'; - } + o_default, 1); +#ifdef VMS + vms_export_dcl_symbol ("MAKEOVERRIDES", "${-*-command-variables-*-}"); #endif - if (chdir (dir) < 0) - pfatal_with_name (dir); - } } -#ifdef WINDOWS32 - /* - * THIS BLOCK OF CODE MUST COME AFTER chdir() CALL ABOVE IN ORDER - * TO NOT CONFUSE THE DEPENDENCY CHECKING CODE IN implicit.c. - * - * The functions in dir.c can incorrectly cache information for "." - * before we have changed directory and this can cause file - * lookups to fail because the current directory (.) was pointing - * at the wrong place when it was first evaluated. - */ - no_default_sh_exe = !find_and_set_default_shell (NULL); -#endif /* WINDOWS32 */ - - /* Except under -s, always do -w in sub-makes and under -C. */ - if (!silent_flag && (directories != 0 || makelevel > 0)) - print_directory_flag = 1; - - /* Let the user disable that with --no-print-directory. */ - if (inhibit_print_directory_flag) - print_directory_flag = 0; - - /* If -R was given, set -r too (doesn't make sense otherwise!) */ - if (no_builtin_variables_flag) - no_builtin_rules_flag = 1; - - /* Construct the list of include directories to search. */ - - construct_include_path (include_directories == 0 - ? 0 : include_directories->list); - - /* If we chdir'ed, figure out where we are now. */ - if (directories) - { -#ifdef WINDOWS32 - if (getcwd_fs (current_directory, GET_PATH_MAX) == 0) -#else - if (getcwd (current_directory, GET_PATH_MAX) == 0) -#endif - { -#ifdef HAVE_GETCWD - perror_with_name ("getcwd", ""); -#else - OS (error, NILF, "getwd: %s", current_directory); -#endif - starting_directory = 0; - } - else - starting_directory = current_directory; - } - - define_variable_cname ("CURDIR", current_directory, o_file, 0); - /* Read any stdin makefiles into temporary files. */ if (makefiles != 0) @@ -1515,65 +1928,50 @@ main (int argc, char **argv, char **envp) and thus re-read the makefiles, we read standard input into a temporary file and read from that. */ FILE *outfile; - char *template; - const char *tmpdir; + char *newnm; - if (stdin_nm) + if (stdin_offset >= 0) O (fatal, NILF, - _("Makefile from standard input specified twice.")); + _("Makefile from standard input specified twice")); -#define DEFAULT_TMPDIR "/tmp" -#define DEFAULT_TMPFILE "GmXXXXXX" + outfile = get_tmpfile (&newnm); + if (!outfile) + O (fatal, NILF, + _("cannot store makefile from stdin to a temporary file")); - if (((tmpdir = getenv ("TMPDIR")) == NULL || *tmpdir == '\0') - /* These are also used commonly on these platforms. */ - && ((tmpdir = getenv ("TEMP")) == NULL || *tmpdir == '\0') - && ((tmpdir = getenv ("TMP")) == NULL || *tmpdir == '\0') - ) - tmpdir = DEFAULT_TMPDIR; - - template = alloca (strlen (tmpdir) + CSTRLEN (DEFAULT_TMPFILE) + 2); - strcpy (template, tmpdir); - -#ifdef HAVE_DOS_PATHS - if (strchr ("/\\", template[strlen (template) - 1]) == NULL) - strcat (template, "/"); -#else - if (template[strlen (template) - 1] != '/') - strcat (template, "/"); -#endif /* !HAVE_DOS_PATHS */ - - strcat (template, DEFAULT_TMPFILE); - outfile = get_tmpfile (&stdin_nm, template); - if (outfile == 0) - pfatal_with_name (_("fopen (temporary file)")); while (!feof (stdin) && ! ferror (stdin)) { char buf[2048]; size_t n = fread (buf, 1, sizeof (buf), stdin); if (n > 0 && fwrite (buf, 1, n, outfile) != n) - pfatal_with_name (_("fwrite (temporary file)")); + OSS (fatal, NILF, + _("fwrite: temporary file %s: %s"), newnm, strerror (errno)); } fclose (outfile); - /* Replace the name that read_all_makefiles will - see with the name of the temporary file. */ - makefiles->list[i] = strcache_add (stdin_nm); + /* Replace the name that read_all_makefiles will see with the name + of the temporary file. */ + makefiles->list[i] = strcache_add (newnm); + stdin_offset = i; - /* Make sure the temporary file will not be remade. */ - { - struct file *f = enter_file (strcache_add (stdin_nm)); - f->updated = 1; - f->update_status = us_success; - f->command_state = cs_finished; - /* Can't be intermediate, or it'll be removed too early for - make re-exec. */ - f->intermediate = 0; - f->dontcare = 0; - } + free (newnm); } } + /* Make sure the temporary file is never considered updated. */ + if (stdin_offset >= 0) + { + struct file *f = enter_file (makefiles->list[stdin_offset]); + f->updated = 1; + f->update_status = us_success; + f->command_state = cs_finished; + /* Can't be intermediate, or it'll be removed before make re-exec. */ + f->intermediate = 0; + f->dontcare = 0; + /* Avoid re-exec due to stdin temp file timestamps. */ + f->last_mtime = f->mtime_before_update = f_mtime (f, 0); + } + #ifndef __EMX__ /* Don't use a SIGCHLD handler for OS/2 */ #if !defined(HAVE_WAIT_NOHANG) || defined(MAKE_JOBSERVER) /* Set up to handle children dying. This must be done before @@ -1597,7 +1995,7 @@ main (int argc, char **argv, char **envp) # endif } -#ifdef HAVE_PSELECT +#if defined(HAVE_PSELECT) && !defined(MK_OS_ZOS) /* If we have pselect() then we need to block SIGCHLD so it's deferred. */ { sigset_t block; @@ -1612,24 +2010,19 @@ main (int argc, char **argv, char **envp) #endif /* Let the user send us SIGUSR1 to toggle the -d flag during the run. */ +#ifdef SIGUSR1 bsd_signal (SIGUSR1, debug_signal_handler); +#endif /* Define the initial list of suffixes for old-style rules. */ set_default_suffixes (); - /* Define the file rules for the built-in suffix rules. These will later - be converted into pattern rules. We used to do this in - install_default_implicit_rules, but since that happens after reading - makefiles, it results in the built-in pattern rules taking precedence - over makefile-specified suffix rules, which is wrong. */ - install_default_suffix_rules (); - /* Define some internal and special variables. */ define_automatic_variables (); /* Set up the MAKEFLAGS and MFLAGS variables for makefiles to see. Initialize it to be exported but allow the makefile to reset it. */ - define_makeflags (0, 0)->export = v_export; + define_makeflags (0)->export = v_export; /* Define the default variables. */ define_default_variables (); @@ -1643,7 +2036,7 @@ main (int argc, char **argv, char **envp) if (eval_strings) { - char *p, *value; + char *p, *endp, *value; unsigned int i; size_t len = (CSTRLEN ("--eval=") + 1) * eval_strings->idx; @@ -1655,46 +2048,36 @@ main (int argc, char **argv, char **envp) free (p); } - p = value = alloca (len); + p = endp = value = alloca (len); for (i = 0; i < eval_strings->idx; ++i) { - strcpy (p, "--eval="); - p += CSTRLEN ("--eval="); + p = stpcpy (p, "--eval="); p = quote_for_env (p, eval_strings->list[i]); - *(p++) = ' '; + endp = p++; + *endp = ' '; } -#pragma GCC push_options -#pragma GCC diagnostic ignored "-Wstringop-overflow" /* wut */ - p[-1] = '\0'; -#pragma GCC pop_options + *endp = '\0'; define_variable_cname ("-*-eval-flags-*-", value, o_automatic, 0); } - /* Read all the makefiles. */ - - read_files = read_all_makefiles (makefiles == 0 ? 0 : makefiles->list); - -#ifdef WINDOWS32 - /* look one last time after reading all Makefiles */ - if (no_default_sh_exe) - no_default_sh_exe = !find_and_set_default_shell (NULL); -#endif /* WINDOWS32 */ - { int old_builtin_rules_flag = no_builtin_rules_flag; int old_builtin_variables_flag = no_builtin_variables_flag; int old_arg_job_slots = arg_job_slots; + /* Read all the makefiles. */ + read_files = read_all_makefiles (makefiles == 0 ? 0 : makefiles->list); + arg_job_slots = INVALID_JOB_SLOTS; /* Decode switches again, for variables set by the makefile. */ - decode_env_switches (STRING_SIZE_TUPLE ("GNUMAKEFLAGS")); + decode_env_switches (STRING_SIZE_TUPLE (GNUMAKEFLAGS_NAME), o_env); /* Clear GNUMAKEFLAGS to avoid duplication. */ - define_variable_cname ("GNUMAKEFLAGS", "", o_override, 0); + define_variable_cname (GNUMAKEFLAGS_NAME, "", o_override, 0); - decode_env_switches (STRING_SIZE_TUPLE ("MAKEFLAGS")); + decode_env_switches (STRING_SIZE_TUPLE (MAKEFLAGS_NAME), o_env); #if 0 decode_env_switches (STRING_SIZE_TUPLE ("MFLAGS")); #endif @@ -1704,7 +2087,7 @@ main (int argc, char **argv, char **envp) if (arg_job_slots == INVALID_JOB_SLOTS || argv_slots != INVALID_JOB_SLOTS) arg_job_slots = old_arg_job_slots; - else if (jobserver_auth) + else if (jobserver_auth && arg_job_slots != old_arg_job_slots) { /* Makefile MAKEFLAGS set -j, but we already have a jobserver. Make us the master of a new jobserver group. */ @@ -1727,6 +2110,10 @@ main (int argc, char **argv, char **envp) make_sync.syncout = syncing; OUTPUT_SET (&make_sync); + /* If -R was given, set -r too (doesn't make sense otherwise!) */ + if (no_builtin_variables_flag) + no_builtin_rules_flag = 1; + /* If we've disabled builtin rules, get rid of them. */ if (no_builtin_rules_flag && ! old_builtin_rules_flag) { @@ -1743,6 +2130,34 @@ main (int argc, char **argv, char **envp) undefine_default_variables (); } +#ifdef WINDOWS32 + /* look one last time after reading all Makefiles */ + if (no_default_sh_exe) + no_default_sh_exe = !find_and_set_default_shell (NULL); +#endif /* WINDOWS32 */ + +#if defined (__MSDOS__) || defined (__EMX__) || defined (VMS) + /* We need to know what kind of shell we will be using. */ + { + extern int _is_unixy_shell (const char *_path); + struct variable *shv = lookup_variable (STRING_SIZE_TUPLE ("SHELL")); + extern int unixy_shell; + extern const char *default_shell; + + if (shv && *shv->value) + { + char *shell_path = recursively_expand (shv); + + if (shell_path && _is_unixy_shell (shell_path)) + unixy_shell = 1; + else + unixy_shell = 0; + if (shell_path) + default_shell = shell_path; + } + } +#endif /* __MSDOS__ || __EMX__ */ + /* Final jobserver configuration. If we have jobserver_auth then we are a client in an existing jobserver @@ -1766,6 +2181,21 @@ main (int argc, char **argv, char **envp) else job_slots = arg_job_slots; +#if defined (__MSDOS__) || defined (__EMX__) || defined (VMS) + if (job_slots != 1 +# ifdef __EMX__ + && _osmode != OS2_MODE /* turn off -j if we are in DOS mode */ +# endif + ) + { + O (error, NILF, + _("Parallel jobs (-j) are not supported on this platform.")); + O (error, NILF, _("Resetting to single job (-j1) mode.")); + arg_job_slots = INVALID_JOB_SLOTS; + job_slots = 1; + } +#endif + /* If we have >1 slot at this point, then we're a top-level make. Set up the jobserver. @@ -1773,7 +2203,7 @@ main (int argc, char **argv, char **envp) submakes it's the token they were given by their parent. For the top make, we just subtract one from the number the user wants. */ - if (job_slots > 1 && jobserver_setup (job_slots - 1)) + if (job_slots > 1 && jobserver_setup (job_slots - 1, jobserver_style)) { /* Fill in the jobserver_auth for our children. */ jobserver_auth = jobserver_get_auth (); @@ -1797,6 +2227,29 @@ main (int argc, char **argv, char **envp) output_sync = OUTPUT_SYNC_NONE; } + if (syncing) + { + /* If there is no mutex we're the base: create one. Else parse it. */ + if (!sync_mutex) + { + osync_setup (); + sync_mutex = osync_get_mutex (); + } + else if (!osync_parse_mutex (sync_mutex)) + { + /* Parsing failed; continue without output sync. */ + osync_clear (); + free (sync_mutex); + sync_mutex = NULL; + syncing = 0; + } + } + + if (jobserver_auth) + DB (DB_VERBOSE|DB_JOBS, (_("Using jobserver controller %s\n"), jobserver_auth)); + if (sync_mutex) + DB (DB_VERBOSE, (_("Using output-sync mutex %s\n"), sync_mutex)); + #ifndef MAKE_SYMLINKS if (check_symlink_flag) { @@ -1807,13 +2260,18 @@ main (int argc, char **argv, char **envp) /* Set up MAKEFLAGS and MFLAGS again, so they will be right. */ - define_makeflags (1, 0); + define_makeflags (0); /* Make each 'struct goaldep' point at the 'struct file' for the file depended on. Also do magic for special targets. */ snap_deps (); + /* Define the file rules for the built-in suffix rules. These will later + be converted into pattern rules. */ + + install_default_suffix_rules (); + /* Convert old-style suffix rules to pattern rules. It is important to do this before installing the built-in pattern rules below, so that makefile-specified suffix rules take precedence over built-in pattern @@ -1871,23 +2329,35 @@ main (int argc, char **argv, char **envp) OUTPUT_UNSET (); output_close (&make_sync); + if (shuffle_mode) + DB (DB_BASIC, (_("Enabled shuffle mode: %s\n"), shuffle_mode)); + if (read_files) { /* Update any makefiles if necessary. */ FILE_TIMESTAMP *makefile_mtimes; - char **aargv = NULL; - const char **nargv; - int nargc; + struct goaldep *skipped_makefiles = NULL; + const char **nargv = (const char **) argv; + int any_failed = 0; enum update_status status; DB (DB_BASIC, (_("Updating makefiles....\n"))); + /* Count the makefiles, and reverse the order so that we attempt to + rebuild them in the order they were read. */ { - struct goaldep *d; unsigned int num_mkfiles = 0; - for (d = read_files; d != NULL; d = d->next) - ++num_mkfiles; + struct goaldep *d = read_files; + read_files = NULL; + while (d != NULL) + { + struct goaldep *t = d; + d = d->next; + t->next = read_files; + read_files = t; + ++num_mkfiles; + } makefile_mtimes = alloca (num_mkfiles * sizeof (FILE_TIMESTAMP)); } @@ -1901,21 +2371,34 @@ main (int argc, char **argv, char **envp) while (d != 0) { - struct file *f; + int skip = 0; + struct file *f = d->file; - for (f = d->file->double_colon; f != NULL; f = f->prev) - if (f->deps == 0 && f->cmds != 0) - break; + /* Check for makefiles that are either phony or a :: target with + commands, but no dependencies. These will always be remade, + which will cause an infinite restart loop, so don't try to + remake it (this will only happen if your makefiles are written + exceptionally stupidly; but if you work for Athena, that's how + you write your makefiles.) */ - if (f) + if (f->phony) + skip = 1; + else + for (f = f->double_colon; f != NULL; f = f->prev) + if (f->deps == NULL && f->cmds != NULL) + { + skip = 1; + break; + } + + if (!skip) + { + makefile_mtimes[mm_idx++] = file_mtime_no_search (d->file); + last = d; + d = d->next; + } + else { - /* This makefile is a :: target with commands, but no - dependencies. So, it will always be remade. This might - well cause an infinite loop, so don't try to remake it. - (This will only happen if your makefiles are written - exceptionally stupidly; but if you work for Athena, that's - how you write your makefiles.) */ - DB (DB_VERBOSE, (_("Makefile '%s' might loop; not remaking it.\n"), f->name)); @@ -1925,22 +2408,24 @@ main (int argc, char **argv, char **envp) else read_files = d->next; - /* Free the storage. */ - free_goaldep (d); + if (d->error && ! (d->flags & RM_DONTCARE)) + { + /* This file won't be rebuilt, was not found, and we care, + so remember it to report later. */ + d->next = skipped_makefiles; + skipped_makefiles = d; + any_failed = 1; + } + else + free_goaldep (d); d = last ? last->next : read_files; } - else - { - makefile_mtimes[mm_idx++] = file_mtime_no_search (d->file); - last = d; - d = d->next; - } } } /* Set up 'MAKEFLAGS' specially while remaking makefiles. */ - define_makeflags (1, 1); + define_makeflags (1); { int orig_db_level = db_level; @@ -1955,6 +2440,23 @@ main (int argc, char **argv, char **envp) db_level = orig_db_level; } + /* Report errors for makefiles that needed to be remade but were not. */ + while (skipped_makefiles != NULL) + { + struct goaldep *d = skipped_makefiles; + const char *err = strerror (d->error); + + OSS (error, &d->floc, _("%s: %s"), dep_name (d), err); + + skipped_makefiles = skipped_makefiles->next; + free_goaldep (d); + } + + /* If we couldn't build something we need but otherwise we succeeded, + reset the status. */ + if (any_failed && status == us_success) + status = us_none; + switch (status) { case us_question: @@ -1962,9 +2464,48 @@ main (int argc, char **argv, char **envp) for one of the makefiles to be remade as a target on the command line. Since we're not actually updating anything with -q we can treat this as "did nothing". */ + break; case us_none: - /* Did nothing. */ + { + /* Reload any unloaded shared objects. Do not re-exec to have + that shared object loaded: a re-exec would cause an infinite + loop, because the shared object was not updated. */ + struct goaldep *d; + + for (d = read_files; d; d = d->next) + if (d->file->unloaded) + { + struct file *f = d->file; + /* Load the file. 0 means failure. */ + if (load_file (&d->floc, f, 0) == 0) + OS (fatal, &d->floc, _("%s: failed to load"), f->name); + f->unloaded = 0; + f->loaded = 1; + } + } + + /* No makefiles needed to be updated. If we couldn't read some + included file that we care about, fail. */ + if (0) + { + /* This runs afoul of https://savannah.gnu.org/bugs/?61226 + The problem is that many makefiles use a "dummy rule" to + pretend that an included file is rebuilt, without actually + rebuilding it, and this has always worked. There are a + number of solutions proposed in that bug but for now we'll + put things back so they work the way they did before. */ + struct goaldep *d; + + for (d = read_files; d != 0; d = d->next) + if (d->error && ! (d->flags & RM_DONTCARE)) + { + /* This makefile couldn't be loaded, and we care. */ + const char *err = strerror (d->error); + OSS (error, &d->floc, _("%s: %s"), dep_name (d), err); + any_failed = 1; + } + } break; case us_failed: @@ -1972,9 +2513,6 @@ main (int argc, char **argv, char **envp) { /* Nonzero if any makefile was successfully remade. */ int any_remade = 0; - /* Nonzero if any makefile we care about failed - in updating or could not be found at all. */ - int any_failed = 0; unsigned int i; struct goaldep *d; @@ -1984,51 +2522,48 @@ main (int argc, char **argv, char **envp) { /* This makefile was updated. */ if (d->file->update_status == us_success) - { - /* It was successfully updated. */ - any_remade |= (file_mtime_no_search (d->file) - != makefile_mtimes[i]); - } + /* It was successfully updated. */ + any_remade |= (file_mtime_no_search (d->file) + != makefile_mtimes[i]); else if (! (d->flags & RM_DONTCARE)) { FILE_TIMESTAMP mtime; /* The update failed and this makefile was not from the MAKEFILES variable, so we care. */ - OS (error, NILF, _("Failed to remake makefile '%s'."), + OS (error, &d->floc, + _("Failed to remake makefile '%s'."), d->file->name); mtime = file_mtime_no_search (d->file); any_remade |= (mtime != NONEXISTENT_MTIME && mtime != makefile_mtimes[i]); makefile_status = MAKE_FAILURE; + any_failed = 1; } } - else - /* This makefile was not found at all. */ - if (! (d->flags & RM_DONTCARE)) - { - const char *dnm = dep_name (d); - size_t l = strlen (dnm); - /* This is a makefile we care about. See how much. */ - if (d->flags & RM_INCLUDED) - /* An included makefile. We don't need to die, but we - do want to complain. */ - error (NILF, l, - _("Included makefile '%s' was not found."), dnm); - else - { - /* A normal makefile. We must die later. */ - error (NILF, l, - _("Makefile '%s' was not found"), dnm); - any_failed = 1; - } - } + /* This makefile was not found at all. */ + else if (! (d->flags & RM_DONTCARE)) + { + const char *dnm = dep_name (d); + + /* This is a makefile we care about. See how much. */ + if (d->flags & RM_INCLUDED) + /* An included makefile. We don't need to die, but we + do want to complain. */ + OS (error, &d->floc, + _("Included makefile '%s' was not found."), dnm); + else + { + /* A normal makefile. We must die later. */ + OS (error, NILF, _("Makefile '%s' was not found"), dnm); + any_failed = 1; + } + } } if (any_remade) goto re_exec; - if (any_failed) - die (MAKE_FAILURE); + break; } @@ -2045,33 +2580,116 @@ main (int argc, char **argv, char **envp) if (makefiles != 0) { - /* These names might have changed. */ - int i, j = 0; - for (i = 1; i < argc; ++i) - if (strneq (argv[i], "-f", 2)) /* XXX */ - { - if (argv[i][2] == '\0') - /* This cast is OK since we never modify argv. */ - argv[++i] = (char *) makefiles->list[j]; - else - argv[i] = xstrdup (concat (2, "-f", makefiles->list[j])); - ++j; - } - } + /* Makefile names might have changed due to expansion. + It's possible we'll need one extra argument: + make -Rf- + will expand to: + make -R --temp-stdin= + so allocate more space. + */ + int mfidx = 0; + char** av = argv; + const char** nv; - /* Add -o option for the stdin temporary file, if necessary. */ - nargc = argc; - if (stdin_nm) - { - void *m = xmalloc ((nargc + 2) * sizeof (char *)); - aargv = m; - memcpy (aargv, argv, argc * sizeof (char *)); - aargv[nargc++] = xstrdup (concat (2, "-o", stdin_nm)); - aargv[nargc] = 0; - nargv = m; + nv = nargv = alloca (sizeof (char*) * (argc + 1 + 1)); + *(nv++) = *(av++); + + for (; *av; ++av, ++nv) + { + char *f; + char *a = *av; + const char *mf = makefiles->list[mfidx]; + + assert (strlen (a) > 0); + + *nv = a; + + /* Not an option: we handled option args earlier. */ + if (a[0] != '-') + continue; + + /* See if this option specifies a filename. If so we need + to replace it with the value from makefiles->list. + + To simplify, we'll replace all possible versions of this + flag with a simple "-f". */ + + /* Handle long options. */ + if (a[1] == '-') + { + if (strcmp (a, "--file") == 0 || strcmp (a, "--makefile") == 0) + /* Skip the next arg as we'll combine them. */ + ++av; + else if (!strneq (a, "--file=", 7) + && !strneq (a, "--makefile=", 11)) + continue; + + if (mfidx == stdin_offset) + { + char *na = alloca (CSTRLEN ("--temp-stdin=") + + strlen (mf) + 1); + sprintf (na, "--temp-stdin=%s", mf); + *nv = na; + } + else + { + char *na = alloca (strlen (mf) + 3); + sprintf (na, "-f%s", mf); + *nv = na; + } + + ++mfidx; + continue; + } + + /* Handle short options. If 'f' is the last option, it may + be followed by . */ + f = strchr (a, 'f'); + if (!f) + continue; + + /* If there's an extra argument option skip it. */ + if (f[1] == '\0') + ++av; + + if (mfidx == stdin_offset) + { + const size_t al = f - a; + char *na; + + if (al > 1) + { + /* Preserve the prior options. */ + na = alloca (al + 1); + memcpy (na, a, al); + na[al] = '\0'; + *(nv++) = na; + } + + /* Remove the "f" and any subsequent content. */ + na = alloca (CSTRLEN ("--temp-stdin=") + strlen (mf) + 1); + sprintf (na, "--temp-stdin=%s", mf); + *nv = na; + } + else if (f[1] == '\0') + /* -f or -xyzf . Replace the name. */ + *(++nv) = mf; + else + { + /* -f or -xyzf. */ + const size_t al = f - a + 1; + const size_t ml = strlen (mf) + 1; + char *na = alloca (al + ml); + memcpy (na, a, al); + memcpy (na + al, mf, ml); + *nv = na; + } + + ++mfidx; + } + + *nv = NULL; } - else - nargv = (const char**)argv; if (directories != 0 && directories->idx > 0) { @@ -2085,7 +2703,7 @@ main (int argc, char **argv, char **envp) } if (bad) O (fatal, NILF, - _("Couldn't change back to original directory.")); + _("Couldn't change back to original directory")); } ++restarts; @@ -2100,6 +2718,7 @@ main (int argc, char **argv, char **envp) fflush (stdout); } +#ifndef _AMIGA { char **p; for (p = environ; *p != 0; ++p) @@ -2108,6 +2727,9 @@ main (int argc, char **argv, char **envp) { *p = alloca (40); sprintf (*p, "%s=%u", MAKELEVEL_NAME, makelevel); +#ifdef VMS + vms_putenv_symbol (*p); +#endif } else if (strneq (*p, "MAKE_RESTARTS=", CSTRLEN ("MAKE_RESTARTS="))) { @@ -2118,6 +2740,18 @@ main (int argc, char **argv, char **envp) } } } +#else /* AMIGA */ + { + char buffer[256]; + + sprintf (buffer, "%u", makelevel); + SetVar (MAKELEVEL_NAME, buffer, -1, GVF_GLOBAL_ONLY); + + sprintf (buffer, "%s%u", OUTPUT_IS_TRACED () ? "-" : "", restarts); + SetVar ("MAKE_RESTARTS", buffer, -1, GVF_GLOBAL_ONLY); + restarts = 0; + } +#endif /* If we didn't set the restarts variable yet, add it. */ if (restarts) @@ -2131,23 +2765,59 @@ main (int argc, char **argv, char **envp) fflush (stdout); fflush (stderr); + osync_clear(); + /* The exec'd "child" will be another make, of course. */ jobserver_pre_child(1); +#ifdef _AMIGA + exec_command (nargv); + exit (0); +#elif defined (__EMX__) + { + /* It is not possible to use execve() here because this + would cause the parent process to be terminated with + exit code 0 before the child process has been terminated. + Therefore it may be the best solution simply to spawn the + child process including all file handles and to wait for its + termination. */ + pid_t pid; + int r; + struct childbase child; + child.cmd_name = NULL; + child.output.syncout = 0; + child.environment = environ; + + pid = child_execute_job (&child, 1, (char **)nargv); + + /* is this loop really necessary? */ + do { + pid = wait (&r); + } while (pid <= 0); + /* use the exit code of the child process */ + exit (WIFEXITED(r) ? WEXITSTATUS(r) : EXIT_FAILURE); + } +#else +#ifdef SET_STACK_SIZE /* Reset limits, if necessary. */ if (stack_limit.rlim_cur) setrlimit (RLIMIT_STACK, &stack_limit); +#endif exec_command ((char **)nargv, environ); - - /* We shouldn't get here but just in case. */ +#endif jobserver_post_child(1); - free (aargv); - break; + + temp_stdin_unlink (); + + _exit (127); } + + if (any_failed) + die (MAKE_FAILURE); } /* Set up 'MAKEFLAGS' again for the normal targets. */ - define_makeflags (1, 0); + define_makeflags (0); /* Set always_make_flag if -B was given. */ always_make_flag = always_make_set; @@ -2163,10 +2833,7 @@ main (int argc, char **argv, char **envp) } } - /* If there is a temp file from reading a makefile from stdin, get rid of - it now. */ - if (stdin_nm && unlink (stdin_nm) < 0 && errno != ENOENT) - perror_with_name (_("unlink (temporary file): "), stdin_nm); + temp_stdin_unlink (); /* If there were no command-line goals, use the default. */ if (goals == 0) @@ -2228,6 +2895,10 @@ main (int argc, char **argv, char **envp) O (fatal, NILF, _("No targets specified and no makefile found")); } + /* Shuffle prerequisites to catch makefiles with incomplete depends. */ + + shuffle_goaldeps_recursive (goals); + /* Update the goals. */ DB (DB_BASIC, (_("Updating goal targets....\n"))); @@ -2334,7 +3005,7 @@ init_switches (void) /* Non-option argument. It might be a variable definition. */ static void -handle_non_switch_argument (const char *arg, int env) +handle_non_switch_argument (const char *arg, enum variable_origin origin) { struct variable *v; @@ -2342,7 +3013,32 @@ handle_non_switch_argument (const char *arg, int env) /* Ignore plain '-' for compatibility. */ return; - v = try_variable_definition (0, arg, o_command, 0); +#ifdef VMS + { + /* VMS DCL quoting can result in foo="bar baz" showing up here. + Need to remove the double quotes from the value. */ + char * eq_ptr; + char * new_arg; + eq_ptr = strchr (arg, '='); + if ((eq_ptr != NULL) && (eq_ptr[1] == '"')) + { + int len; + int seg1; + int seg2; + len = strlen(arg); + new_arg = alloca(len); + seg1 = eq_ptr - arg + 1; + strncpy(new_arg, arg, (seg1)); + seg2 = len - seg1 - 1; + strncpy(&new_arg[seg1], &eq_ptr[2], seg2); + new_arg[seg1 + seg2] = 0; + if (new_arg[seg1 + seg2 - 1] == '"') + new_arg[seg1 + seg2 - 1] = 0; + arg = new_arg; + } + } +#endif + v = try_variable_definition (0, arg, origin, 0); if (v != 0) { /* It is indeed a variable definition. If we don't already have this @@ -2362,11 +3058,12 @@ handle_non_switch_argument (const char *arg, int env) command_variables = cv; } } - else if (! env) + else if (arg[0] != '\0' && origin == o_command) { - /* Not an option or variable definition; it must be a goal - target! Enter it as a file and add it to the dep chain of - goals. */ + /* Not an option or variable definition; it must be a goal target. + Enter it as a file and add it to the dep chain of goals. + Check ARG[0] because if the top makefile resets MAKEOVERRIDES + then ARG points to an empty string in the submake. */ struct file *f = enter_file (strcache_add (expand_command_line_file (arg))); f->cmd_target = 1; @@ -2410,41 +3107,23 @@ handle_non_switch_argument (const char *arg, int env) } } -/* Print a nice usage method. */ - -static void -print_usage (int bad) +/* Called if the makefile resets the MAKEFLAGS variable. */ +void +reset_makeflags (enum variable_origin origin) { - const char *const *cpp; - FILE *usageto; - - if (print_version_flag) - print_version (); - - usageto = bad ? stderr : stdout; - - fprintf (usageto, _("Usage: %s [options] [target] ...\n"), program); - - for (cpp = usage; *cpp; ++cpp) - fputs (_(*cpp), usageto); - - if (!remote_description || *remote_description == '\0') - fprintf (usageto, _("\nThis program built for %s\n"), make_host); - else - fprintf (usageto, _("\nThis program built for %s (%s)\n"), - make_host, remote_description); - - fprintf (usageto, _("Report bugs to \n")); + decode_env_switches (STRING_SIZE_TUPLE(MAKEFLAGS_NAME), origin); + construct_include_path (include_dirs ? include_dirs->list : NULL); + define_makeflags (rebuilding_makefiles); } /* Decode switches from ARGC and ARGV. - They came from the environment if ENV is nonzero. */ + They came from the environment if ORIGIN is o_env. */ static void -decode_switches (int argc, const char **argv, int env) +decode_switches (int argc, const char **argv, enum variable_origin origin) { int bad = 0; - const struct command_switch *cs; + struct command_switch *cs; struct stringlist *sl; int c; @@ -2455,7 +3134,7 @@ decode_switches (int argc, const char **argv, int env) /* Let getopt produce error messages for the command line, but not for options from the environment. */ - opterr = !env; + opterr = origin == o_command; /* Reset getopt's state. */ optind = 0; @@ -2464,14 +3143,14 @@ decode_switches (int argc, const char **argv, int env) const char *coptarg; /* Parse the next argument. */ - c = getopt_long (argc, (char*const*)argv, options, long_options, NULL); + c = getopt_long (argc, (char *const *)argv, options, long_options, NULL); coptarg = optarg; if (c == EOF) /* End of arguments, or "--" marker seen. */ break; else if (c == 1) /* An argument not starting with a dash. */ - handle_non_switch_argument (coptarg, env); + handle_non_switch_argument (coptarg, origin); else if (c == '?') /* Bad option. We will print a usage message and die later. But continue to parse the other options so the user can @@ -2485,7 +3164,12 @@ decode_switches (int argc, const char **argv, int env) this switch. We test this individually inside the switch below rather than just once outside it, so that options which are to be ignored still consume args. */ - int doit = !env || cs->env; + int doit = (origin == o_command + || (cs->env && + (cs->origin == NULL || origin >= *cs->origin))); + + if (doit) + cs->specified = 1; switch (cs->type) { @@ -2498,7 +3182,11 @@ decode_switches (int argc, const char **argv, int env) case flag: case flag_off: if (doit) - *(int *) cs->value_ptr = cs->type == flag; + { + *(int *) cs->value_ptr = cs->type == flag; + if (cs->origin) + *cs->origin = origin; + } break; case string: @@ -2508,7 +3196,7 @@ decode_switches (int argc, const char **argv, int env) break; if (! coptarg) - coptarg = xstrdup (cs->noarg_value); + coptarg = cs->noarg_value; else if (*coptarg == '\0') { char opt[2] = "c"; @@ -2531,6 +3219,8 @@ decode_switches (int argc, const char **argv, int env) char **val = (char **)cs->value_ptr; free (*val); *val = xstrdup (coptarg); + if (cs->origin) + *cs->origin = origin; break; } @@ -2550,10 +3240,41 @@ decode_switches (int argc, const char **argv, int env) sl->list = xrealloc ((void *)sl->list, sl->max * sizeof (char *)); } - if (cs->type == filename) - sl->list[sl->idx++] = expand_command_line_file (coptarg); + + /* Filter out duplicate options. + * Allow duplicate makefiles for backward compatibility. */ + if (cs->c != 'f') + { + unsigned int k; + for (k = 0; k < sl->idx; ++k) + if (streq (sl->list[k], coptarg)) + break; + if (k < sl->idx) + break; + } + + if (cs->type == strlist) + { + sl->list[sl->idx++] = xstrdup (coptarg); + if (cs->origin) + *cs->origin = origin; + } + else if (cs->c == TEMP_STDIN_OPT) + { + if (stdin_offset > 0) + fatal (NILF, 0, "INTERNAL: multiple --temp-stdin options provided!"); + /* We don't need to expand the temp file. */ + stdin_offset = sl->idx; + sl->list[sl->idx++] = strcache_add (coptarg); + if (cs->origin) + *cs->origin = origin; + } else - sl->list[sl->idx++] = xstrdup (coptarg); + { + sl->list[sl->idx++] = expand_command_line_file (coptarg); + if (cs->origin) + *cs->origin = origin; + } sl->list[sl->idx] = 0; break; @@ -2574,14 +3295,10 @@ decode_switches (int argc, const char **argv, int env) if (coptarg) { - int i = atoi (coptarg); - const char *cp; + const char *err; + unsigned int i = make_toui (coptarg, &err); - /* Yes, I realize we're repeating this in some cases. */ - for (cp = coptarg; ISDIGIT (cp[0]); ++cp) - ; - - if (i < 1 || cp[0] != '\0') + if (err || i == 0) { error (NILF, 0, _("the '-%c' option requires a positive integer argument"), @@ -2589,11 +3306,19 @@ decode_switches (int argc, const char **argv, int env) bad = 1; } else - *(unsigned int *) cs->value_ptr = i; + { + *(unsigned int *) cs->value_ptr = i; + if (cs->origin) + *cs->origin = origin; + } } else - *(unsigned int *) cs->value_ptr - = *(unsigned int *) cs->noarg_value; + { + *(unsigned int *) cs->value_ptr + = *(unsigned int *) cs->noarg_value; + if (cs->origin) + *cs->origin = origin; + } break; case floating: @@ -2602,9 +3327,12 @@ decode_switches (int argc, const char **argv, int env) coptarg = argv[optind++]; if (doit) - *(double *) cs->value_ptr - = (coptarg != 0 ? atof (coptarg) - : *(double *) cs->noarg_value); + { + *(double *) cs->value_ptr = (coptarg != 0 ? atof (coptarg) + : *(double *) cs->noarg_value); + if (cs->origin) + *cs->origin = origin; + } break; } @@ -2619,13 +3347,10 @@ decode_switches (int argc, const char **argv, int env) to be returned in order, this only happens when there is a "--" argument to prevent later arguments from being options. */ while (optind < argc) - handle_non_switch_argument (argv[optind++], env); + handle_non_switch_argument (argv[optind++], origin); - if (!env && (bad || print_usage_flag)) - { - print_usage (bad); - die (bad ? MAKE_FAILURE : MAKE_SUCCESS); - } + if (bad && origin == o_command) + print_usage (bad); /* If there are any options that need to be decoded do it now. */ decode_debug_flags (); @@ -2641,7 +3366,7 @@ decode_switches (int argc, const char **argv, int env) decode_switches. */ static void -decode_env_switches (const char *envar, size_t len) +decode_env_switches (const char *envar, size_t len, enum variable_origin origin) { char *varref = alloca (2 + len + 2); char *value, *p, *buf; @@ -2649,11 +3374,12 @@ decode_env_switches (const char *envar, size_t len) const char **argv; /* Get the variable's value. */ - varref[0] = '$'; - varref[1] = '('; - memcpy (&varref[2], envar, len); - varref[2 + len] = ')'; - varref[2 + len + 1] = '\0'; + p = varref; + *(p++) = '$'; + *(p++) = '('; + p = mempcpy (p, envar, len); + *(p++) = ')'; + *p = '\0'; value = variable_expand (varref); /* Skip whitespace, and check for an empty value. */ @@ -2667,7 +3393,7 @@ decode_env_switches (const char *envar, size_t len) /* getopt will look at the arguments starting at ARGV[1]. Prepend a spacer word. */ - argv[0] = 0; + argv[0] = ""; argc = 1; /* We need a buffer to copy the value into while we split it into words @@ -2702,7 +3428,7 @@ decode_env_switches (const char *envar, size_t len) argv[1] = buf; /* Parse those words. */ - decode_switches (argc, argv, 1); + decode_switches (argc, argv, origin); } /* Quote the string IN so that it will be interpreted as a single word with @@ -2727,16 +3453,17 @@ quote_for_env (char *out, const char *in) } /* Define the MAKEFLAGS and MFLAGS variables to reflect the settings of the - command switches. Include options with args if ALL is nonzero. + command switches. Always include options with args. Don't include options with the 'no_makefile' flag set if MAKEFILE. */ -static struct variable * -define_makeflags (int all, int makefile) +struct variable * +define_makeflags (int makefile) { const char ref[] = "MAKEOVERRIDES"; const char posixref[] = "-*-command-variables-*-"; const char evalref[] = "$(-*-eval-flags-*-)"; const struct command_switch *cs; + struct variable *v; char *flagstring; char *p; @@ -2786,72 +3513,60 @@ define_makeflags (int all, int makefile) case flag: case flag_off: if ((!*(int *) cs->value_ptr) == (cs->type == flag_off) - && (cs->default_value == 0 + && (cs->default_value == NULL || cs->specified || *(int *) cs->value_ptr != *(int *) cs->default_value)) ADD_FLAG (0, 0); break; case positive_int: - if (all) + if ((cs->default_value != 0 + && (*(unsigned int *) cs->value_ptr + == *(unsigned int *) cs->default_value))) + break; + if (cs->noarg_value != 0 + && (*(unsigned int *) cs->value_ptr == + *(unsigned int *) cs->noarg_value)) + ADD_FLAG ("", 0); /* Optional value omitted; see below. */ + else { - if ((cs->default_value != 0 - && (*(unsigned int *) cs->value_ptr - == *(unsigned int *) cs->default_value))) - break; - else if (cs->noarg_value != 0 - && (*(unsigned int *) cs->value_ptr == - *(unsigned int *) cs->noarg_value)) - ADD_FLAG ("", 0); /* Optional value omitted; see below. */ - else - { - char *buf = alloca (30); - sprintf (buf, "%u", *(unsigned int *) cs->value_ptr); - ADD_FLAG (buf, strlen (buf)); - } + char *buf = alloca (30); + sprintf (buf, "%u", *(unsigned int *) cs->value_ptr); + ADD_FLAG (buf, strlen (buf)); } break; case floating: - if (all) + if (cs->default_value != 0 + && (*(double *) cs->value_ptr == *(double *) cs->default_value)) + break; + if (cs->noarg_value != 0 + && (*(double *) cs->value_ptr == *(double *) cs->noarg_value)) + ADD_FLAG ("", 0); /* Optional value omitted; see below. */ + else { - if (cs->default_value != 0 - && (*(double *) cs->value_ptr - == *(double *) cs->default_value)) - break; - else if (cs->noarg_value != 0 - && (*(double *) cs->value_ptr - == *(double *) cs->noarg_value)) - ADD_FLAG ("", 0); /* Optional value omitted; see below. */ - else - { - char *buf = alloca (100); - sprintf (buf, "%g", *(double *) cs->value_ptr); - ADD_FLAG (buf, strlen (buf)); - } + char *buf = alloca (100); + sprintf (buf, "%g", *(double *) cs->value_ptr); + ADD_FLAG (buf, strlen (buf)); } break; case string: - if (all) - { - p = *((char **)cs->value_ptr); - if (p) - ADD_FLAG (p, strlen (p)); - } + p = *((char **)cs->value_ptr); + if (p) + ADD_FLAG (p, strlen (p)); break; case filename: case strlist: - if (all) - { - struct stringlist *sl = *(struct stringlist **) cs->value_ptr; - if (sl != 0) - { - unsigned int i; - for (i = 0; i < sl->idx; ++i) - ADD_FLAG (sl->list[i], strlen (sl->list[i])); - } - } + { + struct stringlist *sl = *(struct stringlist **) cs->value_ptr; + if (sl != 0) + { + unsigned int i; + for (i = 0; i < sl->idx; ++i) + ADD_FLAG (sl->list[i], strlen (sl->list[i])); + } + } break; default: @@ -2892,8 +3607,7 @@ define_makeflags (int all, int makefile) { /* Long options require a double-dash. */ *p++ = '-'; - strcpy (p, flags->cs->long_name); - p += strlen (p); + p = stpcpy (p, flags->cs->long_name); } /* An omitted optional argument has an ARG of "". */ if (flags->arg && flags->arg[0] != '\0') @@ -2925,32 +3639,27 @@ define_makeflags (int all, int makefile) if (eval_strings) { *p++ = ' '; - memcpy (p, evalref, CSTRLEN (evalref)); - p += CSTRLEN (evalref); + p = mempcpy (p, evalref, CSTRLEN (evalref)); } - if (all) - { - /* If there are any overrides to add, write a reference to - $(MAKEOVERRIDES), which contains command-line variable definitions. - Separate the variables from the switches with a "--" arg. */ + { + /* If there are any overrides to add, write a reference to + $(MAKEOVERRIDES), which contains command-line variable definitions. + Separate the variables from the switches with a "--" arg. */ - const char *r = posix_pedantic ? posixref : ref; - size_t l = strlen (r); - struct variable *v = lookup_variable (r, l); + const char *r = posix_pedantic ? posixref : ref; + size_t l = strlen (r); + v = lookup_variable (r, l); - if (v && v->value && v->value[0] != '\0') - { - strcpy (p, " -- "); - p += 4; - - *(p++) = '$'; - *(p++) = '('; - memcpy (p, r, l); - p += l; - *(p++) = ')'; - } - } + if (v && v->value && v->value[0] != '\0') + { + p = stpcpy (p, " -- "); + *(p++) = '$'; + *(p++) = '('; + p = mempcpy (p, r, l); + *(p++) = ')'; + } + } /* If there is a leading dash, omit it. */ if (flagstring[0] == '-') @@ -2962,8 +3671,24 @@ define_makeflags (int all, int makefile) lost when users added -e, causing a previous MAKEFLAGS env. var. to take precedence over the new one. Of course, an override or command definition will still take precedence. */ - return define_variable_cname ("MAKEFLAGS", flagstring, - env_overrides ? o_env_override : o_file, 1); + v = define_variable_cname (MAKEFLAGS_NAME, flagstring, + env_overrides ? o_env_override : o_file, 1); + v->special = 1; + + return v; +} + +/* Return 1 if the working directory change message should be printed. + Otherwise, return 0. */ +int +should_print_dir (void) +{ + if (print_directory_flag >= 0) + return print_directory_flag; + + /* If the user didn't specify any print-directory options, compute the + default setting: disable under -s / print in sub-makes and under -C. */ + return !silent_flag && (makelevel > 0 || directories != NULL); } /* Print version information. */ @@ -2979,8 +3704,7 @@ print_version (void) /* Do it only once. */ return; - printf ("%sLandlock Make " LANDLOCKMAKE_VERSION " (GNU Make %s)\n", - precede, version_string); + printf ("%sGNU Make %s\n", precede, version_string); if (!remote_description || *remote_description == '\0') printf (_("%sBuilt for %s\n"), precede, make_host); @@ -2993,21 +3717,15 @@ print_version (void) year, and none of the rest of it should be translated (including the word "Copyright"), so it hardly seems worth it. */ - printf ("%sCopyright (C) 2022 Justine Alexandra Roberts Tunney\n", - precede); - printf ("%sCopyright (C) 1988-2020 Free Software Foundation, Inc.\n", + printf ("%sCopyright (C) 1988-2023 Free Software Foundation, Inc.\n", precede); - printf (_("%sLicense GPLv3+: GNU GPL version 3 or later \n\ + printf (_("%sLicense GPLv3+: GNU GPL version 3 or later \n\ %sThis is free software: you are free to change and redistribute it.\n\ %sThere is NO WARRANTY, to the extent permitted by law.\n"), precede, precede, precede); printed_version = 1; - - /* Flush stdout so the user doesn't have to wait to see the - version information while make thinks about things. */ - fflush (stdout); } /* Print a bunch of information about this and that. */ @@ -3085,6 +3803,9 @@ die (int status) if (print_version_flag) print_version (); + /* Get rid of a temp file from reading a makefile from stdin. */ + temp_stdin_unlink (); + /* Wait for children to die. */ err = (status != 0); while (job_slots_used > 0) @@ -3118,6 +3839,8 @@ die (int status) output_close (NULL); + osync_clear (); + /* Try to move back to the original directory. This is essential on MS-DOS (where there is really only one process), and on Unix it puts core files in the original directory instead of the -C diff --git a/third_party/make/makeint.inc b/third_party/make/makeint.h similarity index 65% rename from third_party/make/makeint.inc rename to third_party/make/makeint.h index 7ba9c3732..6547e8a06 100644 --- a/third_party/make/makeint.inc +++ b/third_party/make/makeint.h @@ -1,5 +1,5 @@ /* Miscellaneous global declarations and portability cruft for GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,59 +12,27 @@ 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 . */ - -#include "libc/assert.h" -#include "libc/calls/calls.h" -#include "libc/calls/makedev.h" -#include "libc/calls/struct/rlimit.h" -#include "libc/calls/struct/rusage.h" -#include "libc/calls/struct/sigaction.h" -#include "libc/calls/struct/siginfo.h" -#include "libc/calls/struct/stat.h" -#include "libc/calls/struct/stat.macros.h" -#include "libc/calls/weirdtypes.h" -#include "libc/errno.h" -#include "libc/fmt/conv.h" -#include "libc/limits.h" -#include "libc/log/log.h" -#include "libc/macros.internal.h" -#include "libc/mem/alg.h" -#include "libc/mem/alloca.h" -#include "libc/mem/mem.h" -#include "libc/runtime/stack.h" -#include "libc/stdio/stdio.h" -#include "libc/str/locale.h" -#include "libc/str/str.h" -#include "libc/sysv/consts/f.h" -#include "libc/sysv/consts/o.h" -#include "libc/sysv/consts/prio.h" -#include "libc/sysv/consts/rlim.h" -#include "libc/sysv/consts/rlimit.h" -#include "libc/sysv/consts/rusage.h" -#include "libc/sysv/consts/s.h" -#include "libc/sysv/consts/sa.h" -#include "libc/sysv/consts/sicode.h" -#include "libc/sysv/consts/w.h" -#include "libc/temp.h" -#include "libc/time/struct/tm.h" -#include "libc/time/time.h" -#include "third_party/gdtoa/gdtoa.h" -#include "third_party/musl/glob.h" +this program. If not, see . */ /* We use instead of "config.h" so that a compilation using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h (which it would do because makeint.h was found in $srcdir). */ -#include "third_party/make/config.h" -#pragma GCC diagnostic ignored "-Wredundant-decls" -#undef HAVE_CONFIG_H -#define HAVE_CONFIG_H 1 +#include "config.h" -/* Specify we want GNU source code. This must be defined before any - system headers are included. */ +/* Some versions of GCC (e.g., 10.x) set the warn_unused_result attribute on + __builtin_alloca. This causes alloca(0) to fail and is not easily worked + around so avoid it via the preprocessor. + See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98055 */ -#define POSIX 1 -#define _GNU_SOURCE 1 +#if defined (__has_builtin) +# if __has_builtin (__builtin_alloca) +# define free_alloca() +# else +# define free_alloca() alloca (0) +# endif +#else +# define free_alloca() alloca (0) +#endif /* Disable assert() unless we're a maintainer. Some asserts are compute-intensive. */ @@ -79,23 +47,106 @@ this program. If not, see . */ #ifdef WINDOWS32 # define GMK_BUILDING_MAKE #endif -#include "third_party/make/gnumake.h" +#include "gnumake.h" + +#ifdef CRAY +/* This must happen before #include so + that the declaration therein is changed. */ +# define signal bsdsignal +#endif /* If we're compiling for the dmalloc debugger, turn off string inlining. */ #if defined(HAVE_DMALLOC_H) && defined(__GNUC__) # define __NO_STRING_INLINES #endif -#ifndef RETSIGTYPE -# define RETSIGTYPE void +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_TIMEB_H +/* SCO 3.2 "devsys 4.2" has a prototype for 'ftime' in that bombs + unless has been included first. */ +# include +#endif +#if HAVE_SYS_TIME_H +# include +#endif +#include + +#include + +#ifndef errno +extern int errno; +#endif + +/* Define macros specifying which OS we are building for. */ +#if __gnu_hurd__ +# define MK_OS_HURD 1 +#endif +#if __CYGWIN__ +# define MK_OS_CYGWIN 1 +#endif +#if defined(__MVS__) +# define MK_OS_ZOS 1 +#endif + +#ifdef __VMS +/* In strict ANSI mode, VMS compilers should not be defining the + VMS macro. Define it here instead of a bulk edit for the correct code. + */ +# ifndef VMS +# define VMS +# endif +#endif + +#ifdef HAVE_UNISTD_H +# include +/* Ultrix's unistd.h always defines _POSIX_VERSION, but you only get + POSIX.1 behavior with 'cc -YPOSIX', which predefines POSIX itself! */ +# if defined (_POSIX_VERSION) && !defined (ultrix) && !defined (VMS) +# define POSIX 1 +# endif +#endif + +/* Some systems define _POSIX_VERSION but are not really POSIX.1. */ +#if (defined (butterfly) || (defined (__mips) && defined (_SYSTYPE_SVR3)) || (defined (sequent) && defined (i386))) +# undef POSIX +#endif + +#if !defined (POSIX) && defined (_AIX) && defined (_POSIX_SOURCE) +# define POSIX 1 #endif #ifndef sigmask # define sigmask(sig) (1 << ((sig) - 1)) #endif -#ifndef MAXPATHLEN -# define MAXPATHLEN 1024 +#ifndef HAVE_SA_RESTART +# define SA_RESTART 0 +#endif + +#ifdef HAVE_VFORK_H +# include +#endif + +#ifdef HAVE_LIMITS_H +# include +#endif +#ifdef HAVE_SYS_PARAM_H +# include +#endif + +#ifndef PATH_MAX +# ifdef MAXPATHLEN +# define PATH_MAX MAXPATHLEN +# else +/* Some systems (HURD) have fully dynamic pathnames with no maximum. + Ideally we'd support this but it will take some work. */ +# define PATH_MAX 4096 +# endif #endif #ifdef PATH_MAX @@ -139,6 +190,30 @@ unsigned int get_path_max (void); # endif #endif /* STAT_MACROS_BROKEN. */ +#ifndef S_ISREG +# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) +#endif +#ifndef S_ISDIR +# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +#endif + +#ifdef VMS +# include +# include +# include +# include +# include +/* Needed to use alloca on VMS. */ +# include + +extern int vms_use_mcr_command; +extern int vms_always_use_cmd_file; +extern int vms_gnv_shell; +extern int vms_comma_separator; +extern int vms_legacy_behavior; +extern int vms_unix_simulation; +#endif + #if !defined(__attribute__) && (__GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__) /* Don't use __attribute__ if it's not supported. */ # define ATTRIBUTE(x) @@ -157,16 +232,26 @@ unsigned int get_path_max (void); #define NORETURN ATTRIBUTE ((noreturn)) #if defined (STDC_HEADERS) || defined (__GNU_LIBRARY__) +# include +# include # define ANSI_STRING 1 #else /* No standard headers. */ # ifdef HAVE_STRING_H +# include # define ANSI_STRING 1 -# else # endif # ifdef HAVE_MEMORY_H +# include # endif # ifdef HAVE_STDLIB_H +# include # else +void *malloc (int); +void *realloc (void *, int); +void free (void *); + +void abort (void) NORETURN; +void exit (int) NORETURN; # endif /* HAVE_STDLIB_H. */ #endif /* Standard headers. */ @@ -180,6 +265,7 @@ unsigned int get_path_max (void); #endif #ifndef ANSI_STRING + /* SCO Xenix has a buggy macro definition in . */ #undef strerror #if !defined(__DECC) @@ -189,6 +275,31 @@ char *strerror (int errnum); #endif /* !ANSI_STRING. */ #undef ANSI_STRING +#if HAVE_INTTYPES_H +# include +#endif +#if HAVE_STDINT_H +# include +#endif + +#if HAVE_STRINGS_H +# include /* Needed for strcasecmp / strncasecmp. */ +#endif + +#if defined _MSC_VER || defined __MINGW32__ +# define MK_PRI64_PREFIX "I64" +#else +# define MK_PRI64_PREFIX "ll" +#endif +#ifndef PRIdMAX +# define PRIdMAX MK_PRI64_PREFIX "d" +#endif +#ifndef PRIuMAX +# define PRIuMAX MK_PRI64_PREFIX "u" +#endif +#ifndef SCNdMAX +# define SCNdMAX PRIdMAX +#endif #define FILE_TIMESTAMP uintmax_t #if !defined(HAVE_STRSIGNAL) @@ -238,13 +349,26 @@ extern mode_t umask (mode_t); /* Handle gettext and locales. */ -#include "third_party/make/gettext.h" +#if HAVE_LOCALE_H +# include +#else +# define setlocale(category, locale) +#endif + +#include "gettext.h" #define _(msgid) gettext (msgid) #define N_(msgid) gettext_noop (msgid) #define S_(msg1,msg2,num) ngettext (msg1,msg2,num) +/* This is needed for getcwd() and chdir(), on some W32 systems. */ +#if defined(HAVE_DIRECT_H) +# include +#endif + #ifdef WINDOWS32 +# include +# include # define pipe(_p) _pipe((_p), 512, O_BINARY) # define kill(_pid,_sig) w32_kill((_pid),(_sig)) /* MSVC and Watcom C don't have ftruncate. */ @@ -272,14 +396,19 @@ extern int unixy_shell; # endif /* Include only the minimal stuff from windows.h. */ -# define WIN32_LEAN_AND_MEAN +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif #endif /* WINDOWS32 */ +/* ALL_SET() evaluates the second argument twice. */ #define ANY_SET(_v,_m) (((_v)&(_m)) != 0) #define NONE_SET(_v,_m) (! ANY_SET ((_v),(_m))) +#define ALL_SET(_v,_m) (((_v)&(_m)) == (_m)) +/* Bitmasks for the STOPCHAR array. */ #define MAP_NUL 0x0001 -#define MAP_BLANK 0x0002 +#define MAP_BLANK 0x0002 /* space, TAB */ #define MAP_NEWLINE 0x0004 #define MAP_COMMENT 0x0008 #define MAP_SEMI 0x0010 @@ -297,7 +426,11 @@ extern int unixy_shell; /* The set of characters which are directory separators is OS-specific. */ #define MAP_DIRSEP 0x8000 -#define MAP_VMSCOMMA 0x0000 +#ifdef VMS +# define MAP_VMSCOMMA MAP_COMMA +#else +# define MAP_VMSCOMMA 0x0000 +#endif #define MAP_SPACE (MAP_BLANK|MAP_NEWLINE) @@ -323,27 +456,58 @@ extern int unixy_shell; # define MAP_PATHSEP MAP_SEMI #elif PATH_SEPARATOR_CHAR == ',' # define MAP_PATHSEP MAP_COMMA + #else # error "Unknown PATH_SEPARATOR_CHAR" #endif #define STOP_SET(_v,_m) ANY_SET(stopchar_map[(unsigned char)(_v)],(_m)) +/* True if C is whitespace but not newline. */ #define ISBLANK(c) STOP_SET((c),MAP_BLANK) +/* True if C is whitespace including newlines. */ #define ISSPACE(c) STOP_SET((c),MAP_SPACE) +/* True if C is nul or whitespace (including newline). */ +#define END_OF_TOKEN(c) STOP_SET((c),MAP_SPACE|MAP_NUL) +/* Move S past all whitespace (including newlines). */ #define NEXT_TOKEN(s) while (ISSPACE (*(s))) ++(s) -#define END_OF_TOKEN(s) while (! STOP_SET (*(s), MAP_SPACE|MAP_NUL)) ++(s) + +/* True if C is a directory separator on the current system. */ +#define ISDIRSEP(c) STOP_SET((c),MAP_DIRSEP) + +/* True if S starts with a drive specifier. */ +#if defined(HAVE_DOS_PATHS) +# define HAS_DRIVESPEC(_s) ((((_s)[0] >= 'a' && (_s)[0] <= 'z') \ + || ((_s)[0] >= 'A' && (_s)[0] <= 'Z')) \ + && (_s)[1] == ':') +#else +# define HAS_DRIVESPEC(_s) 0 +#endif /* We can't run setrlimit when using posix_spawn. */ +#if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) && !defined(USE_POSIX_SPAWN) +# define SET_STACK_SIZE +#endif +#ifdef SET_STACK_SIZE +# include extern struct rlimit stack_limit; +#endif + +#include "glob.h" #define NILF ((floc *)0) +/* Number of characters in a string constant. Does NOT include the \0 byte. */ #define CSTRLEN(_s) (sizeof (_s)-1) + +/* Only usable when NOT calling a macro: only use it for local functions. */ #define STRING_SIZE_TUPLE(_s) (_s), CSTRLEN(_s) -/* The number of bytes needed to represent the largest integer as a string. */ -#define INTSTR_LENGTH CSTRLEN ("18446744073709551616") +/* The number of bytes needed to represent the largest signed and unsigned + integers as a string. + Does NOT include space for \0 so be sure to add it if needed. + Math suggested by Edward Welbourne */ +#define INTSTR_LENGTH (53 * sizeof(uintmax_t) / 22 + 3) #define DEFAULT_TTYNAME "true" #ifdef HAVE_TTYNAME @@ -352,8 +516,19 @@ extern struct rlimit stack_limit; # define TTYNAME(_f) DEFAULT_TTYNAME #endif +#ifdef VMS +# define DEFAULT_TMPDIR "/sys$scratch/" +#elif defined(P_tmpdir) +# define DEFAULT_TMPDIR P_tmpdir +#else +# define DEFAULT_TMPDIR "/tmp" +#endif + + +struct file; + /* Specify the location of elements read from makefiles. */ typedef struct { @@ -369,7 +544,7 @@ void error (const floc *flocp, size_t length, const char *fmt, ...) ATTRIBUTE ((__format__ (__printf__, 3, 4))); void fatal (const floc *flocp, size_t length, const char *fmt, ...) ATTRIBUTE ((noreturn, __format__ (__printf__, 3, 4))); -void out_of_memory () NORETURN; +void out_of_memory (void) NORETURN; /* When adding macros to this list be sure to update the value of XGETTEXT_OPTIONS in the po/Makevars file. */ @@ -387,11 +562,25 @@ void out_of_memory () NORETURN; #define ONS(_t,_a,_f,_n,_s) _t((_a), INTSTR_LENGTH + strlen (_s), \ (_f), (_n), (_s)) +enum variable_origin; +struct variable; + +void reset_makeflags (enum variable_origin origin); +struct variable *define_makeflags (int makefile); +int should_print_dir (void); +void temp_stdin_unlink (void); void die (int) NORETURN; void pfatal_with_name (const char *) NORETURN; void perror_with_name (const char *, const char *); #define xstrlen(_s) ((_s)==NULL ? 0 : strlen (_s)) +unsigned int make_toui (const char*, const char**); +char *make_lltoa (long long, char *); +char *make_ulltoa (unsigned long long, char *); +void make_seed (unsigned int); +unsigned int make_rand (void); +pid_t make_pid (void); void *xmalloc (size_t); +void *xcalloc (size_t); void *xrealloc (void *, size_t); char *xstrdup (const char *); char *xstrndup (const char *, size_t); @@ -404,23 +593,30 @@ int alpha_compare (const void *, const void *); void print_spaces (unsigned int); char *find_percent (char *); const char *find_percent_cached (const char **); -FILE *get_tmpfile (char **, const char *); +const char *get_tmpdir (void); +int get_tmpfd (char **); +FILE *get_tmpfile (char **); ssize_t writebuf (int, const void *, size_t); ssize_t readbuf (int, void *, size_t); +#ifndef HAVE_MEMRCHR +void *memrchr(const void *, int, size_t); +#endif + #ifndef NO_ARCHIVES int ar_name (const char *); void ar_parse_name (const char *, char **, char **); int ar_touch (const char *); time_t ar_member_date (const char *); -typedef long int (*ar_member_func_t) (int desc, const char *mem, int truncated, +typedef intmax_t (*ar_member_func_t) (int desc, const char *mem, int truncated, long int hdrpos, long int datapos, - long int size, long int date, int uid, + long int size, intmax_t date, int uid, int gid, unsigned int mode, const void *arg); -long int ar_scan (const char *archive, ar_member_func_t function, const void *arg); +intmax_t ar_scan (const char *archive, ar_member_func_t function, + const void *arg); int ar_name_equal (const char *name, const char *mem, int truncated); #ifndef VMS int ar_member_touch (const char *arname, const char *memname); @@ -450,10 +646,6 @@ int gpath_search (const char *file, size_t len); void construct_include_path (const char **arg_dirs); -void user_access (void); -void make_access (void); -void child_access (void); - char *strip_whitespace (const char **begpp, const char **endpp); void show_goal_error (void); @@ -470,15 +662,19 @@ int guile_gmake_setup (const floc *flocp); /* Loadable object support. Sets to the strcached name of the loaded file. */ typedef int (*load_func_t)(const floc *flocp); -int load_file (const floc *flocp, const char **filename, int noerror); -void unload_file (const char *name); +int load_file (const floc *flocp, struct file *file, int noerror); +int unload_file (const char *name); /* Maintainer mode support */ #ifdef MAKE_MAINTAINER_MODE # define SPIN(_s) spin (_s) void spin (const char* suffix); +# define DBG(_f) dbg _f +void dbg (const char *fmt, ...); #else # define SPIN(_s) +/* Never put this code into Git or a release. */ +# define DBG(_f) compile-error #endif /* We omit these declarations on non-POSIX systems which define _POSIX_VERSION, @@ -486,17 +682,16 @@ void spin (const char* suffix); #if !defined (__GNU_LIBRARY__) && !defined (POSIX) && !defined (_POSIX_VERSION) && !defined(WINDOWS32) -long int atol (); # ifndef VMS long int lseek (); # endif # ifdef HAVE_GETCWD # if !defined(VMS) && !defined(__DECC) -char *getcwd (); +char *getcwd (void); # endif # else -char *getwd (); +char *getwd (void); # define getcwd(buf, len) getwd (buf) # endif @@ -507,9 +702,6 @@ char *getwd (); # define strcasecmp stricmp # elif HAVE_STRCMPI # define strcasecmp strcmpi -# else -/* Create our own, in misc.c */ -int strcasecmp (const char *s1, const char *s2); # endif #endif @@ -518,9 +710,6 @@ int strcasecmp (const char *s1, const char *s2); # define strncasecmp strnicmp # elif HAVE_STRNCMPI # define strncasecmp strncmpi -# else -/* Create our own, in misc.c */ -int strncasecmp (const char *s1, const char *s2, int n); # endif #endif @@ -540,21 +729,38 @@ extern unsigned short stopchar_map[]; extern int just_print_flag, run_silent, ignore_errors_flag, keep_going_flag; extern int print_data_base_flag, question_flag, touch_flag, always_make_flag; extern int env_overrides, no_builtin_rules_flag, no_builtin_variables_flag; -extern int print_version_flag, print_directory_flag, check_symlink_flag; -extern int warn_undefined_variables_flag, trace_flag, posix_pedantic; +extern int print_version_flag, check_symlink_flag; +extern int warn_undefined_variables_flag, posix_pedantic; extern int not_parallel, second_expansion, clock_skew_detected; extern int rebuilding_makefiles, one_shell, output_sync, verify_flag; +extern unsigned long command_count; extern const char *default_shell; /* can we run commands via 'sh -c xxx' or must we use batch files? */ extern int batch_mode_shell; +#define GNUMAKEFLAGS_NAME "GNUMAKEFLAGS" +#define MAKEFLAGS_NAME "MAKEFLAGS" + /* Resetting the command script introduction prefix character. */ -#define RECIPEPREFIX_NAME ".RECIPEPREFIX" -#define RECIPEPREFIX_DEFAULT '\t' +#define RECIPEPREFIX_NAME ".RECIPEPREFIX" +#define RECIPEPREFIX_DEFAULT '\t' extern char cmd_prefix; +extern unsigned int no_intermediates; + +#if HAVE_MKFIFO +/* It seems that mkfifo() is not working correctly, or at least not the way + GNU make wants it to work, on GNU/Hurd and Cygwin so don't use it there. */ +# if !defined(JOBSERVER_USE_FIFO) && !MK_OS_HURD && !MK_OS_CYGWIN +# define JOBSERVER_USE_FIFO 1 +# endif +#endif + +#define JOBSERVER_AUTH_OPT "jobserver-auth" + +extern char *jobserver_auth; extern unsigned int job_slots; extern double max_load_average; @@ -607,7 +813,14 @@ extern char *version_string, *remote_description, *make_host; extern unsigned int commands_started; -extern int handling_fatal_signal; +extern volatile sig_atomic_t handling_fatal_signal; + +#ifndef MIN +#define MIN(_a,_b) ((_a)<(_b)?(_a):(_b)) +#endif +#ifndef MAX +#define MAX(_a,_b) ((_a)>(_b)?(_a):(_b)) +#endif #define MAKE_SUCCESS 0 #define MAKE_TROUBLE 1 @@ -615,6 +828,37 @@ extern int handling_fatal_signal; /* Set up heap debugging library dmalloc. */ +#ifdef HAVE_DMALLOC_H +#include +#endif + +#ifndef initialize_main +# ifdef __EMX__ +# define initialize_main(pargc, pargv) \ + { _wildcard(pargc, pargv); _response(pargc, pargv); } +# else +# define initialize_main(pargc, pargv) +# endif +#endif + +#ifdef __EMX__ +# if !defined chdir +# define chdir _chdir2 +# endif +# if !defined getcwd +# define getcwd _getcwd2 +# endif + +/* NO_CHDIR2 causes make not to use _chdir2() and _getcwd2() instead of + chdir() and getcwd(). This avoids some error messages for the + make testsuite but restricts the drive letter support. */ +# ifdef NO_CHDIR2 +# warning NO_CHDIR2: usage of drive letters restricted +# undef chdir +# undef getcwd +# endif +#endif + #ifndef initialize_main # define initialize_main(pargc, pargv) #endif diff --git a/third_party/make/misc.c b/third_party/make/misc.c index 0a06bd3ad..eb14f4051 100644 --- a/third_party/make/misc.c +++ b/third_party/make/misc.c @@ -1,5 +1,5 @@ /* Miscellaneous generic support functions for GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,15 +12,97 @@ 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 . */ +this program. If not, see . */ -#include "third_party/make/makeint.inc" -#include "third_party/make/filedef.h" -#include "third_party/make/dep.h" -#include "third_party/make/debug.h" -#include "libc/calls/calls.h" +#include "makeint.h" +#include "filedef.h" +#include "dep.h" +#include "os.h" +#include "debug.h" -/* GNU make no longer supports pre-ANSI89 environments. */ +#include +#include + +#ifdef WINDOWS32 +# include +# include +#endif + +#ifdef __EMX__ +# define INCL_DOS +# include +#endif + +#ifdef HAVE_FCNTL_H +# include +#else +# include +#endif + +unsigned int +make_toui (const char *str, const char **error) +{ + char *end; + unsigned long val = strtoul (str, &end, 10); + + if (error) + { + if (str[0] == '\0') + *error = "Missing value"; + else if (*end != '\0') + *error = "Invalid value"; + else + *error = NULL; + } + + return val; +} + +/* Convert val into a string, written to buf. buf must be large enough + to hold the largest possible value, plus a nul byte. Returns buf. + We can't use standard PRI* here: those are based on intNN_t types. */ + +char * +make_lltoa (long long val, char *buf) +{ + sprintf (buf, "%" MK_PRI64_PREFIX "d", val); + return buf; +} + +char * +make_ulltoa (unsigned long long val, char *buf) +{ + sprintf (buf, "%" MK_PRI64_PREFIX "u", val); + return buf; +} + +/* Simple random number generator, for use with shuffle. + This doesn't need to be truly random, just pretty random. Use our own + implementation rather than relying on the C runtime's rand() so we always + get the same results for a given seed, regardless of C runtime. */ + +static unsigned int mk_state = 0; + +void +make_seed (unsigned int seed) +{ + mk_state = seed; +} + +unsigned int +make_rand () +{ + /* mk_state must never be 0. */ + if (mk_state == 0) + mk_state = (unsigned int)(time (NULL) ^ make_pid ()) + 1; + + /* A simple xorshift RNG. */ + mk_state ^= mk_state << 13; + mk_state ^= mk_state >> 17; + mk_state ^= mk_state << 5; + + return mk_state; +} /* Compare strings *S1 and *S2. Return negative if the first is less, positive if it is greater, @@ -81,7 +163,7 @@ collapse_continuations (char *line) if (i & 1) { /* Backslash/newline handling: - In traditional GNU make all trailing whitespace, consecutive + In traditional GNU Make all trailing whitespace, consecutive backslash/newlines, and any leading non-newline whitespace on the next line is reduced to a single space. In POSIX, each backslash/newline and is replaced by a space. */ @@ -162,6 +244,85 @@ concat (unsigned int num, ...) } +#ifndef HAVE_UNISTD_H +pid_t getpid (); +#endif + +pid_t make_pid () +{ + return getpid (); +} + +/* Like malloc but get fatal error if memory is exhausted. */ +/* Don't bother if we're using dmalloc; it provides these for us. */ + +#ifndef HAVE_DMALLOC_H + +#undef xmalloc +#undef xcalloc +#undef xrealloc +#undef xstrdup + +void * +xmalloc (size_t size) +{ + /* Make sure we don't allocate 0, for pre-ISO implementations. */ + void *result = malloc (size ? size : 1); + if (result == 0) + out_of_memory (); + return result; +} + + +void * +xcalloc (size_t size) +{ + /* Make sure we don't allocate 0, for pre-ISO implementations. */ + void *result = calloc (size ? size : 1, 1); + if (result == 0) + out_of_memory (); + return result; +} + + +void * +xrealloc (void *ptr, size_t size) +{ + void *result; + + /* Some older implementations of realloc() don't conform to ISO. */ + if (! size) + size = 1; + result = ptr ? realloc (ptr, size) : malloc (size); + if (result == 0) + out_of_memory (); + return result; +} + + +char * +xstrdup (const char *ptr) +{ + char *result; + +#ifdef HAVE_STRDUP + result = strdup (ptr); +#else + result = malloc (strlen (ptr) + 1); +#endif + + if (result == 0) + out_of_memory (); + +#ifdef HAVE_STRDUP + return result; +#else + return strcpy (result, ptr); +#endif +} + +#endif /* HAVE_DMALLOC_H */ + char * xstrndup (const char *str, size_t length) { @@ -181,6 +342,29 @@ xstrndup (const char *str, size_t length) return result; } +#ifndef HAVE_MEMRCHR +void * +memrchr(const void* str, int ch, size_t len) +{ + const char* sp = str; + const char* cp = sp; + + if (len == 0) + return NULL; + + cp += len - 1; + + while (cp[0] != ch) + { + if (cp == sp) + return NULL; + --cp; + } + + return (void*)cp; +} +#endif + /* Limited INDEX: @@ -204,7 +388,8 @@ lindex (const char *s, const char *limit, int c) char * end_of_token (const char *s) { - END_OF_TOKEN (s); + while (! END_OF_TOKEN (*s)) + ++s; return (char *)s; } @@ -340,11 +525,31 @@ spin (const char* type) { fprintf (stderr, "SPIN on %s\n", filenm); do +#ifdef WINDOWS32 + Sleep (1000); +#else sleep (1); +#endif while (stat (filenm, &dummy) == 0); } } +void +dbg (const char *fmt, ...) +{ + FILE *fp = fopen ("/tmp/gmkdebug.log", "a+"); + va_list args; + char buf[4096]; + + va_start (args, fmt); + vsprintf (buf, fmt, args); + va_end (args); + + fprintf(fp, "%u: %s\n", (unsigned) make_pid (), buf); + fflush (fp); + fclose (fp); +} + #endif @@ -359,283 +564,314 @@ char *mktemp (char *template); # endif #endif -FILE * -get_tmpfile (char **name, const char *template) +#ifndef HAVE_UMASK +mode_t +umask (mode_t mask) { - FILE *file; -#ifdef HAVE_FDOPEN - int fd; + return 0; +} #endif +#ifdef VMS +# define DEFAULT_TMPFILE "sys$scratch:gnv$make_cmdXXXXXX.com" +#else +# define DEFAULT_TMPFILE "GmXXXXXX" +#endif + +const char * +get_tmpdir () +{ + static const char *tmpdir = NULL; + + if (!tmpdir) + { +#if defined (__MSDOS__) || defined (WINDOWS32) || defined (__EMX__) +# define TMP_EXTRAS "TMP", "TEMP", +#else +# define TMP_EXTRAS +#endif + const char *tlist[] = { "MAKE_TMPDIR", "TMPDIR", TMP_EXTRAS NULL }; + const char **tp; + unsigned int found = 0; + + for (tp = tlist; *tp; ++tp) + if ((tmpdir = getenv (*tp)) && *tmpdir != '\0') + { + struct stat st; + int r; + found = 1; + EINTRLOOP(r, stat (tmpdir, &st)); + if (r < 0) + OSSS (error, NILF, + _("%s value %s: %s"), *tp, tmpdir, strerror (errno)); + else if (! S_ISDIR (st.st_mode)) + OSS (error, NILF, + _("%s value %s: not a directory"), *tp, tmpdir); + else + return tmpdir; + } + + tmpdir = DEFAULT_TMPDIR; + + if (found) + OS (error, NILF, _("using default temporary directory '%s'"), tmpdir); + } + + return tmpdir; +} + +static char * +get_tmptemplate () +{ + const char *tmpdir = get_tmpdir (); + char *template; + char *cp; + + template = xmalloc (strlen (tmpdir) + CSTRLEN (DEFAULT_TMPFILE) + 2); + cp = stpcpy (template, tmpdir); + +#if !defined VMS + /* It's not possible for tmpdir to be empty. */ + if (! ISDIRSEP (cp[-1])) + *(cp++) = '/'; +#endif + + strcpy (cp, DEFAULT_TMPFILE); + + return template; +} + +#if !HAVE_MKSTEMP || !HAVE_FDOPEN +/* Generate a temporary filename. This is not safe as another program could + snipe our filename after we've generated it: use this only on systems + without more secure alternatives. */ + +static char * +get_tmppath () +{ + char *path; + +# ifdef HAVE_MKTEMP + path = get_tmptemplate (); + if (*mktemp (path) == '\0') + { + OSS (error, NILF, + _("cannot generate temp path from %s: %s"), path, strerror (errno)); + return NULL; + } +# else + path = xmalloc (L_tmpnam + 1); + if (tmpnam (path) == NULL) + { + OS (error, NILF, + _("cannot generate temp name: %s"), strerror (errno)); + return NULL; + } +# endif + + return path; +} +#endif + +/* Generate a temporary file and return an fd for it. If name is NULL then + the temp file is anonymous and will be deleted when the process exits. If + name is not null then *name will point to an allocated buffer, or set to + NULL on failure. */ +int +get_tmpfd (char **name) +{ + int fd = -1; + char *tmpnm; + mode_t mask; + + if (name) + *name = NULL; + else + { + /* If there's an os-specific way to get an anonymous temp file use it. */ + fd = os_anontmp (); + if (fd >= 0) + return fd; + } + + /* Preserve the current umask, and set a restrictive one for temp files. + Only really needed for mkstemp() but won't hurt for the open method. */ + mask = umask (0077); + +#if defined(HAVE_MKSTEMP) + tmpnm = get_tmptemplate (); + + /* It's safest to use mkstemp(), if we can. */ + EINTRLOOP (fd, mkstemp (tmpnm)); +#else + tmpnm = get_tmppath (); + if (!tmpnm) + return -1; + + /* Can't use mkstemp(), but try to guard against a race condition. */ + EINTRLOOP (fd, open (tmpnm, O_CREAT|O_EXCL|O_RDWR, 0600)); +#endif + if (fd < 0) + { + OSS (error, NILF, + _("cannot create temporary file %s: %s"), tmpnm, strerror (errno)); + free (tmpnm); + return -1; + } + + if (name) + *name = tmpnm; + else + { + int r; + EINTRLOOP (r, unlink (tmpnm)); + if (r < 0) + OSS (error, NILF, + _("cannot unlink temporary file %s: %s"), tmpnm, strerror (errno)); + free (tmpnm); + } + + umask (mask); + + return fd; +} + +/* Return a FILE* for a temporary file, opened in the safest way possible. + Set name to point to an allocated buffer containing the name of the file, + or NULL on failure. Note, name cannot be NULL! */ +FILE * +get_tmpfile (char **name) +{ + /* Be consistent with tmpfile, which opens as if by "wb+". */ + const char *tmpfile_mode = "wb+"; + FILE *file; + +#if defined(HAVE_FDOPEN) + int fd; + assert (name); + fd = get_tmpfd (name); + if (fd < 0) + return NULL; + assert (*name); + + ENULLLOOP (file, fdopen (fd, tmpfile_mode)); + if (file == NULL) + OSS (error, NILF, + _("fdopen: temporary file %s: %s"), *name, strerror (errno)); +#else /* Preserve the current umask, and set a restrictive one for temp files. */ mode_t mask = umask (0077); -#if defined(HAVE_MKSTEMP) || defined(HAVE_MKTEMP) -# define TEMPLATE_LEN strlen (template) -#else -# define TEMPLATE_LEN L_tmpnam -#endif - *name = xmalloc (TEMPLATE_LEN + 1); - strcpy (*name, template); + assert (name); + *name = get_tmppath (); + if (!*name) + return NULL; -#if defined(HAVE_MKSTEMP) && defined(HAVE_FDOPEN) - /* It's safest to use mkstemp(), if we can. */ - EINTRLOOP (fd, mkstemp (*name)); - if (fd == -1) - file = NULL; - else - file = fdopen (fd, "w"); -#else -# ifdef HAVE_MKTEMP - (void) mktemp (*name); -# else - (void) tmpnam (*name); -# endif + /* Although this fopen is insecure, it is executed only on non-fdopen + platforms, which should be a rarity nowadays. */ -# ifdef HAVE_FDOPEN - /* Can't use mkstemp(), but guard against a race condition. */ - EINTRLOOP (fd, open (*name, O_CREAT|O_EXCL|O_WRONLY, 0600)); - if (fd == -1) - return 0; - file = fdopen (fd, "w"); -# else - /* Not secure, but what can we do? */ - file = fopen (*name, "w"); -# endif -#endif + ENULLLOOP (file, fopen (*name, tmpfile_mode)); + if (file == NULL) + { + OSS (error, NILF, + _("fopen: temporary file %s: %s"), *name, strerror (errno)); + free (*name); + *name = NULL; + } umask (mask); +#endif return file; } -#ifdef GETLOADAVG_PRIVILEGED -#ifdef POSIX - -/* Hopefully if a system says it's POSIX.1 and has the setuid and setgid - functions, they work as POSIX.1 says. Some systems (Alpha OSF/1 1.2, - for example) which claim to be POSIX.1 also have the BSD setreuid and - setregid functions, but they don't work as in BSD and only the POSIX.1 - way works. */ - -#undef HAVE_SETREUID -#undef HAVE_SETREGID - -#else /* Not POSIX. */ - -/* Some POSIX.1 systems have the seteuid and setegid functions. In a - POSIX-like system, they are the best thing to use. However, some - non-POSIX systems have them too but they do not work in the POSIX style - and we must use setreuid and setregid instead. */ - -#undef HAVE_SETEUID -#undef HAVE_SETEGID - -#endif /* POSIX. */ - -/* Keep track of the user and group IDs for user- and make- access. */ -static int user_uid = -1, user_gid = -1, make_uid = -1, make_gid = -1; -#define access_inited (user_uid != -1) -static enum { make, user } current_access; - - -/* Under -d, write a message describing the current IDs. */ - -static void -log_access (const char *flavor) +#if HAVE_TTYNAME && defined(__EMX__) +/* OS/2 kLIBC has a declaration for ttyname(), so configure finds it. + But, it is not implemented! Roll our own. */ +char *ttyname (int fd) { - if (! ISDB (DB_JOBS)) - return; + ULONG type; + ULONG attr; + ULONG rc; - /* All the other debugging messages go to stdout, - but we write this one to stderr because it might be - run in a child fork whose stdout is piped. */ + rc = DosQueryHType (fd, &type, &attr); + if (rc) + { + errno = EBADF; + return NULL; + } - fprintf (stderr, _("%s: user %lu (real %lu), group %lu (real %lu)\n"), - flavor, (unsigned long) geteuid (), (unsigned long) getuid (), - (unsigned long) getegid (), (unsigned long) getgid ()); - fflush (stderr); + if (type == HANDTYPE_DEVICE) + { + if (attr & 3) /* 1 = KBD$, 2 = SCREEN$ */ + return (char *) "/dev/con"; + + if (attr & 4) /* 4 = NUL */ + return (char *) "/dev/nul"; + + if (attr & 8) /* 8 = CLOCK$ */ + return (char *) "/dev/clock$"; + } + + errno = ENOTTY; + return NULL; } +#endif + +#if !HAVE_STRCASECMP && !HAVE_STRICMP && !HAVE_STRCMPI +/* If we don't have strcasecmp() (from POSIX), or anything that can substitute + for it, define our own version. */ -static void -init_access (void) +int +strcasecmp (const char *s1, const char *s2) { - user_uid = getuid (); - user_gid = getgid (); + while (1) + { + int c1 = (unsigned char) *(s1++); + int c2 = (unsigned char) *(s2++); - make_uid = geteuid (); - make_gid = getegid (); + if (isalpha (c1)) + c1 = tolower (c1); + if (isalpha (c2)) + c2 = tolower (c2); - /* Do these ever fail? */ - if (user_uid == -1 || user_gid == -1 || make_uid == -1 || make_gid == -1) - pfatal_with_name ("get{e}[gu]id"); + if (c1 != '\0' && c1 == c2) + continue; - log_access (_("Initialized access")); - - current_access = make; + return (c1 - c2); + } } +#endif -#endif /* GETLOADAVG_PRIVILEGED */ +#if !HAVE_STRNCASECMP && !HAVE_STRNICMP && !HAVE_STRNCMPI +/* If we don't have strncasecmp() (from POSIX), or anything that can + substitute for it, define our own version. */ -/* Give the process appropriate permissions for access to - user data (i.e., to stat files, or to spawn a child process). */ -void -user_access (void) +int +strncasecmp (const char *s1, const char *s2, size_t n) { -#ifdef GETLOADAVG_PRIVILEGED + while (n-- > 0) + { + int c1 = (unsigned char) *(s1++); + int c2 = (unsigned char) *(s2++); - if (!access_inited) - init_access (); + if (isalpha (c1)) + c1 = tolower (c1); + if (isalpha (c2)) + c2 = tolower (c2); - if (current_access == user) - return; + if (c1 != '\0' && c1 == c2) + continue; - /* We are in "make access" mode. This means that the effective user and - group IDs are those of make (if it was installed setuid or setgid). - We now want to set the effective user and group IDs to the real IDs, - which are the IDs of the process that exec'd make. */ + return (c1 - c2); + } -#ifdef HAVE_SETEUID - - /* Modern systems have the seteuid/setegid calls which set only the - effective IDs, which is ideal. */ - - if (seteuid (user_uid) < 0) - pfatal_with_name ("user_access: seteuid"); - -#else /* Not HAVE_SETEUID. */ - -#ifndef HAVE_SETREUID - - /* System V has only the setuid/setgid calls to set user/group IDs. - There is an effective ID, which can be set by setuid/setgid. - It can be set (unless you are root) only to either what it already is - (returned by geteuid/getegid, now in make_uid/make_gid), - the real ID (return by getuid/getgid, now in user_uid/user_gid), - or the saved set ID (what the effective ID was before this set-ID - executable (make) was exec'd). */ - - if (setuid (user_uid) < 0) - pfatal_with_name ("user_access: setuid"); - -#else /* HAVE_SETREUID. */ - - /* In 4BSD, the setreuid/setregid calls set both the real and effective IDs. - They may be set to themselves or each other. So you have two alternatives - at any one time. If you use setuid/setgid, the effective will be set to - the real, leaving only one alternative. Using setreuid/setregid, however, - you can toggle between your two alternatives by swapping the values in a - single setreuid or setregid call. */ - - if (setreuid (make_uid, user_uid) < 0) - pfatal_with_name ("user_access: setreuid"); - -#endif /* Not HAVE_SETREUID. */ -#endif /* HAVE_SETEUID. */ - -#ifdef HAVE_SETEGID - if (setegid (user_gid) < 0) - pfatal_with_name ("user_access: setegid"); -#else -#ifndef HAVE_SETREGID - if (setgid (user_gid) < 0) - pfatal_with_name ("user_access: setgid"); -#else - if (setregid (make_gid, user_gid) < 0) - pfatal_with_name ("user_access: setregid"); -#endif -#endif - - current_access = user; - - log_access (_("User access")); - -#endif /* GETLOADAVG_PRIVILEGED */ + return 0; } - -/* Give the process appropriate permissions for access to - make data (i.e., the load average). */ -void -make_access (void) -{ -#ifdef GETLOADAVG_PRIVILEGED - - if (!access_inited) - init_access (); - - if (current_access == make) - return; - - /* See comments in user_access, above. */ - -#ifdef HAVE_SETEUID - if (seteuid (make_uid) < 0) - pfatal_with_name ("make_access: seteuid"); -#else -#ifndef HAVE_SETREUID - if (setuid (make_uid) < 0) - pfatal_with_name ("make_access: setuid"); -#else - if (setreuid (user_uid, make_uid) < 0) - pfatal_with_name ("make_access: setreuid"); #endif -#endif - -#ifdef HAVE_SETEGID - if (setegid (make_gid) < 0) - pfatal_with_name ("make_access: setegid"); -#else -#ifndef HAVE_SETREGID - if (setgid (make_gid) < 0) - pfatal_with_name ("make_access: setgid"); -#else - if (setregid (user_gid, make_gid) < 0) - pfatal_with_name ("make_access: setregid"); -#endif -#endif - - current_access = make; - - log_access (_("Make access")); - -#endif /* GETLOADAVG_PRIVILEGED */ -} - -/* Give the process appropriate permissions for a child process. - This is like user_access, but you can't get back to make_access. */ -void -child_access (void) -{ -#ifdef GETLOADAVG_PRIVILEGED - - if (!access_inited) - abort (); - - /* Set both the real and effective UID and GID to the user's. - They cannot be changed back to make's. */ - -#ifndef HAVE_SETREUID - if (setuid (user_uid) < 0) - pfatal_with_name ("child_access: setuid"); -#else - if (setreuid (user_uid, user_uid) < 0) - pfatal_with_name ("child_access: setreuid"); -#endif - -#ifndef HAVE_SETREGID - if (setgid (user_gid) < 0) - pfatal_with_name ("child_access: setgid"); -#else - if (setregid (user_gid, user_gid) < 0) - pfatal_with_name ("child_access: setregid"); -#endif - - log_access (_("Child access")); - -#endif /* GETLOADAVG_PRIVILEGED */ -} + #ifdef NEED_GET_PATH_MAX unsigned int @@ -645,13 +881,163 @@ get_path_max (void) if (value == 0) { - long int x = pathconf ("/", _PC_PATH_MAX); + long x = pathconf ("/", _PC_PATH_MAX); if (x > 0) - value = x; + value = (unsigned int) x; else - return MAXPATHLEN; + value = PATH_MAX; } return value; } #endif + +#if !HAVE_MEMPCPY +void * +mempcpy (void *dest, const void *src, size_t n) +{ + return (char *) memcpy (dest, src, n) + n; +} +#endif + +#if !HAVE_STPCPY +char * +stpcpy (char *dest, const char *src) +{ + char *d = dest; + const char *s = src; + + do + *d++ = *s; + while (*s++ != '\0'); + + return d - 1; +} +#endif + +#if !HAVE_STRTOLL +# undef UNSIGNED +# undef USE_NUMBER_GROUPING +# undef USE_WIDE_CHAR +# define QUAD 1 +# include +#endif + +#if !HAVE_STRERROR +char * +strerror (int errnum) +{ + static char msg[256]; + +#define SETMSG(_e, _m) case _e: strcpy(msg, _m); break + + switch (errnum) + { +#ifdef EPERM + SETMSG (EPERM , "Operation not permitted"); +#endif +#ifdef ENOENT + SETMSG (ENOENT , "No such file or directory"); +#endif +#ifdef ESRCH + SETMSG (ESRCH , "No such process"); +#endif +#ifdef EINTR + SETMSG (EINTR , "Interrupted system call"); +#endif +#ifdef EIO + SETMSG (EIO , "I/O error"); +#endif +#ifdef ENXIO + SETMSG (ENXIO , "No such device or address"); +#endif +#ifdef E2BIG + SETMSG (E2BIG , "Argument list too long"); +#endif +#ifdef ENOEXEC + SETMSG (ENOEXEC, "Exec format error"); +#endif +#ifdef EBADF + SETMSG (EBADF , "Bad file number"); +#endif +#ifdef ECHILD + SETMSG (ECHILD , "No child processes"); +#endif +#ifdef EAGAIN + SETMSG (EAGAIN , "Try again"); +#endif +#ifdef ENOMEM + SETMSG (ENOMEM , "Out of memory"); +#endif +#ifdef EACCES + SETMSG (EACCES , "Permission denied"); +#endif +#ifdef EFAULT + SETMSG (EFAULT , "Bad address"); +#endif +#ifdef ENOTBLK + SETMSG (ENOTBLK, "Block device required"); +#endif +#ifdef EBUSY + SETMSG (EBUSY , "Device or resource busy"); +#endif +#ifdef EEXIST + SETMSG (EEXIST , "File exists"); +#endif +#ifdef EXDEV + SETMSG (EXDEV , "Cross-device link"); +#endif +#ifdef ENODEV + SETMSG (ENODEV , "No such device"); +#endif +#ifdef ENOTDIR + SETMSG (ENOTDIR, "Not a directory"); +#endif +#ifdef EISDIR + SETMSG (EISDIR , "Is a directory"); +#endif +#ifdef EINVAL + SETMSG (EINVAL , "Invalid argument"); +#endif +#ifdef ENFILE + SETMSG (ENFILE , "File table overflow"); +#endif +#ifdef EMFILE + SETMSG (EMFILE , "Too many open files"); +#endif +#ifdef ENOTTY + SETMSG (ENOTTY , "Not a typewriter"); +#endif +#ifdef ETXTBSY + SETMSG (ETXTBSY, "Text file busy"); +#endif +#ifdef EFBIG + SETMSG (EFBIG , "File too large"); +#endif +#ifdef ENOSPC + SETMSG (ENOSPC , "No space left on device"); +#endif +#ifdef ESPIPE + SETMSG (ESPIPE , "Illegal seek"); +#endif +#ifdef EROFS + SETMSG (EROFS , "Read-only file system"); +#endif +#ifdef EMLINK + SETMSG (EMLINK , "Too many links"); +#endif +#ifdef EPIPE + SETMSG (EPIPE , "Broken pipe"); +#endif +#ifdef EDOM + SETMSG (EDOM , "Math argument out of domain of func"); +#endif +#ifdef ERANGE + SETMSG (ERANGE , "Math result not representable"); +#endif + default: sprintf (msg, "Unknown error %d", errnum); break; + } + + return msg; +} +#endif diff --git a/third_party/make/mkconfig.h b/third_party/make/mkconfig.h new file mode 100644 index 000000000..02207d038 --- /dev/null +++ b/third_party/make/mkconfig.h @@ -0,0 +1,37 @@ +/* src/mkconfig.h. Generated from mkconfig.h.in by configure. */ +/* Autoconf values for use on non-POSIX systems. +Copyright (C) 2022-2023 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make 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. + +GNU Make 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 . */ + +/* Name of package */ +#define PACKAGE "make" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "bug-make@gnu.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "GNU Make" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "GNU Make 4.4.1" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "make" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "https://www.gnu.org/software/make/" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "4.4.1" diff --git a/third_party/make/mkcustom.h b/third_party/make/mkcustom.h new file mode 100644 index 000000000..035c50b77 --- /dev/null +++ b/third_party/make/mkcustom.h @@ -0,0 +1,65 @@ +/* Miscellaneous global declarations and portability cruft for GNU Make. +Copyright (C) 2023 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make 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. + +GNU Make 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 . */ + +/* + This file is included at the end of config.h + + That means it's included _everywhere_ as the first thing, + INCLUDING content imported from gnulib. BE AWARE!! +*/ + +#undef HAVE_CONFIG_H +#define HAVE_CONFIG_H 1 + +/* Specify we want GNU source code. This must be defined before any + system headers are included. */ + +#define _GNU_SOURCE 1 + +/* AIX requires this to be the first thing in the file. */ +#if HAVE_ALLOCA_H +# include +#else +# ifdef _AIX + #pragma alloca +# else +# if !defined(__GNUC__) && !defined(WINDOWS32) +# ifndef alloca /* predefined by HP cc +Olibcalls */ +char *alloca (); +# endif +# endif +# endif +#endif + +/* Declare function prototypes for src/misc.c functions if needed. */ + +#include + +#if !HAVE_STRCASECMP && !HAVE_STRICMP && !HAVE_STRCMPI +int strcasecmp (const char *s1, const char *s2); +#endif + +#if !HAVE_STRNCASECMP && !HAVE_STRNICMP && !HAVE_STRNCMPI +int strncasecmp (const char *s1, const char *s2, size_t n); +#endif + +#if !HAVE_MEMPCPY +void *mempcpy (void *dest, const void *src, size_t n); +#endif + +#if !HAVE_STPCPY +char *stpcpy (char *dest, const char *src); +#endif diff --git a/third_party/make/os.h b/third_party/make/os.h index e7bf37a5c..05777a602 100644 --- a/third_party/make/os.h +++ b/third_party/make/os.h @@ -1,5 +1,5 @@ /* Declarations for operating system interfaces for GNU Make. -Copyright (C) 2016-2020 Free Software Foundation, Inc. +Copyright (C) 2016-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,8 +12,35 @@ 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 . */ +this program. If not, see . */ +#define IO_UNKNOWN 0x0001 +#define IO_COMBINED_OUTERR 0x0002 +#define IO_STDIN_OK 0x0004 +#define IO_STDOUT_OK 0x0008 +#define IO_STDERR_OK 0x0010 + +#if defined(VMS) || defined(_AMIGA) || defined(__MSDOS__) +# define check_io_state() (IO_STDIN_OK|IO_STDOUT_OK|IO_STDERR_OK) +# define fd_inherit(_i) (0) +# define fd_noinherit(_i) (0) +# define fd_set_append(_i) (void)(0) +# define os_anontmp() (-1) +#else + +/* Determine the state of stdin/stdout/stderr. */ +unsigned int check_io_state (void); + +/* Set a file descriptor to close/not close in a subprocess. */ +void fd_inherit (int); +void fd_noinherit (int); + +/* If the file descriptor is for a file put it into append mode. */ +void fd_set_append (int); + +/* Return a file descriptor for a new anonymous temp file, or -1. */ +int os_anontmp (void); +#endif /* This section provides OS-specific functions to support the jobserver. */ @@ -22,19 +49,26 @@ this program. If not, see . */ /* Returns 1 if the jobserver is enabled, else 0. */ unsigned int jobserver_enabled (void); -/* Called in the master instance to set up the jobserver initially. */ -unsigned int jobserver_setup (int job_slots); +/* Called in the parent make to set up the jobserver initially. */ +unsigned int jobserver_setup (int job_slots, const char *style); -/* Called in a child instance to connect to the jobserver. */ +/* Called in a child instance to connect to the jobserver. + Return 1 if we got a valid auth, else 0. */ unsigned int jobserver_parse_auth (const char* auth); /* Returns an allocated buffer used to pass to child instances. */ char *jobserver_get_auth (void); -/* Clear this instance's jobserver configuration. */ +/* Returns a pointer to a static string used to indicate that the child + cannot access the jobserver, or NULL if it always can. */ +const char *jobserver_get_invalid_auth (void); + +/* Clear this instance's jobserver configuration. + This method might be invoked from a signal handler. */ void jobserver_clear (void); -/* Recover all the jobserver tokens and return the number we got. */ +/* Recover all the jobserver tokens and return the number we got. + Will also run jobserver_clear() as a side-effect. */ unsigned int jobserver_acquire_all (void); /* Release a jobserver token. If it fails and is_fatal is 1, fatal. */ @@ -61,20 +95,60 @@ unsigned int jobserver_acquire (int timeout); #else -#define jobserver_enabled() (0) -#define jobserver_setup(_slots) (0) -#define jobserver_parse_auth(_auth) (0) -#define jobserver_get_auth() (NULL) -#define jobserver_clear() (void)(0) -#define jobserver_release(_fatal) (void)(0) -#define jobserver_acquire_all() (0) -#define jobserver_signal() (void)(0) -#define jobserver_pre_child(_r) (void)(0) -#define jobserver_post_child(_r) (void)(0) -#define jobserver_pre_acquire() (void)(0) -#define jobserver_acquire(_tmout) (0) +#define jobserver_enabled() (0) +#define jobserver_setup(_slots, _style) (0) +#define jobserver_parse_auth(_auth) (0) +#define jobserver_get_auth() (NULL) +#define jobserver_get_invalid_auth() (NULL) +#define jobserver_clear() (void)(0) +#define jobserver_release(_fatal) (void)(0) +#define jobserver_acquire_all() (0) +#define jobserver_signal() (void)(0) +#define jobserver_pre_child(_r) (void)(0) +#define jobserver_post_child(_r) (void)(0) +#define jobserver_pre_acquire() (void)(0) +#define jobserver_acquire(_tmout) (0) -#endif +#endif /* MAKE_JOBSERVER */ + +#ifndef NO_OUTPUT_SYNC + +/* Returns 1 if output sync is enabled, else 0. */ +unsigned int osync_enabled (void); + +/* Called in the parent make to set up output sync initially. */ +void osync_setup (void); + +/* Returns an allocated buffer containing output sync info to pass to child + instances, or NULL if not needed. */ +char *osync_get_mutex (void); + +/* Called in a child instance to obtain info on the output sync mutex. + Return 1 if we got a valid mutex, else 0. */ +unsigned int osync_parse_mutex (const char *mutex); + +/* Clean up this instance's output sync facilities. + This method might be invoked from a signal handler. */ +void osync_clear (void); + +/* Acquire the output sync lock. This will wait until available. + Returns 0 if there was an error getting the semaphore. */ +unsigned int osync_acquire (void); + +/* Release the output sync lock. */ +void osync_release (void); + +#else + +#define osync_enabled() (0) +#define osync_setup() (void)(0) +#define osync_get_mutex() (0) +#define osync_parse_mutex(_s) (0) +#define osync_clear() (void)(0) +#define osync_acquire() (1) +#define osync_release() (void)(0) + +#endif /* NO_OUTPUT_SYNC */ /* Create a "bad" file descriptor for stdin when parallel jobs are run. */ #if defined(VMS) || defined(WINDOWS32) || defined(_AMIGA) || defined(__MSDOS__) @@ -82,12 +156,3 @@ unsigned int jobserver_acquire (int timeout); #else int get_bad_stdin (void); #endif - -/* Set a file descriptor to close/not close in a subprocess. */ -#if defined(VMS) || defined(_AMIGA) || defined(__MSDOS__) -# define fd_inherit(_i) 0 -# define fd_noinherit(_i) 0 -#else -void fd_inherit (int); -void fd_noinherit (int); -#endif diff --git a/third_party/make/output.c b/third_party/make/output.c index 902d598a3..7e93738db 100644 --- a/third_party/make/output.c +++ b/third_party/make/output.c @@ -1,5 +1,5 @@ -/* Output to stdout / stderr for GNU make -Copyright (C) 2013-2020 Free Software Foundation, Inc. +/* Output to stdout / stderr for GNU Make +Copyright (C) 2013-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,15 +12,27 @@ 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 . */ +this program. If not, see . */ -#include "third_party/make/makeint.inc" -#include "third_party/make/os.h" -#include "third_party/make/output.h" -#include "libc/runtime/runtime.h" -#include "libc/calls/struct/flock.h" +#include "makeint.h" +#include "os.h" +#include "output.h" -/* GNU make no longer supports pre-ANSI89 environments. */ +/* GNU Make no longer supports pre-ANSI89 environments. */ + +#include +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifdef HAVE_FCNTL_H +# include +#else +# include +#endif struct output *output_context = NULL; unsigned int stdio_traced = 0; @@ -29,30 +41,28 @@ unsigned int stdio_traced = 0; #define OUTPUT_ISSET(_out) ((_out)->out >= 0 || (_out)->err >= 0) -#ifdef HAVE_FCNTL_H -# define STREAM_OK(_s) ((fcntl (fileno (_s), F_GETFD) != -1) || (errno != EBADF)) -#else -# define STREAM_OK(_s) 1 -#endif - /* Write a string to the current STDOUT or STDERR. */ static void _outputs (struct output *out, int is_err, const char *msg) { - if (! out || ! out->syncout) - { - FILE *f = is_err ? stderr : stdout; - fputs (msg, f); - fflush (f); - } - else + FILE *f; + + if (out && out->syncout) { int fd = is_err ? out->err : out->out; - size_t len = strlen (msg); - int r; - EINTRLOOP (r, lseek (fd, 0, SEEK_END)); - writebuf (fd, msg, len); + if (fd != OUTPUT_NONE) + { + size_t len = strlen (msg); + int r; + EINTRLOOP (r, lseek (fd, 0, SEEK_END)); + writebuf (fd, msg, len); + return; + } } + + f = is_err ? stderr : stdout; + fputs (msg, f); + fflush (f); } /* Write a message indicating that we've just entered or @@ -125,73 +135,10 @@ log_working_directory (int entering) return 1; } - -/* Set a file descriptor to be in O_APPEND mode. - If it fails, just ignore it. */ - -static void -set_append_mode (int fd) -{ -#if defined(F_GETFL) && defined(F_SETFL) && defined(O_APPEND) - int flags = fcntl (fd, F_GETFL, 0); - if (flags >= 0) - { - int r; - EINTRLOOP(r, fcntl (fd, F_SETFL, flags | O_APPEND)); - } -#endif -} #ifndef NO_OUTPUT_SYNC -/* Semaphore for use in -j mode with output_sync. */ -static sync_handle_t sync_handle = -1; - -#define FD_NOT_EMPTY(_f) ((_f) != OUTPUT_NONE && lseek ((_f), 0, SEEK_END) > 0) - -/* Set up the sync handle. Disables output_sync on error. */ -static int -sync_init (void) -{ - int combined_output = 0; - -#ifdef WINDOWS32 - if ((!STREAM_OK (stdout) && !STREAM_OK (stderr)) - || (sync_handle = create_mutex ()) == -1) - { - perror_with_name ("output-sync suppressed: ", "stderr"); - output_sync = 0; - } - else - { - combined_output = same_stream (stdout, stderr); - prepare_mutex_handle_string (sync_handle); - } - -#else - if (STREAM_OK (stdout)) - { - struct stat stbuf_o, stbuf_e; - - sync_handle = fileno (stdout); - combined_output = (fstat (fileno (stdout), &stbuf_o) == 0 - && fstat (fileno (stderr), &stbuf_e) == 0 - && stbuf_o.st_dev == stbuf_e.st_dev - && stbuf_o.st_ino == stbuf_e.st_ino); - } - else if (STREAM_OK (stderr)) - sync_handle = fileno (stderr); - else - { - perror_with_name ("output-sync suppressed: ", "stderr"); - output_sync = 0; - } -#endif - - return combined_output; -} - /* Support routine for output_sync() */ static void pump_from_tmp (int from, FILE *to) @@ -232,55 +179,13 @@ pump_from_tmp (int from, FILE *to) #endif } -/* Obtain the lock for writing output. */ -static void * -acquire_semaphore (void) -{ - static struct flock fl; - - fl.l_type = F_WRLCK; - fl.l_whence = SEEK_SET; - fl.l_start = 0; - fl.l_len = 1; - if (fcntl (sync_handle, F_SETLKW, &fl) != -1) - return &fl; - perror ("fcntl()"); - return NULL; -} - -/* Release the lock for writing output. */ -static void -release_semaphore (void *sem) -{ - struct flock *flp = (struct flock *)sem; - flp->l_type = F_UNLCK; - if (fcntl (sync_handle, F_SETLKW, flp) == -1) - perror ("fcntl()"); -} - -/* Returns a file descriptor to a temporary file. The file is automatically - closed/deleted on exit. Don't use a FILE* stream. */ +/* Returns a file descriptor to a temporary file, that will be automatically + deleted on exit. */ int output_tmpfd (void) { - mode_t mask = umask (0077); - int fd = -1; - FILE *tfile = tmpfile (); - - if (! tfile) - pfatal_with_name ("tmpfile"); - - /* Create a duplicate so we can close the stream. */ - fd = dup (fileno (tfile)); - if (fd < 0) - pfatal_with_name ("dup"); - - fclose (tfile); - - set_append_mode (fd); - - umask (mask); - + int fd = get_tmpfd (NULL); + fd_set_append (fd); return fd; } @@ -291,13 +196,25 @@ output_tmpfd (void) static void setup_tmpfile (struct output *out) { - /* Is make's stdout going to the same place as stderr? */ - static int combined_output = -1; + static unsigned int in_setup = 0; + unsigned int io_state; - if (combined_output < 0) - combined_output = sync_init (); + /* If something fails during setup we might recurse back into this function + while writing errors. Make sure we don't do so infinitely. */ + if (in_setup) + return; + in_setup = 1; - if (STREAM_OK (stdout)) + io_state = check_io_state (); + + if (NONE_SET (io_state, IO_STDOUT_OK|IO_STDERR_OK)) + { + /* This is probably useless since stdout/stderr aren't working. */ + perror_with_name ("output-sync suppressed: ", "stderr"); + goto error; + } + + if (ANY_SET (io_state, IO_STDOUT_OK)) { int fd = output_tmpfd (); if (fd < 0) @@ -306,9 +223,9 @@ setup_tmpfile (struct output *out) out->out = fd; } - if (STREAM_OK (stderr)) + if (ANY_SET (io_state, IO_STDERR_OK)) { - if (out->out != OUTPUT_NONE && combined_output) + if (out->out != OUTPUT_NONE && ANY_SET (io_state, IO_COMBINED_OUTERR)) out->err = out->out; else { @@ -320,12 +237,18 @@ setup_tmpfile (struct output *out) } } + in_setup = 0; return; /* If we failed to create a temp file, disable output sync going forward. */ error: + O (error, NILF, + _("cannot open output-sync lock file, suppressing output-sync.")); + output_close (out); output_sync = OUTPUT_SYNC_NONE; + osync_clear (); + in_setup = 0; } /* Synchronize the output of jobs in -j mode to keep the results of @@ -336,6 +259,8 @@ setup_tmpfile (struct output *out) void output_dump (struct output *out) { +#define FD_NOT_EMPTY(_f) ((_f) != OUTPUT_NONE && lseek ((_f), 0, SEEK_END) > 0) + int outfd_not_empty = FD_NOT_EMPTY (out->out); int errfd_not_empty = FD_NOT_EMPTY (out->err); @@ -346,10 +271,16 @@ output_dump (struct output *out) /* Try to acquire the semaphore. If it fails, dump the output unsynchronized; still better than silently discarding it. We want to keep this lock for as little time as possible. */ - void *sem = acquire_semaphore (); + if (!osync_acquire ()) + { + O (error, NILF, + _("warning: Cannot acquire output lock, disabling output sync.")); + osync_clear (); + } /* Log the working directory for this dump. */ - if (print_directory_flag && output_sync != OUTPUT_SYNC_RECURSE) + + if (output_sync != OUTPUT_SYNC_RECURSE && should_print_dir ()) traced = log_working_directory (1); if (outfd_not_empty) @@ -361,8 +292,7 @@ output_dump (struct output *out) log_working_directory (0); /* Exit the critical section. */ - if (sem) - release_semaphore (sem); + osync_release (); /* Truncate and reset the output, in case we use it again. */ if (out->out != OUTPUT_NONE) @@ -382,53 +312,6 @@ output_dump (struct output *out) #endif /* NO_OUTPUT_SYNC */ -/* This code is stolen from gnulib. - If/when we abandon the requirement to work with K&R compilers, we can - remove this (and perhaps other parts of GNU make!) and migrate to using - gnulib directly. - - This is called only through atexit(), which means die() has already been - invoked. So, call exit() here directly. Apparently that works...? -*/ - -/* Close standard output, exiting with status 'exit_failure' on failure. - If a program writes *anything* to stdout, that program should close - stdout and make sure that it succeeds before exiting. Otherwise, - suppose that you go to the extreme of checking the return status - of every function that does an explicit write to stdout. The last - printf can succeed in writing to the internal stream buffer, and yet - the fclose(stdout) could still fail (due e.g., to a disk full error) - when it tries to write out that buffered data. Thus, you would be - left with an incomplete output file and the offending program would - exit successfully. Even calling fflush is not always sufficient, - since some file systems (NFS and CODA) buffer written/flushed data - until an actual close call. - - Besides, it's wasteful to check the return value from every call - that writes to stdout -- just let the internal stream state record - the failure. That's what the ferror test is checking below. - - It's important to detect such failures and exit nonzero because many - tools (most notably 'make' and other build-management systems) depend - on being able to detect failure in other tools via their exit status. */ - -static void -close_stdout (void) -{ - int prev_fail = ferror (stdout); - int fclose_fail = fclose (stdout); - - if (prev_fail || fclose_fail) - { - if (fclose_fail) - perror_with_name (_("write error: stdout"), ""); - else - O (error, NILF, _("write error: stdout")); - exit (MAKE_TROUBLE); - } -} - - void output_init (struct output *out) { @@ -439,28 +322,10 @@ output_init (struct output *out) return; } - /* Configure this instance of make. Be sure stdout is line-buffered. */ - -#ifdef HAVE_SETVBUF -# ifdef SETVBUF_REVERSED - setvbuf (stdout, _IOLBF, xmalloc (BUFSIZ), BUFSIZ); -# else /* setvbuf not reversed. */ - /* Some buggy systems lose if we pass 0 instead of allocating ourselves. */ - setvbuf (stdout, 0, _IOLBF, BUFSIZ); -# endif /* setvbuf reversed. */ -#elif HAVE_SETLINEBUF - setlinebuf (stdout); -#endif /* setlinebuf missing. */ - - /* Force stdout/stderr into append mode. This ensures parallel jobs won't - lose output due to overlapping writes. */ - set_append_mode (fileno (stdout)); - set_append_mode (fileno (stderr)); - -#ifdef HAVE_ATEXIT - if (STREAM_OK (stdout)) - atexit (close_stdout); -#endif + /* Force stdout/stderr into append mode (if they are files) to ensure + parallel jobs won't lose output due to overlapping writes. */ + fd_set_append (fileno (stdout)); + fd_set_append (fileno (stderr)); } void @@ -499,7 +364,7 @@ output_start (void) /* If we're not syncing this output per-line or per-target, make sure we emit the "Entering..." message where appropriate. */ if (output_sync == OUTPUT_SYNC_NONE || output_sync == OUTPUT_SYNC_RECURSE) - if (! stdio_traced && print_directory_flag) + if (! stdio_traced && should_print_dir ()) stdio_traced = log_working_directory (1); } @@ -542,10 +407,11 @@ void message (int prefix, size_t len, const char *fmt, ...) { va_list args; + char *start; char *p; len += strlen (fmt) + strlen (program) + INTSTR_LENGTH + 4 + 1 + 1; - p = get_buffer (len); + start = p = get_buffer (len); if (prefix) { @@ -562,8 +428,8 @@ message (int prefix, size_t len, const char *fmt, ...) strcat (p, "\n"); - assert (fmtbuf.buffer[len-1] == '\0'); - outputs (0, fmtbuf.buffer); + assert (start[len-1] == '\0'); + outputs (0, start); } /* Print an error message. */ @@ -572,12 +438,13 @@ void error (const floc *flocp, size_t len, const char *fmt, ...) { va_list args; + char *start; char *p; len += (strlen (fmt) + strlen (program) + (flocp && flocp->filenm ? strlen (flocp->filenm) : 0) + INTSTR_LENGTH + 4 + 1 + 1); - p = get_buffer (len); + start = p = get_buffer (len); if (flocp && flocp->filenm) sprintf (p, "%s:%lu: ", flocp->filenm, flocp->lineno + flocp->offset); @@ -593,8 +460,8 @@ error (const floc *flocp, size_t len, const char *fmt, ...) strcat (p, "\n"); - assert (fmtbuf.buffer[len-1] == '\0'); - outputs (1, fmtbuf.buffer); + assert (start[len-1] == '\0'); + outputs (1, start); } /* Print an error message and exit. */ @@ -604,12 +471,13 @@ fatal (const floc *flocp, size_t len, const char *fmt, ...) { va_list args; const char *stop = _(". Stop.\n"); + char *start; char *p; len += (strlen (fmt) + strlen (program) + (flocp && flocp->filenm ? strlen (flocp->filenm) : 0) + INTSTR_LENGTH + 8 + strlen (stop) + 1); - p = get_buffer (len); + start = p = get_buffer (len); if (flocp && flocp->filenm) sprintf (p, "%s:%lu: *** ", flocp->filenm, flocp->lineno + flocp->offset); @@ -625,8 +493,8 @@ fatal (const floc *flocp, size_t len, const char *fmt, ...) strcat (p, stop); - assert (fmtbuf.buffer[len-1] == '\0'); - outputs (1, fmtbuf.buffer); + assert (start[len-1] == '\0'); + outputs (1, start); die (MAKE_FAILURE); } diff --git a/third_party/make/output.h b/third_party/make/output.h index abc6ca575..50e325949 100644 --- a/third_party/make/output.h +++ b/third_party/make/output.h @@ -1,5 +1,5 @@ -/* Output to stdout / stderr for GNU make -Copyright (C) 2013-2020 Free Software Foundation, Inc. +/* Output to stdout / stderr for GNU Make +Copyright (C) 2013-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,7 +12,7 @@ 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 . */ +this program. If not, see . */ struct output { @@ -50,51 +50,9 @@ void output_start (void); /* Show a message on stdout or stderr. Will start the output if needed. */ void outputs (int is_err, const char *msg); -#ifdef NO_OUTPUT_SYNC -# define RECORD_SYNC_MUTEX(m) \ - O (error, NILF, \ - _("-O[TYPE] (--output-sync[=TYPE]) is not configured for this build.")); +#if defined(NO_OUTPUT_SYNC) +# define output_dump(_o) (void)(0) #else -int output_tmpfd (void); /* Dump any child output content to stdout, and reset it. */ void output_dump (struct output *out); - -# ifdef WINDOWS32 -/* For emulations in w32/compat/posixfcn.c. */ -# define F_GETFD 1 -# define F_SETLKW 2 -/* Implementation note: None of the values of l_type below can be zero - -- they are compared with a static instance of the struct, so zero - means unknown/invalid, see w32/compat/posixfcn.c. */ -# define F_WRLCK 1 -# define F_UNLCK 2 - -struct flock - { - short l_type; - short l_whence; - off_t l_start; - off_t l_len; - pid_t l_pid; - }; - -/* This type is actually a HANDLE, but we want to avoid including - windows.h as much as possible. */ -typedef intptr_t sync_handle_t; - -/* Public functions emulated/provided in posixfcn.c. */ -int fcntl (intptr_t fd, int cmd, ...); -intptr_t create_mutex (void); -int same_stream (FILE *f1, FILE *f2); - -# define RECORD_SYNC_MUTEX(m) record_sync_mutex(m) -void record_sync_mutex (const char *str); -void prepare_mutex_handle_string (intptr_t hdl); -# else /* !WINDOWS32 */ - -typedef int sync_handle_t; /* file descriptor */ - -# define RECORD_SYNC_MUTEX(m) (void)(m) - -# endif -#endif /* !NO_OUTPUT_SYNC */ +#endif diff --git a/third_party/make/posixos.c b/third_party/make/posixos.c index 032a9d611..388b3f092 100644 --- a/third_party/make/posixos.c +++ b/third_party/make/posixos.c @@ -1,5 +1,5 @@ /* POSIX-based operating system interface for GNU Make. -Copyright (C) 2016-2020 Free Software Foundation, Inc. +Copyright (C) 2016-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,26 +12,79 @@ 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 . */ +this program. If not, see . */ -#include "third_party/make/makeint.inc" -/**/ -#include "libc/sock/select.h" -#include "libc/sysv/consts/f.h" -#include "libc/sysv/consts/fd.h" -#include "libc/sysv/consts/sa.h" -#include "libc/sysv/consts/sig.h" -#include "third_party/make/config.h" -#include "third_party/make/debug.h" -#include "third_party/make/job.h" -#include "third_party/make/os.h" +#include "libc/dce.h" +#include "makeint.h" -#ifdef MAKE_JOBSERVER +#include + +#ifdef HAVE_FCNTL_H +# include +# define FD_OK(_f) (fcntl ((_f), F_GETFD) != -1) +#elif defined(HAVE_SYS_FILE_H) +# include +#endif +#if MK_OS_ZOS +/* FIXME: HAVE_PSELECT path hangs on z/OS */ +#undef HAVE_PSELECT +#endif + +#if !defined(FD_OK) +# define FD_OK(_f) 1 +#endif + +#if defined(HAVE_PSELECT) && defined(HAVE_SYS_SELECT_H) +# include +#endif + +#include "debug.h" +#include "job.h" +#include "os.h" + +#define STREAM_OK(_s) ((fcntl (fileno (_s), F_GETFD) != -1) || (errno != EBADF)) + +unsigned int +check_io_state () +{ + static unsigned int state = IO_UNKNOWN; + + /* We only need to compute this once per process. */ + if (state != IO_UNKNOWN) + return state; + + if (STREAM_OK (stdin)) + state |= IO_STDIN_OK; + if (STREAM_OK (stdout)) + state |= IO_STDOUT_OK; + if (STREAM_OK (stderr)) + state |= IO_STDERR_OK; + + if (ALL_SET (state, IO_STDOUT_OK|IO_STDERR_OK)) + { + struct stat stbuf_o, stbuf_e; + + if (fstat (fileno (stdout), &stbuf_o) == 0 + && fstat (fileno (stderr), &stbuf_e) == 0 + && stbuf_o.st_dev == stbuf_e.st_dev + && stbuf_o.st_ino == stbuf_e.st_ino) + state |= IO_COMBINED_OUTERR; + } + + return state; +} + +#if defined(MAKE_JOBSERVER) + +#define FIFO_PREFIX "fifo:" /* This section provides OS-specific functions to support the jobserver. */ +/* True if this is the root make instance. */ +static unsigned char job_root = 0; + /* These track the state of the jobserver pipe. Passed to child instances. */ -static int job_fds[2] = {-1, -1}; +static int job_fds[2] = { -1, -1 }; /* Used to signal read() that a SIGCHLD happened. Always CLOEXEC. If we use pselect() this will never be created and always -1. @@ -41,162 +94,357 @@ static int job_rfd = -1; /* Token written to the pipe (could be any character...) */ static char token = '+'; -static int make_job_rfd(void) { +/* The type of jobserver we're using. */ +enum js_type + { + js_none = 0, /* No jobserver. */ + js_pipe, /* Use a simple pipe as the jobserver. */ + js_fifo /* Use a named pipe as the jobserver. */ + }; + +static enum js_type js_type = js_none; + +/* The name of the named pipe (if used). */ +static char *fifo_name = NULL; + +static int +make_job_rfd () +{ #ifdef HAVE_PSELECT /* Pretend we succeeded. */ return 0; #else - EINTRLOOP(job_rfd, dup(job_fds[0])); - if (job_rfd >= 0) fd_noinherit(job_rfd); + EINTRLOOP (job_rfd, dup (job_fds[0])); + if (job_rfd >= 0) + fd_noinherit (job_rfd); return job_rfd; #endif } -static void set_blocking(int fd, int blocking) { +static void +set_blocking (int fd, int blocking) +{ /* If we're not using pselect() don't change the blocking. */ #ifdef HAVE_PSELECT int flags; - EINTRLOOP(flags, fcntl(fd, F_GETFL)); - if (flags >= 0) { - int r; - flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); - EINTRLOOP(r, fcntl(fd, F_SETFL, flags)); - if (r < 0) pfatal_with_name("fcntl(O_NONBLOCK)"); - } + EINTRLOOP (flags, fcntl (fd, F_GETFL)); + if (flags >= 0) + { + int r; + flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); + EINTRLOOP (r, fcntl (fd, F_SETFL, flags)); + if (r < 0) + pfatal_with_name ("fcntl(O_NONBLOCK)"); + } +#else + (void) fd; + (void) blocking; #endif } -unsigned int jobserver_setup(int slots) { +unsigned int +jobserver_setup (int slots, const char *style) +{ int r; - EINTRLOOP(r, pipe(job_fds)); - if (r < 0) pfatal_with_name(_("creating jobs pipe")); +#if JOBSERVER_USE_FIFO + if (!style || strcmp (style, "fifo") == 0) + { + /* Unfortunately glibc warns about uses of mktemp even though we aren't + using it in dangerous way here. So avoid this by generating our own + temporary file name. */ +# define FNAME_PREFIX "GMfifo" + const char *tmpdir = get_tmpdir (); + + fifo_name = xmalloc (strlen (tmpdir) + CSTRLEN (FNAME_PREFIX) + + INTSTR_LENGTH + 2); + sprintf (fifo_name, "%s/" FNAME_PREFIX "%" MK_PRI64_PREFIX "d", + tmpdir, (long long)make_pid ()); + + EINTRLOOP (r, mkfifo (fifo_name, 0600)); + if (r < 0) + { + perror_with_name("jobserver mkfifo: ", fifo_name); + free (fifo_name); + fifo_name = NULL; + } + else + { + /* We have to open the read side in non-blocking mode, else it will + hang until the write side is open. */ + EINTRLOOP (job_fds[0], open (fifo_name, O_RDONLY|O_NONBLOCK)); + if (job_fds[0] < 0) + OSS (fatal, NILF, _("cannot open jobserver %s: %s"), + fifo_name, strerror (errno)); + + EINTRLOOP (job_fds[1], open (fifo_name, O_WRONLY)); + if (job_fds[0] < 0) + OSS (fatal, NILF, _("cannot open jobserver %s: %s"), + fifo_name, strerror (errno)); + + js_type = js_fifo; + } + } +#endif + + if (js_type == js_none) + { + if (style && strcmp (style, "pipe") != 0) + OS (fatal, NILF, _("unknown jobserver auth style '%s'"), style); + + EINTRLOOP (r, pipe (job_fds)); + if (r < 0) + pfatal_with_name (_("creating jobs pipe")); + + js_type = js_pipe; + } /* By default we don't send the job pipe FDs to our children. See jobserver_pre_child() and jobserver_post_child(). */ - fd_noinherit(job_fds[0]); - fd_noinherit(job_fds[1]); + fd_noinherit (job_fds[0]); + fd_noinherit (job_fds[1]); - if (make_job_rfd() < 0) pfatal_with_name(_("duping jobs pipe")); + if (make_job_rfd () < 0) + pfatal_with_name (_("duping jobs pipe")); - while (slots--) { - EINTRLOOP(r, write(job_fds[1], &token, 1)); - if (r != 1) pfatal_with_name(_("init jobserver pipe")); - } + while (slots--) + { + EINTRLOOP (r, write (job_fds[1], &token, 1)); + if (r != 1) + pfatal_with_name (_("init jobserver pipe")); + } /* When using pselect() we want the read to be non-blocking. */ - set_blocking(job_fds[0], 0); + set_blocking (job_fds[0], 0); + + job_root = 1; return 1; } -unsigned int jobserver_parse_auth(const char *auth) { +unsigned int +jobserver_parse_auth (const char *auth) +{ + int rfd, wfd; + /* Given the command-line parameter, parse it. */ - if (sscanf(auth, "%d,%d", &job_fds[0], &job_fds[1]) != 2) - OS(fatal, NILF, _("internal error: invalid --jobserver-auth string '%s'"), - auth); - DB(DB_JOBS, (_("Jobserver client (fds %d,%d)\n"), job_fds[0], job_fds[1])); + /* First see if we're using a named pipe. */ + if (strncmp (auth, FIFO_PREFIX, CSTRLEN (FIFO_PREFIX)) == 0) + { + fifo_name = xstrdup (auth + CSTRLEN (FIFO_PREFIX)); -#ifdef HAVE_FCNTL_H -#define FD_OK(_f) (fcntl((_f), F_GETFD) != -1) -#else -#define FD_OK(_f) 1 -#endif + EINTRLOOP (job_fds[0], open (fifo_name, O_RDONLY)); + if (job_fds[0] < 0) + { + OSS (error, NILF, + _("cannot open jobserver %s: %s"), fifo_name, strerror (errno)); + return 0; + } - /* Make sure our pipeline is valid, and (possibly) create a duplicate pipe, - that will be closed in the SIGCHLD handler. If this fails with EBADF, - the parent has closed the pipe on us because it didn't think we were a - submake. If so, warn and default to -j1. */ + EINTRLOOP (job_fds[1], open (fifo_name, O_WRONLY)); + if (job_fds[1] < 0) + { + OSS (error, NILF, + _("cannot open jobserver %s: %s"), fifo_name, strerror (errno)); + return 0; + } + js_type = js_fifo; + } + /* If not, it must be a simple pipe. */ + else if (sscanf (auth, "%d,%d", &rfd, &wfd) == 2) + { + /* The parent overrode our FDs because we aren't a recursive make. */ + if (rfd == -2 || wfd == -2) + return 0; - if (!FD_OK(job_fds[0]) || !FD_OK(job_fds[1]) || make_job_rfd() < 0) { - if (errno != EBADF) pfatal_with_name(_("jobserver pipeline")); + /* Make sure our pipeline is valid. */ + if (!FD_OK (rfd) || !FD_OK (wfd)) + return 0; - job_fds[0] = job_fds[1] = -1; + job_fds[0] = rfd; + job_fds[1] = wfd; - return 0; - } + js_type = js_pipe; + } + /* Who knows what it is? */ + else + { + OS (error, NILF, _("invalid --jobserver-auth string '%s'"), auth); + return 0; + } + + /* Create a duplicate pipe, if needed, that will be closed in the SIGCHLD + handler. If this fails with EBADF, the parent closed the pipe on us as + it didn't think we were a submake. If so, warn and default to -j1. */ + + if (make_job_rfd () < 0) + { + if (errno != EBADF) + pfatal_with_name ("jobserver readfd"); + + jobserver_clear (); + + return 0; + } /* When using pselect() we want the read to be non-blocking. */ - set_blocking(job_fds[0], 0); + set_blocking (job_fds[0], 0); + + /* By default we don't send the job pipe FDs to our children. + See jobserver_pre_child() and jobserver_post_child(). */ + fd_noinherit (job_fds[0]); + fd_noinherit (job_fds[1]); return 1; } -char *jobserver_get_auth(void) { - char *auth = xmalloc((INTSTR_LENGTH * 2) + 2); - sprintf(auth, "%d,%d", job_fds[0], job_fds[1]); +char * +jobserver_get_auth () +{ + char *auth; + + if (js_type == js_fifo) { + auth = xmalloc (strlen (fifo_name) + CSTRLEN (FIFO_PREFIX) + 1); + sprintf (auth, FIFO_PREFIX "%s", fifo_name); + } else { + auth = xmalloc ((INTSTR_LENGTH * 2) + 2); + sprintf (auth, "%d,%d", job_fds[0], job_fds[1]); + } + return auth; } -unsigned int jobserver_enabled(void) { - return job_fds[0] >= 0; +const char * +jobserver_get_invalid_auth () +{ + /* If we're using a named pipe we don't need to invalidate the jobserver. */ + if (js_type == js_fifo) { + return NULL; + } + + /* It's not really great that we are assuming the command line option + here but other alternatives are also gross. */ + return " --" JOBSERVER_AUTH_OPT "=-2,-2"; } -void jobserver_clear(void) { - if (job_fds[0] >= 0) close(job_fds[0]); - if (job_fds[1] >= 0) close(job_fds[1]); - if (job_rfd >= 0) close(job_rfd); +unsigned int +jobserver_enabled () +{ + return js_type != js_none; +} + +void +jobserver_clear () +{ + if (job_fds[0] >= 0) + close (job_fds[0]); + if (job_fds[1] >= 0) + close (job_fds[1]); + if (job_rfd >= 0) + close (job_rfd); job_fds[0] = job_fds[1] = job_rfd = -1; + + if (fifo_name) + { + if (job_root) + { + int r; + EINTRLOOP (r, unlink (fifo_name)); + } + + if (!handling_fatal_signal) + { + free (fifo_name); + fifo_name = NULL; + } + } + + js_type = js_none; } -void jobserver_release(int is_fatal) { +void +jobserver_release (int is_fatal) +{ int r; - EINTRLOOP(r, write(job_fds[1], &token, 1)); - if (r != 1) { - if (is_fatal) pfatal_with_name(_("write jobserver")); - perror_with_name("write", ""); - } + EINTRLOOP (r, write (job_fds[1], &token, 1)); + if (r != 1) + { + if (is_fatal) + pfatal_with_name (_("write jobserver")); + perror_with_name ("write", ""); + } } -unsigned int jobserver_acquire_all(void) { +unsigned int +jobserver_acquire_all () +{ + int r; unsigned int tokens = 0; /* Use blocking reads to wait for all outstanding jobs. */ - set_blocking(job_fds[0], 1); + set_blocking (job_fds[0], 1); /* Close the write side, so the read() won't hang forever. */ - close(job_fds[1]); + close (job_fds[1]); job_fds[1] = -1; - while (1) { - char intake; - int r; - EINTRLOOP(r, read(job_fds[0], &intake, 1)); - if (r != 1) return tokens; - ++tokens; - } + while (1) + { + char intake; + EINTRLOOP (r, read (job_fds[0], &intake, 1)); + if (r != 1) + break; + ++tokens; + } + + DB (DB_JOBS, ("Acquired all %u jobserver tokens.\n", tokens)); + + jobserver_clear (); + + return tokens; } /* Prepare the jobserver to start a child process. */ -void jobserver_pre_child(int recursive) { - if (recursive && job_fds[0] >= 0) { - fd_inherit(job_fds[0]); - fd_inherit(job_fds[1]); - } +void +jobserver_pre_child (int recursive) +{ + if (recursive && js_type == js_pipe) + { + fd_inherit (job_fds[0]); + fd_inherit (job_fds[1]); + } } /* Reconfigure the jobserver after starting a child process. */ -void jobserver_post_child(int recursive) { - if (recursive && job_fds[0] >= 0) { - fd_noinherit(job_fds[0]); - fd_noinherit(job_fds[1]); - } +void +jobserver_post_child (int recursive) +{ + if (recursive && js_type == js_pipe) + { + fd_noinherit (job_fds[0]); + fd_noinherit (job_fds[1]); + } } -void jobserver_signal(void) { - if (job_rfd >= 0) { - close(job_rfd); - job_rfd = -1; - } +void +jobserver_signal () +{ + if (job_rfd >= 0) + { + close (job_rfd); + job_rfd = -1; + } } -void jobserver_pre_acquire(void) { +void +jobserver_pre_acquire () +{ /* Make sure we have a dup'd FD. */ - if (job_rfd < 0 && job_fds[0] >= 0 && make_job_rfd() < 0) - pfatal_with_name(_("duping jobs pipe")); + if (job_rfd < 0 && job_fds[0] >= 0 && make_job_rfd () < 0) + pfatal_with_name (_("duping jobs pipe")); } #ifdef HAVE_PSELECT @@ -208,58 +456,69 @@ void jobserver_pre_acquire(void) { and only unblocked (atomically) within the pselect() call, so we can never miss a SIGCHLD. */ -unsigned int jobserver_acquire(int timeout) { +unsigned int +jobserver_acquire (int timeout) +{ struct timespec spec; struct timespec *specp = NULL; sigset_t empty; - sigemptyset(&empty); + sigemptyset (&empty); - if (timeout) { - /* Alarm after one second (is this too granular?) */ - spec.tv_sec = 1; - spec.tv_nsec = 0; - specp = &spec; - } - - while (1) { - fd_set readfds; - int r; - char intake; - - FD_ZERO(&readfds); - FD_SET(job_fds[0], &readfds); - - r = pselect(job_fds[0] + 1, &readfds, NULL, NULL, specp, &empty); - if (r < 0) - { - if (errno == EINTR) - /* SIGCHLD will show up as an EINTR. */ - return 0; - if (errno == EBADF) - /* Someone closed the jobs pipe. - That shouldn't happen but if it does we're done. */ - O(fatal, NILF, _("job server shut down")); - pfatal_with_name(_("pselect jobs pipe")); - } - - if (r == 0) /* Timeout. */ - return 0; - - /* The read FD is ready: read it! This is non-blocking. */ - EINTRLOOP(r, read(job_fds[0], &intake, 1)); - - if (r < 0) { - /* Someone sniped our token! Try again. */ - if (errno == EAGAIN) continue; - - pfatal_with_name(_("read jobs pipe")); + if (timeout) + { + /* Alarm after one second (is this too granular?) */ + spec.tv_sec = 1; + spec.tv_nsec = 0; + specp = &spec; } - /* read() should never return 0: only the master make can reap all the - tokens and close the write side...?? */ - return r > 0; - } + while (1) + { + fd_set readfds; + int r; + char intake; + + FD_ZERO (&readfds); + FD_SET (job_fds[0], &readfds); + + r = pselect (job_fds[0]+1, &readfds, NULL, NULL, specp, &empty); + if (r < 0) + switch (errno) + { + case EINTR: + /* SIGCHLD will show up as an EINTR. */ + return 0; + + case EBADF: + /* Someone closed the jobs pipe. + That shouldn't happen but if it does we're done. */ + O (fatal, NILF, _("job server shut down")); + + default: + pfatal_with_name (_("pselect jobs pipe")); + } + + if (r == 0) + /* Timeout. */ + return 0; + + /* The read FD is ready: read it! This is non-blocking. */ + EINTRLOOP (r, read (job_fds[0], &intake, 1)); + + if (r < 0) + { + /* Someone sniped our token! Try again. */ + if (errno == EAGAIN) + continue; + + pfatal_with_name (_("read jobs pipe")); + } + + /* read() should never return 0: only the parent make can reap all the + tokens and close the write side...?? */ + return r > 0; + } } #else @@ -288,69 +547,89 @@ unsigned int jobserver_acquire(int timeout) { during the section mentioned above, the read(2) will be invoked with an invalid FD and will return immediately with EBADF. */ -static RETSIGTYPE job_noop(int sig UNUSED) { +static void +job_noop (int sig UNUSED) +{ } /* Set the child handler action flags to FLAGS. */ -static void set_child_handler_action_flags(int set_handler, int set_alarm) { +static void +set_child_handler_action_flags (int set_handler, int set_alarm) +{ struct sigaction sa; - memset(&sa, '\0', sizeof sa); +#ifdef __EMX__ + /* The child handler must be turned off here. */ + signal (SIGCHLD, SIG_DFL); +#endif + + memset (&sa, '\0', sizeof sa); sa.sa_handler = child_handler; sa.sa_flags = set_handler ? 0 : SA_RESTART; #if defined SIGCHLD - if (sigaction(SIGCHLD, &sa, NULL) < 0) pfatal_with_name("sigaction: SIGCHLD"); + if (sigaction (SIGCHLD, &sa, NULL) < 0) + pfatal_with_name ("sigaction: SIGCHLD"); #endif #if defined SIGCLD && SIGCLD != SIGCHLD - if (sigaction(SIGCLD, &sa, NULL) < 0) pfatal_with_name("sigaction: SIGCLD"); + if (sigaction (SIGCLD, &sa, NULL) < 0) + pfatal_with_name ("sigaction: SIGCLD"); #endif #if defined SIGALRM - if (set_alarm) { - /* If we're about to enter the read(), set an alarm to wake up in a - second so we can check if the load has dropped and we can start more - work. On the way out, turn off the alarm and set SIG_DFL. */ - if (set_handler) { - sa.sa_handler = job_noop; - sa.sa_flags = 0; - if (sigaction(SIGALRM, &sa, NULL) < 0) - pfatal_with_name("sigaction: SIGALRM"); - alarm(1); - } else { - alarm(0); - sa.sa_handler = SIG_DFL; - sa.sa_flags = 0; - if (sigaction(SIGALRM, &sa, NULL) < 0) - pfatal_with_name("sigaction: SIGALRM"); + if (set_alarm) + { + /* If we're about to enter the read(), set an alarm to wake up in a + second so we can check if the load has dropped and we can start more + work. On the way out, turn off the alarm and set SIG_DFL. */ + if (set_handler) + { + sa.sa_handler = job_noop; + sa.sa_flags = 0; + if (sigaction (SIGALRM, &sa, NULL) < 0) + pfatal_with_name ("sigaction: SIGALRM"); + alarm (1); + } + else + { + alarm (0); + sa.sa_handler = SIG_DFL; + sa.sa_flags = 0; + if (sigaction (SIGALRM, &sa, NULL) < 0) + pfatal_with_name ("sigaction: SIGALRM"); + } } - } #endif } -unsigned int jobserver_acquire(int timeout) { +unsigned int +jobserver_acquire (int timeout) +{ char intake; int got_token; int saved_errno; /* Set interruptible system calls, and read() for a job token. */ - set_child_handler_action_flags(1, timeout); + set_child_handler_action_flags (1, timeout); - EINTRLOOP(got_token, read(job_rfd, &intake, 1)); + EINTRLOOP (got_token, read (job_rfd, &intake, 1)); saved_errno = errno; - set_child_handler_action_flags(0, timeout); + set_child_handler_action_flags (0, timeout); - if (got_token == 1) return 1; + if (got_token == 1) + return 1; /* If the error _wasn't_ expected (EINTR or EBADF), fatal. Otherwise, go back and reap_children(), and try again. */ errno = saved_errno; - if (errno != EINTR && errno != EBADF) pfatal_with_name(_("read jobs pipe")); + if (errno != EINTR && errno != EBADF && errno != EAGAIN) + pfatal_with_name (_("read jobs pipe")); - if (errno == EBADF) DB(DB_JOBS, ("Read returned EBADF.\n")); + if (errno == EBADF) + DB (DB_JOBS, ("Read returned EBADF.\n")); return 0; } @@ -359,28 +638,153 @@ unsigned int jobserver_acquire(int timeout) { #endif /* MAKE_JOBSERVER */ +#if !defined(NO_OUTPUT_SYNC) + +#define MUTEX_PREFIX "fnm:" + +static int osync_handle = -1; + +static char *osync_tmpfile = NULL; + +static unsigned int sync_root = 0; + +unsigned int +osync_enabled () +{ + return osync_handle >= 0; +} + +void +osync_setup () +{ + osync_handle = get_tmpfd (&osync_tmpfile); + fd_noinherit (osync_handle); + sync_root = 1; +} + +char * +osync_get_mutex () +{ + char *mutex = NULL; + + if (osync_enabled ()) + { + /* Prepare the mutex handle string for our children. */ + mutex = xmalloc (strlen (osync_tmpfile) + CSTRLEN (MUTEX_PREFIX) + 1); + sprintf (mutex, MUTEX_PREFIX "%s", osync_tmpfile); + } + + return mutex; +} + +unsigned int +osync_parse_mutex (const char *mutex) +{ + if (strncmp (mutex, MUTEX_PREFIX, CSTRLEN (MUTEX_PREFIX)) != 0) + { + OS (error, NILF, _("invalid --sync-mutex string '%s'"), mutex); + return 0; + } + + free (osync_tmpfile); + osync_tmpfile = xstrdup (mutex + CSTRLEN (MUTEX_PREFIX)); + + EINTRLOOP (osync_handle, open (osync_tmpfile, O_WRONLY)); + if (osync_handle < 0) + OSS (fatal, NILF, _("cannot open output sync mutex %s: %s"), + osync_tmpfile, strerror (errno)); + + fd_noinherit (osync_handle); + + return 1; +} + +void +osync_clear () +{ + if (osync_handle >= 0) + { + close (osync_handle); + osync_handle = -1; + } + + if (sync_root && osync_tmpfile) + { + int r; + + EINTRLOOP (r, unlink (osync_tmpfile)); + free (osync_tmpfile); + osync_tmpfile = NULL; + } +} + +unsigned int +osync_acquire () +{ + if (osync_enabled()) + { + struct flock fl; + + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 1; + /* We don't want to keep waiting on EINTR. */ + if (fcntl (osync_handle, F_SETLKW, &fl) == -1) + { + perror ("fcntl()"); + return 0; + } + } + + return 1; +} + +void +osync_release () +{ + if (osync_enabled()) + { + struct flock fl; + + fl.l_type = F_UNLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 1; + /* We don't want to keep waiting on EINTR. */ + if (fcntl (osync_handle, F_SETLKW, &fl) == -1) + perror ("fcntl()"); + } +} + +#endif + /* Create a "bad" file descriptor for stdin when parallel jobs are run. */ -int get_bad_stdin(void) { +int +get_bad_stdin () +{ static int bad_stdin = -1; /* Set up a bad standard input that reads from a broken pipe. */ - if (bad_stdin == -1) { - /* Make a file descriptor that is the read end of a broken pipe. - This will be used for some children's standard inputs. */ - int pd[2]; - if (pipe(pd) == 0) { - /* Close the write side. */ - (void)close(pd[1]); - /* Save the read side. */ - bad_stdin = pd[0]; + if (bad_stdin == -1) + { + /* Make a file descriptor that is the read end of a broken pipe. + This will be used for some children's standard inputs. */ + int pd[2]; + if (pipe (pd) == 0) + { + /* Close the write side. */ + close (pd[1]); + /* Save the read side. */ + bad_stdin = pd[0]; - /* Set the descriptor to close on exec, so it does not litter any - child's descriptor table. When it is dup2'd onto descriptor 0, - that descriptor will not close on exec. */ - fd_noinherit(bad_stdin); + /* Set the descriptor to close on exec, so it does not litter any + child's descriptor table. When it is dup2'd onto descriptor 0, + that descriptor will not close on exec. */ + fd_noinherit (bad_stdin); + } } - } return bad_stdin; } @@ -388,31 +792,107 @@ int get_bad_stdin(void) { /* Set file descriptors to be inherited / not inherited by subprocesses. */ #if !defined(F_SETFD) || !defined(F_GETFD) -void fd_inherit(int fd) {} -void fd_noinherit(int fd) {} +void fd_inherit (int fd) {} +void fd_noinherit (int fd) {} + #else -#ifndef FD_CLOEXEC -#define FD_CLOEXEC 1 -#endif +# ifndef FD_CLOEXEC +# define FD_CLOEXEC 1 +# endif -void fd_inherit(int fd) { +void +fd_inherit (int fd) +{ int flags; - EINTRLOOP(flags, fcntl(fd, F_GETFD)); - if (flags >= 0) { - int r; - flags &= ~FD_CLOEXEC; - EINTRLOOP(r, fcntl(fd, F_SETFD, flags)); - } + EINTRLOOP (flags, fcntl (fd, F_GETFD)); + if (flags >= 0) + { + int r; + flags &= ~FD_CLOEXEC; + EINTRLOOP (r, fcntl (fd, F_SETFD, flags)); + } } -void fd_noinherit(int fd) { - int flags; - EINTRLOOP(flags, fcntl(fd, F_GETFD)); - if (flags >= 0) { - int r; - flags |= FD_CLOEXEC; - EINTRLOOP(r, fcntl(fd, F_SETFD, flags)); - } +void +fd_noinherit (int fd) +{ + int flags; + EINTRLOOP (flags, fcntl(fd, F_GETFD)); + if (flags >= 0) + { + int r; + flags |= FD_CLOEXEC; + EINTRLOOP (r, fcntl(fd, F_SETFD, flags)); + } } #endif + +/* Set a file descriptor referring to a regular file to be in O_APPEND mode. + If it fails, just ignore it. */ + +void +fd_set_append (int fd) +{ +#if defined(F_GETFL) && defined(F_SETFL) && defined(O_APPEND) + struct stat stbuf; + int flags; + if (fstat (fd, &stbuf) == 0 && S_ISREG (stbuf.st_mode)) + { + flags = fcntl (fd, F_GETFL, 0); + if (flags >= 0) + { + int r; + EINTRLOOP(r, fcntl (fd, F_SETFL, flags | O_APPEND)); + } + } +#endif +} + +/* Return a file descriptor for a new anonymous temp file, or -1. */ +int +os_anontmp () +{ + const char *tdir = get_tmpdir (); + int fd = -1; + + if (IsLinux ()) + { + static unsigned int tmpfile_works = 1; + + if (tmpfile_works) + { + EINTRLOOP (fd, open (tdir, O_RDWR | O_TMPFILE | O_EXCL, 0600)); + if (fd >= 0) + return fd; + + DB (DB_BASIC, (_("Cannot open '%s' with O_TMPFILE: %s.\n"), + tdir, strerror (errno))); + tmpfile_works = 0; + } + } + +#if HAVE_DUP + /* If we can dup and we are creating temp files in the default location then + try tmpfile() + dup() + fclose() to avoid ever having a named file. */ + if (streq (tdir, DEFAULT_TMPDIR)) + { + mode_t mask = umask (0077); + FILE *tfile; + ENULLLOOP (tfile, tmpfile ()); + if (!tfile) + { + OS (error, NILF, "tmpfile: %s", strerror (errno)); + return -1; + } + umask (mask); + + EINTRLOOP (fd, dup (fileno (tfile))); + if (fd < 0) + OS (error, NILF, "dup: %s", strerror (errno)); + fclose (tfile); + } +#endif + + return fd; +} diff --git a/third_party/make/read.c b/third_party/make/read.c index e40eab123..11dadd344 100644 --- a/third_party/make/read.c +++ b/third_party/make/read.c @@ -1,5 +1,5 @@ /* Reading and parsing of makefiles for GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,22 +12,33 @@ 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 . */ +this program. If not, see . */ -#include "third_party/make/makeint.inc" -#include "third_party/make/filedef.h" -#include "third_party/make/dep.h" -#include "third_party/make/job.h" -#include "third_party/make/os.h" -#include "third_party/make/commands.h" -#include "third_party/make/variable.h" -#include "third_party/make/rule.h" -#include "third_party/make/debug.h" #include "third_party/musl/passwd.h" -#include "libc/runtime/runtime.h" -#include "third_party/make/hash.h" +#include "makeint.h" -# define GLOB_ALTDIRFUNC (1 << 9)/* Use gl_opendir et al functions. */ +#include + +#include "filedef.h" +#include "dep.h" +#include "job.h" +#include "os.h" +#include "commands.h" +#include "variable.h" +#include "rule.h" +#include "debug.h" +#include "hash.h" + + +#ifdef WINDOWS32 +#else /* !WINDOWS32 */ +#ifndef _AMIGA +#ifndef VMS +#else +struct passwd *getpwnam (char *name); +#endif +#endif +#endif /* !WINDOWS32 */ /* A 'struct ebuffer' controls the origin of the makefile we are currently eval'ing. @@ -50,9 +61,9 @@ struct vmodifiers unsigned int assign_v:1; unsigned int define_v:1; unsigned int undefine_v:1; - unsigned int export_v:1; unsigned int override_v:1; unsigned int private_v:1; + enum variable_export export_v ENUM_BITFIELD (2); }; /* Types of "words" that can be read in a makefile. */ @@ -94,7 +105,9 @@ static const char *default_include_directories[] = This is defined as a placeholder. */ # define INCLUDEDIR "." #endif +#if defined(INCLUDEDIR) INCLUDEDIR, +#endif #ifndef _AMIGA "/usr/gnu/include", "/usr/local/include", @@ -129,6 +142,8 @@ static void do_undefine (char *name, enum variable_origin origin, static struct variable *do_define (char *name, enum variable_origin origin, struct ebuffer *ebuf); static int conditional_line (char *line, size_t len, const floc *flocp); +static void check_specials (struct nameseq *filep, int set_default); +static void check_special_file (struct file *filep, const floc *flocp); static void record_files (struct nameseq *filenames, int are_also_makes, const char *pattern, const char *pattern_percent, char *depstr, @@ -148,9 +163,8 @@ static char *unescape_char (char *string, int c); /* Compare a word, both length and contents. - P must point to the word to be tested, and WLEN must be the length. -*/ -#define word1eq(s) (wlen == CSTRLEN (s) && strneq (s, p, CSTRLEN (s))) + P must point to the word to be tested, and WLEN must be the length. */ +#define word1eq(s) (wlen == CSTRLEN (s) && memcmp (s, p, CSTRLEN (s)) == 0) /* Read in all the makefiles and return a chain of targets to rebuild. */ @@ -176,15 +190,7 @@ read_all_makefiles (const char **makefiles) char *name, *p; size_t length; - { - /* Turn off --warn-undefined-variables while we expand MAKEFILES. */ - int save = warn_undefined_variables_flag; - warn_undefined_variables_flag = 0; - - value = allocated_variable_expand ("$(MAKEFILES)"); - - warn_undefined_variables_flag = save; - } + value = allocated_variable_expand ("$(MAKEFILES)"); /* Set NAME to the start of next token and LENGTH to its length. MAKEFILES is updated for finding remaining tokens. */ @@ -250,10 +256,6 @@ read_all_makefiles (const char **makefiles) { /* No default makefile was found. Add the default makefiles to the 'read_files' chain so they will be updated if possible. */ - struct goaldep *tail = read_files; - /* Add them to the tail, after any MAKEFILES variable makefiles. */ - while (tail != 0 && tail->next != 0) - tail = tail->next; for (p = default_makefiles; *p != 0; ++p) { struct goaldep *d = alloc_goaldep (); @@ -261,14 +263,9 @@ read_all_makefiles (const char **makefiles) /* Tell update_goal_chain to bail out as soon as this file is made, and main not to die if we can't make this file. */ d->flags = RM_DONTCARE; - if (tail == 0) - read_files = d; - else - tail->next = d; - tail = d; + d->next = read_files; + read_files = d; } - if (tail != 0) - tail->next = 0; } } @@ -348,37 +345,45 @@ eval_makefile (const char *filename, unsigned short flags) deps->error = errno; /* Check for unrecoverable errors: out of mem or FILE slots. */ + switch (deps->error) { - if (0 || #ifdef EMFILE - deps->error == EMFILE || + case EMFILE: #endif #ifdef ENFILE - deps->error == ENFILE || + case ENFILE: #endif - deps->error == ENOMEM) + case ENOMEM: { const char *err = strerror (deps->error); OS (fatal, reading_file, "%s", err); } } - /* If the makefile wasn't found and it's either a makefile from - the 'MAKEFILES' variable or an included makefile, - search the included makefile search path for this makefile. */ - if (ebuf.fp == 0 && (flags & RM_INCLUDED) && *filename != '/') + /* If the makefile wasn't found and it's either a makefile from the + 'MAKEFILES' variable or an included makefile, search the included + makefile search path for this makefile. */ + if (ebuf.fp == NULL && deps->error == ENOENT && include_directories + && ANY_SET (flags, RM_INCLUDED) + && !HAS_DRIVESPEC (filename) && !ISDIRSEP (*filename)) { - unsigned int i; - for (i = 0; include_directories[i] != 0; ++i) + const char **dir; + for (dir = include_directories; *dir != NULL; ++dir) { - const char *included = concat (3, include_directories[i], - "/", filename); - ebuf.fp = fopen (included, "r"); + const char *included = concat (3, *dir, "/", filename); + + ENULLLOOP(ebuf.fp, fopen (included, "r")); if (ebuf.fp) { filename = included; break; } + if (errno != ENOENT) + { + filename = included; + deps->error = errno; + break; + } } } @@ -389,6 +394,7 @@ eval_makefile (const char *filename, unsigned short flags) deps->file = enter_file (filename); filename = deps->file->name; deps->flags = flags; + deps->file->is_explicit = 1; free (expanded); @@ -405,6 +411,11 @@ eval_makefile (const char *filename, unsigned short flags) /* Success; clear errno. */ deps->error = 0; + /* If we tried and failed to read the included file before but this + time we succeeded, reset the last mtime. */ + if (deps->file->last_mtime == NONEXISTENT_MTIME) + deps->file->last_mtime = 0; + /* Avoid leaking the makefile to children. */ fd_noinherit (fileno (ebuf.fp)); @@ -427,10 +438,7 @@ eval_makefile (const char *filename, unsigned short flags) fclose (ebuf.fp); free (ebuf.bufstart); - - /* [jart] breaks gcc11 (also wat) */ - void *volatile wat = alloca (0); - (void)wat; + free_alloca (); errno = 0; return deps; @@ -472,9 +480,7 @@ eval_buffer (char *buffer, const floc *flocp) reading_file = curfile; - /* [jart] breaks gcc11 (also wat) */ - void *volatile wat = alloca (0); - (void)wat; + free_alloca (); } /* Check LINE to see if it's a variable assignment or undefine. @@ -489,7 +495,7 @@ eval_buffer (char *buffer, const floc *flocp) based on the modifiers found if any, plus V_ASSIGN is 1. */ static char * -parse_var_assignment (const char *line, struct vmodifiers *vmod) +parse_var_assignment (const char *line, int targvar, struct vmodifiers *vmod) { const char *p; memset (vmod, '\0', sizeof (*vmod)); @@ -517,19 +523,21 @@ parse_var_assignment (const char *line, struct vmodifiers *vmod) wlen = p2 - p; if (word1eq ("export")) - vmod->export_v = 1; + vmod->export_v = v_export; + else if (word1eq ("unexport")) + vmod->export_v = v_noexport; else if (word1eq ("override")) vmod->override_v = 1; else if (word1eq ("private")) vmod->private_v = 1; - else if (word1eq ("define")) + else if (!targvar && word1eq ("define")) { /* We can't have modifiers after 'define' */ vmod->define_v = 1; p = next_token (p2); break; } - else if (word1eq ("undefine")) + else if (!targvar && word1eq ("undefine")) { /* We can't have modifiers after 'undefine' */ vmod->undefine_v = 1; @@ -714,7 +722,7 @@ eval (struct ebuffer *ebuf, int set_default) /* See if this is a variable assignment. We need to do this early, to allow variables with names like 'ifdef', 'export', 'private', etc. */ - p = parse_var_assignment (p, &vmod); + p = parse_var_assignment (p, 0, &vmod); if (vmod.assign_v) { struct variable *v; @@ -743,8 +751,8 @@ eval (struct ebuffer *ebuf, int set_default) assert (v != NULL); - if (vmod.export_v) - v->export = v_export; + if (vmod.export_v != v_default) + v->export = vmod.export_v; if (vmod.private_v) v->private_var = 1; @@ -898,9 +906,7 @@ eval (struct ebuffer *ebuf, int set_default) | (set_default ? 0 : RM_NO_DEFAULT_GOAL)); struct goaldep *d = eval_makefile (files->name, flags); - - if (errno) - d->floc = *fstart; + d->floc = *fstart; free_ns (files); files = next; @@ -944,28 +950,38 @@ eval (struct ebuffer *ebuf, int set_default) struct nameseq *next = files->next; const char *name = files->name; struct goaldep *deps; + struct file *f; int r; - /* Load the file. 0 means failure. */ - r = load_file (&ebuf->floc, &name, noerror); - if (! r && ! noerror) - OS (fatal, &ebuf->floc, _("%s: failed to load"), name); + { + struct file file = {0}; + file.name = name; + /* Load the file. 0 means failure. */ + r = load_file (&ebuf->floc, &file, noerror); + if (! r && ! noerror) + OS (fatal, &ebuf->floc, _("%s: failed to load"), name); + name = file.name; + } + + f = lookup_file (name); + if (!f) + f = enter_file (name); + f->loaded = 1; + f->unloaded = 0; free_ns (files); files = next; - /* Return of -1 means a special load: don't rebuild it. */ + /* Return of -1 means don't ever try to rebuild. */ if (r == -1) continue; - /* It succeeded, so add it to the list "to be rebuilt". */ + /* Otherwise add it to the list to be rebuilt. */ deps = alloc_goaldep (); deps->next = read_files; + deps->floc = ebuf->floc; read_files = deps; - deps->file = lookup_file (name); - if (deps->file == 0) - deps->file = enter_file (name); - deps->file->loaded = 1; + deps->file = f; } continue; @@ -989,7 +1005,7 @@ eval (struct ebuffer *ebuf, int set_default) { enum make_word_type wtype; - char *cmdleft, *semip, *lb_next; + char *cmdleft, *semip = 0, *lb_next; size_t plen = 0; char *colonp; const char *end, *beg; /* Helpers for whitespace stripping. */ @@ -1009,9 +1025,11 @@ eval (struct ebuffer *ebuf, int set_default) cmdleft = 0; } else if (cmdleft != 0) - /* Found one. Cut the line short there before expanding it. */ - *(cmdleft++) = '\0'; - semip = cmdleft; + { + /* Found one. Cut the line short there before expanding it. */ + semip = cmdleft++; + *semip = '\0'; + } collapse_continuations (line); @@ -1085,7 +1103,7 @@ eval (struct ebuffer *ebuf, int set_default) Note that the only separators of targets in this context are whitespace and a left paren. If others are possible, add them to the string in the call to strchr. */ - while (colonp && (colonp[1] == '/' || colonp[1] == '\\') && + while (colonp && ISDIRSEP (colonp[1]) && isalpha ((unsigned char) colonp[-1]) && (colonp == p2 + 1 || strchr (" \t(", colonp[-2]) != 0)) colonp = find_char_unquote (colonp + 1, ':'); @@ -1114,20 +1132,29 @@ eval (struct ebuffer *ebuf, int set_default) p2 = next_token (variable_buffer); - /* If the word we're looking at is EOL, see if there's _anything_ - on the line. If not, a variable expanded to nothing, so ignore - it. If so, we can't parse this line so punt. */ + /* If we're at EOL we didn't find a separator so we don't know what + kind of line this is. */ if (wtype == w_eol) { + /* Ignore an empty line. */ if (*p2 == '\0') continue; - /* There's no need to be ivory-tower about this: check for - one of the most common bugs found in makefiles... */ + /* Check for spaces instead of TAB. */ if (cmd_prefix == '\t' && strneq (line, " ", 8)) O (fatal, fstart, _("missing separator (did you mean TAB instead of 8 spaces?)")); - else - O (fatal, fstart, _("missing separator")); + + /* Check for conditionals without whitespace afterward. + We don't check ifdef/ifndef because there's no real way to miss + whitespace there. */ + p2 = next_token (line); + if (strneq (p2, "if", 2) && + ((strneq (&p2[2], "neq", 3) && !STOP_SET (p2[5], MAP_BLANK)) + || (strneq (&p2[2], "eq", 2) && !STOP_SET (p2[4], MAP_BLANK)))) + O (fatal, fstart, _("missing separator (ifeq/ifneq must be followed by whitespace)")); + + /* No idea... */ + O (fatal, fstart, _("missing separator")); } { @@ -1174,7 +1201,7 @@ eval (struct ebuffer *ebuf, int set_default) p2 = variable_buffer + l; } - p2 = parse_var_assignment (p2, &vmod); + p2 = parse_var_assignment (p2, 1, &vmod); if (vmod.assign_v) { /* If there was a semicolon found, add it back, plus anything @@ -1182,7 +1209,7 @@ eval (struct ebuffer *ebuf, int set_default) if (semip) { size_t l = p2 - variable_buffer; - *__veil("r", (--semip)) = ';'; + *semip = ';'; collapse_continuations (semip); variable_buffer_output (p2 + strlen (p2), semip, strlen (semip)+1); @@ -1256,8 +1283,7 @@ eval (struct ebuffer *ebuf, int set_default) do { check_again = 0; /* For DOS-style paths, skip a "C:\..." or a "C:/..." */ - if (p != 0 && (p[1] == '\\' || p[1] == '/') && - isalpha ((unsigned char)p[-1]) && + if (p != 0 && ISDIRSEP (p[1]) && isalpha ((unsigned char)p[-1]) && (p == p2 + 1 || strchr (" \t:(", p[-2]) != 0)) { p = strchr (p + 1, ':'); check_again = 1; @@ -1314,79 +1340,7 @@ eval (struct ebuffer *ebuf, int set_default) commands[commands_idx++] = '\n'; } - /* Determine if this target should be made default. We used to do - this in record_files() but because of the delayed target recording - and because preprocessor directives are legal in target's commands - it is too late. Consider this fragment for example: - - foo: - - ifeq ($(.DEFAULT_GOAL),foo) - ... - endif - - Because the target is not recorded until after ifeq directive is - evaluated the .DEFAULT_GOAL does not contain foo yet as one - would expect. Because of this we have to move the logic here. */ - - if (set_default && default_goal_var->value[0] == '\0') - { - struct dep *d; - struct nameseq *t = filenames; - - for (; t != 0; t = t->next) - { - int reject = 0; - const char *name = t->name; - - /* We have nothing to do if this is an implicit rule. */ - if (strchr (name, '%') != 0) - break; - - /* See if this target's name does not start with a '.', - unless it contains a slash. */ - if (*name == '.' && strchr (name, '/') == 0 -#ifdef HAVE_DOS_PATHS - && strchr (name, '\\') == 0 -#endif - ) - continue; - - - /* If this file is a suffix, don't let it be - the default goal file. */ - for (d = suffix_file->deps; d != 0; d = d->next) - { - struct dep *d2; - if (*dep_name (d) != '.' && streq (name, dep_name (d))) - { - reject = 1; - break; - } - for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next) - { - size_t l = strlen (dep_name (d2)); - if (!strneq (name, dep_name (d2), l)) - continue; - if (streq (name + l, dep_name (d))) - { - reject = 1; - break; - } - } - - if (reject) - break; - } - - if (!reject) - { - define_variable_global (".DEFAULT_GOAL", 13, t->name, - o_file, 0, NILF); - break; - } - } - } + check_specials (filenames, set_default); } } @@ -1904,7 +1858,8 @@ record_target_var (struct nameseq *filenames, char *defn, /* Set up the variable to be *-specific. */ v->per_target = 1; v->private_var = vmod->private_v; - v->export = vmod->export_v ? v_export : v_default; + if (vmod->export_v != v_default) + v->export = vmod->export_v; /* If it's not an override, check to see if there was a command-line setting. If so, reset the value. */ @@ -1927,6 +1882,131 @@ record_target_var (struct nameseq *filenames, char *defn, } } + +/* Check for special targets. We used to do this in record_files() but that's + too late: by the time we get there we'll have already parsed the next line + and it have been mis-parsed because these special targets haven't been + considered yet. */ + +static void +check_specials (struct nameseq *files, int set_default) +{ + struct nameseq *t; + + for (t = files; t != NULL; t = t->next) + { + const char* nm = t->name; + + if (!posix_pedantic && streq (nm, ".POSIX")) + { + posix_pedantic = 1; + define_variable_cname (".SHELLFLAGS", "-ec", o_default, 0); + /* These default values are based on IEEE Std 1003.1-2008. + It requires '-O 1' for [CF]FLAGS, but GCC doesn't allow + space between -O and the number so omit it here. */ + define_variable_cname ("CC", "c99", o_default, 0); + define_variable_cname ("CFLAGS", "-O1", o_default, 0); + define_variable_cname ("FC", "fort77", o_default, 0); + define_variable_cname ("FFLAGS", "-O1", o_default, 0); + define_variable_cname ("SCCSGETFLAGS", "-s", o_default, 0); + define_variable_cname ("ARFLAGS", "-rv", o_default, 0); + continue; + } + + if (!second_expansion && streq (nm, ".SECONDEXPANSION")) + { + second_expansion = 1; + continue; + } + +#if !defined (__MSDOS__) && !defined (__EMX__) + if (!one_shell && streq (nm, ".ONESHELL")) + { + one_shell = 1; + continue; + } +#endif + + /* Determine if this target should be made default. */ + + if (set_default && default_goal_var->value[0] == '\0') + { + struct dep *d; + int reject = 0; + + /* We have nothing to do if this is an implicit rule. */ + if (strchr (nm, '%') != 0) + break; + + /* See if this target's name does not start with a '.', + unless it contains a slash. */ + if (*nm == '.' && strchr (nm, '/') == 0 +#ifdef HAVE_DOS_PATHS + && strchr (nm, '\\') == 0 +#endif + ) + continue; + + /* If this file is a suffix, it can't be the default goal file. */ + for (d = suffix_file->deps; d != 0; d = d->next) + { + struct dep *d2; + if (*dep_name (d) != '.' && streq (nm, dep_name (d))) + { + reject = 1; + break; + } + for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next) + { + size_t l = strlen (dep_name (d2)); + if (!strneq (nm, dep_name (d2), l)) + continue; + if (streq (nm + l, dep_name (d))) + { + reject = 1; + break; + } + } + + if (reject) + break; + } + + if (!reject) + define_variable_global (".DEFAULT_GOAL", 13, t->name, + o_file, 0, NILF); + } + } +} + +/* Check for special targets. We used to do this in record_files() but that's + too late: by the time we get there we'll have already parsed the next line + and it have been mis-parsed because these special targets haven't been + considered yet. */ + +static void +check_special_file (struct file *file, const floc *flocp) +{ + if (streq (file->name, ".WAIT")) + { + static unsigned int wpre = 0, wcmd = 0; + + if (!wpre && file->deps) + { + O (error, flocp, _(".WAIT should not have prerequisites")); + wpre = 1; + } + + if (!wcmd && file->cmds) + { + O (error, flocp, _(".WAIT should not have commands")); + wcmd = 1; + } + + return; + } +} + /* Record a description line for files FILENAMES, with dependencies DEPS, commands to execute described by COMMANDS and COMMANDS_IDX, coming from FILENAME:COMMANDS_STARTED. @@ -2068,29 +2148,6 @@ record_files (struct nameseq *filenames, int are_also_makes, free_ns (filenames); - /* Check for special targets. Do it here instead of, say, snap_deps() - so that we can immediately use the value. */ - if (!posix_pedantic && streq (name, ".POSIX")) - { - posix_pedantic = 1; - define_variable_cname (".SHELLFLAGS", "-ec", o_default, 0); - /* These default values are based on IEEE Std 1003.1-2008. - It requires '-O 1' for [CF]FLAGS, but GCC doesn't allow space - between -O and the number so omit it here. */ - define_variable_cname ("ARFLAGS", "-rv", o_default, 0); - define_variable_cname ("CC", "c99", o_default, 0); - define_variable_cname ("CFLAGS", "-O1", o_default, 0); - define_variable_cname ("FC", "fort77", o_default, 0); - define_variable_cname ("FFLAGS", "-O1", o_default, 0); - define_variable_cname ("SCCSGETFLAGS", "-s", o_default, 0); - } - else if (!second_expansion && streq (name, ".SECONDEXPANSION")) - second_expansion = 1; -#if !defined (__MSDOS__) && !defined (__EMX__) - else if (!one_shell && streq (name, ".ONESHELL")) - one_shell = 1; -#endif - /* If this is a static pattern rule: 'targets: target%pattern: prereq%pattern; recipe', make sure the pattern matches this target name. */ @@ -2147,6 +2204,11 @@ record_files (struct nameseq *filenames, int are_also_makes, free_dep_chain (f->deps); f->deps = 0; } + /* This file is explicitly mentioned as a target. There is no need + to set is_explicit in the case of double colon below, because an + implicit double colon rule only applies when the prerequisite + exists. A prerequisite which exists is not intermediate anyway. */ + f->is_explicit = 1; } else { @@ -2189,10 +2251,9 @@ record_files (struct nameseq *filenames, int are_also_makes, if (pattern) { static const char *percent = "%"; - char *buffer = variable_expand (""); - char *o = patsubst_expand_pat (buffer, name, pattern, percent, - pattern_percent+1, percent+1); - f->stem = strcache_add_len (buffer, o - buffer); + char *o = patsubst_expand_pat (variable_buffer, name, pattern, + percent, pattern_percent+1, percent+1); + f->stem = strcache_add_len (variable_buffer, o - variable_buffer); if (this) { if (! this->need_2nd_expansion) @@ -2233,6 +2294,8 @@ record_files (struct nameseq *filenames, int are_also_makes, name = f->name; + check_special_file (f, flocp); + /* All done! Set up for the next one. */ if (nextf == 0) break; @@ -2343,8 +2406,12 @@ find_map_unquote (char *string, int stopmap) string_len = strlen (string); /* The number of backslashes is now -I. Copy P over itself to swallow half of them. */ - memmove (&p[i], &p[i/2], (string_len - (p - string)) - (i/2) + 1); - p += i/2; + { + /* Avoid arithmetic conversion of negative values to unsigned. */ + int hi = -(i/2); + memmove (&p[i], &p[i/2], (string_len - (p - string)) + hi + 1); + p += i/2; + } if (i % 2 == 0) /* All the backslashes quoted each other; the STOPCHAR was unquoted. */ @@ -2386,8 +2453,12 @@ find_char_unquote (char *string, int stop) string_len = strlen (string); /* The number of backslashes is now -I. Copy P over itself to swallow half of them. */ - memmove (&p[i], &p[i/2], (string_len - (p - string)) - (i/2) + 1); - p += i/2; + { + /* Avoid arithmetic conversion of negative values to unsigned. */ + int hi = -(i/2); + memmove (&p[i], &p[i/2], (string_len - (p - string)) + hi + 1); + p += i/2; + } if (i % 2 == 0) /* All the backslashes quoted each other; the STOPCHAR was unquoted. */ @@ -2457,81 +2528,65 @@ find_percent (char *pattern) return find_char_unquote (pattern, '%'); } -/* Search STRING for an unquoted % and handle quoting. Returns a pointer to - the % or NULL if no % was found. +/* Return a pointer to the first unescaped %, or NULL if there isn't one. + Compress any escape chars up to the first unescaped %, but not afterward. This version is used with strings in the string cache: if there's a need to - modify the string a new version will be added to the string cache and - *STRING will be set to that. */ + modify the string to handle escape chars a new version will be added to the + string cache and *STRING will be set to that. */ const char * find_percent_cached (const char **string) { - const char *p = *string; - char *new = 0; - size_t slen = 0; + const char *p = strchr (*string, '%'); + char *new, *np; + size_t slen; - /* If the first char is a % return now. This lets us avoid extra tests - inside the loop. */ - if (*p == '%') + /* If there is no % or there is but it's not escaped, reuse this string. */ + if (!p || p == *string || p[-1] != '\\') return p; - while (1) + /* We must create a new cached string with backslashes compressed. */ + slen = strlen (*string); + new = alloca (slen + 1); + memcpy (new, *string, slen + 1); + np = new + (p - *string); + + do { - p = strchr(p, '%'); + /* Remember where the percent is. */ + char *pp = np; + int i = -2; - if (!p) - break; - - /* See if this % is escaped with a backslash; if not we're done. */ - if (p[-1] != '\\') - break; + /* This % is preceded by a backslash; search for more backslashes. */ + while (&np[i] >= new && np[i] == '\\') + --i; + ++i; + /* The number of backslashes is -I. Copy the string over itself to + swallow half of them. */ { - /* Search for more backslashes. */ - char *pv; - int i = -2; - - while (&p[i] >= *string && p[i] == '\\') - --i; - ++i; - - /* At this point we know we'll need to allocate a new string. - Make a copy if we haven't yet done so. */ - if (! new) - { - slen = strlen (*string); - /* [jart] can't prove alloca() isn't returned; let's just leak */ - new = malloc (slen + 1); - memcpy (new, *string, slen + 1); - p = new + (p - *string); - *string = new; - } - - /* At this point *string, p, and new all point into the same string. - Get a non-const version of p so we can modify new. */ - pv = new + (p - *string); - - /* The number of backslashes is now -I. - Copy P over itself to swallow half of them. */ - memmove (&pv[i], &pv[i/2], (slen - (pv - new)) - (i/2) + 1); - p += i/2; - - /* If the backslashes quoted each other; the % was unquoted. */ - if (i % 2 == 0) - break; + /* Avoid arithmetic conversion of negative values to unsigned. */ + int hi = -(i/2); + memmove (&pp[i], &pp[i/2], (slen - (pp - new)) + hi + 1); } - } - /* If we had to change STRING, add it to the strcache. */ - if (new) - { - *string = strcache_add (*string); - if (p) - p = *string + (p - new); + /* Update SLEN and set NP to point after the %. */ + slen += i/2 + i%2; + np += i/2; + + /* If all backslashes quoted each other then % was unquoted. */ + if (i % 2 == 0) + break; + + np = strchr (np, '%'); } + while (np && np[-1] == '\\'); + + /* Add the new string to the strcache. */ + *string = strcache_add (new); /* If we didn't find a %, return NULL. Otherwise return a ptr to it. */ - return p; + return np ? *string + (np - new) : NULL; } /* Find the next line of text in an eval buffer, combining continuation lines @@ -2723,7 +2778,7 @@ get_next_mword (char *buffer, char **startp, size_t *length) char c; /* Skip any leading whitespace. */ - while (ISBLANK (*p)) + while (ISSPACE (*p)) ++p; beg = p; @@ -2809,11 +2864,11 @@ get_next_mword (char *buffer, char **startp, size_t *length) char closeparen; int count; + if (END_OF_TOKEN (c)) + goto done_word; + switch (c) { - case '\0': - case ' ': - case '\t': case '=': goto done_word; @@ -2913,6 +2968,7 @@ construct_include_path (const char **arg_dirs) const char **dirs; const char **cpp; size_t idx; + int disable = 0; /* Compute the number of pointers we need in the table. */ idx = sizeof (default_include_directories) / sizeof (const char *); @@ -2931,7 +2987,8 @@ construct_include_path (const char **arg_dirs) max_incl_len = 0; /* First consider any dirs specified with -I switches. - Ignore any that don't exist. Remember the maximum string length. */ + Ignore any that don't exist. Restart if we find "-". + Remember the maximum string length. */ if (arg_dirs) while (*arg_dirs != 0) @@ -2940,6 +2997,14 @@ construct_include_path (const char **arg_dirs) char *expanded = 0; int e; + if (dir[0] == '-' && dir[1] == '\0') + { + disable = 1; + idx = 0; + max_incl_len = 0; + continue; + } + if (dir[0] == '~') { expanded = tilde_expand (dir); @@ -2963,41 +3028,40 @@ construct_include_path (const char **arg_dirs) } /* Now add the standard default dirs at the end. */ - -#ifdef __MSDOS__ - { - /* The environment variable $DJDIR holds the root of the DJGPP directory - tree; add ${DJDIR}/include. */ - struct variable *djdir = lookup_variable ("DJDIR", 5); - - if (djdir) - { - size_t len = strlen (djdir->value) + 8; - char *defdir = alloca (len + 1); - - strcat (strcpy (defdir, djdir->value), "/include"); - dirs[idx++] = strcache_add (defdir); - - if (len > max_incl_len) - max_incl_len = len; - } - } -#endif - - for (cpp = default_include_directories; *cpp != 0; ++cpp) + if (!disable) { - int e; +#ifdef __MSDOS__ + /* The environment variable $DJDIR holds the root of the DJGPP directory + tree; add ${DJDIR}/include. */ + struct variable *djdir = lookup_variable ("DJDIR", 5); - EINTRLOOP (e, stat (*cpp, &stbuf)); - if (e == 0 && S_ISDIR (stbuf.st_mode)) + if (djdir) { - size_t len = strlen (*cpp); - /* If dir name is written with trailing slashes, discard them. */ - while (len > 1 && (*cpp)[len - 1] == '/') - --len; + size_t len = strlen (djdir->value) + 8; + char *defdir = alloca (len + 1); + + strcat (strcpy (defdir, djdir->value), "/include"); + dirs[idx++] = strcache_add (defdir); + if (len > max_incl_len) max_incl_len = len; - dirs[idx++] = strcache_add_len (*cpp, len); + } +#endif + for (cpp = default_include_directories; *cpp != 0; ++cpp) + { + int e; + + EINTRLOOP (e, stat (*cpp, &stbuf)); + if (e == 0 && S_ISDIR (stbuf.st_mode)) + { + size_t len = strlen (*cpp); + /* If dir name is written with trailing slashes, discard them. */ + while (len > 1 && (*cpp)[len - 1] == '/') + --len; + if (len > max_incl_len) + max_incl_len = len; + dirs[idx++] = strcache_add_len (*cpp, len); + } } } @@ -3005,10 +3069,12 @@ construct_include_path (const char **arg_dirs) /* Now add each dir to the .INCLUDE_DIRS variable. */ + do_variable_definition (NILF, ".INCLUDE_DIRS", "", o_default, f_simple, 0); for (cpp = dirs; *cpp != 0; ++cpp) do_variable_definition (NILF, ".INCLUDE_DIRS", *cpp, o_default, f_append, 0); + free ((void *) include_directories); include_directories = dirs; } @@ -3018,7 +3084,7 @@ construct_include_path (const char **arg_dirs) char * tilde_expand (const char *name) { -#ifndef VMS +#if !defined(VMS) if (name[1] == '/' || name[1] == '\0') { char *home_dir; @@ -3073,8 +3139,9 @@ tilde_expand (const char *name) { if (userend == 0) return xstrdup (pwent->pw_dir); - else - return xstrdup (concat (3, pwent->pw_dir, "/", userend + 1)); + + *userend = '/'; + return xstrdup (concat (3, pwent->pw_dir, "/", userend + 1)); } else if (userend != 0) *userend = '/'; @@ -3107,6 +3174,8 @@ tilde_expand (const char *name) PARSEFS_EXISTS - Only return globbed files that actually exist (cannot also set NOGLOB) PARSEFS_NOCACHE - Do not add filenames to the strcache (caller frees) + PARSEFS_ONEWORD - Don't break the sequence on whitespace + PARSEFS_WAIT - Assume struct dep and handle .WAIT */ void * @@ -3122,16 +3191,22 @@ parse_file_seq (char **stringp, size_t size, int stopmap, struct nameseq *new = 0; struct nameseq **newp = &new; #define NEWELT(_n) do { \ - const char *__n = (_n); \ - *newp = xcalloc (1, size); \ - (*newp)->name = (cachep ? strcache_add (__n) : xstrdup (__n)); \ - newp = &(*newp)->next; \ + struct nameseq *_ns = xcalloc (size); \ + const char *__n = (_n); \ + _ns->name = (cachep ? strcache_add (__n) : xstrdup (__n)); \ + if (found_wait) { \ + ((struct dep*)_ns)->wait_here = 1; \ + found_wait = 0; \ + } \ + *newp = _ns; \ + newp = &_ns->next; \ } while(0) char *p; glob_t gl; char *tp; int findmap = stopmap|MAP_VMSCOMMA|MAP_NUL; + int found_wait = 0; if (NONE_SET (flags, PARSEFS_ONEWORD)) findmap |= MAP_BLANK; @@ -3198,20 +3273,28 @@ parse_file_seq (char **stringp, size_t size, int stopmap, Tokens separated by spaces are treated as separate paths since make doesn't allow path names with spaces. */ if (p && p == s+1 && p[0] == ':' - && isalpha ((unsigned char)s[0]) && STOP_SET (p[1], MAP_DIRSEP)) + && isalpha ((unsigned char)s[0]) && ISDIRSEP (p[1])) p = find_map_unquote (p+1, findmap); #endif if (!p) p = s + strlen (s); + if (ANY_SET (flags, PARSEFS_WAIT) && p - s == CSTRLEN (".WAIT") + && memcmp (s, ".WAIT", CSTRLEN (".WAIT")) == 0) + { + /* Note that we found a .WAIT for the next dep but skip it. */ + found_wait = 1; + continue; + } + /* Strip leading "this directory" references. */ if (NONE_SET (flags, PARSEFS_NOSTRIP)) #ifdef VMS - /* Skip leading '[]'s. should only be one set or bug somwhere else */ + /* Skip leading '[]'s. should only be one set or bug somewhere else */ if (p - s > 2 && s[0] == '[' && s[1] == ']') s += 2; - /* Skip leading '<>'s. should only be one set or bug somwhere else */ + /* Skip leading '<>'s. should only be one set or bug somewhere else */ if (p - s > 2 && s[0] == '<' && s[1] == '>') s += 2; #endif diff --git a/third_party/make/remake.c b/third_party/make/remake.c index 0b24e3dfc..a8afc7e19 100644 --- a/third_party/make/remake.c +++ b/third_party/make/remake.c @@ -1,5 +1,5 @@ /* Basic dependency engine for GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,16 +12,39 @@ 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 . */ +this program. If not, see . */ + +#include "makeint.h" +#include "filedef.h" +#include "job.h" +#include "commands.h" +#include "dep.h" +#include "variable.h" +#include "debug.h" + +#include + +#ifdef HAVE_FCNTL_H +#include +#else +#include +#endif + +#ifdef VMS +#include +#endif +#ifdef WINDOWS32 +#include +#include +#include +#if defined(_MSC_VER) && _MSC_VER > 1200 +/* VC7 or later supports _stat64 to access 64-bit file size. */ +#define STAT _stat64 +#else +#define STAT stat +#endif +#endif -#include "third_party/make/makeint.inc" -#include "third_party/make/filedef.h" -#include "third_party/make/job.h" -#include "third_party/make/commands.h" -#include "third_party/make/dep.h" -#include "third_party/make/variable.h" -#include "libc/runtime/runtime.h" -#include "third_party/make/debug.h" /* The test for circular dependencies is based on the 'updating' bit in 'struct file'. However, double colon targets have separate 'struct @@ -56,8 +79,27 @@ static FILE_TIMESTAMP name_mtime (const char *name); static const char *library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr); -/* Remake all the goals in the 'struct dep' chain GOALS. Return -1 if nothing - was done, 0 if all goals were updated successfully, or 1 if a goal failed. +static void +check_also_make (const struct file *file) +{ + struct dep *ad; + FILE_TIMESTAMP mtime = file->last_mtime; + + if (mtime == UNKNOWN_MTIME) + mtime = name_mtime (file->name); + + /* If we updated the file, check its also-make files. */ + + if (is_ordinary_mtime (mtime) && mtime > file->mtime_before_update) + for (ad = file->also_make; ad; ad = ad->next) + if (ad->file->last_mtime == NONEXISTENT_MTIME) + OS (error, file->cmds ? &file->cmds->fileinfo : NILF, + _("warning: pattern recipe did not update peer target '%s'."), + ad->file->name); +} + +/* Remake all the goals in the 'struct dep' chain GOALS. Return update_status + representing the totality of the status of the goals. If rebuilding_makefiles is nonzero, these goals are makefiles, so -t, -q, and -n should be disabled for them unless they were also command-line @@ -67,12 +109,13 @@ static const char *library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr); enum update_status update_goal_chain (struct goaldep *goaldeps) { + unsigned long last_cmd_count = 0; int t = touch_flag, q = question_flag, n = just_print_flag; enum update_status status = us_none; /* Duplicate the chain so we can remove things from it. */ - - struct dep *goals = copy_dep_chain ((struct dep *)goaldeps); + struct dep *goals_orig = copy_dep_chain ((struct dep *)goaldeps); + struct dep *goals = goals_orig; goal_list = rebuilding_makefiles ? goaldeps : NULL; @@ -86,24 +129,29 @@ update_goal_chain (struct goaldep *goaldeps) while (goals != 0) { - struct dep *g, *lastgoal; + struct dep *gu, *g, *lastgoal; /* Start jobs that are waiting for the load to go down. */ start_waiting_jobs (); - /* Wait for a child to die. */ + /* Check for exited children. If no children have finished since the + last time we looked, then block until one exits. If some have + exited don't block, so we can possibly do more work. */ - reap_children (1, 0); + reap_children (last_cmd_count == command_count, 0); + last_cmd_count = command_count; lastgoal = 0; - g = goals; - while (g != 0) + gu = goals; + while (gu != 0) { /* Iterate over all double-colon entries for this file. */ struct file *file; int stop = 0, any_not_updated = 0; + g = gu->shuf ? gu->shuf : gu; + goal_dep = g; for (file = g->file->double_colon ? g->file->double_colon : g->file; @@ -163,8 +211,7 @@ update_goal_chain (struct goaldep *goaldeps) FILE_TIMESTAMP mtime = MTIME (file); check_renamed (file); - if (file->updated && g->changed && - mtime != file->mtime_before_update) + if (file->updated && mtime != file->mtime_before_update) { /* Updating was done. If this is a makefile and just_print_flag or question_flag is set (meaning @@ -214,31 +261,30 @@ update_goal_chain (struct goaldep *goaldeps) /* This goal is finished. Remove it from the chain. */ if (lastgoal == 0) - goals = g->next; + goals = gu->next; else - lastgoal->next = g->next; + lastgoal->next = gu->next; - /* Free the storage. */ - free (g); - - g = lastgoal == 0 ? goals : lastgoal->next; + gu = lastgoal == 0 ? goals : lastgoal->next; if (stop) break; } else { - lastgoal = g; - g = g->next; + lastgoal = gu; + gu = gu->next; } } /* If we reached the end of the dependency graph update CONSIDERED for the next pass. */ - if (g == 0) + if (gu == 0) ++considered; } + free_dep_chain (goals_orig); + if (rebuilding_makefiles) { touch_flag = t; @@ -266,7 +312,7 @@ show_goal_error (void) if (goal->error) { OSS (error, &goal->floc, "%s: %s", - goal->file->name, strerror ((int)goal->error)); + goal->file->name, strerror (goal->error)); goal->error = 0; } return; @@ -322,8 +368,7 @@ update_file (struct file *file, unsigned int depth) check_renamed (f); /* Clean up any alloca() used during the update. */ - void *volatile wat = alloca (0); - (void)wat; + free_alloca (); /* If we got an error, don't bother with double_colon etc. */ if (new && !keep_going_flag) @@ -395,7 +440,7 @@ complain (struct file *file) } /* Consider a single 'struct file' and update it as appropriate. - Return 0 on success, or non-0 on failure. */ + Return an update_status value; use us_success if we aren't sure yet. */ static enum update_status update_file_1 (struct file *file, unsigned int depth) @@ -404,7 +449,7 @@ update_file_1 (struct file *file, unsigned int depth) FILE_TIMESTAMP this_mtime; int noexist, must_make, deps_changed; struct file *ofile; - struct dep *d, *ad; + struct dep *du, *d, *ad; struct dep amake; int running = 0; @@ -428,7 +473,7 @@ update_file_1 (struct file *file, unsigned int depth) } DBF (DB_VERBOSE, _("File '%s' was considered already.\n")); - return 0; + return us_success; } switch (file->command_state) @@ -438,7 +483,7 @@ update_file_1 (struct file *file, unsigned int depth) break; case cs_running: DBF (DB_VERBOSE, _("Still updating file '%s'.\n")); - return 0; + return us_success; case cs_finished: DBF (DB_VERBOSE, _("Finished updating file '%s'.\n")); return file->update_status; @@ -450,8 +495,6 @@ update_file_1 (struct file *file, unsigned int depth) fail. */ file->no_diag = file->dontcare; - ++depth; - /* Notice recursive update of the same file. */ start_updating (file); @@ -459,6 +502,9 @@ update_file_1 (struct file *file, unsigned int depth) remember this one to turn off updating. */ ofile = file; + /* Increase the depth for reporting how we build the file. */ + ++depth; + /* Looking at the file's modtime beforehand allows the possibility that its name may be changed by a VPATH search, and thus it may not need an implicit rule. If this were not done, the file @@ -470,8 +516,7 @@ update_file_1 (struct file *file, unsigned int depth) noexist = this_mtime == NONEXISTENT_MTIME; if (noexist) DBF (DB_BASIC, _("File '%s' does not exist.\n")); - else if (ORDINARY_MTIME_MIN <= this_mtime && this_mtime <= ORDINARY_MTIME_MAX - && file->low_resolution_time) + else if (is_ordinary_mtime (this_mtime) && file->low_resolution_time) { /* Avoid spurious rebuilds due to low resolution time stamps. */ int ns = FILE_TIMESTAMP_NS (this_mtime); @@ -482,17 +527,34 @@ update_file_1 (struct file *file, unsigned int depth) this_mtime += FILE_TIMESTAMPS_PER_S - 1 - ns; } + /* If any also_make target doesn't exist, we must remake this one too. + If they do exist choose the oldest mtime so they will rebuild. */ + + for (ad = file->also_make; ad && !noexist; ad = ad->next) + { + struct file *adfile = ad->file; + FILE_TIMESTAMP fmtime = file_mtime (adfile); + + noexist = fmtime == NONEXISTENT_MTIME; + if (noexist) + { + check_renamed (adfile); + DBS (DB_BASIC, + (_("Grouped target peer '%s' of file '%s' does not exist.\n"), + adfile->name, file->name)); + } + else if (fmtime < this_mtime) + this_mtime = fmtime; + } + must_make = noexist; - /* If file was specified as a target with no commands, - come up with some default commands. */ + /* If file was specified as a target with no commands, come up with some + default commands. This may also add more also_make files. */ if (!file->phony && file->cmds == 0 && !file->tried_implicit) { - if (try_implicit_rule (file, depth)) - DBF (DB_IMPLICIT, _("Found an implicit rule for '%s'.\n")); - else - DBF (DB_IMPLICIT, _("No implicit rule found for '%s'.\n")); + try_implicit_rule (file, depth); file->tried_implicit = 1; } if (file->cmds == 0 && !file->is_target @@ -514,17 +576,28 @@ update_file_1 (struct file *file, unsigned int depth) { struct dep *lastd = 0; + /* Perform second expansion and enter each dependency name as a file. + We only need to do this if second_expansion has been defined; if it + hasn't then all deps were expanded as the makefile was read in. */ + if (second_expansion) + expand_deps (ad->file); + /* Find the deps we're scanning */ - d = ad->file->deps; + du = ad->file->deps; ad = ad->next; - while (d) + while (du) { enum update_status new; FILE_TIMESTAMP mtime; int maybe_make; int dontcare = 0; + d = du->shuf ? du->shuf : du; + + if (d->wait_here && running) + break; + check_renamed (d->file); mtime = file_mtime (d->file); @@ -534,14 +607,16 @@ update_file_1 (struct file *file, unsigned int depth) { OSS (error, NILF, _("Circular %s <- %s dependency dropped."), file->name, d->file->name); + /* We cannot free D here because our the caller will still have a reference to it when we were called recursively via check_dep below. */ if (lastd == 0) - file->deps = d->next; + file->deps = du->next; else - lastd->next = d->next; - d = d->next; + lastd->next = du->next; + + du = du->next; continue; } @@ -590,8 +665,8 @@ update_file_1 (struct file *file, unsigned int depth) d->changed = ((file_mtime (d->file) != mtime) || (mtime == NONEXISTENT_MTIME)); - lastd = d; - d = d->next; + lastd = du; + du = du->next; } } @@ -600,73 +675,82 @@ update_file_1 (struct file *file, unsigned int depth) if (must_make || always_make_flag) { - for (d = file->deps; d != 0; d = d->next) - if (d->file->intermediate) - { - enum update_status new; - int dontcare = 0; + for (du = file->deps; du != 0; du = du->next) + { + d = du->shuf ? du->shuf : du; - FILE_TIMESTAMP mtime = file_mtime (d->file); - check_renamed (d->file); - d->file->parent = file; + if (d->wait_here && running) + break; + + if (d->file->intermediate) + { + enum update_status new; + int dontcare = 0; + + FILE_TIMESTAMP mtime = file_mtime (d->file); + check_renamed (d->file); + d->file->parent = file; + + /* Inherit dontcare flag from our parent. */ + if (rebuilding_makefiles) + { + dontcare = d->file->dontcare; + d->file->dontcare = file->dontcare; + } + + /* We may have already considered this file, when we didn't know + we'd need to update it. Force update_file() to consider it and + not prune it. */ + d->file->considered = 0; + + new = update_file (d->file, depth); + if (new > dep_status) + dep_status = new; + + /* Restore original dontcare flag. */ + if (rebuilding_makefiles) + d->file->dontcare = dontcare; + + check_renamed (d->file); - /* Inherit dontcare flag from our parent. */ - if (rebuilding_makefiles) { - dontcare = d->file->dontcare; - d->file->dontcare = file->dontcare; + struct file *f = d->file; + if (f->double_colon) + f = f->double_colon; + do + { + running |= (f->command_state == cs_running + || f->command_state == cs_deps_running); + f = f->prev; + } + while (f != 0); } - /* We may have already considered this file, when we didn't know - we'd need to update it. Force update_file() to consider it and - not prune it. */ - d->file->considered = 0; + if (dep_status && !keep_going_flag) + break; - new = update_file (d->file, depth); - if (new > dep_status) - dep_status = new; - - /* Restore original dontcare flag. */ - if (rebuilding_makefiles) - d->file->dontcare = dontcare; - - check_renamed (d->file); - - { - struct file *f = d->file; - if (f->double_colon) - f = f->double_colon; - do - { - running |= (f->command_state == cs_running - || f->command_state == cs_deps_running); - f = f->prev; - } - while (f != 0); + if (!running) + d->changed = ((file->phony && file->cmds != 0) + || file_mtime (d->file) != mtime); } - - if (dep_status && !keep_going_flag) - break; - - if (!running) - d->changed = ((file->phony && file->cmds != 0) - || file_mtime (d->file) != mtime); - } + } } finish_updating (file); finish_updating (ofile); - DBF (DB_VERBOSE, _("Finished prerequisites of target file '%s'.\n")); + /* We've decided what we need to do to build the file. */ + --depth; if (running) { set_command_state (file, cs_deps_running); - --depth; DBF (DB_VERBOSE, _("The prerequisites of '%s' are being made.\n")); - return 0; + return us_success; } + DBF (DB_VERBOSE, _("Finished prerequisites of target file '%s'.\n")); + /* If any dependency failed, give up now. */ if (dep_status) @@ -675,8 +759,6 @@ update_file_1 (struct file *file, unsigned int depth) file->update_status = dep_status == us_none ? us_failed : dep_status; notice_finished_file (file); - --depth; - DBF (DB_VERBOSE, _("Giving up on target file '%s'.\n")); if (depth == 0 && keep_going_flag @@ -751,16 +833,13 @@ update_file_1 (struct file *file, unsigned int depth) if (fmt) { - print_spaces (depth); + print_spaces (depth+1); printf (fmt, dep_name (d), file->name); fflush (stdout); } } } - /* Here depth returns to the value it had when we were called. */ - depth--; - if (file->double_colon && file->deps == 0) { must_make = 1; @@ -792,6 +871,11 @@ update_file_1 (struct file *file, unsigned int depth) fflush (stdout); } + /* Since make has not created this file, make should not remove it, + even if the file is intermediate. */ + if (!file->notintermediate && no_intermediates == 0) + file->secondary = 1; + notice_finished_file (file); /* Since we don't need to remake the file, convert it to use the @@ -804,7 +888,7 @@ update_file_1 (struct file *file, unsigned int depth) file = file->prev; } - return 0; + return us_success; } DBF (DB_BASIC, _("Must remake target '%s'.\n")); @@ -823,7 +907,7 @@ update_file_1 (struct file *file, unsigned int depth) if (file->command_state != cs_finished) { DBF (DB_VERBOSE, _("Recipe of '%s' is being run.\n")); - return 0; + return us_success; } switch (file->update_status) @@ -876,7 +960,7 @@ notice_finished_file (struct file *file) we don't want to do the touching. */ unsigned int i; for (i = 0; i < file->cmds->ncommand_lines; ++i) - if (!(file->cmds->lines_flags[i] & COMMANDS_RECURSE)) + if (NONE_SET (file->cmds->lines_flags[i], COMMANDS_RECURSE)) goto have_nonrecursing; } else @@ -917,7 +1001,7 @@ notice_finished_file (struct file *file) if ((question_flag || just_print_flag || touch_flag) && file->cmds) { for (i = file->cmds->ncommand_lines; i > 0; --i) - if (! (file->cmds->lines_flags[i-1] & COMMANDS_RECURSE)) + if (NONE_SET (file->cmds->lines_flags[i-1], COMMANDS_RECURSE)) break; } @@ -958,23 +1042,30 @@ notice_finished_file (struct file *file) } if (ran && file->update_status != us_none) - /* We actually tried to update FILE, which has - updated its also_make's as well (if it worked). - If it didn't work, it wouldn't work again for them. - So mark them as updated with the same status. */ - for (d = file->also_make; d != 0; d = d->next) - { - d->file->command_state = cs_finished; - d->file->updated = 1; - d->file->update_status = file->update_status; + { + /* We actually tried to update FILE, which has + updated its also_make's as well (if it worked). + If it didn't work, it wouldn't work again for them. + So mark them as updated with the same status. */ + for (d = file->also_make; d != 0; d = d->next) + { + d->file->command_state = cs_finished; + d->file->updated = 1; + d->file->update_status = file->update_status; - if (ran && !d->file->phony) - /* Fetch the new modification time. - We do this instead of just invalidating the cached time - so that a vpath_search can happen. Otherwise, it would - never be done because the target is already updated. */ - f_mtime (d->file, 0); - } + if (ran && !d->file->phony) + /* Fetch the new modification time. + We do this instead of just invalidating the cached time + so that a vpath_search can happen. Otherwise, it would + never be done because the target is already updated. */ + f_mtime (d->file, 0); + } + + /* If the target was created by an implicit rule, and it was updated, + warn about any of its also_make targets that don't exist. */ + if (file->tried_implicit && file->also_make) + check_also_make (file); + } else if (file->update_status == us_none) /* Nothing was done for FILE, but it needed nothing done. So mark it now as "succeeded". */ @@ -995,7 +1086,6 @@ check_dep (struct file *file, unsigned int depth, struct dep *d; enum update_status dep_status = us_success; - ++depth; start_updating (file); /* We might change file if we find a different one via vpath; @@ -1021,10 +1111,7 @@ check_dep (struct file *file, unsigned int depth, if (!file->phony && file->cmds == 0 && !file->tried_implicit) { - if (try_implicit_rule (file, depth)) - DBF (DB_IMPLICIT, _("Found an implicit rule for '%s'.\n")); - else - DBF (DB_IMPLICIT, _("No implicit rule found for '%s'.\n")); + try_implicit_rule (file, depth); file->tried_implicit = 1; } if (file->cmds == 0 && !file->is_target @@ -1063,6 +1150,12 @@ check_dep (struct file *file, unsigned int depth, } ld = 0; + /* Perform second expansion and enter each dependency name as a file. + We only need to do this if second_expansion has been defined; if it + hasn't then all deps were expanded as the makefile was read in. */ + if (second_expansion) + expand_deps (file); + d = file->deps; while (d != 0) { @@ -1090,7 +1183,7 @@ check_dep (struct file *file, unsigned int depth, d->file->parent = file; maybe_make = *must_make_ptr; - new = check_dep (d->file, depth, this_mtime, &maybe_make); + new = check_dep (d->file, depth+1, this_mtime, &maybe_make); if (new > dep_status) dep_status = new; @@ -1249,7 +1342,7 @@ f_mtime (struct file *file, int search) if (ar_name (file->name)) { /* This file is an archive-member reference. */ - + FILE_TIMESTAMP memmtime; char *arname, *memname; struct file *arfile; time_t member_date; @@ -1257,6 +1350,9 @@ f_mtime (struct file *file, int search) /* Find the archive's name. */ ar_parse_name (file->name, &arname, &memname); + /* Find the mtime of the member file (it might not exist). */ + memmtime = name_mtime (memname); + /* Find the modification time of the archive itself. Also allow for its name to be changed via VPATH search. */ arfile = lookup_file (arname); @@ -1300,9 +1396,16 @@ f_mtime (struct file *file, int search) return NONEXISTENT_MTIME; member_date = ar_member_date (file->hname); - mtime = (member_date == (time_t) -1 - ? NONEXISTENT_MTIME - : file_timestamp_cons (file->hname, member_date, 0)); + + if (member_date == (time_t) -1 + || (memmtime != NONEXISTENT_MTIME + && (time_t) FILE_TIMESTAMP_S (memmtime) > member_date)) + /* If the member file exists and is newer than the member in the + archive, pretend it's nonexistent. This means the member file was + updated but not added to the archive yet. */ + mtime = NONEXISTENT_MTIME; + else + mtime = file_timestamp_cons (file->hname, member_date, 0); } else #endif @@ -1328,7 +1431,13 @@ f_mtime (struct file *file, int search) /* If we found it in VPATH, see if it's in GPATH too; if so, change the name right now; if not, defer until after the dependencies are updated. */ +#ifndef VMS name_len = strlen (name) - strlen (file->name) - 1; +#else + name_len = strlen (name) - strlen (file->name); + if (name[name_len - 1] == '/') + name_len--; +#endif if (gpath_search (name, name_len)) { rename_file (file, name); @@ -1386,7 +1495,7 @@ f_mtime (struct file *file, int search) / 1e9)); char from_now_string[100]; - if (from_now >= 99 && from_now <= ULONG_MAX) + if (from_now >= 100.0 && from_now < (double) ULONG_MAX) sprintf (from_now_string, "%lu", (unsigned long) from_now); else sprintf (from_now_string, "%.2g", from_now); @@ -1438,12 +1547,16 @@ static FILE_TIMESTAMP name_mtime (const char *name) { FILE_TIMESTAMP mtime; +#if defined(WINDOWS32) + struct STAT st; +#else struct stat st; +#endif int e; #if defined(WINDOWS32) { - char tem[MAXPATHLEN], *tstart, *tend; + char tem[MAX_PATH+1], *tstart, *tend; const char *p = name + strlen (name); /* Remove any trailing slashes and "."/"..". MS-Windows stat @@ -1461,7 +1574,7 @@ name_mtime (const char *name) tend--; if (*tend == '.' && tend > tstart) tend--; - for ( ; tend > tstart && (*tend == '/' || *tend == '\\'); tend--) + for ( ; tend > tstart && ISDIRSEP (*tend); tend--) *tend = '\0'; } else @@ -1470,7 +1583,11 @@ name_mtime (const char *name) tend = &tem[0]; } +#if defined(WINDOWS32) + e = STAT (tem, &st); +#else e = stat (tem, &st); +#endif if (e == 0 && !_S_ISDIR (st.st_mode) && tend < tem + (p - name - 1)) { errno = ENOTDIR; @@ -1535,7 +1652,7 @@ name_mtime (const char *name) mtime = ltime; /* Set up to check the file pointed to by this link. */ - EINTRLOOP (llen, readlink (lpath, lbuf, GET_PATH_MAX)); + EINTRLOOP (llen, readlink (lpath, lbuf, GET_PATH_MAX - 1)); if (llen < 0) { /* Eh? Just take what we have. */ @@ -1572,7 +1689,7 @@ library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr) { static const char *dirs[] = { -#if !defined(_AMIGA) && !defined(__COSMOPOLITAN__) +#ifndef _AMIGA "/lib", "/usr/lib", #endif @@ -1583,7 +1700,7 @@ library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr) */ #define LIBDIR "." #endif - LIBDIR, /* Defined by configuration. */ + // LIBDIR, /* Defined by configuration. */ 0 }; @@ -1618,7 +1735,7 @@ library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr) static size_t buflen = 0; static size_t libdir_maxlen = 0; static unsigned int std_dirs = 0; - char *libbuf = variable_expand (""); + char *libbuf; /* Expand the pattern using LIB as a replacement. */ { @@ -1635,10 +1752,12 @@ library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr) p[len] = c; continue; } - p4 = variable_buffer_output (libbuf, p, p3-p); + p4 = variable_buffer_output (variable_buffer, p, p3-p); p4 = variable_buffer_output (p4, lib, liblen); p4 = variable_buffer_output (p4, p3+1, len - (p3-p)); p[len] = c; + + libbuf = variable_buffer; } /* Look first for 'libNAME.a' in the current directory. */ diff --git a/third_party/make/remote-cstms.c b/third_party/make/remote-cstms.c new file mode 100644 index 000000000..bc98a23be --- /dev/null +++ b/third_party/make/remote-cstms.c @@ -0,0 +1,297 @@ +/* GNU Make remote job exportation interface to the Customs daemon. + THIS CODE IS NOT SUPPORTED BY THE GNU PROJECT. + Please do not send bug reports or questions about it to + the Make maintainers. + +Copyright (C) 1988-2023 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make 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. + +GNU Make 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 . */ + +#include "makeint.h" + +#include "filedef.h" +#include "job.h" +#include "commands.h" +#include "debug.h" + +#if HAVE_SYS_TIME_H +# include +#endif +#include + +#include "customs.h" + +char *remote_description = "Customs"; + +/* File name of the Customs 'export' client command. + A full path name can be used to avoid some path-searching overhead. */ +#define EXPORT_COMMAND "/usr/local/bin/export" + +/* ExportPermit gotten by start_remote_job_p, and used by start_remote_job. */ +static ExportPermit permit; + +/* Normalized path name of the current directory. */ +static char *normalized_cwd; + +/* Call once at startup even if no commands are run. */ + +void +remote_setup (void) +{ +} + +/* Called before exit. */ + +void +remote_cleanup (void) +{ +} + +/* Return nonzero if the next job should be done remotely. */ + +int +start_remote_job_p (int first_p) +{ + static int inited = 0; + int status; + int njobs; + + if (!inited) + { + /* Allow the user to turn off job exportation (useful while he is + debugging Customs, for example). */ + if (getenv ("GNU_MAKE_NO_CUSTOMS") != 0) + { + inited = -1; + return 0; + } + + if (ISDB (DB_JOBS)) + Rpc_Debug (1); + + /* Ping the daemon once to see if it is there. */ + inited = Customs_Ping () == RPC_SUCCESS ? 1 : -1; + + if (starting_directory == 0) + /* main couldn't figure it out. */ + inited = -1; + else + { + /* Normalize the current directory path name to something + that should work on all machines exported to. */ + + normalized_cwd = xmalloc (GET_PATH_MAX); + strcpy (normalized_cwd, starting_directory); + if (Customs_NormPath (normalized_cwd, GET_PATH_MAX) < 0) + /* Path normalization failure means using Customs + won't work, but it's not really an error. */ + inited = -1; + } + } + + if (inited < 0) + return 0; + + njobs = job_slots_used; + if (!first_p) + njobs -= 1; /* correction for being called from reap_children() */ + + /* the first job should run locally, or, if the -l flag is given, we use + that as clue as to how many local jobs should be scheduled locally */ + if (max_load_average < 0 && njobs == 0 || njobs < max_load_average) + return 0; + + status = Customs_Host (EXPORT_SAME, &permit); + if (status != RPC_SUCCESS) + { + DB (DB_JOBS, (_("Customs won't export: %s\n"), + Rpc_ErrorMessage (status))); + return 0; + } + + return !CUSTOMS_FAIL (&permit.addr); +} + +/* Start a remote job running the command in ARGV, with environment from + ENVP. It gets standard input from STDIN_FD. On failure, return + nonzero. On success, return zero, and set *USED_STDIN to nonzero if it + will actually use STDIN_FD, zero if not, set *ID_PTR to a unique + identification, and set *IS_REMOTE to nonzero if the job is remote, zero + if it is local (meaning *ID_PTR is a process ID). */ + +int +start_remote_job (char **argv, char **envp, int stdin_fd, + int *is_remote, pid_t *id_ptr, int *used_stdin) +{ + char waybill[MAX_DATA_SIZE], msg[128]; + struct hostent *host; + struct timeval timeout; + struct sockaddr_in sin; + int len; + int retsock, retport, sock; + Rpc_Stat status; + pid_t pid; + + /* Create the return socket. */ + retsock = Rpc_UdpCreate (True, 0); + if (retsock < 0) + { + O (error, NILF, "exporting: Couldn't create return socket."); + return 1; + } + + /* Get the return socket's port number. */ + len = sizeof (sin); + if (getsockname (retsock, (struct sockaddr *) &sin, &len) < 0) + { + (void) close (retsock); + perror_with_name ("exporting: ", "getsockname"); + return 1; + } + retport = sin.sin_port; + + /* Create the TCP socket for talking to the remote child. */ + sock = Rpc_TcpCreate (False, 0); + + /* Create a WayBill to give to the server. */ + len = Customs_MakeWayBill (&permit, normalized_cwd, argv[0], argv, + envp, retport, waybill); + + /* Modify the waybill for the child's uid/gid. */ + { + WayBill *wb = (WayBill *) waybill; + wb->ruid = wb->euid; + wb->rgid = wb->egid; + } + + /* Send the request to the server, timing out in 20 seconds. */ + timeout.tv_usec = 0; + timeout.tv_sec = 20; + sin.sin_family = AF_INET; + sin.sin_port = htons (Customs_Port ()); + sin.sin_addr = permit.addr; + status = Rpc_Call (sock, &sin, (Rpc_Proc) CUSTOMS_IMPORT, + len, (Rpc_Opaque) waybill, + sizeof (msg), (Rpc_Opaque) msg, + 1, &timeout); + + host = gethostbyaddr ((char *)&permit.addr, sizeof(permit.addr), AF_INET); + + { + const char *hnm = host ? host->h_name : inet_ntoa (permit.addr); + size_t hlen = strlen (hnm); + + if (status != RPC_SUCCESS) + { + const char *err = Rpc_ErrorMessage (status); + (void) close (retsock); + (void) close (sock); + error (NILF, hlen + strlen (err), + "exporting to %s: %s", hnm, err); + return 1; + } + else if (msg[0] != 'O' || msg[1] != 'k' || msg[2] != '\0') + { + (void) close (retsock); + (void) close (sock); + error (NILF, hlen + strlen (msg), "exporting to %s: %s", hnm, msg); + return 1; + } + else + { + error (NILF, hlen + INTSTR_LENGTH, + "*** exported to %s (id %u)", hnm, permit.id); + } + + fflush (stdout); + fflush (stderr); + } + + pid = vfork (); + if (pid < 0) + { + /* The fork failed! */ + perror_with_name ("fork", ""); + return 1; + } + else if (pid == 0) + { + /* Child side. Run 'export' to handle the connection. */ + static char sock_buf[INTSTR_LENGTH], retsock_buf[INTSTR_LENGTH]; + static char id_buf[INTSTR_LENGTH]; + static char *new_argv[6] = + { EXPORT_COMMAND, "-id", sock_buf, retsock_buf, id_buf, 0 }; + + /* Set up the arguments. */ + (void) sprintf (sock_buf, "%d", sock); + (void) sprintf (retsock_buf, "%d", retsock); + (void) sprintf (id_buf, "%x", permit.id); + + /* Get the right stdin. */ + if (stdin_fd != 0) + (void) dup2 (stdin_fd, 0); + + /* Unblock signals in the child. */ + unblock_all_sigs (); + + /* Run the command. */ + exec_command (new_argv, envp); + } + + /* Parent side. Return the 'export' process's ID. */ + (void) close (retsock); + (void) close (sock); + *is_remote = 0; + *id_ptr = pid; + *used_stdin = 1; + return 0; +} + +/* Get the status of a dead remote child. Block waiting for one to die + if BLOCK is nonzero. Set *EXIT_CODE_PTR to the exit status, *SIGNAL_PTR + to the termination signal or zero if it exited normally, and *COREDUMP_PTR + nonzero if it dumped core. Return the ID of the child that died, + 0 if we would have to block and !BLOCK, or < 0 if there were none. */ + +int +remote_status (int *exit_code_ptr, int *signal_ptr, int *coredump_ptr, + int block) +{ + return -1; +} + +/* Block asynchronous notification of remote child death. + If this notification is done by raising the child termination + signal, do not block that signal. */ +void +block_remote_children (void) +{ + return; +} + +/* Restore asynchronous notification of remote child death. + If this is done by raising the child termination signal, + do not unblock that signal. */ +void +unblock_remote_children (void) +{ + return; +} + +/* Send signal SIG to child ID. Return 0 if successful, -1 if not. */ +int +remote_kill (pid_t id, int sig) +{ + return -1; +} diff --git a/third_party/make/remote-stub.c b/third_party/make/remote-stub.c index 88a224e37..7815f7379 100644 --- a/third_party/make/remote-stub.c +++ b/third_party/make/remote-stub.c @@ -1,5 +1,5 @@ /* Template for the remote job exportation interface to GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,12 +12,12 @@ 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 . */ +this program. If not, see . */ -#include "third_party/make/makeint.inc" -#include "third_party/make/filedef.h" -#include "third_party/make/job.h" -#include "third_party/make/commands.h" +#include "makeint.h" +#include "filedef.h" +#include "job.h" +#include "commands.h" char *remote_description = 0; diff --git a/third_party/make/rule.c b/third_party/make/rule.c index a0e47c487..d0901f47c 100644 --- a/third_party/make/rule.c +++ b/third_party/make/rule.c @@ -1,5 +1,5 @@ /* Pattern and suffix rule internals for GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,16 +12,18 @@ 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 . */ +this program. If not, see . */ -#include "third_party/make/makeint.inc" -#include "third_party/make/filedef.h" -#include "third_party/make/dep.h" -#include "third_party/make/job.h" -#include "third_party/make/commands.h" -#include "third_party/make/variable.h" -#include "libc/runtime/runtime.h" -#include "third_party/make/rule.h" +#include "makeint.h" + +#include + +#include "filedef.h" +#include "dep.h" +#include "job.h" +#include "commands.h" +#include "variable.h" +#include "rule.h" static void freerule (struct rule *rule, struct rule *lastrule); @@ -57,6 +59,63 @@ struct file *suffix_file; /* Maximum length of a suffix. */ static size_t maxsuffix; + +/* Return the rule definition: space separated rule targets, followed by + either a colon or two colons in the case of a terminal rule, followed by + space separated rule prerequisites, followed by a pipe, followed by + order-only prerequisites, if present. */ + +const char * +get_rule_defn (struct rule *r) +{ + if (r->_defn == NULL) + { + size_t len = 8; /* Reserve for ":: ", " | ", and nul. */ + unsigned int k; + char *p; + const char *sep = ""; + const struct dep *dep, *ood = 0; + + for (k = 0; k < r->num; ++k) + len += r->lens[k] + 1; + + for (dep = r->deps; dep; dep = dep->next) + len += strlen (dep_name (dep)) + (dep->wait_here ? CSTRLEN (" .WAIT") : 0) + 1; + + p = r->_defn = xmalloc (len); + for (k = 0; k < r->num; ++k, sep = " ") + p = mempcpy (mempcpy (p, sep, strlen (sep)), r->targets[k], r->lens[k]); + *p++ = ':'; + if (r->terminal) + *p++ = ':'; + + /* Copy all normal dependencies; note any order-only deps. */ + for (dep = r->deps; dep; dep = dep->next) + if (dep->ignore_mtime == 0) + { + if (dep->wait_here) + p = mempcpy (p, " .WAIT", CSTRLEN (" .WAIT")); + p = mempcpy (mempcpy (p, " ", 1), dep_name (dep), + strlen (dep_name (dep))); + } + else if (ood == 0) + ood = dep; + + /* Copy order-only deps, if we have any. */ + for (sep = " | "; ood; ood = ood->next, sep = " ") + if (ood->ignore_mtime) + { + p = mempcpy (p, sep, strlen (sep)); + if (ood->wait_here) + p = mempcpy (p, ".WAIT ", CSTRLEN (".WAIT ")); + p = mempcpy (p, dep_name (ood), strlen (dep_name (ood))); + } + *p = '\0'; + } + + return r->_defn; +} + /* Compute the maximum dependency length and maximum number of dependencies of all implicit rules. Also sets the subdir flag for a rule when appropriate, @@ -78,7 +137,18 @@ snap_implicit_rules (void) for (dep = prereqs; dep; dep = dep->next) { - size_t l = strlen (dep_name (dep)); + const char *d = dep_name (dep); + size_t l = strlen (d); + + if (dep->need_2nd_expansion) + /* When pattern_search allocates a buffer, allow 5 bytes per each % to + substitute each % with $(*F) while avoiding realloc. */ + while ((d = strchr (d, '%')) != 0) + { + l += 4; + ++d; + } + if (l > max_pattern_dep_length) max_pattern_dep_length = l; ++pre_deps; @@ -101,8 +171,16 @@ snap_implicit_rules (void) const char *dname = dep_name (dep); size_t len = strlen (dname); +#ifdef VMS + const char *p = strrchr (dname, ']'); + const char *p2; + if (p == 0) + p = strrchr (dname, ':'); + p2 = p ? strchr (p, '%') : 0; +#else const char *p = strrchr (dname, '/'); const char *p2 = p ? strchr (p, '%') : 0; +#endif ndeps++; if (len > max_pattern_dep_length) @@ -172,7 +250,11 @@ convert_suffix_rule (const char *target, const char *source, { /* Special case: TARGET being nil means we are defining a '.X.a' suffix rule; the target pattern is always '(%.o)'. */ +#ifdef VMS + *names = strcache_add_len ("(%.obj)", 7); +#else *names = strcache_add_len ("(%.o)", 5); +#endif *percents = *names + 1; } else @@ -264,7 +346,7 @@ convert_to_pattern (void) /* POSIX says that suffix rules can't have prerequisites. In POSIX mode, don't make this a suffix rule. Previous versions - of GNU make did treat this as a suffix rule and ignored the + of GNU Make did treat this as a suffix rule and ignored the prerequisites, which is bad. In the future we'll do the same as POSIX, but for now preserve the old behavior and warn about it. */ if (f->deps != 0) @@ -384,6 +466,7 @@ install_pattern_rule (struct pspec *p, int terminal) r->targets = xmalloc (sizeof (const char *)); r->suffixes = xmalloc (sizeof (const char *)); r->lens = xmalloc (sizeof (unsigned int)); + r->_defn = NULL; r->lens[0] = (unsigned int) strlen (p->target); r->targets[0] = p->target; @@ -425,6 +508,7 @@ freerule (struct rule *rule, struct rule *lastrule) free ((void *)rule->targets); free ((void *)rule->suffixes); free (rule->lens); + free ((void *) rule->_defn); /* We can't free the storage for the commands because there are ways that they could be in more than one place: @@ -474,6 +558,7 @@ create_pattern_rule (const char **targets, const char **target_percents, r->targets = targets; r->suffixes = target_percents; r->lens = xmalloc (n * sizeof (unsigned int)); + r->_defn = NULL; for (i = 0; i < n; ++i) { @@ -491,17 +576,8 @@ create_pattern_rule (const char **targets, const char **target_percents, static void /* Useful to call from gdb. */ print_rule (struct rule *r) { - unsigned int i; - - for (i = 0; i < r->num; ++i) - { - fputs (r->targets[i], stdout); - putchar ((i + 1 == r->num) ? ':' : ' '); - } - if (r->terminal) - putchar (':'); - - print_prereqs (r->deps); + fputs (get_rule_defn (r), stdout); + putchar ('\n'); if (r->cmds != 0) print_commands (r->cmds); diff --git a/third_party/make/rule.h b/third_party/make/rule.h index 120a6827b..03e2e3f17 100644 --- a/third_party/make/rule.h +++ b/third_party/make/rule.h @@ -1,5 +1,5 @@ /* Definitions for using pattern rules in GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,7 +12,7 @@ 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 . */ +this program. If not, see . */ /* Structure used for pattern (implicit) rules. */ @@ -25,6 +25,7 @@ struct rule const char **suffixes; /* Suffixes (after '%') of each target. */ struct dep *deps; /* Dependencies of the rule. */ struct commands *cmds; /* Commands to execute. */ + char *_defn; /* Definition of the rule. */ unsigned short num; /* Number of targets. */ char terminal; /* If terminal (double-colon). */ char in_use; /* If in use by a parent pattern_search. */ @@ -54,4 +55,5 @@ void install_pattern_rule (struct pspec *p, int terminal); void create_pattern_rule (const char **targets, const char **target_percents, unsigned short num, int terminal, struct dep *deps, struct commands *commands, int override); +const char *get_rule_defn (struct rule *rule); void print_rule_data_base (void); diff --git a/third_party/make/shuffle.c b/third_party/make/shuffle.c new file mode 100644 index 000000000..d57acef0a --- /dev/null +++ b/third_party/make/shuffle.c @@ -0,0 +1,237 @@ +/* Provide prerequisite shuffle support. +Copyright (C) 2022-2023 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make 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. + +GNU Make 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 . */ + +#include "makeint.h" + +#include "shuffle.h" + +#include "filedef.h" +#include "dep.h" + +/* Supported shuffle modes. */ +static void random_shuffle_array (void ** a, size_t len); +static void reverse_shuffle_array (void ** a, size_t len); +static void identity_shuffle_array (void ** a, size_t len); + +/* The way goals and rules are shuffled during update. */ +enum shuffle_mode + { + /* No shuffle data is populated or used. */ + sm_none, + /* Random within dependency list. */ + sm_random, + /* Inverse order. */ + sm_reverse, + /* identity order. Differs from SM_NONE by explicitly populating + the traversal order. */ + sm_identity, + }; + +/* Shuffle configuration. */ +static struct + { + enum shuffle_mode mode; + unsigned int seed; + void (*shuffler) (void **a, size_t len); + char strval[INTSTR_LENGTH + 1]; + } config = { sm_none, 0, NULL, "" }; + +/* Return string value of --shuffle= option passed. + If none was passed or --shuffle=none was used function + returns NULL. */ +const char * +shuffle_get_mode () +{ + return config.strval[0] == '\0' ? NULL : config.strval; +} + +void +shuffle_set_mode (const char *cmdarg) +{ + /* Parse supported '--shuffle' mode. */ + if (strcasecmp (cmdarg, "reverse") == 0) + { + config.mode = sm_reverse; + config.shuffler = reverse_shuffle_array; + strcpy (config.strval, "reverse"); + } + else if (strcasecmp (cmdarg, "identity") == 0) + { + config.mode = sm_identity; + config.shuffler = identity_shuffle_array; + strcpy (config.strval, "identity"); + } + else if (strcasecmp (cmdarg, "none") == 0) + { + config.mode = sm_none; + config.shuffler = NULL; + config.strval[0] = '\0'; + } + else + { + if (strcasecmp (cmdarg, "random") == 0) + config.seed = make_rand (); + else + { + /* Assume explicit seed. */ + const char *err; + config.seed = make_toui (cmdarg, &err); + if (err) + OSS (fatal, NILF, _("invalid shuffle mode: %s: '%s'"), err, cmdarg); + } + + config.mode = sm_random; + config.shuffler = random_shuffle_array; + sprintf (config.strval, "%u", config.seed); + } +} + +/* Shuffle array elements using RAND(). */ +static void +random_shuffle_array (void **a, size_t len) +{ + size_t i; + for (i = 0; i < len; i++) + { + void *t; + + /* Pick random element and swap. */ + unsigned int j = make_rand () % len; + if (i == j) + continue; + + /* Swap. */ + t = a[i]; + a[i] = a[j]; + a[j] = t; + } +} + +/* Shuffle array elements using reverse order. */ +static void +reverse_shuffle_array (void **a, size_t len) +{ + size_t i; + for (i = 0; i < len / 2; i++) + { + void *t; + + /* Pick mirror and swap. */ + size_t j = len - 1 - i; + + /* Swap. */ + t = a[i]; + a[i] = a[j]; + a[j] = t; + } +} + +/* Shuffle array elements using identity order. */ +static void +identity_shuffle_array (void **a UNUSED, size_t len UNUSED) +{ + /* No-op! */ +} + +/* Shuffle list of dependencies by populating '->shuf' + field in each 'struct dep'. */ +static void +shuffle_deps (struct dep *deps) +{ + size_t ndeps = 0; + struct dep *dep; + void **da; + void **dp; + + for (dep = deps; dep; dep = dep->next) + { + /* Do not reshuffle prerequisites if any .WAIT is present. */ + if (dep->wait_here) + return; + + ndeps++; + } + + if (ndeps == 0) + return; + + /* Allocate array of all deps, store, shuffle, write back. */ + da = xmalloc (sizeof (struct dep *) * ndeps); + + /* Store locally. */ + for (dep = deps, dp = da; dep; dep = dep->next, dp++) + *dp = dep; + + /* Shuffle. */ + config.shuffler (da, ndeps); + + /* Write back. */ + for (dep = deps, dp = da; dep; dep = dep->next, dp++) + dep->shuf = *dp; + + free (da); +} + +/* Shuffle 'deps' of each 'file' recursively. */ +static void +shuffle_file_deps_recursive (struct file *f) +{ + struct dep *dep; + + /* Implicit rules do not always provide any depends. */ + if (!f) + return; + + /* Avoid repeated shuffles and loops. */ + if (f->was_shuffled) + return; + f->was_shuffled = 1; + + shuffle_deps (f->deps); + + /* Shuffle dependencies. */ + for (dep = f->deps; dep; dep = dep->next) + shuffle_file_deps_recursive (dep->file); +} + +/* Shuffle goal dependencies first, then shuffle dependency list + of each file reachable from goaldep recursively. Used by + --shuffle flag to introduce artificial non-determinism in build + order. .*/ + +void +shuffle_deps_recursive (struct dep *deps) +{ + struct dep *dep; + + /* Exit early if shuffling was not requested. */ + if (config.mode == sm_none) + return; + + /* Do not reshuffle prerequisites if .NOTPARALLEL was specified. */ + if (not_parallel) + return; + + /* Set specific seed at the top level of recursion. */ + if (config.mode == sm_random) + make_seed (config.seed); + + shuffle_deps (deps); + + /* Shuffle dependencies. */ + for (dep = deps; dep; dep = dep->next) + shuffle_file_deps_recursive (dep->file); +} diff --git a/third_party/make/shuffle.h b/third_party/make/shuffle.h new file mode 100644 index 000000000..6c7faa4bc --- /dev/null +++ b/third_party/make/shuffle.h @@ -0,0 +1,26 @@ +/* Declarations for target shuffling support. +Copyright (C) 2022-2022 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make 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. + +GNU Make 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 . */ + +struct dep; +struct goaldep; + +void shuffle_set_mode (const char *cmdarg); +const char *shuffle_get_mode (void); +void shuffle_deps_recursive (struct dep* g); + +#define shuffle_goaldeps_recursive(_g) do{ \ + shuffle_deps_recursive ((struct dep *)_g); \ + } while(0) diff --git a/third_party/make/signame.c b/third_party/make/signame.c new file mode 100644 index 000000000..50134c45c --- /dev/null +++ b/third_party/make/signame.c @@ -0,0 +1,254 @@ +/* Convert between signal names and numbers. +Copyright (C) 1990-2023 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make 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. + +GNU Make 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 . */ + +#include "makeint.h" + +/* If the system provides strsignal, we don't need it. */ + +#if !HAVE_STRSIGNAL + +/* If the system provides sys_siglist, we'll use that. + Otherwise create our own. + */ + +#if !HAVE_DECL_SYS_SIGLIST + +/* Some systems do not define NSIG in . */ +#ifndef NSIG +#ifdef _NSIG +#define NSIG _NSIG +#else +#define NSIG 32 +#endif +#endif + +/* There is too much variation in Sys V signal numbers and names, so + we must initialize them at runtime. */ + +static const char *undoc; + +static const char *sys_siglist[NSIG]; + +/* Table of abbreviations for signals. Note: A given number can + appear more than once with different abbreviations. */ +#define SIG_TABLE_SIZE (NSIG*2) + +typedef struct + { + int number; + const char *abbrev; + } num_abbrev; + +static num_abbrev sig_table[SIG_TABLE_SIZE]; + +/* Number of elements of sig_table used. */ +static int sig_table_nelts = 0; + +/* Enter signal number NUMBER into the tables with ABBREV and NAME. */ + +static void +init_sig (int number, const char *abbrev, const char *name) +{ + /* If this value is ever greater than NSIG it seems like it'd be a bug in + the system headers, but... better safe than sorry. We know, for + example, that this isn't always true on VMS. */ + + if (number >= 0 && number < NSIG) + sys_siglist[number] = name; + + if (sig_table_nelts < SIG_TABLE_SIZE) + { + sig_table[sig_table_nelts].number = number; + sig_table[sig_table_nelts++].abbrev = abbrev; + } +} + +static int +signame_init (void) +{ + int i; + + undoc = xstrdup (_("unknown signal")); + + /* Initialize signal names. */ + for (i = 0; i < NSIG; i++) + sys_siglist[i] = undoc; + + /* Initialize signal names. */ +#if defined (SIGHUP) + init_sig (SIGHUP, "HUP", _("Hangup")); +#endif +#if defined (SIGINT) + init_sig (SIGINT, "INT", _("Interrupt")); +#endif +#if defined (SIGQUIT) + init_sig (SIGQUIT, "QUIT", _("Quit")); +#endif +#if defined (SIGILL) + init_sig (SIGILL, "ILL", _("Illegal Instruction")); +#endif +#if defined (SIGTRAP) + init_sig (SIGTRAP, "TRAP", _("Trace/breakpoint trap")); +#endif + /* If SIGIOT == SIGABRT, we want to print it as SIGABRT because + SIGABRT is in ANSI and POSIX.1 and SIGIOT isn't. */ +#if defined (SIGABRT) + init_sig (SIGABRT, "ABRT", _("Aborted")); +#endif +#if defined (SIGIOT) + init_sig (SIGIOT, "IOT", _("IOT trap")); +#endif +#if defined (SIGEMT) + init_sig (SIGEMT, "EMT", _("EMT trap")); +#endif +#if defined (SIGFPE) + init_sig (SIGFPE, "FPE", _("Floating point exception")); +#endif +#if defined (SIGKILL) + init_sig (SIGKILL, "KILL", _("Killed")); +#endif +#if defined (SIGBUS) + init_sig (SIGBUS, "BUS", _("Bus error")); +#endif +#if defined (SIGSEGV) + init_sig (SIGSEGV, "SEGV", _("Segmentation fault")); +#endif +#if defined (SIGSYS) + init_sig (SIGSYS, "SYS", _("Bad system call")); +#endif +#if defined (SIGPIPE) + init_sig (SIGPIPE, "PIPE", _("Broken pipe")); +#endif +#if defined (SIGALRM) + init_sig (SIGALRM, "ALRM", _("Alarm clock")); +#endif +#if defined (SIGTERM) + init_sig (SIGTERM, "TERM", _("Terminated")); +#endif +#if defined (SIGUSR1) + init_sig (SIGUSR1, "USR1", _("User defined signal 1")); +#endif +#if defined (SIGUSR2) + init_sig (SIGUSR2, "USR2", _("User defined signal 2")); +#endif + /* If SIGCLD == SIGCHLD, we want to print it as SIGCHLD because that + is what is in POSIX.1. */ +#if defined (SIGCHLD) + init_sig (SIGCHLD, "CHLD", _("Child exited")); +#endif +#if defined (SIGCLD) + init_sig (SIGCLD, "CLD", _("Child exited")); +#endif +#if defined (SIGPWR) + init_sig (SIGPWR, "PWR", _("Power failure")); +#endif +#if defined (SIGTSTP) + init_sig (SIGTSTP, "TSTP", _("Stopped")); +#endif +#if defined (SIGTTIN) + init_sig (SIGTTIN, "TTIN", _("Stopped (tty input)")); +#endif +#if defined (SIGTTOU) + init_sig (SIGTTOU, "TTOU", _("Stopped (tty output)")); +#endif +#if defined (SIGSTOP) + init_sig (SIGSTOP, "STOP", _("Stopped (signal)")); +#endif +#if defined (SIGXCPU) + init_sig (SIGXCPU, "XCPU", _("CPU time limit exceeded")); +#endif +#if defined (SIGXFSZ) + init_sig (SIGXFSZ, "XFSZ", _("File size limit exceeded")); +#endif +#if defined (SIGVTALRM) + init_sig (SIGVTALRM, "VTALRM", _("Virtual timer expired")); +#endif +#if defined (SIGPROF) + init_sig (SIGPROF, "PROF", _("Profiling timer expired")); +#endif +#if defined (SIGWINCH) + /* "Window size changed" might be more accurate, but even if that + is all that it means now, perhaps in the future it will be + extended to cover other kinds of window changes. */ + init_sig (SIGWINCH, "WINCH", _("Window changed")); +#endif +#if defined (SIGCONT) + init_sig (SIGCONT, "CONT", _("Continued")); +#endif +#if defined (SIGURG) + init_sig (SIGURG, "URG", _("Urgent I/O condition")); +#endif +#if defined (SIGIO) + /* "I/O pending" has also been suggested. A disadvantage is that signal + only happens when the process has asked for it, not every time I/O is + pending. Another disadvantage is the confusion from giving it a + different name than under Unix. */ + init_sig (SIGIO, "IO", _("I/O possible")); +#endif +#if defined (SIGWIND) + init_sig (SIGWIND, "WIND", _("SIGWIND")); +#endif +#if defined (SIGPHONE) + init_sig (SIGPHONE, "PHONE", _("SIGPHONE")); +#endif +#if defined (SIGPOLL) + init_sig (SIGPOLL, "POLL", _("I/O possible")); +#endif +#if defined (SIGLOST) + init_sig (SIGLOST, "LOST", _("Resource lost")); +#endif +#if defined (SIGDANGER) + init_sig (SIGDANGER, "DANGER", _("Danger signal")); +#endif +#if defined (SIGINFO) + init_sig (SIGINFO, "INFO", _("Information request")); +#endif +#if defined (SIGNOFP) + init_sig (SIGNOFP, "NOFP", _("Floating point co-processor not available")); +#endif + + return 1; +} + +#endif /* HAVE_DECL_SYS_SIGLIST */ + + +char * +strsignal (int sig) +{ + static char buf[] = "Signal 12345678901234567890"; + +#if ! HAVE_DECL_SYS_SIGLIST +# if HAVE_DECL__SYS_SIGLIST +# define sys_siglist _sys_siglist +# elif HAVE_DECL___SYS_SIGLIST +# define sys_siglist __sys_siglist +# else + static int sig_initted = 0; + + if (!sig_initted) + sig_initted = signame_init (); +# endif +#endif + + if (sig > 0 && sig < NSIG) + return (char *) sys_siglist[sig]; + + sprintf (buf, "Signal %d", sig); + return buf; +} + +#endif /* HAVE_STRSIGNAL */ diff --git a/third_party/make/stddef.h b/third_party/make/stddef.h deleted file mode 100644 index 8b4e07db1..000000000 --- a/third_party/make/stddef.h +++ /dev/null @@ -1,119 +0,0 @@ -/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ -/* A substitute for POSIX 2008 , for platforms that have issues. - - Copyright (C) 2009-2020 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, 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 . */ - -/* Written by Eric Blake. */ - -/* - * POSIX 2008 for platforms that have issues. - * - */ - -#if __GNUC__ >= 3 -#pragma GCC system_header -#endif - - -#if defined __need_wchar_t || defined __need_size_t \ - || defined __need_ptrdiff_t || defined __need_NULL \ - || defined __need_wint_t -/* Special invocation convention inside gcc header files. In - particular, gcc provides a version of that blindly - redefines NULL even when __need_wint_t was defined, even though - wint_t is not normally provided by . Hence, we must - remember if special invocation has ever been used to obtain wint_t, - in which case we need to clean up NULL yet again. */ - -# if !(defined _GL_STDDEF_H && defined _GL_STDDEF_WINT_T) -# ifdef __need_wint_t -# define _GL_STDDEF_WINT_T -# endif -# endif - -#else -/* Normal invocation convention. */ - -# ifndef _GL_STDDEF_H - -/* The include_next requires a split double-inclusion guard. */ - - -/* On NetBSD 5.0, the definition of NULL lacks proper parentheses. */ -# if (0 \ - && (!defined _GL_STDDEF_H || defined _GL_STDDEF_WINT_T)) -# undef NULL -# ifdef __cplusplus - /* ISO C++ says that the macro NULL must expand to an integer constant - expression, hence '((void *) 0)' is not allowed in C++. */ -# if __GNUG__ >= 3 - /* GNU C++ has a __null macro that behaves like an integer ('int' or - 'long') but has the same size as a pointer. Use that, to avoid - warnings. */ -# define NULL __null -# else -# define NULL 0L -# endif -# else -# define NULL ((void *) 0) -# endif -# endif - -# ifndef _GL_STDDEF_H -# define _GL_STDDEF_H - -/* Some platforms lack wchar_t. */ -#if !1 -# define wchar_t int -#endif - -/* Some platforms lack max_align_t. The check for _GCC_MAX_ALIGN_T is - a hack in case the configure-time test was done with g++ even though - we are currently compiling with gcc. - On MSVC, max_align_t is defined only in C++ mode, after was - included. Its definition is good since it has an alignment of 8 (on x86 - and x86_64). */ -#if defined _MSC_VER && defined __cplusplus -#else -# if ! (0 || defined _GCC_MAX_ALIGN_T) -# if !GNULIB_defined_max_align_t -/* On the x86, the maximum storage alignment of double, long, etc. is 4, - but GCC's C11 ABI for x86 says that max_align_t has an alignment of 8, - and the C11 standard allows this. Work around this problem by - using __alignof__ (which returns 8 for double) rather than _Alignof - (which returns 4), and align each union member accordingly. */ -# ifdef __GNUC__ -# define _GL_STDDEF_ALIGNAS(type) \ - __attribute__ ((__aligned__ (__alignof__ (type)))) -# else -# define _GL_STDDEF_ALIGNAS(type) /* */ -# endif -typedef union -{ - char *__p _GL_STDDEF_ALIGNAS (char *); - double __d _GL_STDDEF_ALIGNAS (double); - long double __ld _GL_STDDEF_ALIGNAS (long double); - long int __i _GL_STDDEF_ALIGNAS (long int); -} rpl_max_align_t; -# define max_align_t rpl_max_align_t -# define GNULIB_defined_max_align_t 1 -# endif -# endif -#endif - -# endif /* _GL_STDDEF_H */ -# endif /* _GL_STDDEF_H */ -#endif /* __need_XXX */ diff --git a/third_party/make/stdint.h b/third_party/make/stdint.h deleted file mode 100644 index 2dc75fe88..000000000 --- a/third_party/make/stdint.h +++ /dev/null @@ -1,735 +0,0 @@ -/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ -/* Copyright (C) 2001-2002, 2004-2020 Free Software Foundation, Inc. - Written by Paul Eggert, Bruno Haible, Sam Steingold, Peter Burwood. - This file is part of gnulib. - - 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, 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 . */ - -/* - * ISO C 99 for platforms that lack it. - * - */ - -#ifndef _GL_STDINT_H - -#if __GNUC__ >= 3 -#pragma GCC system_header -#endif - - -/* When including a system file that in turn includes , - use the system , not our substitute. This avoids - problems with (for example) VMS, whose includes - . */ -#define _GL_JUST_INCLUDE_SYSTEM_INTTYPES_H - -/* On Android (Bionic libc), includes this file before - having defined 'time_t'. Therefore in this case avoid including - other system header files; just include the system's . - Ideally we should test __BIONIC__ here, but it is only defined after - has been included; hence test __ANDROID__ instead. */ -#if defined __ANDROID__ && defined _GL_INCLUDING_SYS_TYPES_H -#else - -/* Get those types that are already defined in other system include - files, so that we can "#define int8_t signed char" below without - worrying about a later system include file containing a "typedef - signed char int8_t;" that will get messed up by our macro. Our - macros should all be consistent with the system versions, except - for the "fast" types and macros, which we recommend against using - in public interfaces due to compiler differences. */ - -#if 1 -# if defined __sgi && ! defined __c99 - /* Bypass IRIX's if in C89 mode, since it merely annoys users - with "This header file is to be used only for c99 mode compilations" - diagnostics. */ -# define __STDINT_H__ -# endif - - /* Some pre-C++11 implementations need this. */ -# ifdef __cplusplus -# ifndef __STDC_CONSTANT_MACROS -# define __STDC_CONSTANT_MACROS 1 -# endif -# ifndef __STDC_LIMIT_MACROS -# define __STDC_LIMIT_MACROS 1 -# endif -# endif - - /* Other systems may have an incomplete or buggy . - in would reinclude us, skipping our contents because - _GL_STDINT_H is defined. - The include_next requires a split double-inclusion guard. */ -#endif - -#if ! defined _GL_STDINT_H && ! defined _GL_JUST_INCLUDE_SYSTEM_STDINT_H -#define _GL_STDINT_H - -/* Get SCHAR_MIN, SCHAR_MAX, UCHAR_MAX, INT_MIN, INT_MAX, - LONG_MIN, LONG_MAX, ULONG_MAX, _GL_INTEGER_WIDTH. */ - -/* Override WINT_MIN and WINT_MAX if gnulib's or overrides - wint_t. */ -#if 0 -# undef WINT_MIN -# undef WINT_MAX -# define WINT_MIN 0x0U -# define WINT_MAX 0xffffffffU -#endif - -#if ! 0 - -/* defines some of the stdint.h types as well, on glibc, - IRIX 6.5, and OpenBSD 3.8 (via ). - AIX 5.2 isn't needed and causes troubles. - Mac OS X 10.4.6 includes (which is us), but - relies on the system definitions, so include - after . */ -# if 1 && ! defined _AIX -# endif - -# if 1 - /* In OpenBSD 3.8, includes , which defines - int{8,16,32,64}_t, uint{8,16,32,64}_t and __BIT_TYPES_DEFINED__. - also defines intptr_t and uintptr_t. */ -# elif 0 - /* Solaris 7 has the types except the *_fast*_t types, and - the macros except for *_FAST*_*, INTPTR_MIN, PTRDIFF_MIN, PTRDIFF_MAX. */ -# endif - -# if 0 && ! defined __BIT_TYPES_DEFINED__ - /* Linux libc4 >= 4.6.7 and libc5 have a that defines - int{8,16,32,64}_t and __BIT_TYPES_DEFINED__. In libc5 >= 5.2.2 it is - included by . */ -# endif - -# undef _GL_JUST_INCLUDE_SYSTEM_INTTYPES_H - -/* Minimum and maximum values for an integer type under the usual assumption. - Return an unspecified value if BITS == 0, adding a check to pacify - picky compilers. */ - -/* These are separate macros, because if you try to merge these macros into - a single one, HP-UX cc rejects the resulting expression in constant - expressions. */ -# define _STDINT_UNSIGNED_MIN(bits, zero) \ - (zero) -# define _STDINT_SIGNED_MIN(bits, zero) \ - (~ _STDINT_MAX (1, bits, zero)) - -# define _STDINT_MAX(signed, bits, zero) \ - (((((zero) + 1) << ((bits) ? (bits) - 1 - (signed) : 0)) - 1) * 2 + 1) - -#if !GNULIB_defined_stdint_types - -/* 7.18.1.1. Exact-width integer types */ - -/* Here we assume a standard architecture where the hardware integer - types have 8, 16, 32, optionally 64 bits. */ - -# undef int8_t -# undef uint8_t -typedef signed char gl_int8_t; -typedef unsigned char gl_uint8_t; -# define int8_t gl_int8_t -# define uint8_t gl_uint8_t - -# undef int16_t -# undef uint16_t -typedef short int gl_int16_t; -typedef unsigned short int gl_uint16_t; -# define int16_t gl_int16_t -# define uint16_t gl_uint16_t - -# undef int32_t -# undef uint32_t -typedef int gl_int32_t; -typedef unsigned int gl_uint32_t; -# define int32_t gl_int32_t -# define uint32_t gl_uint32_t - -/* If the system defines INT64_MAX, assume int64_t works. That way, - if the underlying platform defines int64_t to be a 64-bit long long - int, the code below won't mistakenly define it to be a 64-bit long - int, which would mess up C++ name mangling. We must use #ifdef - rather than #if, to avoid an error with HP-UX 10.20 cc. */ - -# ifdef INT64_MAX -# define GL_INT64_T -# else -/* Do not undefine int64_t if gnulib is not being used with 64-bit - types, since otherwise it breaks platforms like Tandem/NSK. */ -# if LONG_MAX >> 31 >> 31 == 1 -# undef int64_t -typedef long int gl_int64_t; -# define int64_t gl_int64_t -# define GL_INT64_T -# elif defined _MSC_VER -# undef int64_t -typedef __int64 gl_int64_t; -# define int64_t gl_int64_t -# define GL_INT64_T -# else -# undef int64_t -typedef long long int gl_int64_t; -# define int64_t gl_int64_t -# define GL_INT64_T -# endif -# endif - -# ifdef UINT64_MAX -# define GL_UINT64_T -# else -# if ULONG_MAX >> 31 >> 31 >> 1 == 1 -# undef uint64_t -typedef unsigned long int gl_uint64_t; -# define uint64_t gl_uint64_t -# define GL_UINT64_T -# elif defined _MSC_VER -# undef uint64_t -typedef unsigned __int64 gl_uint64_t; -# define uint64_t gl_uint64_t -# define GL_UINT64_T -# else -# undef uint64_t -typedef unsigned long long int gl_uint64_t; -# define uint64_t gl_uint64_t -# define GL_UINT64_T -# endif -# endif - -/* Avoid collision with Solaris 2.5.1 etc. */ -# define _UINT8_T -# define _UINT32_T -# define _UINT64_T - - -/* 7.18.1.2. Minimum-width integer types */ - -/* Here we assume a standard architecture where the hardware integer - types have 8, 16, 32, optionally 64 bits. Therefore the leastN_t types - are the same as the corresponding N_t types. */ - -# undef int_least8_t -# undef uint_least8_t -# undef int_least16_t -# undef uint_least16_t -# undef int_least32_t -# undef uint_least32_t -# undef int_least64_t -# undef uint_least64_t -# define int_least8_t int8_t -# define uint_least8_t uint8_t -# define int_least16_t int16_t -# define uint_least16_t uint16_t -# define int_least32_t int32_t -# define uint_least32_t uint32_t -# ifdef GL_INT64_T -# define int_least64_t int64_t -# endif -# ifdef GL_UINT64_T -# define uint_least64_t uint64_t -# endif - -/* 7.18.1.3. Fastest minimum-width integer types */ - -/* Note: Other substitutes may define these types differently. - It is not recommended to use these types in public header files. */ - -/* Here we assume a standard architecture where the hardware integer - types have 8, 16, 32, optionally 64 bits. Therefore the fastN_t types - are taken from the same list of types. The following code normally - uses types consistent with glibc, as that lessens the chance of - incompatibility with older GNU hosts. */ - -# undef int_fast8_t -# undef uint_fast8_t -# undef int_fast16_t -# undef uint_fast16_t -# undef int_fast32_t -# undef uint_fast32_t -# undef int_fast64_t -# undef uint_fast64_t -typedef signed char gl_int_fast8_t; -typedef unsigned char gl_uint_fast8_t; - -# ifdef __sun -/* Define types compatible with SunOS 5.10, so that code compiled under - earlier SunOS versions works with code compiled under SunOS 5.10. */ -typedef int gl_int_fast32_t; -typedef unsigned int gl_uint_fast32_t; -# else -typedef long int gl_int_fast32_t; -typedef unsigned long int gl_uint_fast32_t; -# endif -typedef gl_int_fast32_t gl_int_fast16_t; -typedef gl_uint_fast32_t gl_uint_fast16_t; - -# define int_fast8_t gl_int_fast8_t -# define uint_fast8_t gl_uint_fast8_t -# define int_fast16_t gl_int_fast16_t -# define uint_fast16_t gl_uint_fast16_t -# define int_fast32_t gl_int_fast32_t -# define uint_fast32_t gl_uint_fast32_t -# ifdef GL_INT64_T -# define int_fast64_t int64_t -# endif -# ifdef GL_UINT64_T -# define uint_fast64_t uint64_t -# endif - -/* 7.18.1.4. Integer types capable of holding object pointers */ - -/* kLIBC's defines _INTPTR_T_DECLARED and needs its own - definitions of intptr_t and uintptr_t (which use int and unsigned) - to avoid clashes with declarations of system functions like sbrk. - Similarly, mingw 5.22 defines _INTPTR_T_DEFINED and - _UINTPTR_T_DEFINED and needs its own definitions of intptr_t and - uintptr_t to avoid conflicting declarations of system functions like - _findclose in . */ -# if !((defined __KLIBC__ && defined _INTPTR_T_DECLARED) \ - || (defined __MINGW32__ && defined _INTPTR_T_DEFINED && defined _UINTPTR_T_DEFINED)) -# undef intptr_t -# undef uintptr_t -# ifdef _WIN64 -typedef long long int gl_intptr_t; -typedef unsigned long long int gl_uintptr_t; -# else -typedef long int gl_intptr_t; -typedef unsigned long int gl_uintptr_t; -# endif -# define intptr_t gl_intptr_t -# define uintptr_t gl_uintptr_t -# endif - -/* 7.18.1.5. Greatest-width integer types */ - -/* Note: These types are compiler dependent. It may be unwise to use them in - public header files. */ - -/* If the system defines INTMAX_MAX, assume that intmax_t works, and - similarly for UINTMAX_MAX and uintmax_t. This avoids problems with - assuming one type where another is used by the system. */ - -# ifndef INTMAX_MAX -# undef INTMAX_C -# undef intmax_t -# if LONG_MAX >> 30 == 1 -typedef long long int gl_intmax_t; -# define intmax_t gl_intmax_t -# elif defined GL_INT64_T -# define intmax_t int64_t -# else -typedef long int gl_intmax_t; -# define intmax_t gl_intmax_t -# endif -# endif - -# ifndef UINTMAX_MAX -# undef UINTMAX_C -# undef uintmax_t -# if ULONG_MAX >> 31 == 1 -typedef unsigned long long int gl_uintmax_t; -# define uintmax_t gl_uintmax_t -# elif defined GL_UINT64_T -# define uintmax_t uint64_t -# else -typedef unsigned long int gl_uintmax_t; -# define uintmax_t gl_uintmax_t -# endif -# endif - -/* Verify that intmax_t and uintmax_t have the same size. Too much code - breaks if this is not the case. If this check fails, the reason is likely - to be found in the autoconf macros. */ -typedef int _verify_intmax_size[sizeof (intmax_t) == sizeof (uintmax_t) - ? 1 : -1]; - -# define GNULIB_defined_stdint_types 1 -# endif /* !GNULIB_defined_stdint_types */ - -/* 7.18.2. Limits of specified-width integer types */ - -/* 7.18.2.1. Limits of exact-width integer types */ - -/* Here we assume a standard architecture where the hardware integer - types have 8, 16, 32, optionally 64 bits. */ - -# undef INT8_MIN -# undef INT8_MAX -# undef UINT8_MAX -# define INT8_MIN (~ INT8_MAX) -# define INT8_MAX 127 -# define UINT8_MAX 255 - -# undef INT16_MIN -# undef INT16_MAX -# undef UINT16_MAX -# define INT16_MIN (~ INT16_MAX) -# define INT16_MAX 32767 -# define UINT16_MAX 65535 - -# undef INT32_MIN -# undef INT32_MAX -# undef UINT32_MAX -# define INT32_MIN (~ INT32_MAX) -# define INT32_MAX 2147483647 -# define UINT32_MAX 4294967295U - -# if defined GL_INT64_T && ! defined INT64_MAX -/* Prefer (- INTMAX_C (1) << 63) over (~ INT64_MAX) because SunPRO C 5.0 - evaluates the latter incorrectly in preprocessor expressions. */ -# define INT64_MIN (- INTMAX_C (1) << 63) -# define INT64_MAX INTMAX_C (9223372036854775807) -# endif - -# if defined GL_UINT64_T && ! defined UINT64_MAX -# define UINT64_MAX UINTMAX_C (18446744073709551615) -# endif - -/* 7.18.2.2. Limits of minimum-width integer types */ - -/* Here we assume a standard architecture where the hardware integer - types have 8, 16, 32, optionally 64 bits. Therefore the leastN_t types - are the same as the corresponding N_t types. */ - -# undef INT_LEAST8_MIN -# undef INT_LEAST8_MAX -# undef UINT_LEAST8_MAX -# define INT_LEAST8_MIN INT8_MIN -# define INT_LEAST8_MAX INT8_MAX -# define UINT_LEAST8_MAX UINT8_MAX - -# undef INT_LEAST16_MIN -# undef INT_LEAST16_MAX -# undef UINT_LEAST16_MAX -# define INT_LEAST16_MIN INT16_MIN -# define INT_LEAST16_MAX INT16_MAX -# define UINT_LEAST16_MAX UINT16_MAX - -# undef INT_LEAST32_MIN -# undef INT_LEAST32_MAX -# undef UINT_LEAST32_MAX -# define INT_LEAST32_MIN INT32_MIN -# define INT_LEAST32_MAX INT32_MAX -# define UINT_LEAST32_MAX UINT32_MAX - -# undef INT_LEAST64_MIN -# undef INT_LEAST64_MAX -# ifdef GL_INT64_T -# define INT_LEAST64_MIN INT64_MIN -# define INT_LEAST64_MAX INT64_MAX -# endif - -# undef UINT_LEAST64_MAX -# ifdef GL_UINT64_T -# define UINT_LEAST64_MAX UINT64_MAX -# endif - -/* 7.18.2.3. Limits of fastest minimum-width integer types */ - -/* Here we assume a standard architecture where the hardware integer - types have 8, 16, 32, optionally 64 bits. Therefore the fastN_t types - are taken from the same list of types. */ - -# undef INT_FAST8_MIN -# undef INT_FAST8_MAX -# undef UINT_FAST8_MAX -# define INT_FAST8_MIN SCHAR_MIN -# define INT_FAST8_MAX SCHAR_MAX -# define UINT_FAST8_MAX UCHAR_MAX - -# undef INT_FAST16_MIN -# undef INT_FAST16_MAX -# undef UINT_FAST16_MAX -# define INT_FAST16_MIN INT_FAST32_MIN -# define INT_FAST16_MAX INT_FAST32_MAX -# define UINT_FAST16_MAX UINT_FAST32_MAX - -# undef INT_FAST32_MIN -# undef INT_FAST32_MAX -# undef UINT_FAST32_MAX -# ifdef __sun -# define INT_FAST32_MIN INT_MIN -# define INT_FAST32_MAX INT_MAX -# define UINT_FAST32_MAX UINT_MAX -# else -# define INT_FAST32_MIN LONG_MIN -# define INT_FAST32_MAX LONG_MAX -# define UINT_FAST32_MAX ULONG_MAX -# endif - -# undef INT_FAST64_MIN -# undef INT_FAST64_MAX -# ifdef GL_INT64_T -# define INT_FAST64_MIN INT64_MIN -# define INT_FAST64_MAX INT64_MAX -# endif - -# undef UINT_FAST64_MAX -# ifdef GL_UINT64_T -# define UINT_FAST64_MAX UINT64_MAX -# endif - -/* 7.18.2.4. Limits of integer types capable of holding object pointers */ - -# undef INTPTR_MIN -# undef INTPTR_MAX -# undef UINTPTR_MAX -# ifdef _WIN64 -# define INTPTR_MIN LLONG_MIN -# define INTPTR_MAX LLONG_MAX -# define UINTPTR_MAX ULLONG_MAX -# else -# define INTPTR_MIN LONG_MIN -# define INTPTR_MAX LONG_MAX -# define UINTPTR_MAX ULONG_MAX -# endif - -/* 7.18.2.5. Limits of greatest-width integer types */ - -# ifndef INTMAX_MAX -# undef INTMAX_MIN -# ifdef INT64_MAX -# define INTMAX_MIN INT64_MIN -# define INTMAX_MAX INT64_MAX -# else -# define INTMAX_MIN INT32_MIN -# define INTMAX_MAX INT32_MAX -# endif -# endif - -# ifndef UINTMAX_MAX -# ifdef UINT64_MAX -# define UINTMAX_MAX UINT64_MAX -# else -# define UINTMAX_MAX UINT32_MAX -# endif -# endif - -/* 7.18.3. Limits of other integer types */ - -/* ptrdiff_t limits */ -# undef PTRDIFF_MIN -# undef PTRDIFF_MAX -# if 0 -# ifdef _LP64 -# define PTRDIFF_MIN _STDINT_SIGNED_MIN (64, 0l) -# define PTRDIFF_MAX _STDINT_MAX (1, 64, 0l) -# else -# define PTRDIFF_MIN _STDINT_SIGNED_MIN (32, 0) -# define PTRDIFF_MAX _STDINT_MAX (1, 32, 0) -# endif -# else -# define PTRDIFF_MIN \ - _STDINT_SIGNED_MIN (64, 0l) -# define PTRDIFF_MAX \ - _STDINT_MAX (1, 64, 0l) -# endif - -/* sig_atomic_t limits */ -# undef SIG_ATOMIC_MIN -# undef SIG_ATOMIC_MAX -# if 1 -# define SIG_ATOMIC_MIN \ - _STDINT_SIGNED_MIN (32, 0) -# else -# define SIG_ATOMIC_MIN \ - _STDINT_UNSIGNED_MIN (32, 0) -# endif -# define SIG_ATOMIC_MAX \ - _STDINT_MAX (1, 32, \ - 0) - - -/* size_t limit */ -# undef SIZE_MAX -# if 0 -# ifdef _LP64 -# define SIZE_MAX _STDINT_MAX (0, 64, 0ul) -# else -# define SIZE_MAX _STDINT_MAX (0, 32, 0ul) -# endif -# else -# define SIZE_MAX _STDINT_MAX (0, 64, 0ul) -# endif - -/* wchar_t limits */ -/* Get WCHAR_MIN, WCHAR_MAX. - This include is not on the top, above, because on OSF/1 4.0 we have a - sequence of nested includes - -> -> -> , and the latter includes - and assumes its types are already defined. */ -# if 1 && ! (defined WCHAR_MIN && defined WCHAR_MAX) - /* BSD/OS 4.0.1 has a bug: , and must be - included before . */ -# define _GL_JUST_INCLUDE_SYSTEM_WCHAR_H -# undef _GL_JUST_INCLUDE_SYSTEM_WCHAR_H -# endif -# undef WCHAR_MIN -# undef WCHAR_MAX -# if 1 -# define WCHAR_MIN \ - _STDINT_SIGNED_MIN (32, 0) -# else -# define WCHAR_MIN \ - _STDINT_UNSIGNED_MIN (32, 0) -# endif -# define WCHAR_MAX \ - _STDINT_MAX (1, 32, 0) - -/* wint_t limits */ -/* If gnulib's or overrides wint_t, u is not - accurate, therefore use the definitions from above. */ -# if !0 -# undef WINT_MIN -# undef WINT_MAX -# if 0 -# define WINT_MIN \ - _STDINT_SIGNED_MIN (32, 0u) -# else -# define WINT_MIN \ - _STDINT_UNSIGNED_MIN (32, 0u) -# endif -# define WINT_MAX \ - _STDINT_MAX (0, 32, 0u) -# endif - -/* 7.18.4. Macros for integer constants */ - -/* 7.18.4.1. Macros for minimum-width integer constants */ -/* According to ISO C 99 Technical Corrigendum 1 */ - -/* Here we assume a standard architecture where the hardware integer - types have 8, 16, 32, optionally 64 bits, and int is 32 bits. */ - -# undef INT8_C -# undef UINT8_C -# define INT8_C(x) x -# define UINT8_C(x) x - -# undef INT16_C -# undef UINT16_C -# define INT16_C(x) x -# define UINT16_C(x) x - -# undef INT32_C -# undef UINT32_C -# define INT32_C(x) x -# define UINT32_C(x) x ## U - -# undef INT64_C -# undef UINT64_C -# if LONG_MAX >> 31 >> 31 == 1 -# define INT64_C(x) x##L -# elif defined _MSC_VER -# define INT64_C(x) x##i64 -# else -# define INT64_C(x) x##LL -# endif -# if ULONG_MAX >> 31 >> 31 >> 1 == 1 -# define UINT64_C(x) x##UL -# elif defined _MSC_VER -# define UINT64_C(x) x##ui64 -# else -# define UINT64_C(x) x##ULL -# endif - -/* 7.18.4.2. Macros for greatest-width integer constants */ - -# ifndef INTMAX_C -# if LONG_MAX >> 30 == 1 -# define INTMAX_C(x) x##LL -# elif defined GL_INT64_T -# define INTMAX_C(x) INT64_C(x) -# else -# define INTMAX_C(x) x##L -# endif -# endif - -# ifndef UINTMAX_C -# if ULONG_MAX >> 31 == 1 -# define UINTMAX_C(x) x##ULL -# elif defined GL_UINT64_T -# define UINTMAX_C(x) UINT64_C(x) -# else -# define UINTMAX_C(x) x##UL -# endif -# endif - -#endif /* !0 */ - -/* Macros specified by ISO/IEC TS 18661-1:2014. */ - -#if (!defined UINTMAX_WIDTH \ - && (defined _GNU_SOURCE || defined __STDC_WANT_IEC_60559_BFP_EXT__)) -# ifdef INT8_MAX -# define INT8_WIDTH _GL_INTEGER_WIDTH (INT8_MIN, INT8_MAX) -# endif -# ifdef UINT8_MAX -# define UINT8_WIDTH _GL_INTEGER_WIDTH (0, UINT8_MAX) -# endif -# ifdef INT16_MAX -# define INT16_WIDTH _GL_INTEGER_WIDTH (INT16_MIN, INT16_MAX) -# endif -# ifdef UINT16_MAX -# define UINT16_WIDTH _GL_INTEGER_WIDTH (0, UINT16_MAX) -# endif -# ifdef INT32_MAX -# define INT32_WIDTH _GL_INTEGER_WIDTH (INT32_MIN, INT32_MAX) -# endif -# ifdef UINT32_MAX -# define UINT32_WIDTH _GL_INTEGER_WIDTH (0, UINT32_MAX) -# endif -# ifdef INT64_MAX -# define INT64_WIDTH _GL_INTEGER_WIDTH (INT64_MIN, INT64_MAX) -# endif -# ifdef UINT64_MAX -# define UINT64_WIDTH _GL_INTEGER_WIDTH (0, UINT64_MAX) -# endif -# define INT_LEAST8_WIDTH _GL_INTEGER_WIDTH (INT_LEAST8_MIN, INT_LEAST8_MAX) -# define UINT_LEAST8_WIDTH _GL_INTEGER_WIDTH (0, UINT_LEAST8_MAX) -# define INT_LEAST16_WIDTH _GL_INTEGER_WIDTH (INT_LEAST16_MIN, INT_LEAST16_MAX) -# define UINT_LEAST16_WIDTH _GL_INTEGER_WIDTH (0, UINT_LEAST16_MAX) -# define INT_LEAST32_WIDTH _GL_INTEGER_WIDTH (INT_LEAST32_MIN, INT_LEAST32_MAX) -# define UINT_LEAST32_WIDTH _GL_INTEGER_WIDTH (0, UINT_LEAST32_MAX) -# define INT_LEAST64_WIDTH _GL_INTEGER_WIDTH (INT_LEAST64_MIN, INT_LEAST64_MAX) -# define UINT_LEAST64_WIDTH _GL_INTEGER_WIDTH (0, UINT_LEAST64_MAX) -# define INT_FAST8_WIDTH _GL_INTEGER_WIDTH (INT_FAST8_MIN, INT_FAST8_MAX) -# define UINT_FAST8_WIDTH _GL_INTEGER_WIDTH (0, UINT_FAST8_MAX) -# define INT_FAST16_WIDTH _GL_INTEGER_WIDTH (INT_FAST16_MIN, INT_FAST16_MAX) -# define UINT_FAST16_WIDTH _GL_INTEGER_WIDTH (0, UINT_FAST16_MAX) -# define INT_FAST32_WIDTH _GL_INTEGER_WIDTH (INT_FAST32_MIN, INT_FAST32_MAX) -# define UINT_FAST32_WIDTH _GL_INTEGER_WIDTH (0, UINT_FAST32_MAX) -# define INT_FAST64_WIDTH _GL_INTEGER_WIDTH (INT_FAST64_MIN, INT_FAST64_MAX) -# define UINT_FAST64_WIDTH _GL_INTEGER_WIDTH (0, UINT_FAST64_MAX) -# define INTPTR_WIDTH _GL_INTEGER_WIDTH (INTPTR_MIN, INTPTR_MAX) -# define UINTPTR_WIDTH _GL_INTEGER_WIDTH (0, UINTPTR_MAX) -# define INTMAX_WIDTH _GL_INTEGER_WIDTH (INTMAX_MIN, INTMAX_MAX) -# define UINTMAX_WIDTH _GL_INTEGER_WIDTH (0, UINTMAX_MAX) -# define PTRDIFF_WIDTH _GL_INTEGER_WIDTH (PTRDIFF_MIN, PTRDIFF_MAX) -# define SIZE_WIDTH _GL_INTEGER_WIDTH (0, SIZE_MAX) -# define WCHAR_WIDTH _GL_INTEGER_WIDTH (WCHAR_MIN, WCHAR_MAX) -# ifdef WINT_MAX -# define WINT_WIDTH _GL_INTEGER_WIDTH (WINT_MIN, WINT_MAX) -# endif -# ifdef SIG_ATOMIC_MAX -# define SIG_ATOMIC_WIDTH _GL_INTEGER_WIDTH (SIG_ATOMIC_MIN, SIG_ATOMIC_MAX) -# endif -#endif /* !WINT_WIDTH && (_GNU_SOURCE || __STDC_WANT_IEC_60559_BFP_EXT__) */ - -#endif /* _GL_STDINT_H */ -#endif /* !(defined __ANDROID__ && ...) */ -#endif /* !defined _GL_STDINT_H && !defined _GL_JUST_INCLUDE_SYSTEM_STDINT_H */ diff --git a/third_party/make/stdio.h b/third_party/make/stdio.h deleted file mode 100644 index 91b1b154e..000000000 --- a/third_party/make/stdio.h +++ /dev/null @@ -1,1906 +0,0 @@ -/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ -/* A GNU-like . - - Copyright (C) 2004, 2007-2020 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, 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 . */ - -#if __GNUC__ >= 3 -#pragma GCC system_header -#endif - - -#if defined __need_FILE || defined __need___FILE || defined _GL_ALREADY_INCLUDING_STDIO_H -/* Special invocation convention: - - Inside glibc header files. - - On OSF/1 5.1 we have a sequence of nested includes - -> -> -> -> - -> -> -> . - In this situation, the functions are not yet declared, therefore we cannot - provide the C++ aliases. */ - -#else -/* Normal invocation convention. */ - -#ifndef _GL_STDIO_H - -#define _GL_ALREADY_INCLUDING_STDIO_H - -/* The include_next requires a split double-inclusion guard. */ - -#undef _GL_ALREADY_INCLUDING_STDIO_H - -#ifndef _GL_STDIO_H -#define _GL_STDIO_H - -/* Get va_list. Needed on many systems, including glibc 2.8. */ - -/* Get off_t and ssize_t. Needed on many systems, including glibc 2.8 - and eglibc 2.11.2. - May also define off_t to a 64-bit type on native Windows. */ - -/* The __attribute__ feature is available in gcc versions 2.5 and later. - The __-protected variants of the attributes 'format' and 'printf' are - accepted by gcc versions 2.6.4 (effectively 2.7) and later. - We enable _GL_ATTRIBUTE_FORMAT only if these are supported too, because - gnulib and libintl do '#define printf __printf__' when they override - the 'printf' function. */ -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7) -# define _GL_ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec)) -#else -# define _GL_ATTRIBUTE_FORMAT(spec) /* empty */ -#endif - -/* _GL_ATTRIBUTE_FORMAT_PRINTF - indicates to GCC that the function takes a format string and arguments, - where the format string directives are the ones standardized by ISO C99 - and POSIX. */ -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) -# define _GL_ATTRIBUTE_FORMAT_PRINTF(formatstring_parameter, first_argument) \ - _GL_ATTRIBUTE_FORMAT ((__gnu_printf__, formatstring_parameter, first_argument)) -#else -# define _GL_ATTRIBUTE_FORMAT_PRINTF(formatstring_parameter, first_argument) \ - _GL_ATTRIBUTE_FORMAT ((__printf__, formatstring_parameter, first_argument)) -#endif - -/* _GL_ATTRIBUTE_FORMAT_PRINTF_SYSTEM is like _GL_ATTRIBUTE_FORMAT_PRINTF, - except that it indicates to GCC that the supported format string directives - are the ones of the system printf(), rather than the ones standardized by - ISO C99 and POSIX. */ -#if GNULIB_PRINTF_ATTRIBUTE_FLAVOR_GNU -# define _GL_ATTRIBUTE_FORMAT_PRINTF_SYSTEM(formatstring_parameter, first_argument) \ - _GL_ATTRIBUTE_FORMAT_PRINTF (formatstring_parameter, first_argument) -#else -# define _GL_ATTRIBUTE_FORMAT_PRINTF_SYSTEM(formatstring_parameter, first_argument) \ - _GL_ATTRIBUTE_FORMAT ((__printf__, formatstring_parameter, first_argument)) -#endif - -/* _GL_ATTRIBUTE_FORMAT_SCANF - indicates to GCC that the function takes a format string and arguments, - where the format string directives are the ones standardized by ISO C99 - and POSIX. */ -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) -# define _GL_ATTRIBUTE_FORMAT_SCANF(formatstring_parameter, first_argument) \ - _GL_ATTRIBUTE_FORMAT ((__gnu_scanf__, formatstring_parameter, first_argument)) -#else -# define _GL_ATTRIBUTE_FORMAT_SCANF(formatstring_parameter, first_argument) \ - _GL_ATTRIBUTE_FORMAT ((__scanf__, formatstring_parameter, first_argument)) -#endif - -/* _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM is like _GL_ATTRIBUTE_FORMAT_SCANF, - except that it indicates to GCC that the supported format string directives - are the ones of the system scanf(), rather than the ones standardized by - ISO C99 and POSIX. */ -#define _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM(formatstring_parameter, first_argument) \ - _GL_ATTRIBUTE_FORMAT ((__scanf__, formatstring_parameter, first_argument)) - -/* Solaris 10 and NetBSD 7.0 declare renameat in , not in . */ -/* But in any case avoid namespace pollution on glibc systems. */ -#if (0 || defined GNULIB_POSIXCHECK) && (defined __sun || defined __NetBSD__) \ - && ! defined __GLIBC__ -#endif - -/* Android 4.3 declares renameat in , not in . */ -/* But in any case avoid namespace pollution on glibc systems. */ -#if (0 || defined GNULIB_POSIXCHECK) && defined __ANDROID__ \ - && ! defined __GLIBC__ -#endif - -/* MSVC declares 'perror' in , not in . We must include - it before we #define perror rpl_perror. */ -/* But in any case avoid namespace pollution on glibc systems. */ -#if (0 || defined GNULIB_POSIXCHECK) \ - && (defined _WIN32 && ! defined __CYGWIN__) \ - && ! defined __GLIBC__ -#endif - -/* MSVC declares 'remove' in , not in . We must include - it before we #define remove rpl_remove. */ -/* MSVC declares 'rename' in , not in . We must include - it before we #define rename rpl_rename. */ -/* But in any case avoid namespace pollution on glibc systems. */ -#if (0 || 0 || defined GNULIB_POSIXCHECK) \ - && (defined _WIN32 && ! defined __CYGWIN__) \ - && ! defined __GLIBC__ -#endif - - -/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ -/* C++ compatible function declaration macros. - Copyright (C) 2010-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -#ifndef _GL_CXXDEFS_H -#define _GL_CXXDEFS_H - -/* Begin/end the GNULIB_NAMESPACE namespace. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -# define _GL_BEGIN_NAMESPACE namespace GNULIB_NAMESPACE { -# define _GL_END_NAMESPACE } -#else -# define _GL_BEGIN_NAMESPACE -# define _GL_END_NAMESPACE -#endif - -/* The three most frequent use cases of these macros are: - - * For providing a substitute for a function that is missing on some - platforms, but is declared and works fine on the platforms on which - it exists: - - #if @GNULIB_FOO@ - # if !@HAVE_FOO@ - _GL_FUNCDECL_SYS (foo, ...); - # endif - _GL_CXXALIAS_SYS (foo, ...); - _GL_CXXALIASWARN (foo); - #elif defined GNULIB_POSIXCHECK - ... - #endif - - * For providing a replacement for a function that exists on all platforms, - but is broken/insufficient and needs to be replaced on some platforms: - - #if @GNULIB_FOO@ - # if @REPLACE_FOO@ - # if !(defined __cplusplus && defined GNULIB_NAMESPACE) - # undef foo - # define foo rpl_foo - # endif - _GL_FUNCDECL_RPL (foo, ...); - _GL_CXXALIAS_RPL (foo, ...); - # else - _GL_CXXALIAS_SYS (foo, ...); - # endif - _GL_CXXALIASWARN (foo); - #elif defined GNULIB_POSIXCHECK - ... - #endif - - * For providing a replacement for a function that exists on some platforms - but is broken/insufficient and needs to be replaced on some of them and - is additionally either missing or undeclared on some other platforms: - - #if @GNULIB_FOO@ - # if @REPLACE_FOO@ - # if !(defined __cplusplus && defined GNULIB_NAMESPACE) - # undef foo - # define foo rpl_foo - # endif - _GL_FUNCDECL_RPL (foo, ...); - _GL_CXXALIAS_RPL (foo, ...); - # else - # if !@HAVE_FOO@ or if !@HAVE_DECL_FOO@ - _GL_FUNCDECL_SYS (foo, ...); - # endif - _GL_CXXALIAS_SYS (foo, ...); - # endif - _GL_CXXALIASWARN (foo); - #elif defined GNULIB_POSIXCHECK - ... - #endif -*/ - -/* _GL_EXTERN_C declaration; - performs the declaration with C linkage. */ -#if defined __cplusplus -# define _GL_EXTERN_C extern "C" -#else -# define _GL_EXTERN_C extern -#endif - -/* _GL_FUNCDECL_RPL (func, rettype, parameters_and_attributes); - declares a replacement function, named rpl_func, with the given prototype, - consisting of return type, parameters, and attributes. - Example: - _GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...) - _GL_ARG_NONNULL ((1))); - */ -#define _GL_FUNCDECL_RPL(func,rettype,parameters_and_attributes) \ - _GL_FUNCDECL_RPL_1 (rpl_##func, rettype, parameters_and_attributes) -#define _GL_FUNCDECL_RPL_1(rpl_func,rettype,parameters_and_attributes) \ - _GL_EXTERN_C rettype rpl_func parameters_and_attributes - -/* _GL_FUNCDECL_SYS (func, rettype, parameters_and_attributes); - declares the system function, named func, with the given prototype, - consisting of return type, parameters, and attributes. - Example: - _GL_FUNCDECL_SYS (open, int, (const char *filename, int flags, ...) - _GL_ARG_NONNULL ((1))); - */ -#define _GL_FUNCDECL_SYS(func,rettype,parameters_and_attributes) \ - _GL_EXTERN_C rettype func parameters_and_attributes - -/* _GL_CXXALIAS_RPL (func, rettype, parameters); - declares a C++ alias called GNULIB_NAMESPACE::func - that redirects to rpl_func, if GNULIB_NAMESPACE is defined. - Example: - _GL_CXXALIAS_RPL (open, int, (const char *filename, int flags, ...)); - - Wrapping rpl_func in an object with an inline conversion operator - avoids a reference to rpl_func unless GNULIB_NAMESPACE::func is - actually used in the program. */ -#define _GL_CXXALIAS_RPL(func,rettype,parameters) \ - _GL_CXXALIAS_RPL_1 (func, rpl_##func, rettype, parameters) -#if defined __cplusplus && defined GNULIB_NAMESPACE -# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \ - namespace GNULIB_NAMESPACE \ - { \ - static const struct _gl_ ## func ## _wrapper \ - { \ - typedef rettype (*type) parameters; \ - \ - inline operator type () const \ - { \ - return ::rpl_func; \ - } \ - } func = {}; \ - } \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#else -# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIAS_RPL_CAST_1 (func, rpl_func, rettype, parameters); - is like _GL_CXXALIAS_RPL_1 (func, rpl_func, rettype, parameters); - except that the C function rpl_func may have a slightly different - declaration. A cast is used to silence the "invalid conversion" error - that would otherwise occur. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -# define _GL_CXXALIAS_RPL_CAST_1(func,rpl_func,rettype,parameters) \ - namespace GNULIB_NAMESPACE \ - { \ - static const struct _gl_ ## func ## _wrapper \ - { \ - typedef rettype (*type) parameters; \ - \ - inline operator type () const \ - { \ - return reinterpret_cast(::rpl_func); \ - } \ - } func = {}; \ - } \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#else -# define _GL_CXXALIAS_RPL_CAST_1(func,rpl_func,rettype,parameters) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIAS_SYS (func, rettype, parameters); - declares a C++ alias called GNULIB_NAMESPACE::func - that redirects to the system provided function func, if GNULIB_NAMESPACE - is defined. - Example: - _GL_CXXALIAS_SYS (open, int, (const char *filename, int flags, ...)); - - Wrapping func in an object with an inline conversion operator - avoids a reference to func unless GNULIB_NAMESPACE::func is - actually used in the program. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -# define _GL_CXXALIAS_SYS(func,rettype,parameters) \ - namespace GNULIB_NAMESPACE \ - { \ - static const struct _gl_ ## func ## _wrapper \ - { \ - typedef rettype (*type) parameters; \ - \ - inline operator type () const \ - { \ - return ::func; \ - } \ - } func = {}; \ - } \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#else -# define _GL_CXXALIAS_SYS(func,rettype,parameters) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIAS_SYS_CAST (func, rettype, parameters); - is like _GL_CXXALIAS_SYS (func, rettype, parameters); - except that the C function func may have a slightly different declaration. - A cast is used to silence the "invalid conversion" error that would - otherwise occur. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -# define _GL_CXXALIAS_SYS_CAST(func,rettype,parameters) \ - namespace GNULIB_NAMESPACE \ - { \ - static const struct _gl_ ## func ## _wrapper \ - { \ - typedef rettype (*type) parameters; \ - \ - inline operator type () const \ - { \ - return reinterpret_cast(::func); \ - } \ - } func = {}; \ - } \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#else -# define _GL_CXXALIAS_SYS_CAST(func,rettype,parameters) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIAS_SYS_CAST2 (func, rettype, parameters, rettype2, parameters2); - is like _GL_CXXALIAS_SYS (func, rettype, parameters); - except that the C function is picked among a set of overloaded functions, - namely the one with rettype2 and parameters2. Two consecutive casts - are used to silence the "cannot find a match" and "invalid conversion" - errors that would otherwise occur. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE - /* The outer cast must be a reinterpret_cast. - The inner cast: When the function is defined as a set of overloaded - functions, it works as a static_cast<>, choosing the designated variant. - When the function is defined as a single variant, it works as a - reinterpret_cast<>. The parenthesized cast syntax works both ways. */ -# define _GL_CXXALIAS_SYS_CAST2(func,rettype,parameters,rettype2,parameters2) \ - namespace GNULIB_NAMESPACE \ - { \ - static const struct _gl_ ## func ## _wrapper \ - { \ - typedef rettype (*type) parameters; \ - \ - inline operator type () const \ - { \ - return reinterpret_cast((rettype2 (*) parameters2)(::func)); \ - } \ - } func = {}; \ - } \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#else -# define _GL_CXXALIAS_SYS_CAST2(func,rettype,parameters,rettype2,parameters2) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIASWARN (func); - causes a warning to be emitted when ::func is used but not when - GNULIB_NAMESPACE::func is used. func must be defined without overloaded - variants. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -# define _GL_CXXALIASWARN(func) \ - _GL_CXXALIASWARN_1 (func, GNULIB_NAMESPACE) -# define _GL_CXXALIASWARN_1(func,namespace) \ - _GL_CXXALIASWARN_2 (func, namespace) -/* To work around GCC bug , - we enable the warning only when not optimizing. */ -# if !__OPTIMIZE__ -# define _GL_CXXALIASWARN_2(func,namespace) \ - _GL_WARN_ON_USE (func, \ - "The symbol ::" #func " refers to the system function. " \ - "Use " #namespace "::" #func " instead.") -# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING -# define _GL_CXXALIASWARN_2(func,namespace) \ - extern __typeof__ (func) func -# else -# define _GL_CXXALIASWARN_2(func,namespace) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -# endif -#else -# define _GL_CXXALIASWARN(func) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIASWARN1 (func, rettype, parameters_and_attributes); - causes a warning to be emitted when the given overloaded variant of ::func - is used but not when GNULIB_NAMESPACE::func is used. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -# define _GL_CXXALIASWARN1(func,rettype,parameters_and_attributes) \ - _GL_CXXALIASWARN1_1 (func, rettype, parameters_and_attributes, \ - GNULIB_NAMESPACE) -# define _GL_CXXALIASWARN1_1(func,rettype,parameters_and_attributes,namespace) \ - _GL_CXXALIASWARN1_2 (func, rettype, parameters_and_attributes, namespace) -/* To work around GCC bug , - we enable the warning only when not optimizing. */ -# if !__OPTIMIZE__ -# define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \ - _GL_WARN_ON_USE_CXX (func, rettype, parameters_and_attributes, \ - "The symbol ::" #func " refers to the system function. " \ - "Use " #namespace "::" #func " instead.") -# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING -# define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \ - extern __typeof__ (func) func -# else -# define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -# endif -#else -# define _GL_CXXALIASWARN1(func,rettype,parameters_and_attributes) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -#endif /* _GL_CXXDEFS_H */ - -/* The definition of _GL_ARG_NONNULL is copied here. */ -/* A C macro for declaring that specific arguments must not be NULL. - Copyright (C) 2009-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -/* _GL_ARG_NONNULL((n,...,m)) tells the compiler and static analyzer tools - that the values passed as arguments n, ..., m must be non-NULL pointers. - n = 1 stands for the first argument, n = 2 for the second argument etc. */ -#ifndef _GL_ARG_NONNULL -# if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || __GNUC__ > 3 -# define _GL_ARG_NONNULL(params) __attribute__ ((__nonnull__ params)) -# else -# define _GL_ARG_NONNULL(params) -# endif -#endif - -/* The definition of _GL_WARN_ON_USE is copied here. */ -/* A C macro for emitting warnings if a function is used. - Copyright (C) 2010-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -/* _GL_WARN_ON_USE (function, "literal string") issues a declaration - for FUNCTION which will then trigger a compiler warning containing - the text of "literal string" anywhere that function is called, if - supported by the compiler. If the compiler does not support this - feature, the macro expands to an unused extern declaration. - - _GL_WARN_ON_USE_ATTRIBUTE ("literal string") expands to the - attribute used in _GL_WARN_ON_USE. If the compiler does not support - this feature, it expands to empty. - - These macros are useful for marking a function as a potential - portability trap, with the intent that "literal string" include - instructions on the replacement function that should be used - instead. - _GL_WARN_ON_USE is for functions with 'extern' linkage. - _GL_WARN_ON_USE_ATTRIBUTE is for functions with 'static' or 'inline' - linkage. - - However, one of the reasons that a function is a portability trap is - if it has the wrong signature. Declaring FUNCTION with a different - signature in C is a compilation error, so this macro must use the - same type as any existing declaration so that programs that avoid - the problematic FUNCTION do not fail to compile merely because they - included a header that poisoned the function. But this implies that - _GL_WARN_ON_USE is only safe to use if FUNCTION is known to already - have a declaration. Use of this macro implies that there must not - be any other macro hiding the declaration of FUNCTION; but - undefining FUNCTION first is part of the poisoning process anyway - (although for symbols that are provided only via a macro, the result - is a compilation error rather than a warning containing - "literal string"). Also note that in C++, it is only safe to use if - FUNCTION has no overloads. - - For an example, it is possible to poison 'getline' by: - [getline]) in configure.ac, which potentially defines - HAVE_RAW_DECL_GETLINE - - adding this code to a header that wraps the system : - #undef getline - #if HAVE_RAW_DECL_GETLINE - _GL_WARN_ON_USE (getline, "getline is required by POSIX 2008, but" - "not universally present; use the gnulib module getline"); - #endif - - It is not possible to directly poison global variables. But it is - possible to write a wrapper accessor function, and poison that - (less common usage, like &environ, will cause a compilation error - rather than issue the nice warning, but the end result of informing - the developer about their portability problem is still achieved): - #if HAVE_RAW_DECL_ENVIRON - static char *** - rpl_environ (void) { return &environ; } - _GL_WARN_ON_USE (rpl_environ, "environ is not always properly declared"); - # undef environ - # define environ (*rpl_environ ()) - #endif - or better (avoiding contradictory use of 'static' and 'extern'): - #if HAVE_RAW_DECL_ENVIRON - static char *** - _GL_WARN_ON_USE_ATTRIBUTE ("environ is not always properly declared") - rpl_environ (void) { return &environ; } - # undef environ - # define environ (*rpl_environ ()) - #endif - */ -#ifndef _GL_WARN_ON_USE - -# if 4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) -/* A compiler attribute is available in gcc versions 4.3.0 and later. */ -# define _GL_WARN_ON_USE(function, message) \ -extern __typeof__ (function) function __attribute__ ((__warning__ (message))) -# define _GL_WARN_ON_USE_ATTRIBUTE(message) \ - __attribute__ ((__warning__ (message))) -# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING -/* Verify the existence of the function. */ -# define _GL_WARN_ON_USE(function, message) \ -extern __typeof__ (function) function -# define _GL_WARN_ON_USE_ATTRIBUTE(message) -# else /* Unsupported. */ -# define _GL_WARN_ON_USE(function, message) \ -_GL_WARN_EXTERN_C int _gl_warn_on_use -# define _GL_WARN_ON_USE_ATTRIBUTE(message) -# endif -#endif - -/* _GL_WARN_ON_USE_CXX (function, rettype, parameters_and_attributes, "string") - is like _GL_WARN_ON_USE (function, "string"), except that the function is - declared with the given prototype, consisting of return type, parameters, - and attributes. - This variant is useful for overloaded functions in C++. _GL_WARN_ON_USE does - not work in this case. */ -#ifndef _GL_WARN_ON_USE_CXX -# if 4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) -# define _GL_WARN_ON_USE_CXX(function,rettype,parameters_and_attributes,msg) \ -extern rettype function parameters_and_attributes \ - __attribute__ ((__warning__ (msg))) -# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING -/* Verify the existence of the function. */ -# define _GL_WARN_ON_USE_CXX(function,rettype,parameters_and_attributes,msg) \ -extern rettype function parameters_and_attributes -# else /* Unsupported. */ -# define _GL_WARN_ON_USE_CXX(function,rettype,parameters_and_attributes,msg) \ -_GL_WARN_EXTERN_C int _gl_warn_on_use -# endif -#endif - -/* _GL_WARN_EXTERN_C declaration; - performs the declaration with C linkage. */ -#ifndef _GL_WARN_EXTERN_C -# if defined __cplusplus -# define _GL_WARN_EXTERN_C extern "C" -# else -# define _GL_WARN_EXTERN_C extern -# endif -#endif - -/* Macros for stringification. */ -#define _GL_STDIO_STRINGIZE(token) #token -#define _GL_STDIO_MACROEXPAND_AND_STRINGIZE(token) _GL_STDIO_STRINGIZE(token) - -/* When also using extern inline, suppress the use of static inline in - standard headers of problematic Apple configurations, as Libc at - least through Libc-825.26 (2013-04-09) mishandles it; see, e.g., - . - Perhaps Apple will fix this some day. */ -#if (defined _GL_EXTERN_INLINE_IN_USE && defined __APPLE__ \ - && defined __GNUC__ && defined __STDC__) -# undef putc_unlocked -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define dprintf rpl_dprintf -# endif -_GL_FUNCDECL_RPL (dprintf, int, (int fd, const char *format, ...) - _GL_ATTRIBUTE_FORMAT_PRINTF (2, 3) - _GL_ARG_NONNULL ((2))); -_GL_CXXALIAS_RPL (dprintf, int, (int fd, const char *format, ...)); -# else -# if !1 -_GL_FUNCDECL_SYS (dprintf, int, (int fd, const char *format, ...) - _GL_ATTRIBUTE_FORMAT_PRINTF (2, 3) - _GL_ARG_NONNULL ((2))); -# endif -_GL_CXXALIAS_SYS (dprintf, int, (int fd, const char *format, ...)); -# endif -_GL_CXXALIASWARN (dprintf); -#elif defined GNULIB_POSIXCHECK -# undef dprintf -# if HAVE_RAW_DECL_DPRINTF -_GL_WARN_ON_USE (dprintf, "dprintf is unportable - " - "use gnulib module dprintf for portability"); -# endif -#endif - -#if 0 -/* Close STREAM and its underlying file descriptor. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define fclose rpl_fclose -# endif -_GL_FUNCDECL_RPL (fclose, int, (FILE *stream) _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (fclose, int, (FILE *stream)); -# else -_GL_CXXALIAS_SYS (fclose, int, (FILE *stream)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (fclose); -# endif -#elif defined GNULIB_POSIXCHECK -# undef fclose -/* Assume fclose is always declared. */ -_GL_WARN_ON_USE (fclose, "fclose is not always POSIX compliant - " - "use gnulib module fclose for portable POSIX compliance"); -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef fdopen -# define fdopen rpl_fdopen -# endif -_GL_FUNCDECL_RPL (fdopen, FILE *, (int fd, const char *mode) - _GL_ARG_NONNULL ((2))); -_GL_CXXALIAS_RPL (fdopen, FILE *, (int fd, const char *mode)); -# else -_GL_CXXALIAS_SYS (fdopen, FILE *, (int fd, const char *mode)); -# endif -_GL_CXXALIASWARN (fdopen); -#elif defined GNULIB_POSIXCHECK -# undef fdopen -/* Assume fdopen is always declared. */ -_GL_WARN_ON_USE (fdopen, "fdopen on native Windows platforms is not POSIX compliant - " - "use gnulib module fdopen for portability"); -#endif - -#if 0 -/* Flush all pending data on STREAM according to POSIX rules. Both - output and seekable input streams are supported. - Note! LOSS OF DATA can occur if fflush is applied on an input stream - that is _not_seekable_ or on an update stream that is _not_seekable_ - and in which the most recent operation was input. Seekability can - be tested with lseek(fileno(fp),0,SEEK_CUR). */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define fflush rpl_fflush -# endif -_GL_FUNCDECL_RPL (fflush, int, (FILE *gl_stream)); -_GL_CXXALIAS_RPL (fflush, int, (FILE *gl_stream)); -# else -_GL_CXXALIAS_SYS (fflush, int, (FILE *gl_stream)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (fflush); -# endif -#elif defined GNULIB_POSIXCHECK -# undef fflush -/* Assume fflush is always declared. */ -_GL_WARN_ON_USE (fflush, "fflush is not always POSIX compliant - " - "use gnulib module fflush for portable POSIX compliance"); -#endif - -#if 1 -# if 0 && 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef fgetc -# define fgetc rpl_fgetc -# endif -_GL_FUNCDECL_RPL (fgetc, int, (FILE *stream) _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (fgetc, int, (FILE *stream)); -# else -_GL_CXXALIAS_SYS (fgetc, int, (FILE *stream)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (fgetc); -# endif -#endif - -#if 1 -# if 0 && 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef fgets -# define fgets rpl_fgets -# endif -_GL_FUNCDECL_RPL (fgets, char *, (char *s, int n, FILE *stream) - _GL_ARG_NONNULL ((1, 3))); -_GL_CXXALIAS_RPL (fgets, char *, (char *s, int n, FILE *stream)); -# else -_GL_CXXALIAS_SYS (fgets, char *, (char *s, int n, FILE *stream)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (fgets); -# endif -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef fopen -# define fopen rpl_fopen -# endif -_GL_FUNCDECL_RPL (fopen, FILE *, (const char *filename, const char *mode) - _GL_ARG_NONNULL ((1, 2))); -_GL_CXXALIAS_RPL (fopen, FILE *, (const char *filename, const char *mode)); -# else -_GL_CXXALIAS_SYS (fopen, FILE *, (const char *filename, const char *mode)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (fopen); -# endif -#elif defined GNULIB_POSIXCHECK -# undef fopen -/* Assume fopen is always declared. */ -_GL_WARN_ON_USE (fopen, "fopen on native Windows platforms is not POSIX compliant - " - "use gnulib module fopen for portability"); -#endif - -#if 0 || 1 -# if (0 && 0) \ - || (1 && 0 && (0 || 0)) -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define fprintf rpl_fprintf -# endif -# define GNULIB_overrides_fprintf 1 -# if 0 || 0 -_GL_FUNCDECL_RPL (fprintf, int, (FILE *fp, const char *format, ...) - _GL_ATTRIBUTE_FORMAT_PRINTF (2, 3) - _GL_ARG_NONNULL ((1, 2))); -# else -_GL_FUNCDECL_RPL (fprintf, int, (FILE *fp, const char *format, ...) - _GL_ATTRIBUTE_FORMAT_PRINTF_SYSTEM (2, 3) - _GL_ARG_NONNULL ((1, 2))); -# endif -_GL_CXXALIAS_RPL (fprintf, int, (FILE *fp, const char *format, ...)); -# else -_GL_CXXALIAS_SYS (fprintf, int, (FILE *fp, const char *format, ...)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (fprintf); -# endif -#endif -#if !0 && defined GNULIB_POSIXCHECK -# if !GNULIB_overrides_fprintf -# undef fprintf -# endif -/* Assume fprintf is always declared. */ -_GL_WARN_ON_USE (fprintf, "fprintf is not always POSIX compliant - " - "use gnulib module fprintf-posix for portable " - "POSIX compliance"); -#endif - -#if 0 -/* Discard all pending buffered I/O data on STREAM. - STREAM must not be wide-character oriented. - When discarding pending output, the file position is set back to where it - was before the write calls. When discarding pending input, the file - position is advanced to match the end of the previously read input. - Return 0 if successful. Upon error, return -1 and set errno. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define fpurge rpl_fpurge -# endif -_GL_FUNCDECL_RPL (fpurge, int, (FILE *gl_stream) _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (fpurge, int, (FILE *gl_stream)); -# else -# if !1 -_GL_FUNCDECL_SYS (fpurge, int, (FILE *gl_stream) _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (fpurge, int, (FILE *gl_stream)); -# endif -_GL_CXXALIASWARN (fpurge); -#elif defined GNULIB_POSIXCHECK -# undef fpurge -# if HAVE_RAW_DECL_FPURGE -_GL_WARN_ON_USE (fpurge, "fpurge is not always present - " - "use gnulib module fpurge for portability"); -# endif -#endif - -#if 1 -# if 0 && (0 || 0) -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef fputc -# define fputc rpl_fputc -# endif -_GL_FUNCDECL_RPL (fputc, int, (int c, FILE *stream) _GL_ARG_NONNULL ((2))); -_GL_CXXALIAS_RPL (fputc, int, (int c, FILE *stream)); -# else -_GL_CXXALIAS_SYS (fputc, int, (int c, FILE *stream)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (fputc); -# endif -#endif - -#if 1 -# if 0 && (0 || 0) -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef fputs -# define fputs rpl_fputs -# endif -_GL_FUNCDECL_RPL (fputs, int, (const char *string, FILE *stream) - _GL_ARG_NONNULL ((1, 2))); -_GL_CXXALIAS_RPL (fputs, int, (const char *string, FILE *stream)); -# else -_GL_CXXALIAS_SYS (fputs, int, (const char *string, FILE *stream)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (fputs); -# endif -#endif - -#if 1 -# if 0 && 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef fread -# define fread rpl_fread -# endif -_GL_FUNCDECL_RPL (fread, size_t, (void *ptr, size_t s, size_t n, FILE *stream) - _GL_ARG_NONNULL ((4))); -_GL_CXXALIAS_RPL (fread, size_t, (void *ptr, size_t s, size_t n, FILE *stream)); -# else -_GL_CXXALIAS_SYS (fread, size_t, (void *ptr, size_t s, size_t n, FILE *stream)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (fread); -# endif -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef freopen -# define freopen rpl_freopen -# endif -_GL_FUNCDECL_RPL (freopen, FILE *, - (const char *filename, const char *mode, FILE *stream) - _GL_ARG_NONNULL ((2, 3))); -_GL_CXXALIAS_RPL (freopen, FILE *, - (const char *filename, const char *mode, FILE *stream)); -# else -_GL_CXXALIAS_SYS (freopen, FILE *, - (const char *filename, const char *mode, FILE *stream)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (freopen); -# endif -#elif defined GNULIB_POSIXCHECK -# undef freopen -/* Assume freopen is always declared. */ -_GL_WARN_ON_USE (freopen, - "freopen on native Windows platforms is not POSIX compliant - " - "use gnulib module freopen for portability"); -#endif - -#if 1 -# if 0 && 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef fscanf -# define fscanf rpl_fscanf -# endif -_GL_FUNCDECL_RPL (fscanf, int, (FILE *stream, const char *format, ...) - _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (2, 3) - _GL_ARG_NONNULL ((1, 2))); -_GL_CXXALIAS_RPL (fscanf, int, (FILE *stream, const char *format, ...)); -# else -_GL_CXXALIAS_SYS (fscanf, int, (FILE *stream, const char *format, ...)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (fscanf); -# endif -#endif - - -/* Set up the following warnings, based on which modules are in use. - GNU Coding Standards discourage the use of fseek, since it imposes - an arbitrary limitation on some 32-bit hosts. Remember that the - fseek module depends on the fseeko module, so we only have three - cases to consider: - - 1. The developer is not using either module. Issue a warning under - GNULIB_POSIXCHECK for both functions, to remind them that both - functions have bugs on some systems. _GL_NO_LARGE_FILES has no - impact on this warning. - - 2. The developer is using both modules. They may be unaware of the - arbitrary limitations of fseek, so issue a warning under - GNULIB_POSIXCHECK. On the other hand, they may be using both - modules intentionally, so the developer can define - _GL_NO_LARGE_FILES in the compilation units where the use of fseek - is safe, to silence the warning. - - 3. The developer is using the fseeko module, but not fseek. Gnulib - guarantees that fseek will still work around platform bugs in that - case, but we presume that the developer is aware of the pitfalls of - fseek and was trying to avoid it, so issue a warning even when - GNULIB_POSIXCHECK is undefined. Again, _GL_NO_LARGE_FILES can be - defined to silence the warning in particular compilation units. - In C++ compilations with GNULIB_NAMESPACE, in order to avoid that - fseek gets defined as a macro, it is recommended that the developer - uses the fseek module, even if he is not calling the fseek function. - - Most gnulib clients that perform stream operations should fall into - category 3. */ - -#if 0 -# if defined GNULIB_POSIXCHECK && !defined _GL_NO_LARGE_FILES -# define _GL_FSEEK_WARN /* Category 2, above. */ -# undef fseek -# endif -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef fseek -# define fseek rpl_fseek -# endif -_GL_FUNCDECL_RPL (fseek, int, (FILE *fp, long offset, int whence) - _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (fseek, int, (FILE *fp, long offset, int whence)); -# else -_GL_CXXALIAS_SYS (fseek, int, (FILE *fp, long offset, int whence)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (fseek); -# endif -#endif - -#if 0 -# if !0 && !defined _GL_NO_LARGE_FILES -# define _GL_FSEEK_WARN /* Category 3, above. */ -# undef fseek -# endif -# if 0 -/* Provide an fseeko function that is aware of a preceding fflush(), and which - detects pipes. */ -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef fseeko -# define fseeko rpl_fseeko -# endif -_GL_FUNCDECL_RPL (fseeko, int, (FILE *fp, off_t offset, int whence) - _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (fseeko, int, (FILE *fp, off_t offset, int whence)); -# else -# if ! 1 -_GL_FUNCDECL_SYS (fseeko, int, (FILE *fp, off_t offset, int whence) - _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (fseeko, int, (FILE *fp, off_t offset, int whence)); -# endif -_GL_CXXALIASWARN (fseeko); -#elif defined GNULIB_POSIXCHECK -# define _GL_FSEEK_WARN /* Category 1, above. */ -# undef fseek -# undef fseeko -# if HAVE_RAW_DECL_FSEEKO -_GL_WARN_ON_USE (fseeko, "fseeko is unportable - " - "use gnulib module fseeko for portability"); -# endif -#endif - -#ifdef _GL_FSEEK_WARN -# undef _GL_FSEEK_WARN -/* Here, either fseek is undefined (but C89 guarantees that it is - declared), or it is defined as rpl_fseek (declared above). */ -_GL_WARN_ON_USE (fseek, "fseek cannot handle files larger than 4 GB " - "on 32-bit platforms - " - "use fseeko function for handling of large files"); -#endif - - -/* ftell, ftello. See the comments on fseek/fseeko. */ - -#if 0 -# if defined GNULIB_POSIXCHECK && !defined _GL_NO_LARGE_FILES -# define _GL_FTELL_WARN /* Category 2, above. */ -# undef ftell -# endif -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef ftell -# define ftell rpl_ftell -# endif -_GL_FUNCDECL_RPL (ftell, long, (FILE *fp) _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (ftell, long, (FILE *fp)); -# else -_GL_CXXALIAS_SYS (ftell, long, (FILE *fp)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (ftell); -# endif -#endif - -#if 0 -# if !0 && !defined _GL_NO_LARGE_FILES -# define _GL_FTELL_WARN /* Category 3, above. */ -# undef ftell -# endif -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef ftello -# define ftello rpl_ftello -# endif -_GL_FUNCDECL_RPL (ftello, off_t, (FILE *fp) _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (ftello, off_t, (FILE *fp)); -# else -# if ! 1 -_GL_FUNCDECL_SYS (ftello, off_t, (FILE *fp) _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (ftello, off_t, (FILE *fp)); -# endif -_GL_CXXALIASWARN (ftello); -#elif defined GNULIB_POSIXCHECK -# define _GL_FTELL_WARN /* Category 1, above. */ -# undef ftell -# undef ftello -# if HAVE_RAW_DECL_FTELLO -_GL_WARN_ON_USE (ftello, "ftello is unportable - " - "use gnulib module ftello for portability"); -# endif -#endif - -#ifdef _GL_FTELL_WARN -# undef _GL_FTELL_WARN -/* Here, either ftell is undefined (but C89 guarantees that it is - declared), or it is defined as rpl_ftell (declared above). */ -_GL_WARN_ON_USE (ftell, "ftell cannot handle files larger than 4 GB " - "on 32-bit platforms - " - "use ftello function for handling of large files"); -#endif - - -#if 1 -# if 0 && (0 || 0) -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef fwrite -# define fwrite rpl_fwrite -# endif -_GL_FUNCDECL_RPL (fwrite, size_t, - (const void *ptr, size_t s, size_t n, FILE *stream) - _GL_ARG_NONNULL ((1, 4))); -_GL_CXXALIAS_RPL (fwrite, size_t, - (const void *ptr, size_t s, size_t n, FILE *stream)); -# else -_GL_CXXALIAS_SYS (fwrite, size_t, - (const void *ptr, size_t s, size_t n, FILE *stream)); - -/* Work around bug 11959 when fortifying glibc 2.4 through 2.15 - , - which sometimes causes an unwanted diagnostic for fwrite calls. - This affects only function declaration attributes under certain - versions of gcc and clang, and is not needed for C++. */ -# if (0 < __USE_FORTIFY_LEVEL \ - && __GLIBC__ == 2 && 4 <= __GLIBC_MINOR__ && __GLIBC_MINOR__ <= 15 \ - && 3 < __GNUC__ + (4 <= __GNUC_MINOR__) \ - && !defined __cplusplus) -# undef fwrite -# undef fwrite_unlocked -extern size_t __REDIRECT (rpl_fwrite, - (const void *__restrict, size_t, size_t, - FILE *__restrict), - fwrite); -extern size_t __REDIRECT (rpl_fwrite_unlocked, - (const void *__restrict, size_t, size_t, - FILE *__restrict), - fwrite_unlocked); -# define fwrite rpl_fwrite -# define fwrite_unlocked rpl_fwrite_unlocked -# endif -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (fwrite); -# endif -#endif - -#if 1 -# if 0 && 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef getc -# define getc rpl_fgetc -# endif -_GL_FUNCDECL_RPL (fgetc, int, (FILE *stream) _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL_1 (getc, rpl_fgetc, int, (FILE *stream)); -# else -_GL_CXXALIAS_SYS (getc, int, (FILE *stream)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (getc); -# endif -#endif - -#if 1 -# if 0 && 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef getchar -# define getchar rpl_getchar -# endif -_GL_FUNCDECL_RPL (getchar, int, (void)); -_GL_CXXALIAS_RPL (getchar, int, (void)); -# else -_GL_CXXALIAS_SYS (getchar, int, (void)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (getchar); -# endif -#endif - -#if 0 -/* Read input, up to (and including) the next occurrence of DELIMITER, from - STREAM, store it in *LINEPTR (and NUL-terminate it). - *LINEPTR is a pointer returned from malloc (or NULL), pointing to *LINESIZE - bytes of space. It is realloc'd as necessary. - Return the number of bytes read and stored at *LINEPTR (not including the - NUL terminator), or -1 on error or EOF. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef getdelim -# define getdelim rpl_getdelim -# endif -_GL_FUNCDECL_RPL (getdelim, ssize_t, - (char **lineptr, size_t *linesize, int delimiter, - FILE *stream) - _GL_ARG_NONNULL ((1, 2, 4))); -_GL_CXXALIAS_RPL (getdelim, ssize_t, - (char **lineptr, size_t *linesize, int delimiter, - FILE *stream)); -# else -# if !1 -_GL_FUNCDECL_SYS (getdelim, ssize_t, - (char **lineptr, size_t *linesize, int delimiter, - FILE *stream) - _GL_ARG_NONNULL ((1, 2, 4))); -# endif -_GL_CXXALIAS_SYS (getdelim, ssize_t, - (char **lineptr, size_t *linesize, int delimiter, - FILE *stream)); -# endif -_GL_CXXALIASWARN (getdelim); -#elif defined GNULIB_POSIXCHECK -# undef getdelim -# if HAVE_RAW_DECL_GETDELIM -_GL_WARN_ON_USE (getdelim, "getdelim is unportable - " - "use gnulib module getdelim for portability"); -# endif -#endif - -#if 0 -/* Read a line, up to (and including) the next newline, from STREAM, store it - in *LINEPTR (and NUL-terminate it). - *LINEPTR is a pointer returned from malloc (or NULL), pointing to *LINESIZE - bytes of space. It is realloc'd as necessary. - Return the number of bytes read and stored at *LINEPTR (not including the - NUL terminator), or -1 on error or EOF. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef getline -# define getline rpl_getline -# endif -_GL_FUNCDECL_RPL (getline, ssize_t, - (char **lineptr, size_t *linesize, FILE *stream) - _GL_ARG_NONNULL ((1, 2, 3))); -_GL_CXXALIAS_RPL (getline, ssize_t, - (char **lineptr, size_t *linesize, FILE *stream)); -# else -# if !1 -_GL_FUNCDECL_SYS (getline, ssize_t, - (char **lineptr, size_t *linesize, FILE *stream) - _GL_ARG_NONNULL ((1, 2, 3))); -# endif -_GL_CXXALIAS_SYS (getline, ssize_t, - (char **lineptr, size_t *linesize, FILE *stream)); -# endif -# if 1 -_GL_CXXALIASWARN (getline); -# endif -#elif defined GNULIB_POSIXCHECK -# undef getline -# if HAVE_RAW_DECL_GETLINE -_GL_WARN_ON_USE (getline, "getline is unportable - " - "use gnulib module getline for portability"); -# endif -#endif - -/* It is very rare that the developer ever has full control of stdin, - so any use of gets warrants an unconditional warning; besides, C11 - removed it. */ -#undef gets -#if HAVE_RAW_DECL_GETS && !defined __cplusplus -_GL_WARN_ON_USE (gets, "gets is a security hole - use fgets instead"); -#endif - -#if 0 || 0 -struct obstack; -/* Grow an obstack with formatted output. Return the number of - bytes added to OBS. No trailing nul byte is added, and the - object should be closed with obstack_finish before use. Upon - memory allocation error, call obstack_alloc_failed_handler. Upon - other error, return -1. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define obstack_printf rpl_obstack_printf -# endif -_GL_FUNCDECL_RPL (obstack_printf, int, - (struct obstack *obs, const char *format, ...) - _GL_ATTRIBUTE_FORMAT_PRINTF (2, 3) - _GL_ARG_NONNULL ((1, 2))); -_GL_CXXALIAS_RPL (obstack_printf, int, - (struct obstack *obs, const char *format, ...)); -# else -# if !1 -_GL_FUNCDECL_SYS (obstack_printf, int, - (struct obstack *obs, const char *format, ...) - _GL_ATTRIBUTE_FORMAT_PRINTF (2, 3) - _GL_ARG_NONNULL ((1, 2))); -# endif -_GL_CXXALIAS_SYS (obstack_printf, int, - (struct obstack *obs, const char *format, ...)); -# endif -_GL_CXXALIASWARN (obstack_printf); -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define obstack_vprintf rpl_obstack_vprintf -# endif -_GL_FUNCDECL_RPL (obstack_vprintf, int, - (struct obstack *obs, const char *format, va_list args) - _GL_ATTRIBUTE_FORMAT_PRINTF (2, 0) - _GL_ARG_NONNULL ((1, 2))); -_GL_CXXALIAS_RPL (obstack_vprintf, int, - (struct obstack *obs, const char *format, va_list args)); -# else -# if !1 -_GL_FUNCDECL_SYS (obstack_vprintf, int, - (struct obstack *obs, const char *format, va_list args) - _GL_ATTRIBUTE_FORMAT_PRINTF (2, 0) - _GL_ARG_NONNULL ((1, 2))); -# endif -_GL_CXXALIAS_SYS (obstack_vprintf, int, - (struct obstack *obs, const char *format, va_list args)); -# endif -_GL_CXXALIASWARN (obstack_vprintf); -#endif - -#if 0 -# if !1 -_GL_FUNCDECL_SYS (pclose, int, (FILE *stream) _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (pclose, int, (FILE *stream)); -_GL_CXXALIASWARN (pclose); -#elif defined GNULIB_POSIXCHECK -# undef pclose -# if HAVE_RAW_DECL_PCLOSE -_GL_WARN_ON_USE (pclose, "pclose is unportable - " - "use gnulib module pclose for more portability"); -# endif -#endif - -#if 0 -/* Print a message to standard error, describing the value of ERRNO, - (if STRING is not NULL and not empty) prefixed with STRING and ": ", - and terminated with a newline. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define perror rpl_perror -# endif -_GL_FUNCDECL_RPL (perror, void, (const char *string)); -_GL_CXXALIAS_RPL (perror, void, (const char *string)); -# else -_GL_CXXALIAS_SYS (perror, void, (const char *string)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (perror); -# endif -#elif defined GNULIB_POSIXCHECK -# undef perror -/* Assume perror is always declared. */ -_GL_WARN_ON_USE (perror, "perror is not always POSIX compliant - " - "use gnulib module perror for portability"); -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef popen -# define popen rpl_popen -# endif -_GL_FUNCDECL_RPL (popen, FILE *, (const char *cmd, const char *mode) - _GL_ARG_NONNULL ((1, 2))); -_GL_CXXALIAS_RPL (popen, FILE *, (const char *cmd, const char *mode)); -# else -# if !1 -_GL_FUNCDECL_SYS (popen, FILE *, (const char *cmd, const char *mode) - _GL_ARG_NONNULL ((1, 2))); -# endif -_GL_CXXALIAS_SYS (popen, FILE *, (const char *cmd, const char *mode)); -# endif -_GL_CXXALIASWARN (popen); -#elif defined GNULIB_POSIXCHECK -# undef popen -# if HAVE_RAW_DECL_POPEN -_GL_WARN_ON_USE (popen, "popen is buggy on some platforms - " - "use gnulib module popen or pipe for more portability"); -# endif -#endif - -#if 0 || 1 -# if (0 && 0) \ - || (1 && 0 && (0 || 0)) -# if defined __GNUC__ -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -/* Don't break __attribute__((format(printf,M,N))). */ -# define printf __printf__ -# endif -# if 0 || 0 -_GL_FUNCDECL_RPL_1 (__printf__, int, - (const char *format, ...) - __asm__ ( - _GL_STDIO_MACROEXPAND_AND_STRINGIZE(rpl_printf)) - _GL_ATTRIBUTE_FORMAT_PRINTF (1, 2) - _GL_ARG_NONNULL ((1))); -# else -_GL_FUNCDECL_RPL_1 (__printf__, int, - (const char *format, ...) - __asm__ ( - _GL_STDIO_MACROEXPAND_AND_STRINGIZE(rpl_printf)) - _GL_ATTRIBUTE_FORMAT_PRINTF_SYSTEM (1, 2) - _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_RPL_1 (printf, __printf__, int, (const char *format, ...)); -# else -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define printf rpl_printf -# endif -_GL_FUNCDECL_RPL (printf, int, - (const char *format, ...) - _GL_ATTRIBUTE_FORMAT_PRINTF (1, 2) - _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (printf, int, (const char *format, ...)); -# endif -# define GNULIB_overrides_printf 1 -# else -_GL_CXXALIAS_SYS (printf, int, (const char *format, ...)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (printf); -# endif -#endif -#if !0 && defined GNULIB_POSIXCHECK -# if !GNULIB_overrides_printf -# undef printf -# endif -/* Assume printf is always declared. */ -_GL_WARN_ON_USE (printf, "printf is not always POSIX compliant - " - "use gnulib module printf-posix for portable " - "POSIX compliance"); -#endif - -#if 1 -# if 0 && (0 || 0) -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef putc -# define putc rpl_fputc -# endif -_GL_FUNCDECL_RPL (fputc, int, (int c, FILE *stream) _GL_ARG_NONNULL ((2))); -_GL_CXXALIAS_RPL_1 (putc, rpl_fputc, int, (int c, FILE *stream)); -# else -_GL_CXXALIAS_SYS (putc, int, (int c, FILE *stream)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (putc); -# endif -#endif - -#if 1 -# if 0 && (0 || 0) -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef putchar -# define putchar rpl_putchar -# endif -_GL_FUNCDECL_RPL (putchar, int, (int c)); -_GL_CXXALIAS_RPL (putchar, int, (int c)); -# else -_GL_CXXALIAS_SYS (putchar, int, (int c)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (putchar); -# endif -#endif - -#if 1 -# if 0 && (0 || 0) -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef puts -# define puts rpl_puts -# endif -_GL_FUNCDECL_RPL (puts, int, (const char *string) _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (puts, int, (const char *string)); -# else -_GL_CXXALIAS_SYS (puts, int, (const char *string)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (puts); -# endif -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef remove -# define remove rpl_remove -# endif -_GL_FUNCDECL_RPL (remove, int, (const char *name) _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (remove, int, (const char *name)); -# else -_GL_CXXALIAS_SYS (remove, int, (const char *name)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (remove); -# endif -#elif defined GNULIB_POSIXCHECK -# undef remove -/* Assume remove is always declared. */ -_GL_WARN_ON_USE (remove, "remove cannot handle directories on some platforms - " - "use gnulib module remove for more portability"); -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef rename -# define rename rpl_rename -# endif -_GL_FUNCDECL_RPL (rename, int, - (const char *old_filename, const char *new_filename) - _GL_ARG_NONNULL ((1, 2))); -_GL_CXXALIAS_RPL (rename, int, - (const char *old_filename, const char *new_filename)); -# else -_GL_CXXALIAS_SYS (rename, int, - (const char *old_filename, const char *new_filename)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (rename); -# endif -#elif defined GNULIB_POSIXCHECK -# undef rename -/* Assume rename is always declared. */ -_GL_WARN_ON_USE (rename, "rename is buggy on some platforms - " - "use gnulib module rename for more portability"); -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef renameat -# define renameat rpl_renameat -# endif -_GL_FUNCDECL_RPL (renameat, int, - (int fd1, char const *file1, int fd2, char const *file2) - _GL_ARG_NONNULL ((2, 4))); -_GL_CXXALIAS_RPL (renameat, int, - (int fd1, char const *file1, int fd2, char const *file2)); -# else -# if !1 -_GL_FUNCDECL_SYS (renameat, int, - (int fd1, char const *file1, int fd2, char const *file2) - _GL_ARG_NONNULL ((2, 4))); -# endif -_GL_CXXALIAS_SYS (renameat, int, - (int fd1, char const *file1, int fd2, char const *file2)); -# endif -_GL_CXXALIASWARN (renameat); -#elif defined GNULIB_POSIXCHECK -# undef renameat -# if HAVE_RAW_DECL_RENAMEAT -_GL_WARN_ON_USE (renameat, "renameat is not portable - " - "use gnulib module renameat for portability"); -# endif -#endif - -#if 1 -# if 0 && 0 -# if defined __GNUC__ -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef scanf -/* Don't break __attribute__((format(scanf,M,N))). */ -# define scanf __scanf__ -# endif -_GL_FUNCDECL_RPL_1 (__scanf__, int, - (const char *format, ...) - __asm__ ( - _GL_STDIO_MACROEXPAND_AND_STRINGIZE(rpl_scanf)) - _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (1, 2) - _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL_1 (scanf, __scanf__, int, (const char *format, ...)); -# else -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef scanf -# define scanf rpl_scanf -# endif -_GL_FUNCDECL_RPL (scanf, int, (const char *format, ...) - _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (1, 2) - _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (scanf, int, (const char *format, ...)); -# endif -# else -_GL_CXXALIAS_SYS (scanf, int, (const char *format, ...)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (scanf); -# endif -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define snprintf rpl_snprintf -# endif -_GL_FUNCDECL_RPL (snprintf, int, - (char *str, size_t size, const char *format, ...) - _GL_ATTRIBUTE_FORMAT_PRINTF (3, 4) - _GL_ARG_NONNULL ((3))); -_GL_CXXALIAS_RPL (snprintf, int, - (char *str, size_t size, const char *format, ...)); -# else -# if !1 -_GL_FUNCDECL_SYS (snprintf, int, - (char *str, size_t size, const char *format, ...) - _GL_ATTRIBUTE_FORMAT_PRINTF (3, 4) - _GL_ARG_NONNULL ((3))); -# endif -_GL_CXXALIAS_SYS (snprintf, int, - (char *str, size_t size, const char *format, ...)); -# endif -_GL_CXXALIASWARN (snprintf); -#elif defined GNULIB_POSIXCHECK -# undef snprintf -# if HAVE_RAW_DECL_SNPRINTF -_GL_WARN_ON_USE (snprintf, "snprintf is unportable - " - "use gnulib module snprintf for portability"); -# endif -#endif - -/* Some people would argue that all sprintf uses should be warned about - (for example, OpenBSD issues a link warning for it), - since it can cause security holes due to buffer overruns. - However, we believe that sprintf can be used safely, and is more - efficient than snprintf in those safe cases; and as proof of our - belief, we use sprintf in several gnulib modules. So this header - intentionally avoids adding a warning to sprintf except when - GNULIB_POSIXCHECK is defined. */ - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define sprintf rpl_sprintf -# endif -_GL_FUNCDECL_RPL (sprintf, int, (char *str, const char *format, ...) - _GL_ATTRIBUTE_FORMAT_PRINTF (2, 3) - _GL_ARG_NONNULL ((1, 2))); -_GL_CXXALIAS_RPL (sprintf, int, (char *str, const char *format, ...)); -# else -_GL_CXXALIAS_SYS (sprintf, int, (char *str, const char *format, ...)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (sprintf); -# endif -#elif defined GNULIB_POSIXCHECK -# undef sprintf -/* Assume sprintf is always declared. */ -_GL_WARN_ON_USE (sprintf, "sprintf is not always POSIX compliant - " - "use gnulib module sprintf-posix for portable " - "POSIX compliance"); -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define tmpfile rpl_tmpfile -# endif -_GL_FUNCDECL_RPL (tmpfile, FILE *, (void)); -_GL_CXXALIAS_RPL (tmpfile, FILE *, (void)); -# else -_GL_CXXALIAS_SYS (tmpfile, FILE *, (void)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (tmpfile); -# endif -#elif defined GNULIB_POSIXCHECK -# undef tmpfile -# if HAVE_RAW_DECL_TMPFILE -_GL_WARN_ON_USE (tmpfile, "tmpfile is not usable on mingw - " - "use gnulib module tmpfile for portability"); -# endif -#endif - -#if 0 -/* Write formatted output to a string dynamically allocated with malloc(). - If the memory allocation succeeds, store the address of the string in - *RESULT and return the number of resulting bytes, excluding the trailing - NUL. Upon memory allocation error, or some other error, return -1. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define asprintf rpl_asprintf -# endif -_GL_FUNCDECL_RPL (asprintf, int, - (char **result, const char *format, ...) - _GL_ATTRIBUTE_FORMAT_PRINTF (2, 3) - _GL_ARG_NONNULL ((1, 2))); -_GL_CXXALIAS_RPL (asprintf, int, - (char **result, const char *format, ...)); -# else -# if !1 -_GL_FUNCDECL_SYS (asprintf, int, - (char **result, const char *format, ...) - _GL_ATTRIBUTE_FORMAT_PRINTF (2, 3) - _GL_ARG_NONNULL ((1, 2))); -# endif -_GL_CXXALIAS_SYS (asprintf, int, - (char **result, const char *format, ...)); -# endif -_GL_CXXALIASWARN (asprintf); -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define vasprintf rpl_vasprintf -# endif -_GL_FUNCDECL_RPL (vasprintf, int, - (char **result, const char *format, va_list args) - _GL_ATTRIBUTE_FORMAT_PRINTF (2, 0) - _GL_ARG_NONNULL ((1, 2))); -_GL_CXXALIAS_RPL (vasprintf, int, - (char **result, const char *format, va_list args)); -# else -# if !1 -_GL_FUNCDECL_SYS (vasprintf, int, - (char **result, const char *format, va_list args) - _GL_ATTRIBUTE_FORMAT_PRINTF (2, 0) - _GL_ARG_NONNULL ((1, 2))); -# endif -_GL_CXXALIAS_SYS (vasprintf, int, - (char **result, const char *format, va_list args)); -# endif -_GL_CXXALIASWARN (vasprintf); -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define vdprintf rpl_vdprintf -# endif -_GL_FUNCDECL_RPL (vdprintf, int, (int fd, const char *format, va_list args) - _GL_ATTRIBUTE_FORMAT_PRINTF (2, 0) - _GL_ARG_NONNULL ((2))); -_GL_CXXALIAS_RPL (vdprintf, int, (int fd, const char *format, va_list args)); -# else -# if !1 -_GL_FUNCDECL_SYS (vdprintf, int, (int fd, const char *format, va_list args) - _GL_ATTRIBUTE_FORMAT_PRINTF (2, 0) - _GL_ARG_NONNULL ((2))); -# endif -/* Need to cast, because on Solaris, the third parameter will likely be - __va_list args. */ -_GL_CXXALIAS_SYS_CAST (vdprintf, int, - (int fd, const char *format, va_list args)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (vdprintf); -# endif -#elif defined GNULIB_POSIXCHECK -# undef vdprintf -# if HAVE_RAW_DECL_VDPRINTF -_GL_WARN_ON_USE (vdprintf, "vdprintf is unportable - " - "use gnulib module vdprintf for portability"); -# endif -#endif - -#if 0 || 1 -# if (0 && 0) \ - || (1 && 0 && (0 || 0)) -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define vfprintf rpl_vfprintf -# endif -# define GNULIB_overrides_vfprintf 1 -# if 0 -_GL_FUNCDECL_RPL (vfprintf, int, (FILE *fp, const char *format, va_list args) - _GL_ATTRIBUTE_FORMAT_PRINTF (2, 0) - _GL_ARG_NONNULL ((1, 2))); -# else -_GL_FUNCDECL_RPL (vfprintf, int, (FILE *fp, const char *format, va_list args) - _GL_ATTRIBUTE_FORMAT_PRINTF_SYSTEM (2, 0) - _GL_ARG_NONNULL ((1, 2))); -# endif -_GL_CXXALIAS_RPL (vfprintf, int, (FILE *fp, const char *format, va_list args)); -# else -/* Need to cast, because on Solaris, the third parameter is - __va_list args - and GCC's fixincludes did not change this to __gnuc_va_list. */ -_GL_CXXALIAS_SYS_CAST (vfprintf, int, - (FILE *fp, const char *format, va_list args)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (vfprintf); -# endif -#endif -#if !0 && defined GNULIB_POSIXCHECK -# if !GNULIB_overrides_vfprintf -# undef vfprintf -# endif -/* Assume vfprintf is always declared. */ -_GL_WARN_ON_USE (vfprintf, "vfprintf is not always POSIX compliant - " - "use gnulib module vfprintf-posix for portable " - "POSIX compliance"); -#endif - -#if 0 -# if 0 && 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef vfscanf -# define vfscanf rpl_vfscanf -# endif -_GL_FUNCDECL_RPL (vfscanf, int, - (FILE *stream, const char *format, va_list args) - _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (2, 0) - _GL_ARG_NONNULL ((1, 2))); -_GL_CXXALIAS_RPL (vfscanf, int, - (FILE *stream, const char *format, va_list args)); -# else -_GL_CXXALIAS_SYS (vfscanf, int, - (FILE *stream, const char *format, va_list args)); -# endif -_GL_CXXALIASWARN (vfscanf); -#endif - -#if 0 || 1 -# if (0 && 0) \ - || (1 && 0 && (0 || 0)) -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define vprintf rpl_vprintf -# endif -# define GNULIB_overrides_vprintf 1 -# if 0 || 0 -_GL_FUNCDECL_RPL (vprintf, int, (const char *format, va_list args) - _GL_ATTRIBUTE_FORMAT_PRINTF (1, 0) - _GL_ARG_NONNULL ((1))); -# else -_GL_FUNCDECL_RPL (vprintf, int, (const char *format, va_list args) - _GL_ATTRIBUTE_FORMAT_PRINTF_SYSTEM (1, 0) - _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_RPL (vprintf, int, (const char *format, va_list args)); -# else -/* Need to cast, because on Solaris, the second parameter is - __va_list args - and GCC's fixincludes did not change this to __gnuc_va_list. */ -_GL_CXXALIAS_SYS_CAST (vprintf, int, (const char *format, va_list args)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (vprintf); -# endif -#endif -#if !0 && defined GNULIB_POSIXCHECK -# if !GNULIB_overrides_vprintf -# undef vprintf -# endif -/* Assume vprintf is always declared. */ -_GL_WARN_ON_USE (vprintf, "vprintf is not always POSIX compliant - " - "use gnulib module vprintf-posix for portable " - "POSIX compliance"); -#endif - -#if 0 -# if 0 && 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef vscanf -# define vscanf rpl_vscanf -# endif -_GL_FUNCDECL_RPL (vscanf, int, (const char *format, va_list args) - _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (1, 0) - _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (vscanf, int, (const char *format, va_list args)); -# else -_GL_CXXALIAS_SYS (vscanf, int, (const char *format, va_list args)); -# endif -_GL_CXXALIASWARN (vscanf); -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define vsnprintf rpl_vsnprintf -# endif -_GL_FUNCDECL_RPL (vsnprintf, int, - (char *str, size_t size, const char *format, va_list args) - _GL_ATTRIBUTE_FORMAT_PRINTF (3, 0) - _GL_ARG_NONNULL ((3))); -_GL_CXXALIAS_RPL (vsnprintf, int, - (char *str, size_t size, const char *format, va_list args)); -# else -# if !1 -_GL_FUNCDECL_SYS (vsnprintf, int, - (char *str, size_t size, const char *format, va_list args) - _GL_ATTRIBUTE_FORMAT_PRINTF (3, 0) - _GL_ARG_NONNULL ((3))); -# endif -_GL_CXXALIAS_SYS (vsnprintf, int, - (char *str, size_t size, const char *format, va_list args)); -# endif -_GL_CXXALIASWARN (vsnprintf); -#elif defined GNULIB_POSIXCHECK -# undef vsnprintf -# if HAVE_RAW_DECL_VSNPRINTF -_GL_WARN_ON_USE (vsnprintf, "vsnprintf is unportable - " - "use gnulib module vsnprintf for portability"); -# endif -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define vsprintf rpl_vsprintf -# endif -_GL_FUNCDECL_RPL (vsprintf, int, - (char *str, const char *format, va_list args) - _GL_ATTRIBUTE_FORMAT_PRINTF (2, 0) - _GL_ARG_NONNULL ((1, 2))); -_GL_CXXALIAS_RPL (vsprintf, int, - (char *str, const char *format, va_list args)); -# else -/* Need to cast, because on Solaris, the third parameter is - __va_list args - and GCC's fixincludes did not change this to __gnuc_va_list. */ -_GL_CXXALIAS_SYS_CAST (vsprintf, int, - (char *str, const char *format, va_list args)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (vsprintf); -# endif -#elif defined GNULIB_POSIXCHECK -# undef vsprintf -/* Assume vsprintf is always declared. */ -_GL_WARN_ON_USE (vsprintf, "vsprintf is not always POSIX compliant - " - "use gnulib module vsprintf-posix for portable " - "POSIX compliance"); -#endif - -#endif /* _GL_STDIO_H */ -#endif /* _GL_STDIO_H */ -#endif diff --git a/third_party/make/stdlib.h b/third_party/make/stdlib.h deleted file mode 100644 index eb4eb77b8..000000000 --- a/third_party/make/stdlib.h +++ /dev/null @@ -1,1615 +0,0 @@ -/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ -/* A GNU-like . - - Copyright (C) 1995, 2001-2004, 2006-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -#if __GNUC__ >= 3 -#pragma GCC system_header -#endif - - -#if defined __need_system_stdlib_h || defined __need_malloc_and_calloc -/* Special invocation conventions inside some gnulib header files, - and inside some glibc header files, respectively. */ - - -#else -/* Normal invocation convention. */ - -#ifndef _GL_STDLIB_H - -/* The include_next requires a split double-inclusion guard. */ - -#ifndef _GL_STDLIB_H -#define _GL_STDLIB_H - -/* NetBSD 5.0 mis-defines NULL. */ - -/* MirBSD 10 defines WEXITSTATUS in , not in . */ -#if 0 && !defined WEXITSTATUS -#endif - -/* Solaris declares getloadavg() in . */ -#if (1 || defined GNULIB_POSIXCHECK) && 0 -/* OpenIndiana has a bug: must be included before - . */ -#endif - -/* Native Windows platforms declare mktemp() in . */ -#if 0 && (defined _WIN32 && ! defined __CYGWIN__) -#endif - -#if 0 - -/* OSF/1 5.1 declares 'struct random_data' in , which is included - from if _REENTRANT is defined. Include it whenever we need - 'struct random_data'. */ -# if 1 -# endif - -# if !1 || 0 || !1 -# endif - -# if !1 -/* Define 'struct random_data'. - But allow multiple gnulib generated replacements to coexist. */ -# if !GNULIB_defined_struct_random_data -struct random_data -{ - int32_t *fptr; /* Front pointer. */ - int32_t *rptr; /* Rear pointer. */ - int32_t *state; /* Array of state values. */ - int rand_type; /* Type of random number generator. */ - int rand_deg; /* Degree of random number generator. */ - int rand_sep; /* Distance between front and rear. */ - int32_t *end_ptr; /* Pointer behind state table. */ -}; -# define GNULIB_defined_struct_random_data 1 -# endif -# endif -#endif - -#if (0 || 0 || 0 || 0 || 0 || defined GNULIB_POSIXCHECK) && ! defined __GLIBC__ && !(defined _WIN32 && ! defined __CYGWIN__) -/* On Mac OS X 10.3, only declares mkstemp. */ -/* On Mac OS X 10.5, only declares mkstemps. */ -/* On Mac OS X 10.13, only declares mkostemp and mkostemps. */ -/* On Cygwin 1.7.1, only declares getsubopt. */ -/* But avoid namespace pollution on glibc systems and native Windows. */ -#endif - -/* The __attribute__ feature is available in gcc versions 2.5 and later. - The attribute __pure__ was added in gcc 2.96. */ -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) -# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__)) -#else -# define _GL_ATTRIBUTE_PURE /* empty */ -#endif - -/* The definition of _Noreturn is copied here. */ -/* A C macro for declaring that a function does not return. - Copyright (C) 2011-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -#ifndef _Noreturn -# if (defined __cplusplus \ - && ((201103 <= __cplusplus && !(__GNUC__ == 4 && __GNUC_MINOR__ == 7)) \ - || (defined _MSC_VER && 1900 <= _MSC_VER)) \ - && 0) - /* [[noreturn]] is not practically usable, because with it the syntax - extern _Noreturn void func (...); - would not be valid; such a declaration would only be valid with 'extern' - and '_Noreturn' swapped, or without the 'extern' keyword. However, some - AIX system header files and several gnulib header files use precisely - this syntax with 'extern'. */ -# define _Noreturn [[noreturn]] -# elif ((!defined __cplusplus || defined __clang__) \ - && (201112 <= (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) \ - || 4 < __GNUC__ + (7 <= __GNUC_MINOR__))) - /* _Noreturn works as-is. */ -# elif 2 < __GNUC__ + (8 <= __GNUC_MINOR__) || 0x5110 <= __SUNPRO_C -# define _Noreturn __attribute__ ((__noreturn__)) -# elif 1200 <= (defined _MSC_VER ? _MSC_VER : 0) -# define _Noreturn __declspec (noreturn) -# else -# define _Noreturn -# endif -#endif - -/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ -/* C++ compatible function declaration macros. - Copyright (C) 2010-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -#ifndef _GL_CXXDEFS_H -#define _GL_CXXDEFS_H - -/* Begin/end the GNULIB_NAMESPACE namespace. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -# define _GL_BEGIN_NAMESPACE namespace GNULIB_NAMESPACE { -# define _GL_END_NAMESPACE } -#else -# define _GL_BEGIN_NAMESPACE -# define _GL_END_NAMESPACE -#endif - -/* The three most frequent use cases of these macros are: - - * For providing a substitute for a function that is missing on some - platforms, but is declared and works fine on the platforms on which - it exists: - - #if @GNULIB_FOO@ - # if !@HAVE_FOO@ - _GL_FUNCDECL_SYS (foo, ...); - # endif - _GL_CXXALIAS_SYS (foo, ...); - _GL_CXXALIASWARN (foo); - #elif defined GNULIB_POSIXCHECK - ... - #endif - - * For providing a replacement for a function that exists on all platforms, - but is broken/insufficient and needs to be replaced on some platforms: - - #if @GNULIB_FOO@ - # if @REPLACE_FOO@ - # if !(defined __cplusplus && defined GNULIB_NAMESPACE) - # undef foo - # define foo rpl_foo - # endif - _GL_FUNCDECL_RPL (foo, ...); - _GL_CXXALIAS_RPL (foo, ...); - # else - _GL_CXXALIAS_SYS (foo, ...); - # endif - _GL_CXXALIASWARN (foo); - #elif defined GNULIB_POSIXCHECK - ... - #endif - - * For providing a replacement for a function that exists on some platforms - but is broken/insufficient and needs to be replaced on some of them and - is additionally either missing or undeclared on some other platforms: - - #if @GNULIB_FOO@ - # if @REPLACE_FOO@ - # if !(defined __cplusplus && defined GNULIB_NAMESPACE) - # undef foo - # define foo rpl_foo - # endif - _GL_FUNCDECL_RPL (foo, ...); - _GL_CXXALIAS_RPL (foo, ...); - # else - # if !@HAVE_FOO@ or if !@HAVE_DECL_FOO@ - _GL_FUNCDECL_SYS (foo, ...); - # endif - _GL_CXXALIAS_SYS (foo, ...); - # endif - _GL_CXXALIASWARN (foo); - #elif defined GNULIB_POSIXCHECK - ... - #endif -*/ - -/* _GL_EXTERN_C declaration; - performs the declaration with C linkage. */ -#if defined __cplusplus -# define _GL_EXTERN_C extern "C" -#else -# define _GL_EXTERN_C extern -#endif - -/* _GL_FUNCDECL_RPL (func, rettype, parameters_and_attributes); - declares a replacement function, named rpl_func, with the given prototype, - consisting of return type, parameters, and attributes. - Example: - _GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...) - _GL_ARG_NONNULL ((1))); - */ -#define _GL_FUNCDECL_RPL(func,rettype,parameters_and_attributes) \ - _GL_FUNCDECL_RPL_1 (rpl_##func, rettype, parameters_and_attributes) -#define _GL_FUNCDECL_RPL_1(rpl_func,rettype,parameters_and_attributes) \ - _GL_EXTERN_C rettype rpl_func parameters_and_attributes - -/* _GL_FUNCDECL_SYS (func, rettype, parameters_and_attributes); - declares the system function, named func, with the given prototype, - consisting of return type, parameters, and attributes. - Example: - _GL_FUNCDECL_SYS (open, int, (const char *filename, int flags, ...) - _GL_ARG_NONNULL ((1))); - */ -#define _GL_FUNCDECL_SYS(func,rettype,parameters_and_attributes) \ - _GL_EXTERN_C rettype func parameters_and_attributes - -/* _GL_CXXALIAS_RPL (func, rettype, parameters); - declares a C++ alias called GNULIB_NAMESPACE::func - that redirects to rpl_func, if GNULIB_NAMESPACE is defined. - Example: - _GL_CXXALIAS_RPL (open, int, (const char *filename, int flags, ...)); - - Wrapping rpl_func in an object with an inline conversion operator - avoids a reference to rpl_func unless GNULIB_NAMESPACE::func is - actually used in the program. */ -#define _GL_CXXALIAS_RPL(func,rettype,parameters) \ - _GL_CXXALIAS_RPL_1 (func, rpl_##func, rettype, parameters) -#if defined __cplusplus && defined GNULIB_NAMESPACE -# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \ - namespace GNULIB_NAMESPACE \ - { \ - static const struct _gl_ ## func ## _wrapper \ - { \ - typedef rettype (*type) parameters; \ - \ - inline operator type () const \ - { \ - return ::rpl_func; \ - } \ - } func = {}; \ - } \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#else -# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIAS_RPL_CAST_1 (func, rpl_func, rettype, parameters); - is like _GL_CXXALIAS_RPL_1 (func, rpl_func, rettype, parameters); - except that the C function rpl_func may have a slightly different - declaration. A cast is used to silence the "invalid conversion" error - that would otherwise occur. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -# define _GL_CXXALIAS_RPL_CAST_1(func,rpl_func,rettype,parameters) \ - namespace GNULIB_NAMESPACE \ - { \ - static const struct _gl_ ## func ## _wrapper \ - { \ - typedef rettype (*type) parameters; \ - \ - inline operator type () const \ - { \ - return reinterpret_cast(::rpl_func); \ - } \ - } func = {}; \ - } \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#else -# define _GL_CXXALIAS_RPL_CAST_1(func,rpl_func,rettype,parameters) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIAS_SYS (func, rettype, parameters); - declares a C++ alias called GNULIB_NAMESPACE::func - that redirects to the system provided function func, if GNULIB_NAMESPACE - is defined. - Example: - _GL_CXXALIAS_SYS (open, int, (const char *filename, int flags, ...)); - - Wrapping func in an object with an inline conversion operator - avoids a reference to func unless GNULIB_NAMESPACE::func is - actually used in the program. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -# define _GL_CXXALIAS_SYS(func,rettype,parameters) \ - namespace GNULIB_NAMESPACE \ - { \ - static const struct _gl_ ## func ## _wrapper \ - { \ - typedef rettype (*type) parameters; \ - \ - inline operator type () const \ - { \ - return ::func; \ - } \ - } func = {}; \ - } \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#else -# define _GL_CXXALIAS_SYS(func,rettype,parameters) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIAS_SYS_CAST (func, rettype, parameters); - is like _GL_CXXALIAS_SYS (func, rettype, parameters); - except that the C function func may have a slightly different declaration. - A cast is used to silence the "invalid conversion" error that would - otherwise occur. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -# define _GL_CXXALIAS_SYS_CAST(func,rettype,parameters) \ - namespace GNULIB_NAMESPACE \ - { \ - static const struct _gl_ ## func ## _wrapper \ - { \ - typedef rettype (*type) parameters; \ - \ - inline operator type () const \ - { \ - return reinterpret_cast(::func); \ - } \ - } func = {}; \ - } \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#else -# define _GL_CXXALIAS_SYS_CAST(func,rettype,parameters) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIAS_SYS_CAST2 (func, rettype, parameters, rettype2, parameters2); - is like _GL_CXXALIAS_SYS (func, rettype, parameters); - except that the C function is picked among a set of overloaded functions, - namely the one with rettype2 and parameters2. Two consecutive casts - are used to silence the "cannot find a match" and "invalid conversion" - errors that would otherwise occur. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE - /* The outer cast must be a reinterpret_cast. - The inner cast: When the function is defined as a set of overloaded - functions, it works as a static_cast<>, choosing the designated variant. - When the function is defined as a single variant, it works as a - reinterpret_cast<>. The parenthesized cast syntax works both ways. */ -# define _GL_CXXALIAS_SYS_CAST2(func,rettype,parameters,rettype2,parameters2) \ - namespace GNULIB_NAMESPACE \ - { \ - static const struct _gl_ ## func ## _wrapper \ - { \ - typedef rettype (*type) parameters; \ - \ - inline operator type () const \ - { \ - return reinterpret_cast((rettype2 (*) parameters2)(::func)); \ - } \ - } func = {}; \ - } \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#else -# define _GL_CXXALIAS_SYS_CAST2(func,rettype,parameters,rettype2,parameters2) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIASWARN (func); - causes a warning to be emitted when ::func is used but not when - GNULIB_NAMESPACE::func is used. func must be defined without overloaded - variants. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -# define _GL_CXXALIASWARN(func) \ - _GL_CXXALIASWARN_1 (func, GNULIB_NAMESPACE) -# define _GL_CXXALIASWARN_1(func,namespace) \ - _GL_CXXALIASWARN_2 (func, namespace) -/* To work around GCC bug , - we enable the warning only when not optimizing. */ -# if !__OPTIMIZE__ -# define _GL_CXXALIASWARN_2(func,namespace) \ - _GL_WARN_ON_USE (func, \ - "The symbol ::" #func " refers to the system function. " \ - "Use " #namespace "::" #func " instead.") -# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING -# define _GL_CXXALIASWARN_2(func,namespace) \ - extern __typeof__ (func) func -# else -# define _GL_CXXALIASWARN_2(func,namespace) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -# endif -#else -# define _GL_CXXALIASWARN(func) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIASWARN1 (func, rettype, parameters_and_attributes); - causes a warning to be emitted when the given overloaded variant of ::func - is used but not when GNULIB_NAMESPACE::func is used. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -# define _GL_CXXALIASWARN1(func,rettype,parameters_and_attributes) \ - _GL_CXXALIASWARN1_1 (func, rettype, parameters_and_attributes, \ - GNULIB_NAMESPACE) -# define _GL_CXXALIASWARN1_1(func,rettype,parameters_and_attributes,namespace) \ - _GL_CXXALIASWARN1_2 (func, rettype, parameters_and_attributes, namespace) -/* To work around GCC bug , - we enable the warning only when not optimizing. */ -# if !__OPTIMIZE__ -# define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \ - _GL_WARN_ON_USE_CXX (func, rettype, parameters_and_attributes, \ - "The symbol ::" #func " refers to the system function. " \ - "Use " #namespace "::" #func " instead.") -# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING -# define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \ - extern __typeof__ (func) func -# else -# define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -# endif -#else -# define _GL_CXXALIASWARN1(func,rettype,parameters_and_attributes) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -#endif /* _GL_CXXDEFS_H */ - -/* The definition of _GL_ARG_NONNULL is copied here. */ -/* A C macro for declaring that specific arguments must not be NULL. - Copyright (C) 2009-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -/* _GL_ARG_NONNULL((n,...,m)) tells the compiler and static analyzer tools - that the values passed as arguments n, ..., m must be non-NULL pointers. - n = 1 stands for the first argument, n = 2 for the second argument etc. */ -#ifndef _GL_ARG_NONNULL -# if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || __GNUC__ > 3 -# define _GL_ARG_NONNULL(params) __attribute__ ((__nonnull__ params)) -# else -# define _GL_ARG_NONNULL(params) -# endif -#endif - -/* The definition of _GL_WARN_ON_USE is copied here. */ -/* A C macro for emitting warnings if a function is used. - Copyright (C) 2010-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -/* _GL_WARN_ON_USE (function, "literal string") issues a declaration - for FUNCTION which will then trigger a compiler warning containing - the text of "literal string" anywhere that function is called, if - supported by the compiler. If the compiler does not support this - feature, the macro expands to an unused extern declaration. - - _GL_WARN_ON_USE_ATTRIBUTE ("literal string") expands to the - attribute used in _GL_WARN_ON_USE. If the compiler does not support - this feature, it expands to empty. - - These macros are useful for marking a function as a potential - portability trap, with the intent that "literal string" include - instructions on the replacement function that should be used - instead. - _GL_WARN_ON_USE is for functions with 'extern' linkage. - _GL_WARN_ON_USE_ATTRIBUTE is for functions with 'static' or 'inline' - linkage. - - However, one of the reasons that a function is a portability trap is - if it has the wrong signature. Declaring FUNCTION with a different - signature in C is a compilation error, so this macro must use the - same type as any existing declaration so that programs that avoid - the problematic FUNCTION do not fail to compile merely because they - included a header that poisoned the function. But this implies that - _GL_WARN_ON_USE is only safe to use if FUNCTION is known to already - have a declaration. Use of this macro implies that there must not - be any other macro hiding the declaration of FUNCTION; but - undefining FUNCTION first is part of the poisoning process anyway - (although for symbols that are provided only via a macro, the result - is a compilation error rather than a warning containing - "literal string"). Also note that in C++, it is only safe to use if - FUNCTION has no overloads. - - For an example, it is possible to poison 'getline' by: - [getline]) in configure.ac, which potentially defines - HAVE_RAW_DECL_GETLINE - - adding this code to a header that wraps the system : - #undef getline - #if HAVE_RAW_DECL_GETLINE - _GL_WARN_ON_USE (getline, "getline is required by POSIX 2008, but" - "not universally present; use the gnulib module getline"); - #endif - - It is not possible to directly poison global variables. But it is - possible to write a wrapper accessor function, and poison that - (less common usage, like &environ, will cause a compilation error - rather than issue the nice warning, but the end result of informing - the developer about their portability problem is still achieved): - #if HAVE_RAW_DECL_ENVIRON - static char *** - rpl_environ (void) { return &environ; } - _GL_WARN_ON_USE (rpl_environ, "environ is not always properly declared"); - # undef environ - # define environ (*rpl_environ ()) - #endif - or better (avoiding contradictory use of 'static' and 'extern'): - #if HAVE_RAW_DECL_ENVIRON - static char *** - _GL_WARN_ON_USE_ATTRIBUTE ("environ is not always properly declared") - rpl_environ (void) { return &environ; } - # undef environ - # define environ (*rpl_environ ()) - #endif - */ -#ifndef _GL_WARN_ON_USE - -# if 4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) -/* A compiler attribute is available in gcc versions 4.3.0 and later. */ -# define _GL_WARN_ON_USE(function, message) \ -extern __typeof__ (function) function __attribute__ ((__warning__ (message))) -# define _GL_WARN_ON_USE_ATTRIBUTE(message) \ - __attribute__ ((__warning__ (message))) -# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING -/* Verify the existence of the function. */ -# define _GL_WARN_ON_USE(function, message) \ -extern __typeof__ (function) function -# define _GL_WARN_ON_USE_ATTRIBUTE(message) -# else /* Unsupported. */ -# define _GL_WARN_ON_USE(function, message) \ -_GL_WARN_EXTERN_C int _gl_warn_on_use -# define _GL_WARN_ON_USE_ATTRIBUTE(message) -# endif -#endif - -/* _GL_WARN_ON_USE_CXX (function, rettype, parameters_and_attributes, "string") - is like _GL_WARN_ON_USE (function, "string"), except that the function is - declared with the given prototype, consisting of return type, parameters, - and attributes. - This variant is useful for overloaded functions in C++. _GL_WARN_ON_USE does - not work in this case. */ -#ifndef _GL_WARN_ON_USE_CXX -# if 4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) -# define _GL_WARN_ON_USE_CXX(function,rettype,parameters_and_attributes,msg) \ -extern rettype function parameters_and_attributes \ - __attribute__ ((__warning__ (msg))) -# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING -/* Verify the existence of the function. */ -# define _GL_WARN_ON_USE_CXX(function,rettype,parameters_and_attributes,msg) \ -extern rettype function parameters_and_attributes -# else /* Unsupported. */ -# define _GL_WARN_ON_USE_CXX(function,rettype,parameters_and_attributes,msg) \ -_GL_WARN_EXTERN_C int _gl_warn_on_use -# endif -#endif - -/* _GL_WARN_EXTERN_C declaration; - performs the declaration with C linkage. */ -#ifndef _GL_WARN_EXTERN_C -# if defined __cplusplus -# define _GL_WARN_EXTERN_C extern "C" -# else -# define _GL_WARN_EXTERN_C extern -# endif -#endif - - -/* Some systems do not define EXIT_*, despite otherwise supporting C89. */ -#ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 -#endif -/* Tandem/NSK and other platforms that define EXIT_FAILURE as -1 interfere - with proper operation of xargs. */ -#ifndef EXIT_FAILURE -# define EXIT_FAILURE 1 -#elif EXIT_FAILURE != 1 -# undef EXIT_FAILURE -# define EXIT_FAILURE 1 -#endif - - -#if 0 -/* Terminate the current process with the given return code, without running - the 'atexit' handlers. */ -# if !1 -_GL_FUNCDECL_SYS (_Exit, _Noreturn void, (int status)); -# endif -_GL_CXXALIAS_SYS (_Exit, void, (int status)); -_GL_CXXALIASWARN (_Exit); -#elif defined GNULIB_POSIXCHECK -# undef _Exit -# if HAVE_RAW_DECL__EXIT -_GL_WARN_ON_USE (_Exit, "_Exit is unportable - " - "use gnulib module _Exit for portability"); -# endif -#endif - - -#if 0 -/* Parse a signed decimal integer. - Returns the value of the integer. Errors are not detected. */ -# if !1 -_GL_FUNCDECL_SYS (atoll, long long, (const char *string) - _GL_ATTRIBUTE_PURE - _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (atoll, long long, (const char *string)); -_GL_CXXALIASWARN (atoll); -#elif defined GNULIB_POSIXCHECK -# undef atoll -# if HAVE_RAW_DECL_ATOLL -_GL_WARN_ON_USE (atoll, "atoll is unportable - " - "use gnulib module atoll for portability"); -# endif -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef calloc -# define calloc rpl_calloc -# endif -_GL_FUNCDECL_RPL (calloc, void *, (size_t nmemb, size_t size)); -_GL_CXXALIAS_RPL (calloc, void *, (size_t nmemb, size_t size)); -# else -_GL_CXXALIAS_SYS (calloc, void *, (size_t nmemb, size_t size)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (calloc); -# endif -#elif defined GNULIB_POSIXCHECK -# undef calloc -/* Assume calloc is always declared. */ -_GL_WARN_ON_USE (calloc, "calloc is not POSIX compliant everywhere - " - "use gnulib module calloc-posix for portability"); -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define canonicalize_file_name rpl_canonicalize_file_name -# endif -_GL_FUNCDECL_RPL (canonicalize_file_name, char *, (const char *name) - _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (canonicalize_file_name, char *, (const char *name)); -# else -# if !1 -_GL_FUNCDECL_SYS (canonicalize_file_name, char *, (const char *name) - _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (canonicalize_file_name, char *, (const char *name)); -# endif -_GL_CXXALIASWARN (canonicalize_file_name); -#elif defined GNULIB_POSIXCHECK -# undef canonicalize_file_name -# if HAVE_RAW_DECL_CANONICALIZE_FILE_NAME -_GL_WARN_ON_USE (canonicalize_file_name, - "canonicalize_file_name is unportable - " - "use gnulib module canonicalize-lgpl for portability"); -# endif -#endif - -#if 1 -/* Store max(NELEM,3) load average numbers in LOADAVG[]. - The three numbers are the load average of the last 1 minute, the last 5 - minutes, and the last 15 minutes, respectively. - LOADAVG is an array of NELEM numbers. */ -# if !0 -_GL_FUNCDECL_SYS (getloadavg, int, (double loadavg[], int nelem) - _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (getloadavg, int, (double loadavg[], int nelem)); -_GL_CXXALIASWARN (getloadavg); -#elif defined GNULIB_POSIXCHECK -# undef getloadavg -# if HAVE_RAW_DECL_GETLOADAVG -_GL_WARN_ON_USE (getloadavg, "getloadavg is not portable - " - "use gnulib module getloadavg for portability"); -# endif -#endif - -#if 0 -/* Assuming *OPTIONP is a comma separated list of elements of the form - "token" or "token=value", getsubopt parses the first of these elements. - If the first element refers to a "token" that is member of the given - NULL-terminated array of tokens: - - It replaces the comma with a NUL byte, updates *OPTIONP to point past - the first option and the comma, sets *VALUEP to the value of the - element (or NULL if it doesn't contain an "=" sign), - - It returns the index of the "token" in the given array of tokens. - Otherwise it returns -1, and *OPTIONP and *VALUEP are undefined. - For more details see the POSIX specification. - https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsubopt.html */ -# if !1 -_GL_FUNCDECL_SYS (getsubopt, int, - (char **optionp, char *const *tokens, char **valuep) - _GL_ARG_NONNULL ((1, 2, 3))); -# endif -_GL_CXXALIAS_SYS (getsubopt, int, - (char **optionp, char *const *tokens, char **valuep)); -_GL_CXXALIASWARN (getsubopt); -#elif defined GNULIB_POSIXCHECK -# undef getsubopt -# if HAVE_RAW_DECL_GETSUBOPT -_GL_WARN_ON_USE (getsubopt, "getsubopt is unportable - " - "use gnulib module getsubopt for portability"); -# endif -#endif - -#if 0 -/* Change the ownership and access permission of the slave side of the - pseudo-terminal whose master side is specified by FD. */ -# if !1 -_GL_FUNCDECL_SYS (grantpt, int, (int fd)); -# endif -_GL_CXXALIAS_SYS (grantpt, int, (int fd)); -_GL_CXXALIASWARN (grantpt); -#elif defined GNULIB_POSIXCHECK -# undef grantpt -# if HAVE_RAW_DECL_GRANTPT -_GL_WARN_ON_USE (grantpt, "grantpt is not portable - " - "use gnulib module grantpt for portability"); -# endif -#endif - -/* If _GL_USE_STDLIB_ALLOC is nonzero, the including module does not - rely on GNU or POSIX semantics for malloc and realloc (for example, - by never specifying a zero size), so it does not need malloc or - realloc to be redefined. */ -#if 1 -# if 0 -# if !((defined __cplusplus && defined GNULIB_NAMESPACE) \ - || _GL_USE_STDLIB_ALLOC) -# undef malloc -# define malloc rpl_malloc -# endif -_GL_FUNCDECL_RPL (malloc, void *, (size_t size)); -_GL_CXXALIAS_RPL (malloc, void *, (size_t size)); -# else -_GL_CXXALIAS_SYS (malloc, void *, (size_t size)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (malloc); -# endif -#elif defined GNULIB_POSIXCHECK && !_GL_USE_STDLIB_ALLOC -# undef malloc -/* Assume malloc is always declared. */ -_GL_WARN_ON_USE (malloc, "malloc is not POSIX compliant everywhere - " - "use gnulib module malloc-posix for portability"); -#endif - -/* Convert a multibyte character to a wide character. */ -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef mbtowc -# define mbtowc rpl_mbtowc -# endif -_GL_FUNCDECL_RPL (mbtowc, int, (wchar_t *pwc, const char *s, size_t n)); -_GL_CXXALIAS_RPL (mbtowc, int, (wchar_t *pwc, const char *s, size_t n)); -# else -# if !1 -_GL_FUNCDECL_SYS (mbtowc, int, (wchar_t *pwc, const char *s, size_t n)); -# endif -_GL_CXXALIAS_SYS (mbtowc, int, (wchar_t *pwc, const char *s, size_t n)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (mbtowc); -# endif -#elif defined GNULIB_POSIXCHECK -# undef mbtowc -# if HAVE_RAW_DECL_MBTOWC -_GL_WARN_ON_USE (mbtowc, "mbtowc is not portable - " - "use gnulib module mbtowc for portability"); -# endif -#endif - -#if 0 -/* Create a unique temporary directory from TEMPLATE. - The last six characters of TEMPLATE must be "XXXXXX"; - they are replaced with a string that makes the directory name unique. - Returns TEMPLATE, or a null pointer if it cannot get a unique name. - The directory is created mode 700. */ -# if !1 -_GL_FUNCDECL_SYS (mkdtemp, char *, (char * /*template*/) _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (mkdtemp, char *, (char * /*template*/)); -_GL_CXXALIASWARN (mkdtemp); -#elif defined GNULIB_POSIXCHECK -# undef mkdtemp -# if HAVE_RAW_DECL_MKDTEMP -_GL_WARN_ON_USE (mkdtemp, "mkdtemp is unportable - " - "use gnulib module mkdtemp for portability"); -# endif -#endif - -#if 0 -/* Create a unique temporary file from TEMPLATE. - The last six characters of TEMPLATE must be "XXXXXX"; - they are replaced with a string that makes the file name unique. - The flags are a bitmask, possibly including O_CLOEXEC (defined in ) - and O_TEXT, O_BINARY (defined in "binary-io.h"). - The file is then created, with the specified flags, ensuring it didn't exist - before. - The file is created read-write (mask at least 0600 & ~umask), but it may be - world-readable and world-writable (mask 0666 & ~umask), depending on the - implementation. - Returns the open file descriptor if successful, otherwise -1 and errno - set. */ -# if !1 -_GL_FUNCDECL_SYS (mkostemp, int, (char * /*template*/, int /*flags*/) - _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (mkostemp, int, (char * /*template*/, int /*flags*/)); -_GL_CXXALIASWARN (mkostemp); -#elif defined GNULIB_POSIXCHECK -# undef mkostemp -# if HAVE_RAW_DECL_MKOSTEMP -_GL_WARN_ON_USE (mkostemp, "mkostemp is unportable - " - "use gnulib module mkostemp for portability"); -# endif -#endif - -#if 0 -/* Create a unique temporary file from TEMPLATE. - The last six characters of TEMPLATE before a suffix of length - SUFFIXLEN must be "XXXXXX"; - they are replaced with a string that makes the file name unique. - The flags are a bitmask, possibly including O_CLOEXEC (defined in ) - and O_TEXT, O_BINARY (defined in "binary-io.h"). - The file is then created, with the specified flags, ensuring it didn't exist - before. - The file is created read-write (mask at least 0600 & ~umask), but it may be - world-readable and world-writable (mask 0666 & ~umask), depending on the - implementation. - Returns the open file descriptor if successful, otherwise -1 and errno - set. */ -# if !1 -_GL_FUNCDECL_SYS (mkostemps, int, - (char * /*template*/, int /*suffixlen*/, int /*flags*/) - _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (mkostemps, int, - (char * /*template*/, int /*suffixlen*/, int /*flags*/)); -_GL_CXXALIASWARN (mkostemps); -#elif defined GNULIB_POSIXCHECK -# undef mkostemps -# if HAVE_RAW_DECL_MKOSTEMPS -_GL_WARN_ON_USE (mkostemps, "mkostemps is unportable - " - "use gnulib module mkostemps for portability"); -# endif -#endif - -#if 0 -/* Create a unique temporary file from TEMPLATE. - The last six characters of TEMPLATE must be "XXXXXX"; - they are replaced with a string that makes the file name unique. - The file is then created, ensuring it didn't exist before. - The file is created read-write (mask at least 0600 & ~umask), but it may be - world-readable and world-writable (mask 0666 & ~umask), depending on the - implementation. - Returns the open file descriptor if successful, otherwise -1 and errno - set. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define mkstemp rpl_mkstemp -# endif -_GL_FUNCDECL_RPL (mkstemp, int, (char * /*template*/) _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (mkstemp, int, (char * /*template*/)); -# else -# if ! 1 -_GL_FUNCDECL_SYS (mkstemp, int, (char * /*template*/) _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (mkstemp, int, (char * /*template*/)); -# endif -_GL_CXXALIASWARN (mkstemp); -#elif defined GNULIB_POSIXCHECK -# undef mkstemp -# if HAVE_RAW_DECL_MKSTEMP -_GL_WARN_ON_USE (mkstemp, "mkstemp is unportable - " - "use gnulib module mkstemp for portability"); -# endif -#endif - -#if 0 -/* Create a unique temporary file from TEMPLATE. - The last six characters of TEMPLATE prior to a suffix of length - SUFFIXLEN must be "XXXXXX"; - they are replaced with a string that makes the file name unique. - The file is then created, ensuring it didn't exist before. - The file is created read-write (mask at least 0600 & ~umask), but it may be - world-readable and world-writable (mask 0666 & ~umask), depending on the - implementation. - Returns the open file descriptor if successful, otherwise -1 and errno - set. */ -# if !1 -_GL_FUNCDECL_SYS (mkstemps, int, (char * /*template*/, int /*suffixlen*/) - _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (mkstemps, int, (char * /*template*/, int /*suffixlen*/)); -_GL_CXXALIASWARN (mkstemps); -#elif defined GNULIB_POSIXCHECK -# undef mkstemps -# if HAVE_RAW_DECL_MKSTEMPS -_GL_WARN_ON_USE (mkstemps, "mkstemps is unportable - " - "use gnulib module mkstemps for portability"); -# endif -#endif - -#if 0 -/* Return an FD open to the master side of a pseudo-terminal. Flags should - include O_RDWR, and may also include O_NOCTTY. */ -# if !1 -_GL_FUNCDECL_SYS (posix_openpt, int, (int flags)); -# endif -_GL_CXXALIAS_SYS (posix_openpt, int, (int flags)); -_GL_CXXALIASWARN (posix_openpt); -#elif defined GNULIB_POSIXCHECK -# undef posix_openpt -# if HAVE_RAW_DECL_POSIX_OPENPT -_GL_WARN_ON_USE (posix_openpt, "posix_openpt is not portable - " - "use gnulib module posix_openpt for portability"); -# endif -#endif - -#if 0 -/* Return the pathname of the pseudo-terminal slave associated with - the master FD is open on, or NULL on errors. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef ptsname -# define ptsname rpl_ptsname -# endif -_GL_FUNCDECL_RPL (ptsname, char *, (int fd)); -_GL_CXXALIAS_RPL (ptsname, char *, (int fd)); -# else -# if !1 -_GL_FUNCDECL_SYS (ptsname, char *, (int fd)); -# endif -_GL_CXXALIAS_SYS (ptsname, char *, (int fd)); -# endif -_GL_CXXALIASWARN (ptsname); -#elif defined GNULIB_POSIXCHECK -# undef ptsname -# if HAVE_RAW_DECL_PTSNAME -_GL_WARN_ON_USE (ptsname, "ptsname is not portable - " - "use gnulib module ptsname for portability"); -# endif -#endif - -#if 0 -/* Set the pathname of the pseudo-terminal slave associated with - the master FD is open on and return 0, or set errno and return - non-zero on errors. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef ptsname_r -# define ptsname_r rpl_ptsname_r -# endif -_GL_FUNCDECL_RPL (ptsname_r, int, (int fd, char *buf, size_t len)); -_GL_CXXALIAS_RPL (ptsname_r, int, (int fd, char *buf, size_t len)); -# else -# if !1 -_GL_FUNCDECL_SYS (ptsname_r, int, (int fd, char *buf, size_t len)); -# endif -_GL_CXXALIAS_SYS (ptsname_r, int, (int fd, char *buf, size_t len)); -# endif -_GL_CXXALIASWARN (ptsname_r); -#elif defined GNULIB_POSIXCHECK -# undef ptsname_r -# if HAVE_RAW_DECL_PTSNAME_R -_GL_WARN_ON_USE (ptsname_r, "ptsname_r is not portable - " - "use gnulib module ptsname_r for portability"); -# endif -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef putenv -# define putenv rpl_putenv -# endif -_GL_FUNCDECL_RPL (putenv, int, (char *string) _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (putenv, int, (char *string)); -# else -_GL_CXXALIAS_SYS (putenv, int, (char *string)); -# endif -_GL_CXXALIASWARN (putenv); -#endif - -#if 0 -/* Sort an array of NMEMB elements, starting at address BASE, each element - occupying SIZE bytes, in ascending order according to the comparison - function COMPARE. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef qsort_r -# define qsort_r rpl_qsort_r -# endif -_GL_FUNCDECL_RPL (qsort_r, void, (void *base, size_t nmemb, size_t size, - int (*compare) (void const *, void const *, - void *), - void *arg) _GL_ARG_NONNULL ((1, 4))); -_GL_CXXALIAS_RPL (qsort_r, void, (void *base, size_t nmemb, size_t size, - int (*compare) (void const *, void const *, - void *), - void *arg)); -# else -# if !1 -_GL_FUNCDECL_SYS (qsort_r, void, (void *base, size_t nmemb, size_t size, - int (*compare) (void const *, void const *, - void *), - void *arg) _GL_ARG_NONNULL ((1, 4))); -# endif -_GL_CXXALIAS_SYS (qsort_r, void, (void *base, size_t nmemb, size_t size, - int (*compare) (void const *, void const *, - void *), - void *arg)); -# endif -_GL_CXXALIASWARN (qsort_r); -#elif defined GNULIB_POSIXCHECK -# undef qsort_r -# if HAVE_RAW_DECL_QSORT_R -_GL_WARN_ON_USE (qsort_r, "qsort_r is not portable - " - "use gnulib module qsort_r for portability"); -# endif -#endif - - -#if 0 -# if !1 -# ifndef RAND_MAX -# define RAND_MAX 2147483647 -# endif -# endif -#endif - - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef random -# define random rpl_random -# endif -_GL_FUNCDECL_RPL (random, long, (void)); -_GL_CXXALIAS_RPL (random, long, (void)); -# else -# if !1 -_GL_FUNCDECL_SYS (random, long, (void)); -# endif -/* Need to cast, because on Haiku, the return type is - int. */ -_GL_CXXALIAS_SYS_CAST (random, long, (void)); -# endif -_GL_CXXALIASWARN (random); -#elif defined GNULIB_POSIXCHECK -# undef random -# if HAVE_RAW_DECL_RANDOM -_GL_WARN_ON_USE (random, "random is unportable - " - "use gnulib module random for portability"); -# endif -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef srandom -# define srandom rpl_srandom -# endif -_GL_FUNCDECL_RPL (srandom, void, (unsigned int seed)); -_GL_CXXALIAS_RPL (srandom, void, (unsigned int seed)); -# else -# if !1 -_GL_FUNCDECL_SYS (srandom, void, (unsigned int seed)); -# endif -/* Need to cast, because on FreeBSD, the first parameter is - unsigned long seed. */ -_GL_CXXALIAS_SYS_CAST (srandom, void, (unsigned int seed)); -# endif -_GL_CXXALIASWARN (srandom); -#elif defined GNULIB_POSIXCHECK -# undef srandom -# if HAVE_RAW_DECL_SRANDOM -_GL_WARN_ON_USE (srandom, "srandom is unportable - " - "use gnulib module random for portability"); -# endif -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef initstate -# define initstate rpl_initstate -# endif -_GL_FUNCDECL_RPL (initstate, char *, - (unsigned int seed, char *buf, size_t buf_size) - _GL_ARG_NONNULL ((2))); -_GL_CXXALIAS_RPL (initstate, char *, - (unsigned int seed, char *buf, size_t buf_size)); -# else -# if !1 || !1 -_GL_FUNCDECL_SYS (initstate, char *, - (unsigned int seed, char *buf, size_t buf_size) - _GL_ARG_NONNULL ((2))); -# endif -/* Need to cast, because on FreeBSD, the first parameter is - unsigned long seed. */ -_GL_CXXALIAS_SYS_CAST (initstate, char *, - (unsigned int seed, char *buf, size_t buf_size)); -# endif -_GL_CXXALIASWARN (initstate); -#elif defined GNULIB_POSIXCHECK -# undef initstate -# if HAVE_RAW_DECL_INITSTATE -_GL_WARN_ON_USE (initstate, "initstate is unportable - " - "use gnulib module random for portability"); -# endif -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef setstate -# define setstate rpl_setstate -# endif -_GL_FUNCDECL_RPL (setstate, char *, (char *arg_state) _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (setstate, char *, (char *arg_state)); -# else -# if !1 || !1 -_GL_FUNCDECL_SYS (setstate, char *, (char *arg_state) _GL_ARG_NONNULL ((1))); -# endif -/* Need to cast, because on Mac OS X 10.13, HP-UX, Solaris the first parameter - is const char *arg_state. */ -_GL_CXXALIAS_SYS_CAST (setstate, char *, (char *arg_state)); -# endif -_GL_CXXALIASWARN (setstate); -#elif defined GNULIB_POSIXCHECK -# undef setstate -# if HAVE_RAW_DECL_SETSTATE -_GL_WARN_ON_USE (setstate, "setstate is unportable - " - "use gnulib module random for portability"); -# endif -#endif - - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef random_r -# define random_r rpl_random_r -# endif -_GL_FUNCDECL_RPL (random_r, int, (struct random_data *buf, int32_t *result) - _GL_ARG_NONNULL ((1, 2))); -_GL_CXXALIAS_RPL (random_r, int, (struct random_data *buf, int32_t *result)); -# else -# if !1 -_GL_FUNCDECL_SYS (random_r, int, (struct random_data *buf, int32_t *result) - _GL_ARG_NONNULL ((1, 2))); -# endif -_GL_CXXALIAS_SYS (random_r, int, (struct random_data *buf, int32_t *result)); -# endif -_GL_CXXALIASWARN (random_r); -#elif defined GNULIB_POSIXCHECK -# undef random_r -# if HAVE_RAW_DECL_RANDOM_R -_GL_WARN_ON_USE (random_r, "random_r is unportable - " - "use gnulib module random_r for portability"); -# endif -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef srandom_r -# define srandom_r rpl_srandom_r -# endif -_GL_FUNCDECL_RPL (srandom_r, int, - (unsigned int seed, struct random_data *rand_state) - _GL_ARG_NONNULL ((2))); -_GL_CXXALIAS_RPL (srandom_r, int, - (unsigned int seed, struct random_data *rand_state)); -# else -# if !1 -_GL_FUNCDECL_SYS (srandom_r, int, - (unsigned int seed, struct random_data *rand_state) - _GL_ARG_NONNULL ((2))); -# endif -_GL_CXXALIAS_SYS (srandom_r, int, - (unsigned int seed, struct random_data *rand_state)); -# endif -_GL_CXXALIASWARN (srandom_r); -#elif defined GNULIB_POSIXCHECK -# undef srandom_r -# if HAVE_RAW_DECL_SRANDOM_R -_GL_WARN_ON_USE (srandom_r, "srandom_r is unportable - " - "use gnulib module random_r for portability"); -# endif -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef initstate_r -# define initstate_r rpl_initstate_r -# endif -_GL_FUNCDECL_RPL (initstate_r, int, - (unsigned int seed, char *buf, size_t buf_size, - struct random_data *rand_state) - _GL_ARG_NONNULL ((2, 4))); -_GL_CXXALIAS_RPL (initstate_r, int, - (unsigned int seed, char *buf, size_t buf_size, - struct random_data *rand_state)); -# else -# if !1 -_GL_FUNCDECL_SYS (initstate_r, int, - (unsigned int seed, char *buf, size_t buf_size, - struct random_data *rand_state) - _GL_ARG_NONNULL ((2, 4))); -# endif -/* Need to cast, because on Haiku, the third parameter is - unsigned long buf_size. */ -_GL_CXXALIAS_SYS_CAST (initstate_r, int, - (unsigned int seed, char *buf, size_t buf_size, - struct random_data *rand_state)); -# endif -_GL_CXXALIASWARN (initstate_r); -#elif defined GNULIB_POSIXCHECK -# undef initstate_r -# if HAVE_RAW_DECL_INITSTATE_R -_GL_WARN_ON_USE (initstate_r, "initstate_r is unportable - " - "use gnulib module random_r for portability"); -# endif -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef setstate_r -# define setstate_r rpl_setstate_r -# endif -_GL_FUNCDECL_RPL (setstate_r, int, - (char *arg_state, struct random_data *rand_state) - _GL_ARG_NONNULL ((1, 2))); -_GL_CXXALIAS_RPL (setstate_r, int, - (char *arg_state, struct random_data *rand_state)); -# else -# if !1 -_GL_FUNCDECL_SYS (setstate_r, int, - (char *arg_state, struct random_data *rand_state) - _GL_ARG_NONNULL ((1, 2))); -# endif -/* Need to cast, because on Haiku, the first parameter is - void *arg_state. */ -_GL_CXXALIAS_SYS_CAST (setstate_r, int, - (char *arg_state, struct random_data *rand_state)); -# endif -_GL_CXXALIASWARN (setstate_r); -#elif defined GNULIB_POSIXCHECK -# undef setstate_r -# if HAVE_RAW_DECL_SETSTATE_R -_GL_WARN_ON_USE (setstate_r, "setstate_r is unportable - " - "use gnulib module random_r for portability"); -# endif -#endif - - -#if 0 -# if 0 -# if !((defined __cplusplus && defined GNULIB_NAMESPACE) \ - || _GL_USE_STDLIB_ALLOC) -# undef realloc -# define realloc rpl_realloc -# endif -_GL_FUNCDECL_RPL (realloc, void *, (void *ptr, size_t size)); -_GL_CXXALIAS_RPL (realloc, void *, (void *ptr, size_t size)); -# else -_GL_CXXALIAS_SYS (realloc, void *, (void *ptr, size_t size)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (realloc); -# endif -#elif defined GNULIB_POSIXCHECK && !_GL_USE_STDLIB_ALLOC -# undef realloc -/* Assume realloc is always declared. */ -_GL_WARN_ON_USE (realloc, "realloc is not POSIX compliant everywhere - " - "use gnulib module realloc-posix for portability"); -#endif - - -#if 0 -# if ! 1 -_GL_FUNCDECL_SYS (reallocarray, void *, - (void *ptr, size_t nmemb, size_t size)); -# endif -_GL_CXXALIAS_SYS (reallocarray, void *, - (void *ptr, size_t nmemb, size_t size)); -_GL_CXXALIASWARN (reallocarray); -#elif defined GNULIB_POSIXCHECK -# undef reallocarray -# if HAVE_RAW_DECL_REALLOCARRAY -_GL_WARN_ON_USE (reallocarray, "reallocarray is not portable - " - "use gnulib module reallocarray for portability"); -# endif -#endif - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define realpath rpl_realpath -# endif -_GL_FUNCDECL_RPL (realpath, char *, (const char *name, char *resolved) - _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (realpath, char *, (const char *name, char *resolved)); -# else -# if !1 -_GL_FUNCDECL_SYS (realpath, char *, (const char *name, char *resolved) - _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (realpath, char *, (const char *name, char *resolved)); -# endif -_GL_CXXALIASWARN (realpath); -#elif defined GNULIB_POSIXCHECK -# undef realpath -# if HAVE_RAW_DECL_REALPATH -_GL_WARN_ON_USE (realpath, "realpath is unportable - use gnulib module " - "canonicalize or canonicalize-lgpl for portability"); -# endif -#endif - -#if 0 -/* Test a user response to a question. - Return 1 if it is affirmative, 0 if it is negative, or -1 if not clear. */ -# if !1 -_GL_FUNCDECL_SYS (rpmatch, int, (const char *response) _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (rpmatch, int, (const char *response)); -_GL_CXXALIASWARN (rpmatch); -#elif defined GNULIB_POSIXCHECK -# undef rpmatch -# if HAVE_RAW_DECL_RPMATCH -_GL_WARN_ON_USE (rpmatch, "rpmatch is unportable - " - "use gnulib module rpmatch for portability"); -# endif -#endif - -#if 0 -/* Look up NAME in the environment, returning 0 in insecure situations. */ -# if !1 -_GL_FUNCDECL_SYS (secure_getenv, char *, - (char const *name) _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (secure_getenv, char *, (char const *name)); -_GL_CXXALIASWARN (secure_getenv); -#elif defined GNULIB_POSIXCHECK -# undef secure_getenv -# if HAVE_RAW_DECL_SECURE_GETENV -_GL_WARN_ON_USE (secure_getenv, "secure_getenv is unportable - " - "use gnulib module secure_getenv for portability"); -# endif -#endif - -#if 0 -/* Set NAME to VALUE in the environment. - If REPLACE is nonzero, overwrite an existing value. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef setenv -# define setenv rpl_setenv -# endif -_GL_FUNCDECL_RPL (setenv, int, - (const char *name, const char *value, int replace) - _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (setenv, int, - (const char *name, const char *value, int replace)); -# else -# if !1 -_GL_FUNCDECL_SYS (setenv, int, - (const char *name, const char *value, int replace) - _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (setenv, int, - (const char *name, const char *value, int replace)); -# endif -# if !(0 && !1) -_GL_CXXALIASWARN (setenv); -# endif -#elif defined GNULIB_POSIXCHECK -# undef setenv -# if HAVE_RAW_DECL_SETENV -_GL_WARN_ON_USE (setenv, "setenv is unportable - " - "use gnulib module setenv for portability"); -# endif -#endif - -#if 0 - /* Parse a double from STRING, updating ENDP if appropriate. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define strtod rpl_strtod -# endif -# define GNULIB_defined_strtod_function 1 -_GL_FUNCDECL_RPL (strtod, double, (const char *str, char **endp) - _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (strtod, double, (const char *str, char **endp)); -# else -# if !1 -_GL_FUNCDECL_SYS (strtod, double, (const char *str, char **endp) - _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (strtod, double, (const char *str, char **endp)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (strtod); -# endif -#elif defined GNULIB_POSIXCHECK -# undef strtod -# if HAVE_RAW_DECL_STRTOD -_GL_WARN_ON_USE (strtod, "strtod is unportable - " - "use gnulib module strtod for portability"); -# endif -#endif - -#if 0 - /* Parse a 'long double' from STRING, updating ENDP if appropriate. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define strtold rpl_strtold -# endif -# define GNULIB_defined_strtold_function 1 -_GL_FUNCDECL_RPL (strtold, long double, (const char *str, char **endp) - _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (strtold, long double, (const char *str, char **endp)); -# else -# if !1 -_GL_FUNCDECL_SYS (strtold, long double, (const char *str, char **endp) - _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (strtold, long double, (const char *str, char **endp)); -# endif -_GL_CXXALIASWARN (strtold); -#elif defined GNULIB_POSIXCHECK -# undef strtold -# if HAVE_RAW_DECL_STRTOLD -_GL_WARN_ON_USE (strtold, "strtold is unportable - " - "use gnulib module strtold for portability"); -# endif -#endif - -#if 0 -/* Parse a signed integer whose textual representation starts at STRING. - The integer is expected to be in base BASE (2 <= BASE <= 36); if BASE == 0, - it may be decimal or octal (with prefix "0") or hexadecimal (with prefix - "0x"). - If ENDPTR is not NULL, the address of the first byte after the integer is - stored in *ENDPTR. - Upon overflow, the return value is LLONG_MAX or LLONG_MIN, and errno is set - to ERANGE. */ -# if !1 -_GL_FUNCDECL_SYS (strtoll, long long, - (const char *string, char **endptr, int base) - _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (strtoll, long long, - (const char *string, char **endptr, int base)); -_GL_CXXALIASWARN (strtoll); -#elif defined GNULIB_POSIXCHECK -# undef strtoll -# if HAVE_RAW_DECL_STRTOLL -_GL_WARN_ON_USE (strtoll, "strtoll is unportable - " - "use gnulib module strtoll for portability"); -# endif -#endif - -#if 0 -/* Parse an unsigned integer whose textual representation starts at STRING. - The integer is expected to be in base BASE (2 <= BASE <= 36); if BASE == 0, - it may be decimal or octal (with prefix "0") or hexadecimal (with prefix - "0x"). - If ENDPTR is not NULL, the address of the first byte after the integer is - stored in *ENDPTR. - Upon overflow, the return value is ULLONG_MAX, and errno is set to - ERANGE. */ -# if !1 -_GL_FUNCDECL_SYS (strtoull, unsigned long long, - (const char *string, char **endptr, int base) - _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (strtoull, unsigned long long, - (const char *string, char **endptr, int base)); -_GL_CXXALIASWARN (strtoull); -#elif defined GNULIB_POSIXCHECK -# undef strtoull -# if HAVE_RAW_DECL_STRTOULL -_GL_WARN_ON_USE (strtoull, "strtoull is unportable - " - "use gnulib module strtoull for portability"); -# endif -#endif - -#if 0 -/* Unlock the slave side of the pseudo-terminal whose master side is specified - by FD, so that it can be opened. */ -# if !1 -_GL_FUNCDECL_SYS (unlockpt, int, (int fd)); -# endif -_GL_CXXALIAS_SYS (unlockpt, int, (int fd)); -_GL_CXXALIASWARN (unlockpt); -#elif defined GNULIB_POSIXCHECK -# undef unlockpt -# if HAVE_RAW_DECL_UNLOCKPT -_GL_WARN_ON_USE (unlockpt, "unlockpt is not portable - " - "use gnulib module unlockpt for portability"); -# endif -#endif - -#if 0 -/* Remove the variable NAME from the environment. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef unsetenv -# define unsetenv rpl_unsetenv -# endif -_GL_FUNCDECL_RPL (unsetenv, int, (const char *name) _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (unsetenv, int, (const char *name)); -# else -# if !1 -_GL_FUNCDECL_SYS (unsetenv, int, (const char *name) _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (unsetenv, int, (const char *name)); -# endif -# if !(0 && !1) -_GL_CXXALIASWARN (unsetenv); -# endif -#elif defined GNULIB_POSIXCHECK -# undef unsetenv -# if HAVE_RAW_DECL_UNSETENV -_GL_WARN_ON_USE (unsetenv, "unsetenv is unportable - " - "use gnulib module unsetenv for portability"); -# endif -#endif - -/* Convert a wide character to a multibyte character. */ -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef wctomb -# define wctomb rpl_wctomb -# endif -_GL_FUNCDECL_RPL (wctomb, int, (char *s, wchar_t wc)); -_GL_CXXALIAS_RPL (wctomb, int, (char *s, wchar_t wc)); -# else -_GL_CXXALIAS_SYS (wctomb, int, (char *s, wchar_t wc)); -# endif -# if __GLIBC__ >= 2 -_GL_CXXALIASWARN (wctomb); -# endif -#endif - - -#endif /* _GL_STDLIB_H */ -#endif /* _GL_STDLIB_H */ -#endif diff --git a/third_party/make/strcache.c b/third_party/make/strcache.c index f22e58ab5..baa3a9fbe 100644 --- a/third_party/make/strcache.c +++ b/third_party/make/strcache.c @@ -1,5 +1,5 @@ /* Constant string caching for GNU Make. -Copyright (C) 2006-2020 Free Software Foundation, Inc. +Copyright (C) 2006-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,10 +12,14 @@ 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 . */ +this program. If not, see . */ -#include "third_party/make/makeint.inc" -#include "third_party/make/hash.h" +#include "makeint.h" + +#include +#include + +#include "hash.h" /* A string cached here will never be freed, so we don't need to worry about reference counting. We just store the string, and then remember it in a @@ -49,7 +53,7 @@ static unsigned long total_size = 0; /* Add a new buffer to the cache. Add it at the front to reduce search time. This can also increase the overhead, since it's less likely that older - buffers will be filled in. However, GNU make has so many smaller strings + buffers will be filled in. However, GNU Make has so many smaller strings that this doesn't seem to be much of an issue in practice. */ static struct strcache * @@ -252,8 +256,7 @@ strcache_add_len (const char *str, size_t len) void strcache_init (void) { - // [jart] increased from 8000 - hash_init (&strings, 131072, str_hash_1, str_hash_2, str_hash_cmp); + hash_init (&strings, 8000, str_hash_1, str_hash_2, str_hash_cmp); } diff --git a/third_party/make/stripslash.c b/third_party/make/stripslash.c deleted file mode 100644 index 7e2b986d3..000000000 --- a/third_party/make/stripslash.c +++ /dev/null @@ -1,45 +0,0 @@ -/* stripslash.c -- remove redundant trailing slashes from a file name - - Copyright (C) 1990, 2001, 2003-2006, 2009-2020 Free Software Foundation, - Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -#include "third_party/make/config.h" - -#include "third_party/make/dirname.h" - -/* Remove trailing slashes from FILE. Return true if a trailing slash - was removed. This is useful when using file name completion from a - shell that adds a "/" after directory names (such as tcsh and - bash), because on symlinks to directories, several system calls - have different semantics according to whether a trailing slash is - present. */ - -bool -strip_trailing_slashes (char *file) -{ - char *base = last_component (file); - char *base_lim; - bool had_slash; - - /* last_component returns "" for file system roots, but we need to turn - "///" into "/". */ - if (! *base) - base = file; - base_lim = base + base_len (base); - had_slash = (*base_lim != '\0'); - *base_lim = '\0'; - return had_slash; -} diff --git a/third_party/make/unistd.c b/third_party/make/unistd.c deleted file mode 100644 index cfbab7415..000000000 --- a/third_party/make/unistd.c +++ /dev/null @@ -1,4 +0,0 @@ -#include "third_party/make/config.h" -#define _GL_UNISTD_INLINE _GL_EXTERN_INLINE -#include "third_party/make/unistd.h" -typedef int dummy; diff --git a/third_party/make/unistd.h b/third_party/make/unistd.h deleted file mode 100644 index 5e0a56513..000000000 --- a/third_party/make/unistd.h +++ /dev/null @@ -1,2173 +0,0 @@ -/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ -/* Substitute for and wrapper around . - Copyright (C) 2003-2020 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, 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 . */ - -#ifndef _GL_UNISTD_H - -#if __GNUC__ >= 3 -#pragma GCC system_header -#endif - - -#if 1 && defined _GL_INCLUDING_UNISTD_H -/* Special invocation convention: - - On Mac OS X 10.3.9 we have a sequence of nested includes - -> -> -> - In this situation, the functions are not yet declared, therefore we cannot - provide the C++ aliases. */ - - -#else -/* Normal invocation convention. */ - -/* The include_next requires a split double-inclusion guard. */ -#if 1 -# define _GL_INCLUDING_UNISTD_H -# undef _GL_INCLUDING_UNISTD_H -#endif - -/* Get all possible declarations of gethostname(). */ -#if 0 && 0 \ - && !defined _GL_INCLUDING_WINSOCK2_H -# define _GL_INCLUDING_WINSOCK2_H -# undef _GL_INCLUDING_WINSOCK2_H -#endif - -#if !defined _GL_UNISTD_H && !defined _GL_INCLUDING_WINSOCK2_H -#define _GL_UNISTD_H - -/* NetBSD 5.0 mis-defines NULL. Also get size_t. */ -/* But avoid namespace pollution on glibc systems. */ -#ifndef __GLIBC__ -#endif - -/* mingw doesn't define the SEEK_* or *_FILENO macros in . */ -/* MSVC declares 'unlink' in , not in . We must include - it before we #define unlink rpl_unlink. */ -/* Cygwin 1.7.1 declares symlinkat in , not in . */ -/* But avoid namespace pollution on glibc systems. */ -#if (!(defined SEEK_CUR && defined SEEK_END && defined SEEK_SET) \ - || ((0 || defined GNULIB_POSIXCHECK) \ - && (defined _WIN32 && ! defined __CYGWIN__)) \ - || ((0 || defined GNULIB_POSIXCHECK) \ - && defined __CYGWIN__)) \ - && ! defined __GLIBC__ -#endif - -/* Cygwin 1.7.1 and Android 4.3 declare unlinkat in , not in - . */ -/* But avoid namespace pollution on glibc systems. */ -#if (0 || defined GNULIB_POSIXCHECK) \ - && (defined __CYGWIN__ || defined __ANDROID__) \ - && ! defined __GLIBC__ -#endif - -/* mingw fails to declare _exit in . */ -/* mingw, MSVC, BeOS, Haiku declare environ in , not in - . */ -/* Solaris declares getcwd not only in but also in . */ -/* OSF Tru64 Unix cannot see gnulib rpl_strtod when system is - included here. */ -/* But avoid namespace pollution on glibc systems. */ -#if !defined __GLIBC__ && !defined __osf__ -# define __need_system_stdlib_h -# undef __need_system_stdlib_h -#endif - -/* Native Windows platforms declare chdir, getcwd, rmdir in - and/or , not in . - They also declare access(), chmod(), close(), dup(), dup2(), isatty(), - lseek(), read(), unlink(), write() in . */ -#if ((0 || 0 || 0 \ - || defined GNULIB_POSIXCHECK) \ - && (defined _WIN32 && ! defined __CYGWIN__)) -#elif (1 || 0 || 1 || 0 \ - || 0 || 0 || 0 || 0 \ - || defined GNULIB_POSIXCHECK) \ - && (defined _WIN32 && ! defined __CYGWIN__) -#endif - -/* AIX and OSF/1 5.1 declare getdomainname in , not in . - NonStop Kernel declares gethostname in , not in . */ -/* But avoid namespace pollution on glibc systems. */ -#if ((0 && (defined _AIX || defined __osf__)) \ - || (0 && defined __TANDEM)) \ - && !defined __GLIBC__ -#endif - -/* Android 4.3 declares fchownat in , not in . */ -/* But avoid namespace pollution on glibc systems. */ -#if (0 || defined GNULIB_POSIXCHECK) && defined __ANDROID__ \ - && !defined __GLIBC__ -#endif - -/* MSVC defines off_t in . - May also define off_t to a 64-bit type on native Windows. */ -/* But avoid namespace pollution on glibc systems. */ -#ifndef __GLIBC__ -/* Get off_t, ssize_t. */ -#endif - -/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ -/* C++ compatible function declaration macros. - Copyright (C) 2010-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -#ifndef _GL_CXXDEFS_H -#define _GL_CXXDEFS_H - -/* Begin/end the GNULIB_NAMESPACE namespace. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -# define _GL_BEGIN_NAMESPACE namespace GNULIB_NAMESPACE { -# define _GL_END_NAMESPACE } -#else -# define _GL_BEGIN_NAMESPACE -# define _GL_END_NAMESPACE -#endif - -/* The three most frequent use cases of these macros are: - - * For providing a substitute for a function that is missing on some - platforms, but is declared and works fine on the platforms on which - it exists: - - #if @GNULIB_FOO@ - # if !@HAVE_FOO@ - _GL_FUNCDECL_SYS (foo, ...); - # endif - _GL_CXXALIAS_SYS (foo, ...); - _GL_CXXALIASWARN (foo); - #elif defined GNULIB_POSIXCHECK - ... - #endif - - * For providing a replacement for a function that exists on all platforms, - but is broken/insufficient and needs to be replaced on some platforms: - - #if @GNULIB_FOO@ - # if @REPLACE_FOO@ - # if !(defined __cplusplus && defined GNULIB_NAMESPACE) - # undef foo - # define foo rpl_foo - # endif - _GL_FUNCDECL_RPL (foo, ...); - _GL_CXXALIAS_RPL (foo, ...); - # else - _GL_CXXALIAS_SYS (foo, ...); - # endif - _GL_CXXALIASWARN (foo); - #elif defined GNULIB_POSIXCHECK - ... - #endif - - * For providing a replacement for a function that exists on some platforms - but is broken/insufficient and needs to be replaced on some of them and - is additionally either missing or undeclared on some other platforms: - - #if @GNULIB_FOO@ - # if @REPLACE_FOO@ - # if !(defined __cplusplus && defined GNULIB_NAMESPACE) - # undef foo - # define foo rpl_foo - # endif - _GL_FUNCDECL_RPL (foo, ...); - _GL_CXXALIAS_RPL (foo, ...); - # else - # if !@HAVE_FOO@ or if !@HAVE_DECL_FOO@ - _GL_FUNCDECL_SYS (foo, ...); - # endif - _GL_CXXALIAS_SYS (foo, ...); - # endif - _GL_CXXALIASWARN (foo); - #elif defined GNULIB_POSIXCHECK - ... - #endif -*/ - -/* _GL_EXTERN_C declaration; - performs the declaration with C linkage. */ -#if defined __cplusplus -# define _GL_EXTERN_C extern "C" -#else -# define _GL_EXTERN_C extern -#endif - -/* _GL_FUNCDECL_RPL (func, rettype, parameters_and_attributes); - declares a replacement function, named rpl_func, with the given prototype, - consisting of return type, parameters, and attributes. - Example: - _GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...) - _GL_ARG_NONNULL ((1))); - */ -#define _GL_FUNCDECL_RPL(func,rettype,parameters_and_attributes) \ - _GL_FUNCDECL_RPL_1 (rpl_##func, rettype, parameters_and_attributes) -#define _GL_FUNCDECL_RPL_1(rpl_func,rettype,parameters_and_attributes) \ - _GL_EXTERN_C rettype rpl_func parameters_and_attributes - -/* _GL_FUNCDECL_SYS (func, rettype, parameters_and_attributes); - declares the system function, named func, with the given prototype, - consisting of return type, parameters, and attributes. - Example: - _GL_FUNCDECL_SYS (open, int, (const char *filename, int flags, ...) - _GL_ARG_NONNULL ((1))); - */ -#define _GL_FUNCDECL_SYS(func,rettype,parameters_and_attributes) \ - _GL_EXTERN_C rettype func parameters_and_attributes - -/* _GL_CXXALIAS_RPL (func, rettype, parameters); - declares a C++ alias called GNULIB_NAMESPACE::func - that redirects to rpl_func, if GNULIB_NAMESPACE is defined. - Example: - _GL_CXXALIAS_RPL (open, int, (const char *filename, int flags, ...)); - - Wrapping rpl_func in an object with an inline conversion operator - avoids a reference to rpl_func unless GNULIB_NAMESPACE::func is - actually used in the program. */ -#define _GL_CXXALIAS_RPL(func,rettype,parameters) \ - _GL_CXXALIAS_RPL_1 (func, rpl_##func, rettype, parameters) -#if defined __cplusplus && defined GNULIB_NAMESPACE -# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \ - namespace GNULIB_NAMESPACE \ - { \ - static const struct _gl_ ## func ## _wrapper \ - { \ - typedef rettype (*type) parameters; \ - \ - inline operator type () const \ - { \ - return ::rpl_func; \ - } \ - } func = {}; \ - } \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#else -# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIAS_RPL_CAST_1 (func, rpl_func, rettype, parameters); - is like _GL_CXXALIAS_RPL_1 (func, rpl_func, rettype, parameters); - except that the C function rpl_func may have a slightly different - declaration. A cast is used to silence the "invalid conversion" error - that would otherwise occur. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -# define _GL_CXXALIAS_RPL_CAST_1(func,rpl_func,rettype,parameters) \ - namespace GNULIB_NAMESPACE \ - { \ - static const struct _gl_ ## func ## _wrapper \ - { \ - typedef rettype (*type) parameters; \ - \ - inline operator type () const \ - { \ - return reinterpret_cast(::rpl_func); \ - } \ - } func = {}; \ - } \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#else -# define _GL_CXXALIAS_RPL_CAST_1(func,rpl_func,rettype,parameters) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIAS_SYS (func, rettype, parameters); - declares a C++ alias called GNULIB_NAMESPACE::func - that redirects to the system provided function func, if GNULIB_NAMESPACE - is defined. - Example: - _GL_CXXALIAS_SYS (open, int, (const char *filename, int flags, ...)); - - Wrapping func in an object with an inline conversion operator - avoids a reference to func unless GNULIB_NAMESPACE::func is - actually used in the program. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -# define _GL_CXXALIAS_SYS(func,rettype,parameters) \ - namespace GNULIB_NAMESPACE \ - { \ - static const struct _gl_ ## func ## _wrapper \ - { \ - typedef rettype (*type) parameters; \ - \ - inline operator type () const \ - { \ - return ::func; \ - } \ - } func = {}; \ - } \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#else -# define _GL_CXXALIAS_SYS(func,rettype,parameters) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIAS_SYS_CAST (func, rettype, parameters); - is like _GL_CXXALIAS_SYS (func, rettype, parameters); - except that the C function func may have a slightly different declaration. - A cast is used to silence the "invalid conversion" error that would - otherwise occur. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -# define _GL_CXXALIAS_SYS_CAST(func,rettype,parameters) \ - namespace GNULIB_NAMESPACE \ - { \ - static const struct _gl_ ## func ## _wrapper \ - { \ - typedef rettype (*type) parameters; \ - \ - inline operator type () const \ - { \ - return reinterpret_cast(::func); \ - } \ - } func = {}; \ - } \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#else -# define _GL_CXXALIAS_SYS_CAST(func,rettype,parameters) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIAS_SYS_CAST2 (func, rettype, parameters, rettype2, parameters2); - is like _GL_CXXALIAS_SYS (func, rettype, parameters); - except that the C function is picked among a set of overloaded functions, - namely the one with rettype2 and parameters2. Two consecutive casts - are used to silence the "cannot find a match" and "invalid conversion" - errors that would otherwise occur. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE - /* The outer cast must be a reinterpret_cast. - The inner cast: When the function is defined as a set of overloaded - functions, it works as a static_cast<>, choosing the designated variant. - When the function is defined as a single variant, it works as a - reinterpret_cast<>. The parenthesized cast syntax works both ways. */ -# define _GL_CXXALIAS_SYS_CAST2(func,rettype,parameters,rettype2,parameters2) \ - namespace GNULIB_NAMESPACE \ - { \ - static const struct _gl_ ## func ## _wrapper \ - { \ - typedef rettype (*type) parameters; \ - \ - inline operator type () const \ - { \ - return reinterpret_cast((rettype2 (*) parameters2)(::func)); \ - } \ - } func = {}; \ - } \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#else -# define _GL_CXXALIAS_SYS_CAST2(func,rettype,parameters,rettype2,parameters2) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIASWARN (func); - causes a warning to be emitted when ::func is used but not when - GNULIB_NAMESPACE::func is used. func must be defined without overloaded - variants. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -# define _GL_CXXALIASWARN(func) \ - _GL_CXXALIASWARN_1 (func, GNULIB_NAMESPACE) -# define _GL_CXXALIASWARN_1(func,namespace) \ - _GL_CXXALIASWARN_2 (func, namespace) -/* To work around GCC bug , - we enable the warning only when not optimizing. */ -# if !__OPTIMIZE__ -# define _GL_CXXALIASWARN_2(func,namespace) \ - _GL_WARN_ON_USE (func, \ - "The symbol ::" #func " refers to the system function. " \ - "Use " #namespace "::" #func " instead.") -# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING -# define _GL_CXXALIASWARN_2(func,namespace) \ - extern __typeof__ (func) func -# else -# define _GL_CXXALIASWARN_2(func,namespace) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -# endif -#else -# define _GL_CXXALIASWARN(func) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -/* _GL_CXXALIASWARN1 (func, rettype, parameters_and_attributes); - causes a warning to be emitted when the given overloaded variant of ::func - is used but not when GNULIB_NAMESPACE::func is used. */ -#if defined __cplusplus && defined GNULIB_NAMESPACE -# define _GL_CXXALIASWARN1(func,rettype,parameters_and_attributes) \ - _GL_CXXALIASWARN1_1 (func, rettype, parameters_and_attributes, \ - GNULIB_NAMESPACE) -# define _GL_CXXALIASWARN1_1(func,rettype,parameters_and_attributes,namespace) \ - _GL_CXXALIASWARN1_2 (func, rettype, parameters_and_attributes, namespace) -/* To work around GCC bug , - we enable the warning only when not optimizing. */ -# if !__OPTIMIZE__ -# define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \ - _GL_WARN_ON_USE_CXX (func, rettype, parameters_and_attributes, \ - "The symbol ::" #func " refers to the system function. " \ - "Use " #namespace "::" #func " instead.") -# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING -# define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \ - extern __typeof__ (func) func -# else -# define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -# endif -#else -# define _GL_CXXALIASWARN1(func,rettype,parameters_and_attributes) \ - _GL_EXTERN_C int _gl_cxxalias_dummy -#endif - -#endif /* _GL_CXXDEFS_H */ - -/* The definition of _GL_ARG_NONNULL is copied here. */ -/* A C macro for declaring that specific arguments must not be NULL. - Copyright (C) 2009-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -/* _GL_ARG_NONNULL((n,...,m)) tells the compiler and static analyzer tools - that the values passed as arguments n, ..., m must be non-NULL pointers. - n = 1 stands for the first argument, n = 2 for the second argument etc. */ -#ifndef _GL_ARG_NONNULL -# if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || __GNUC__ > 3 -# define _GL_ARG_NONNULL(params) __attribute__ ((__nonnull__ params)) -# else -# define _GL_ARG_NONNULL(params) -# endif -#endif - -/* The definition of _GL_WARN_ON_USE is copied here. */ -/* A C macro for emitting warnings if a function is used. - Copyright (C) 2010-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -/* _GL_WARN_ON_USE (function, "literal string") issues a declaration - for FUNCTION which will then trigger a compiler warning containing - the text of "literal string" anywhere that function is called, if - supported by the compiler. If the compiler does not support this - feature, the macro expands to an unused extern declaration. - - _GL_WARN_ON_USE_ATTRIBUTE ("literal string") expands to the - attribute used in _GL_WARN_ON_USE. If the compiler does not support - this feature, it expands to empty. - - These macros are useful for marking a function as a potential - portability trap, with the intent that "literal string" include - instructions on the replacement function that should be used - instead. - _GL_WARN_ON_USE is for functions with 'extern' linkage. - _GL_WARN_ON_USE_ATTRIBUTE is for functions with 'static' or 'inline' - linkage. - - However, one of the reasons that a function is a portability trap is - if it has the wrong signature. Declaring FUNCTION with a different - signature in C is a compilation error, so this macro must use the - same type as any existing declaration so that programs that avoid - the problematic FUNCTION do not fail to compile merely because they - included a header that poisoned the function. But this implies that - _GL_WARN_ON_USE is only safe to use if FUNCTION is known to already - have a declaration. Use of this macro implies that there must not - be any other macro hiding the declaration of FUNCTION; but - undefining FUNCTION first is part of the poisoning process anyway - (although for symbols that are provided only via a macro, the result - is a compilation error rather than a warning containing - "literal string"). Also note that in C++, it is only safe to use if - FUNCTION has no overloads. - - For an example, it is possible to poison 'getline' by: - [getline]) in configure.ac, which potentially defines - HAVE_RAW_DECL_GETLINE - - adding this code to a header that wraps the system : - #undef getline - #if HAVE_RAW_DECL_GETLINE - _GL_WARN_ON_USE (getline, "getline is required by POSIX 2008, but" - "not universally present; use the gnulib module getline"); - #endif - - It is not possible to directly poison global variables. But it is - possible to write a wrapper accessor function, and poison that - (less common usage, like &environ, will cause a compilation error - rather than issue the nice warning, but the end result of informing - the developer about their portability problem is still achieved): - #if HAVE_RAW_DECL_ENVIRON - static char *** - rpl_environ (void) { return &environ; } - _GL_WARN_ON_USE (rpl_environ, "environ is not always properly declared"); - # undef environ - # define environ (*rpl_environ ()) - #endif - or better (avoiding contradictory use of 'static' and 'extern'): - #if HAVE_RAW_DECL_ENVIRON - static char *** - _GL_WARN_ON_USE_ATTRIBUTE ("environ is not always properly declared") - rpl_environ (void) { return &environ; } - # undef environ - # define environ (*rpl_environ ()) - #endif - */ -#ifndef _GL_WARN_ON_USE - -# if 4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) -/* A compiler attribute is available in gcc versions 4.3.0 and later. */ -# define _GL_WARN_ON_USE(function, message) \ -extern __typeof__ (function) function __attribute__ ((__warning__ (message))) -# define _GL_WARN_ON_USE_ATTRIBUTE(message) \ - __attribute__ ((__warning__ (message))) -# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING -/* Verify the existence of the function. */ -# define _GL_WARN_ON_USE(function, message) \ -extern __typeof__ (function) function -# define _GL_WARN_ON_USE_ATTRIBUTE(message) -# else /* Unsupported. */ -# define _GL_WARN_ON_USE(function, message) \ -_GL_WARN_EXTERN_C int _gl_warn_on_use -# define _GL_WARN_ON_USE_ATTRIBUTE(message) -# endif -#endif - -/* _GL_WARN_ON_USE_CXX (function, rettype, parameters_and_attributes, "string") - is like _GL_WARN_ON_USE (function, "string"), except that the function is - declared with the given prototype, consisting of return type, parameters, - and attributes. - This variant is useful for overloaded functions in C++. _GL_WARN_ON_USE does - not work in this case. */ -#ifndef _GL_WARN_ON_USE_CXX -# if 4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) -# define _GL_WARN_ON_USE_CXX(function,rettype,parameters_and_attributes,msg) \ -extern rettype function parameters_and_attributes \ - __attribute__ ((__warning__ (msg))) -# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING -/* Verify the existence of the function. */ -# define _GL_WARN_ON_USE_CXX(function,rettype,parameters_and_attributes,msg) \ -extern rettype function parameters_and_attributes -# else /* Unsupported. */ -# define _GL_WARN_ON_USE_CXX(function,rettype,parameters_and_attributes,msg) \ -_GL_WARN_EXTERN_C int _gl_warn_on_use -# endif -#endif - -/* _GL_WARN_EXTERN_C declaration; - performs the declaration with C linkage. */ -#ifndef _GL_WARN_EXTERN_C -# if defined __cplusplus -# define _GL_WARN_EXTERN_C extern "C" -# else -# define _GL_WARN_EXTERN_C extern -# endif -#endif - - -/* Get getopt(), optarg, optind, opterr, optopt. */ -#if 0 && !defined _GL_SYSTEM_GETOPT -#endif - -#ifndef _GL_INLINE_HEADER_BEGIN - #error "Please include config.h first." -#endif -_GL_INLINE_HEADER_BEGIN -#ifndef _GL_UNISTD_INLINE -# define _GL_UNISTD_INLINE _GL_INLINE -#endif - -/* Hide some function declarations from . */ - -#if 0 && 0 -# if !defined _GL_SYS_SOCKET_H -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef socket -# define socket socket_used_without_including_sys_socket_h -# undef connect -# define connect connect_used_without_including_sys_socket_h -# undef accept -# define accept accept_used_without_including_sys_socket_h -# undef bind -# define bind bind_used_without_including_sys_socket_h -# undef getpeername -# define getpeername getpeername_used_without_including_sys_socket_h -# undef getsockname -# define getsockname getsockname_used_without_including_sys_socket_h -# undef getsockopt -# define getsockopt getsockopt_used_without_including_sys_socket_h -# undef listen -# define listen listen_used_without_including_sys_socket_h -# undef recv -# define recv recv_used_without_including_sys_socket_h -# undef send -# define send send_used_without_including_sys_socket_h -# undef recvfrom -# define recvfrom recvfrom_used_without_including_sys_socket_h -# undef sendto -# define sendto sendto_used_without_including_sys_socket_h -# undef setsockopt -# define setsockopt setsockopt_used_without_including_sys_socket_h -# undef shutdown -# define shutdown shutdown_used_without_including_sys_socket_h -# else - _GL_WARN_ON_USE (socket, - "socket() used without including "); - _GL_WARN_ON_USE (connect, - "connect() used without including "); - _GL_WARN_ON_USE (accept, - "accept() used without including "); - _GL_WARN_ON_USE (bind, - "bind() used without including "); - _GL_WARN_ON_USE (getpeername, - "getpeername() used without including "); - _GL_WARN_ON_USE (getsockname, - "getsockname() used without including "); - _GL_WARN_ON_USE (getsockopt, - "getsockopt() used without including "); - _GL_WARN_ON_USE (listen, - "listen() used without including "); - _GL_WARN_ON_USE (recv, - "recv() used without including "); - _GL_WARN_ON_USE (send, - "send() used without including "); - _GL_WARN_ON_USE (recvfrom, - "recvfrom() used without including "); - _GL_WARN_ON_USE (sendto, - "sendto() used without including "); - _GL_WARN_ON_USE (setsockopt, - "setsockopt() used without including "); - _GL_WARN_ON_USE (shutdown, - "shutdown() used without including "); -# endif -# endif -# if !defined _GL_SYS_SELECT_H -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef select -# define select select_used_without_including_sys_select_h -# else - _GL_WARN_ON_USE (select, - "select() used without including "); -# endif -# endif -#endif - - -/* OS/2 EMX lacks these macros. */ -#ifndef STDIN_FILENO -# define STDIN_FILENO 0 -#endif -#ifndef STDOUT_FILENO -# define STDOUT_FILENO 1 -#endif -#ifndef STDERR_FILENO -# define STDERR_FILENO 2 -#endif - -/* Ensure *_OK macros exist. */ -#ifndef F_OK -# define F_OK 0 -# define X_OK 1 -# define W_OK 2 -# define R_OK 4 -#endif - - -/* Declare overridden functions. */ - - -#if 1 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef access -# define access rpl_access -# endif -_GL_FUNCDECL_RPL (access, int, (const char *file, int mode) - _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (access, int, (const char *file, int mode)); -# else -_GL_CXXALIAS_SYS (access, int, (const char *file, int mode)); -# endif -_GL_CXXALIASWARN (access); -#elif defined GNULIB_POSIXCHECK -# undef access -# if HAVE_RAW_DECL_ACCESS -/* The access() function is a security risk. */ -_GL_WARN_ON_USE (access, "access does not always support X_OK - " - "use gnulib module access for portability; " - "also, this function is a security risk - " - "use the gnulib module faccessat instead"); -# endif -#endif - - -#if 0 -_GL_CXXALIAS_SYS (chdir, int, (const char *file) _GL_ARG_NONNULL ((1))); -_GL_CXXALIASWARN (chdir); -#elif defined GNULIB_POSIXCHECK -# undef chdir -# if HAVE_RAW_DECL_CHDIR -_GL_WARN_ON_USE (chown, "chdir is not always in - " - "use gnulib module chdir for portability"); -# endif -#endif - - -#if 0 -/* Change the owner of FILE to UID (if UID is not -1) and the group of FILE - to GID (if GID is not -1). Follow symbolic links. - Return 0 if successful, otherwise -1 and errno set. - See the POSIX:2008 specification - . */ -# if 1 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define dup2 rpl_dup2 -# endif -_GL_FUNCDECL_RPL (dup2, int, (int oldfd, int newfd)); -_GL_CXXALIAS_RPL (dup2, int, (int oldfd, int newfd)); -# else -# if !1 -_GL_FUNCDECL_SYS (dup2, int, (int oldfd, int newfd)); -# endif -_GL_CXXALIAS_SYS (dup2, int, (int oldfd, int newfd)); -# endif -_GL_CXXALIASWARN (dup2); -#elif defined GNULIB_POSIXCHECK -# undef dup2 -# if HAVE_RAW_DECL_DUP2 -_GL_WARN_ON_USE (dup2, "dup2 is unportable - " - "use gnulib module dup2 for portability"); -# endif -#endif - - -#if 0 -/* Copy the file descriptor OLDFD into file descriptor NEWFD, with the - specified flags. - The flags are a bitmask, possibly including O_CLOEXEC (defined in ) - and O_TEXT, O_BINARY (defined in "binary-io.h"). - Close NEWFD first if it is open. - Return newfd if successful, otherwise -1 and errno set. - See the Linux man page at - . */ -# if 1 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define dup3 rpl_dup3 -# endif -_GL_FUNCDECL_RPL (dup3, int, (int oldfd, int newfd, int flags)); -_GL_CXXALIAS_RPL (dup3, int, (int oldfd, int newfd, int flags)); -# else -_GL_FUNCDECL_SYS (dup3, int, (int oldfd, int newfd, int flags)); -_GL_CXXALIAS_SYS (dup3, int, (int oldfd, int newfd, int flags)); -# endif -_GL_CXXALIASWARN (dup3); -#elif defined GNULIB_POSIXCHECK -# undef dup3 -# if HAVE_RAW_DECL_DUP3 -_GL_WARN_ON_USE (dup3, "dup3 is unportable - " - "use gnulib module dup3 for portability"); -# endif -#endif - - -#if 0 -# if defined __CYGWIN__ && !defined __i386__ -/* The 'environ' variable is defined in a DLL. Therefore its declaration needs - the '__declspec(dllimport)' attribute, but the system's lacks it. - This leads to a link error on 64-bit Cygwin when the option - -Wl,--disable-auto-import is in use. */ -_GL_EXTERN_C __declspec(dllimport) char **environ; -# endif -# if !1 -/* Set of environment variables and values. An array of strings of the form - "VARIABLE=VALUE", terminated with a NULL. */ -# if defined __APPLE__ && defined __MACH__ -# if !TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR -# define _GL_USE_CRT_EXTERNS -# endif -# endif -# ifdef _GL_USE_CRT_EXTERNS -# define environ (*_NSGetEnviron ()) -# else -# ifdef __cplusplus -extern "C" { -# endif -extern char **environ; -# ifdef __cplusplus -} -# endif -# endif -# endif -#elif defined GNULIB_POSIXCHECK -# if HAVE_RAW_DECL_ENVIRON -_GL_UNISTD_INLINE char *** -_GL_WARN_ON_USE_ATTRIBUTE ("environ is unportable - " - "use gnulib module environ for portability") -rpl_environ (void) -{ - return &environ; -} -# undef environ -# define environ (*rpl_environ ()) -# endif -#endif - - -#if 0 -/* Like access(), except that it uses the effective user id and group id of - the current process. */ -# if !1 -_GL_FUNCDECL_SYS (euidaccess, int, (const char *filename, int mode) - _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (euidaccess, int, (const char *filename, int mode)); -_GL_CXXALIASWARN (euidaccess); -# if defined GNULIB_POSIXCHECK -/* Like access(), this function is a security risk. */ -_GL_WARN_ON_USE (euidaccess, "the euidaccess function is a security risk - " - "use the gnulib module faccessat instead"); -# endif -#elif defined GNULIB_POSIXCHECK -# undef euidaccess -# if HAVE_RAW_DECL_EUIDACCESS -_GL_WARN_ON_USE (euidaccess, "euidaccess is unportable - " - "use gnulib module euidaccess for portability"); -# endif -#endif - - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef faccessat -# define faccessat rpl_faccessat -# endif -_GL_FUNCDECL_RPL (faccessat, int, - (int fd, char const *name, int mode, int flag) - _GL_ARG_NONNULL ((2))); -_GL_CXXALIAS_RPL (faccessat, int, - (int fd, char const *name, int mode, int flag)); -# else -# if !1 -_GL_FUNCDECL_SYS (faccessat, int, - (int fd, char const *file, int mode, int flag) - _GL_ARG_NONNULL ((2))); -# endif -_GL_CXXALIAS_SYS (faccessat, int, - (int fd, char const *file, int mode, int flag)); -# endif -_GL_CXXALIASWARN (faccessat); -#elif defined GNULIB_POSIXCHECK -# undef faccessat -# if HAVE_RAW_DECL_FACCESSAT -_GL_WARN_ON_USE (faccessat, "faccessat is not portable - " - "use gnulib module faccessat for portability"); -# endif -#endif - - -#if 0 -/* Change the process' current working directory to the directory on which - the given file descriptor is open. - Return 0 if successful, otherwise -1 and errno set. - See the POSIX:2008 specification - . */ -# if ! 1 -_GL_FUNCDECL_SYS (fchdir, int, (int /*fd*/)); - -/* Gnulib internal hooks needed to maintain the fchdir metadata. */ -_GL_EXTERN_C int _gl_register_fd (int fd, const char *filename) - _GL_ARG_NONNULL ((2)); -_GL_EXTERN_C void _gl_unregister_fd (int fd); -_GL_EXTERN_C int _gl_register_dup (int oldfd, int newfd); -_GL_EXTERN_C const char *_gl_directory_name (int fd); - -# else -# if !1 -_GL_FUNCDECL_SYS (fchdir, int, (int /*fd*/)); -# endif -# endif -_GL_CXXALIAS_SYS (fchdir, int, (int /*fd*/)); -_GL_CXXALIASWARN (fchdir); -#elif defined GNULIB_POSIXCHECK -# undef fchdir -# if HAVE_RAW_DECL_FCHDIR -_GL_WARN_ON_USE (fchdir, "fchdir is unportable - " - "use gnulib module fchdir for portability"); -# endif -#endif - - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef fchownat -# define fchownat rpl_fchownat -# endif -_GL_FUNCDECL_RPL (fchownat, int, (int fd, char const *file, - uid_t owner, gid_t group, int flag) - _GL_ARG_NONNULL ((2))); -_GL_CXXALIAS_RPL (fchownat, int, (int fd, char const *file, - uid_t owner, gid_t group, int flag)); -# else -# if !1 -_GL_FUNCDECL_SYS (fchownat, int, (int fd, char const *file, - uid_t owner, gid_t group, int flag) - _GL_ARG_NONNULL ((2))); -# endif -_GL_CXXALIAS_SYS (fchownat, int, (int fd, char const *file, - uid_t owner, gid_t group, int flag)); -# endif -_GL_CXXALIASWARN (fchownat); -#elif defined GNULIB_POSIXCHECK -# undef fchownat -# if HAVE_RAW_DECL_FCHOWNAT -_GL_WARN_ON_USE (fchownat, "fchownat is not portable - " - "use gnulib module openat for portability"); -# endif -#endif - - -#if 0 -/* Synchronize changes to a file. - Return 0 if successful, otherwise -1 and errno set. - See POSIX:2008 specification - . */ -# if !1 || !1 -_GL_FUNCDECL_SYS (fdatasync, int, (int fd)); -# endif -_GL_CXXALIAS_SYS (fdatasync, int, (int fd)); -_GL_CXXALIASWARN (fdatasync); -#elif defined GNULIB_POSIXCHECK -# undef fdatasync -# if HAVE_RAW_DECL_FDATASYNC -_GL_WARN_ON_USE (fdatasync, "fdatasync is unportable - " - "use gnulib module fdatasync for portability"); -# endif -#endif - - -#if 0 -/* Synchronize changes, including metadata, to a file. - Return 0 if successful, otherwise -1 and errno set. - See POSIX:2008 specification - . */ -# if !1 -_GL_FUNCDECL_SYS (fsync, int, (int fd)); -# endif -_GL_CXXALIAS_SYS (fsync, int, (int fd)); -_GL_CXXALIASWARN (fsync); -#elif defined GNULIB_POSIXCHECK -# undef fsync -# if HAVE_RAW_DECL_FSYNC -_GL_WARN_ON_USE (fsync, "fsync is unportable - " - "use gnulib module fsync for portability"); -# endif -#endif - - -#if 0 -/* Change the size of the file to which FD is opened to become equal to LENGTH. - Return 0 if successful, otherwise -1 and errno set. - See the POSIX:2008 specification - . */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef ftruncate -# define ftruncate rpl_ftruncate -# endif -_GL_FUNCDECL_RPL (ftruncate, int, (int fd, off_t length)); -_GL_CXXALIAS_RPL (ftruncate, int, (int fd, off_t length)); -# else -# if !1 -_GL_FUNCDECL_SYS (ftruncate, int, (int fd, off_t length)); -# endif -_GL_CXXALIAS_SYS (ftruncate, int, (int fd, off_t length)); -# endif -_GL_CXXALIASWARN (ftruncate); -#elif defined GNULIB_POSIXCHECK -# undef ftruncate -# if HAVE_RAW_DECL_FTRUNCATE -_GL_WARN_ON_USE (ftruncate, "ftruncate is unportable - " - "use gnulib module ftruncate for portability"); -# endif -#endif - - -#if 0 -/* Get the name of the current working directory, and put it in SIZE bytes - of BUF. - Return BUF if successful, or NULL if the directory couldn't be determined - or SIZE was too small. - See the POSIX:2008 specification - . - Additionally, the gnulib module 'getcwd' guarantees the following GNU - extension: If BUF is NULL, an array is allocated with 'malloc'; the array - is SIZE bytes long, unless SIZE == 0, in which case it is as big as - necessary. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define getcwd rpl_getcwd -# endif -_GL_FUNCDECL_RPL (getcwd, char *, (char *buf, size_t size)); -_GL_CXXALIAS_RPL (getcwd, char *, (char *buf, size_t size)); -# else -/* Need to cast, because on mingw, the second parameter is - int size. */ -_GL_CXXALIAS_SYS_CAST (getcwd, char *, (char *buf, size_t size)); -# endif -_GL_CXXALIASWARN (getcwd); -#elif defined GNULIB_POSIXCHECK -# undef getcwd -# if HAVE_RAW_DECL_GETCWD -_GL_WARN_ON_USE (getcwd, "getcwd is unportable - " - "use gnulib module getcwd for portability"); -# endif -#endif - - -#if 0 -/* Return the NIS domain name of the machine. - WARNING! The NIS domain name is unrelated to the fully qualified host name - of the machine. It is also unrelated to email addresses. - WARNING! The NIS domain name is usually the empty string or "(none)" when - not using NIS. - - Put up to LEN bytes of the NIS domain name into NAME. - Null terminate it if the name is shorter than LEN. - If the NIS domain name is longer than LEN, set errno = EINVAL and return -1. - Return 0 if successful, otherwise set errno and return -1. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef getdomainname -# define getdomainname rpl_getdomainname -# endif -_GL_FUNCDECL_RPL (getdomainname, int, (char *name, size_t len) - _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (getdomainname, int, (char *name, size_t len)); -# else -# if !1 -_GL_FUNCDECL_SYS (getdomainname, int, (char *name, size_t len) - _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (getdomainname, int, (char *name, size_t len)); -# endif -_GL_CXXALIASWARN (getdomainname); -#elif defined GNULIB_POSIXCHECK -# undef getdomainname -# if HAVE_RAW_DECL_GETDOMAINNAME -_GL_WARN_ON_USE (getdomainname, "getdomainname is unportable - " - "use gnulib module getdomainname for portability"); -# endif -#endif - - -#if 1 -/* Return the maximum number of file descriptors in the current process. - In POSIX, this is same as sysconf (_SC_OPEN_MAX). */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef getdtablesize -# define getdtablesize rpl_getdtablesize -# endif -_GL_FUNCDECL_RPL (getdtablesize, int, (void)); -_GL_CXXALIAS_RPL (getdtablesize, int, (void)); -# else -# if !1 -_GL_FUNCDECL_SYS (getdtablesize, int, (void)); -# endif -/* Need to cast, because on AIX, the parameter list is - (...). */ -_GL_CXXALIAS_SYS_CAST (getdtablesize, int, (void)); -# endif -_GL_CXXALIASWARN (getdtablesize); -#elif defined GNULIB_POSIXCHECK -# undef getdtablesize -# if HAVE_RAW_DECL_GETDTABLESIZE -_GL_WARN_ON_USE (getdtablesize, "getdtablesize is unportable - " - "use gnulib module getdtablesize for portability"); -# endif -#endif - - -#if 0 -/* Return the supplemental groups that the current process belongs to. - It is unspecified whether the effective group id is in the list. - If N is 0, return the group count; otherwise, N describes how many - entries are available in GROUPS. Return -1 and set errno if N is - not 0 and not large enough. Fails with ENOSYS on some systems. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef getgroups -# define getgroups rpl_getgroups -# endif -_GL_FUNCDECL_RPL (getgroups, int, (int n, gid_t *groups)); -_GL_CXXALIAS_RPL (getgroups, int, (int n, gid_t *groups)); -# else -# if !1 -_GL_FUNCDECL_SYS (getgroups, int, (int n, gid_t *groups)); -# endif -_GL_CXXALIAS_SYS (getgroups, int, (int n, gid_t *groups)); -# endif -_GL_CXXALIASWARN (getgroups); -#elif defined GNULIB_POSIXCHECK -# undef getgroups -# if HAVE_RAW_DECL_GETGROUPS -_GL_WARN_ON_USE (getgroups, "getgroups is unportable - " - "use gnulib module getgroups for portability"); -# endif -#endif - - -#if 0 -/* Return the standard host name of the machine. - WARNING! The host name may or may not be fully qualified. - - Put up to LEN bytes of the host name into NAME. - Null terminate it if the name is shorter than LEN. - If the host name is longer than LEN, set errno = EINVAL and return -1. - Return 0 if successful, otherwise set errno and return -1. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef gethostname -# define gethostname rpl_gethostname -# endif -_GL_FUNCDECL_RPL (gethostname, int, (char *name, size_t len) - _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (gethostname, int, (char *name, size_t len)); -# else -# if !1 -_GL_FUNCDECL_SYS (gethostname, int, (char *name, size_t len) - _GL_ARG_NONNULL ((1))); -# endif -/* Need to cast, because on Solaris 10 and OSF/1 5.1 systems, the second - parameter is - int len. */ -_GL_CXXALIAS_SYS_CAST (gethostname, int, (char *name, size_t len)); -# endif -_GL_CXXALIASWARN (gethostname); -#elif 0 -# undef gethostname -# define gethostname gethostname_used_without_requesting_gnulib_module_gethostname -#elif defined GNULIB_POSIXCHECK -# undef gethostname -# if HAVE_RAW_DECL_GETHOSTNAME -_GL_WARN_ON_USE (gethostname, "gethostname is unportable - " - "use gnulib module gethostname for portability"); -# endif -#endif - - -#if 0 -/* Returns the user's login name, or NULL if it cannot be found. Upon error, - returns NULL with errno set. - - See . - - Most programs don't need to use this function, because the information is - available through environment variables: - ${LOGNAME-$USER} on Unix platforms, - $USERNAME on native Windows platforms. - */ -# if !1 -_GL_FUNCDECL_SYS (getlogin, char *, (void)); -# endif -_GL_CXXALIAS_SYS (getlogin, char *, (void)); -_GL_CXXALIASWARN (getlogin); -#elif defined GNULIB_POSIXCHECK -# undef getlogin -# if HAVE_RAW_DECL_GETLOGIN -_GL_WARN_ON_USE (getlogin, "getlogin is unportable - " - "use gnulib module getlogin for portability"); -# endif -#endif - - -#if 0 -/* Copies the user's login name to NAME. - The array pointed to by NAME has room for SIZE bytes. - - Returns 0 if successful. Upon error, an error number is returned, or -1 in - the case that the login name cannot be found but no specific error is - provided (this case is hopefully rare but is left open by the POSIX spec). - - See . - - Most programs don't need to use this function, because the information is - available through environment variables: - ${LOGNAME-$USER} on Unix platforms, - $USERNAME on native Windows platforms. - */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define getlogin_r rpl_getlogin_r -# endif -_GL_FUNCDECL_RPL (getlogin_r, int, (char *name, size_t size) - _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (getlogin_r, int, (char *name, size_t size)); -# else -# if !1 -_GL_FUNCDECL_SYS (getlogin_r, int, (char *name, size_t size) - _GL_ARG_NONNULL ((1))); -# endif -/* Need to cast, because on Solaris 10 systems, the second argument is - int size. */ -_GL_CXXALIAS_SYS_CAST (getlogin_r, int, (char *name, size_t size)); -# endif -_GL_CXXALIASWARN (getlogin_r); -#elif defined GNULIB_POSIXCHECK -# undef getlogin_r -# if HAVE_RAW_DECL_GETLOGIN_R -_GL_WARN_ON_USE (getlogin_r, "getlogin_r is unportable - " - "use gnulib module getlogin_r for portability"); -# endif -#endif - - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define getpagesize rpl_getpagesize -# endif -_GL_FUNCDECL_RPL (getpagesize, int, (void)); -_GL_CXXALIAS_RPL (getpagesize, int, (void)); -# else -/* On HP-UX, getpagesize exists, but it is not declared in even if - the compiler options -D_HPUX_SOURCE -D_XOPEN_SOURCE=600 are used. */ -# if defined __hpux -_GL_FUNCDECL_SYS (getpagesize, int, (void)); -# endif -# if !1 -# if !defined getpagesize -/* This is for POSIX systems. */ -# if !defined _gl_getpagesize && defined _SC_PAGESIZE -# if ! (defined __VMS && __VMS_VER < 70000000) -# define _gl_getpagesize() sysconf (_SC_PAGESIZE) -# endif -# endif -/* This is for older VMS. */ -# if !defined _gl_getpagesize && defined __VMS -# ifdef __ALPHA -# define _gl_getpagesize() 8192 -# else -# define _gl_getpagesize() 512 -# endif -# endif -/* This is for BeOS. */ -# if !defined _gl_getpagesize && 0 -# if defined B_PAGE_SIZE -# define _gl_getpagesize() B_PAGE_SIZE -# endif -# endif -/* This is for AmigaOS4.0. */ -# if !defined _gl_getpagesize && defined __amigaos4__ -# define _gl_getpagesize() 2048 -# endif -/* This is for older Unix systems. */ -# if !defined _gl_getpagesize && 0 -# ifdef EXEC_PAGESIZE -# define _gl_getpagesize() EXEC_PAGESIZE -# else -# ifdef NBPG -# ifndef CLSIZE -# define CLSIZE 1 -# endif -# define _gl_getpagesize() (NBPG * CLSIZE) -# else -# ifdef NBPC -# define _gl_getpagesize() NBPC -# endif -# endif -# endif -# endif -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define getpagesize() _gl_getpagesize () -# else -# if !GNULIB_defined_getpagesize_function -_GL_UNISTD_INLINE int -getpagesize () -{ - return _gl_getpagesize (); -} -# define GNULIB_defined_getpagesize_function 1 -# endif -# endif -# endif -# endif -/* Need to cast, because on Cygwin 1.5.x systems, the return type is size_t. */ -_GL_CXXALIAS_SYS_CAST (getpagesize, int, (void)); -# endif -# if 1 -_GL_CXXALIASWARN (getpagesize); -# endif -#elif defined GNULIB_POSIXCHECK -# undef getpagesize -# if HAVE_RAW_DECL_GETPAGESIZE -_GL_WARN_ON_USE (getpagesize, "getpagesize is unportable - " - "use gnulib module getpagesize for portability"); -# endif -#endif - - -#if 0 -/* Function getpass() from module 'getpass': - Read a password from /dev/tty or stdin. - Function getpass() from module 'getpass-gnu': - Read a password of arbitrary length from /dev/tty or stdin. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef getpass -# define getpass rpl_getpass -# endif -_GL_FUNCDECL_RPL (getpass, char *, (const char *prompt) - _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (getpass, char *, (const char *prompt)); -# else -# if !1 -_GL_FUNCDECL_SYS (getpass, char *, (const char *prompt) - _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (getpass, char *, (const char *prompt)); -# endif -_GL_CXXALIASWARN (getpass); -#elif defined GNULIB_POSIXCHECK -# undef getpass -# if HAVE_RAW_DECL_GETPASS -_GL_WARN_ON_USE (getpass, "getpass is unportable - " - "use gnulib module getpass or getpass-gnu for portability"); -# endif -#endif - - -#if 0 -/* Return the next valid login shell on the system, or NULL when the end of - the list has been reached. */ -# if !1 -_GL_FUNCDECL_SYS (getusershell, char *, (void)); -# endif -_GL_CXXALIAS_SYS (getusershell, char *, (void)); -_GL_CXXALIASWARN (getusershell); -#elif defined GNULIB_POSIXCHECK -# undef getusershell -# if HAVE_RAW_DECL_GETUSERSHELL -_GL_WARN_ON_USE (getusershell, "getusershell is unportable - " - "use gnulib module getusershell for portability"); -# endif -#endif - -#if 0 -/* Rewind to pointer that is advanced at each getusershell() call. */ -# if !1 -_GL_FUNCDECL_SYS (setusershell, void, (void)); -# endif -_GL_CXXALIAS_SYS (setusershell, void, (void)); -_GL_CXXALIASWARN (setusershell); -#elif defined GNULIB_POSIXCHECK -# undef setusershell -# if HAVE_RAW_DECL_SETUSERSHELL -_GL_WARN_ON_USE (setusershell, "setusershell is unportable - " - "use gnulib module getusershell for portability"); -# endif -#endif - -#if 0 -/* Free the pointer that is advanced at each getusershell() call and - associated resources. */ -# if !1 -_GL_FUNCDECL_SYS (endusershell, void, (void)); -# endif -_GL_CXXALIAS_SYS (endusershell, void, (void)); -_GL_CXXALIASWARN (endusershell); -#elif defined GNULIB_POSIXCHECK -# undef endusershell -# if HAVE_RAW_DECL_ENDUSERSHELL -_GL_WARN_ON_USE (endusershell, "endusershell is unportable - " - "use gnulib module getusershell for portability"); -# endif -#endif - - -#if 0 -/* Determine whether group id is in calling user's group list. */ -# if !1 -_GL_FUNCDECL_SYS (group_member, int, (gid_t gid)); -# endif -_GL_CXXALIAS_SYS (group_member, int, (gid_t gid)); -_GL_CXXALIASWARN (group_member); -#elif defined GNULIB_POSIXCHECK -# undef group_member -# if HAVE_RAW_DECL_GROUP_MEMBER -_GL_WARN_ON_USE (group_member, "group_member is unportable - " - "use gnulib module group-member for portability"); -# endif -#endif - - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef isatty -# define isatty rpl_isatty -# endif -_GL_FUNCDECL_RPL (isatty, int, (int fd)); -_GL_CXXALIAS_RPL (isatty, int, (int fd)); -# else -_GL_CXXALIAS_SYS (isatty, int, (int fd)); -# endif -_GL_CXXALIASWARN (isatty); -#elif defined GNULIB_POSIXCHECK -# undef isatty -# if HAVE_RAW_DECL_ISATTY -_GL_WARN_ON_USE (isatty, "isatty has portability problems on native Windows - " - "use gnulib module isatty for portability"); -# endif -#endif - - -#if 0 -/* Change the owner of FILE to UID (if UID is not -1) and the group of FILE - to GID (if GID is not -1). Do not follow symbolic links. - Return 0 if successful, otherwise -1 and errno set. - See the POSIX:2008 specification - . */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef lchown -# define lchown rpl_lchown -# endif -_GL_FUNCDECL_RPL (lchown, int, (char const *file, uid_t owner, gid_t group) - _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (lchown, int, (char const *file, uid_t owner, gid_t group)); -# else -# if !1 -_GL_FUNCDECL_SYS (lchown, int, (char const *file, uid_t owner, gid_t group) - _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (lchown, int, (char const *file, uid_t owner, gid_t group)); -# endif -_GL_CXXALIASWARN (lchown); -#elif defined GNULIB_POSIXCHECK -# undef lchown -# if HAVE_RAW_DECL_LCHOWN -_GL_WARN_ON_USE (lchown, "lchown is unportable to pre-POSIX.1-2001 systems - " - "use gnulib module lchown for portability"); -# endif -#endif - - -#if 0 -/* Create a new hard link for an existing file. - Return 0 if successful, otherwise -1 and errno set. - See POSIX:2008 specification - . */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define link rpl_link -# endif -_GL_FUNCDECL_RPL (link, int, (const char *path1, const char *path2) - _GL_ARG_NONNULL ((1, 2))); -_GL_CXXALIAS_RPL (link, int, (const char *path1, const char *path2)); -# else -# if !1 -_GL_FUNCDECL_SYS (link, int, (const char *path1, const char *path2) - _GL_ARG_NONNULL ((1, 2))); -# endif -_GL_CXXALIAS_SYS (link, int, (const char *path1, const char *path2)); -# endif -_GL_CXXALIASWARN (link); -#elif defined GNULIB_POSIXCHECK -# undef link -# if HAVE_RAW_DECL_LINK -_GL_WARN_ON_USE (link, "link is unportable - " - "use gnulib module link for portability"); -# endif -#endif - - -#if 0 -/* Create a new hard link for an existing file, relative to two - directories. FLAG controls whether symlinks are followed. - Return 0 if successful, otherwise -1 and errno set. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef linkat -# define linkat rpl_linkat -# endif -_GL_FUNCDECL_RPL (linkat, int, - (int fd1, const char *path1, int fd2, const char *path2, - int flag) - _GL_ARG_NONNULL ((2, 4))); -_GL_CXXALIAS_RPL (linkat, int, - (int fd1, const char *path1, int fd2, const char *path2, - int flag)); -# else -# if !1 -_GL_FUNCDECL_SYS (linkat, int, - (int fd1, const char *path1, int fd2, const char *path2, - int flag) - _GL_ARG_NONNULL ((2, 4))); -# endif -_GL_CXXALIAS_SYS (linkat, int, - (int fd1, const char *path1, int fd2, const char *path2, - int flag)); -# endif -_GL_CXXALIASWARN (linkat); -#elif defined GNULIB_POSIXCHECK -# undef linkat -# if HAVE_RAW_DECL_LINKAT -_GL_WARN_ON_USE (linkat, "linkat is unportable - " - "use gnulib module linkat for portability"); -# endif -#endif - - -#if 0 -/* Set the offset of FD relative to SEEK_SET, SEEK_CUR, or SEEK_END. - Return the new offset if successful, otherwise -1 and errno set. - See the POSIX:2008 specification - . */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define lseek rpl_lseek -# endif -_GL_FUNCDECL_RPL (lseek, off_t, (int fd, off_t offset, int whence)); -_GL_CXXALIAS_RPL (lseek, off_t, (int fd, off_t offset, int whence)); -# else -_GL_CXXALIAS_SYS (lseek, off_t, (int fd, off_t offset, int whence)); -# endif -_GL_CXXALIASWARN (lseek); -#elif defined GNULIB_POSIXCHECK -# undef lseek -# if HAVE_RAW_DECL_LSEEK -_GL_WARN_ON_USE (lseek, "lseek does not fail with ESPIPE on pipes on some " - "systems - use gnulib module lseek for portability"); -# endif -#endif - - -#if 0 -/* Create a pipe, defaulting to O_BINARY mode. - Store the read-end as fd[0] and the write-end as fd[1]. - Return 0 upon success, or -1 with errno set upon failure. */ -# if !1 -_GL_FUNCDECL_SYS (pipe, int, (int fd[2]) _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (pipe, int, (int fd[2])); -_GL_CXXALIASWARN (pipe); -#elif defined GNULIB_POSIXCHECK -# undef pipe -# if HAVE_RAW_DECL_PIPE -_GL_WARN_ON_USE (pipe, "pipe is unportable - " - "use gnulib module pipe-posix for portability"); -# endif -#endif - - -#if 0 -/* Create a pipe, applying the given flags when opening the read-end of the - pipe and the write-end of the pipe. - The flags are a bitmask, possibly including O_CLOEXEC (defined in ) - and O_TEXT, O_BINARY (defined in "binary-io.h"). - Store the read-end as fd[0] and the write-end as fd[1]. - Return 0 upon success, or -1 with errno set upon failure. - See also the Linux man page at - . */ -# if 1 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define pipe2 rpl_pipe2 -# endif -_GL_FUNCDECL_RPL (pipe2, int, (int fd[2], int flags) _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (pipe2, int, (int fd[2], int flags)); -# else -_GL_FUNCDECL_SYS (pipe2, int, (int fd[2], int flags) _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_SYS (pipe2, int, (int fd[2], int flags)); -# endif -_GL_CXXALIASWARN (pipe2); -#elif defined GNULIB_POSIXCHECK -# undef pipe2 -# if HAVE_RAW_DECL_PIPE2 -_GL_WARN_ON_USE (pipe2, "pipe2 is unportable - " - "use gnulib module pipe2 for portability"); -# endif -#endif - - -#if 0 -/* Read at most BUFSIZE bytes from FD into BUF, starting at OFFSET. - Return the number of bytes placed into BUF if successful, otherwise - set errno and return -1. 0 indicates EOF. - See the POSIX:2008 specification - . */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef pread -# define pread rpl_pread -# endif -_GL_FUNCDECL_RPL (pread, ssize_t, - (int fd, void *buf, size_t bufsize, off_t offset) - _GL_ARG_NONNULL ((2))); -_GL_CXXALIAS_RPL (pread, ssize_t, - (int fd, void *buf, size_t bufsize, off_t offset)); -# else -# if !1 -_GL_FUNCDECL_SYS (pread, ssize_t, - (int fd, void *buf, size_t bufsize, off_t offset) - _GL_ARG_NONNULL ((2))); -# endif -_GL_CXXALIAS_SYS (pread, ssize_t, - (int fd, void *buf, size_t bufsize, off_t offset)); -# endif -_GL_CXXALIASWARN (pread); -#elif defined GNULIB_POSIXCHECK -# undef pread -# if HAVE_RAW_DECL_PREAD -_GL_WARN_ON_USE (pread, "pread is unportable - " - "use gnulib module pread for portability"); -# endif -#endif - - -#if 0 -/* Write at most BUFSIZE bytes from BUF into FD, starting at OFFSET. - Return the number of bytes written if successful, otherwise - set errno and return -1. 0 indicates nothing written. See the - POSIX:2008 specification - . */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef pwrite -# define pwrite rpl_pwrite -# endif -_GL_FUNCDECL_RPL (pwrite, ssize_t, - (int fd, const void *buf, size_t bufsize, off_t offset) - _GL_ARG_NONNULL ((2))); -_GL_CXXALIAS_RPL (pwrite, ssize_t, - (int fd, const void *buf, size_t bufsize, off_t offset)); -# else -# if !1 -_GL_FUNCDECL_SYS (pwrite, ssize_t, - (int fd, const void *buf, size_t bufsize, off_t offset) - _GL_ARG_NONNULL ((2))); -# endif -_GL_CXXALIAS_SYS (pwrite, ssize_t, - (int fd, const void *buf, size_t bufsize, off_t offset)); -# endif -_GL_CXXALIASWARN (pwrite); -#elif defined GNULIB_POSIXCHECK -# undef pwrite -# if HAVE_RAW_DECL_PWRITE -_GL_WARN_ON_USE (pwrite, "pwrite is unportable - " - "use gnulib module pwrite for portability"); -# endif -#endif - - -#if 0 -/* Read up to COUNT bytes from file descriptor FD into the buffer starting - at BUF. See the POSIX:2008 specification - . */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef read -# define read rpl_read -# endif -_GL_FUNCDECL_RPL (read, ssize_t, (int fd, void *buf, size_t count) - _GL_ARG_NONNULL ((2))); -_GL_CXXALIAS_RPL (read, ssize_t, (int fd, void *buf, size_t count)); -# else -/* Need to cast, because on mingw, the third parameter is - unsigned int count - and the return type is 'int'. */ -_GL_CXXALIAS_SYS_CAST (read, ssize_t, (int fd, void *buf, size_t count)); -# endif -_GL_CXXALIASWARN (read); -#endif - - -#if 0 -/* Read the contents of the symbolic link FILE and place the first BUFSIZE - bytes of it into BUF. Return the number of bytes placed into BUF if - successful, otherwise -1 and errno set. - See the POSIX:2008 specification - . */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define readlink rpl_readlink -# endif -_GL_FUNCDECL_RPL (readlink, ssize_t, - (const char *file, char *buf, size_t bufsize) - _GL_ARG_NONNULL ((1, 2))); -_GL_CXXALIAS_RPL (readlink, ssize_t, - (const char *file, char *buf, size_t bufsize)); -# else -# if !1 -_GL_FUNCDECL_SYS (readlink, ssize_t, - (const char *file, char *buf, size_t bufsize) - _GL_ARG_NONNULL ((1, 2))); -# endif -_GL_CXXALIAS_SYS (readlink, ssize_t, - (const char *file, char *buf, size_t bufsize)); -# endif -_GL_CXXALIASWARN (readlink); -#elif defined GNULIB_POSIXCHECK -# undef readlink -# if HAVE_RAW_DECL_READLINK -_GL_WARN_ON_USE (readlink, "readlink is unportable - " - "use gnulib module readlink for portability"); -# endif -#endif - - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define readlinkat rpl_readlinkat -# endif -_GL_FUNCDECL_RPL (readlinkat, ssize_t, - (int fd, char const *file, char *buf, size_t len) - _GL_ARG_NONNULL ((2, 3))); -_GL_CXXALIAS_RPL (readlinkat, ssize_t, - (int fd, char const *file, char *buf, size_t len)); -# else -# if !1 -_GL_FUNCDECL_SYS (readlinkat, ssize_t, - (int fd, char const *file, char *buf, size_t len) - _GL_ARG_NONNULL ((2, 3))); -# endif -_GL_CXXALIAS_SYS (readlinkat, ssize_t, - (int fd, char const *file, char *buf, size_t len)); -# endif -_GL_CXXALIASWARN (readlinkat); -#elif defined GNULIB_POSIXCHECK -# undef readlinkat -# if HAVE_RAW_DECL_READLINKAT -_GL_WARN_ON_USE (readlinkat, "readlinkat is not portable - " - "use gnulib module readlinkat for portability"); -# endif -#endif - - -#if 0 -/* Remove the directory DIR. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# define rmdir rpl_rmdir -# endif -_GL_FUNCDECL_RPL (rmdir, int, (char const *name) _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (rmdir, int, (char const *name)); -# else -_GL_CXXALIAS_SYS (rmdir, int, (char const *name)); -# endif -_GL_CXXALIASWARN (rmdir); -#elif defined GNULIB_POSIXCHECK -# undef rmdir -# if HAVE_RAW_DECL_RMDIR -_GL_WARN_ON_USE (rmdir, "rmdir is unportable - " - "use gnulib module rmdir for portability"); -# endif -#endif - - -#if 0 -/* Set the host name of the machine. - The host name may or may not be fully qualified. - - Put LEN bytes of NAME into the host name. - Return 0 if successful, otherwise, set errno and return -1. - - Platforms with no ability to set the hostname return -1 and set - errno = ENOSYS. */ -# if !1 || !1 -_GL_FUNCDECL_SYS (sethostname, int, (const char *name, size_t len) - _GL_ARG_NONNULL ((1))); -# endif -/* Need to cast, because on Solaris 11 2011-10, Mac OS X 10.5, IRIX 6.5 - and FreeBSD 6.4 the second parameter is int. On Solaris 11 - 2011-10, the first parameter is not const. */ -_GL_CXXALIAS_SYS_CAST (sethostname, int, (const char *name, size_t len)); -_GL_CXXALIASWARN (sethostname); -#elif defined GNULIB_POSIXCHECK -# undef sethostname -# if HAVE_RAW_DECL_SETHOSTNAME -_GL_WARN_ON_USE (sethostname, "sethostname is unportable - " - "use gnulib module sethostname for portability"); -# endif -#endif - - -#if 0 -/* Pause the execution of the current thread for N seconds. - Returns the number of seconds left to sleep. - See the POSIX:2008 specification - . */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef sleep -# define sleep rpl_sleep -# endif -_GL_FUNCDECL_RPL (sleep, unsigned int, (unsigned int n)); -_GL_CXXALIAS_RPL (sleep, unsigned int, (unsigned int n)); -# else -# if !1 -_GL_FUNCDECL_SYS (sleep, unsigned int, (unsigned int n)); -# endif -_GL_CXXALIAS_SYS (sleep, unsigned int, (unsigned int n)); -# endif -_GL_CXXALIASWARN (sleep); -#elif defined GNULIB_POSIXCHECK -# undef sleep -# if HAVE_RAW_DECL_SLEEP -_GL_WARN_ON_USE (sleep, "sleep is unportable - " - "use gnulib module sleep for portability"); -# endif -#endif - - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef symlink -# define symlink rpl_symlink -# endif -_GL_FUNCDECL_RPL (symlink, int, (char const *contents, char const *file) - _GL_ARG_NONNULL ((1, 2))); -_GL_CXXALIAS_RPL (symlink, int, (char const *contents, char const *file)); -# else -# if !1 -_GL_FUNCDECL_SYS (symlink, int, (char const *contents, char const *file) - _GL_ARG_NONNULL ((1, 2))); -# endif -_GL_CXXALIAS_SYS (symlink, int, (char const *contents, char const *file)); -# endif -_GL_CXXALIASWARN (symlink); -#elif defined GNULIB_POSIXCHECK -# undef symlink -# if HAVE_RAW_DECL_SYMLINK -_GL_WARN_ON_USE (symlink, "symlink is not portable - " - "use gnulib module symlink for portability"); -# endif -#endif - - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef symlinkat -# define symlinkat rpl_symlinkat -# endif -_GL_FUNCDECL_RPL (symlinkat, int, - (char const *contents, int fd, char const *file) - _GL_ARG_NONNULL ((1, 3))); -_GL_CXXALIAS_RPL (symlinkat, int, - (char const *contents, int fd, char const *file)); -# else -# if !1 -_GL_FUNCDECL_SYS (symlinkat, int, - (char const *contents, int fd, char const *file) - _GL_ARG_NONNULL ((1, 3))); -# endif -_GL_CXXALIAS_SYS (symlinkat, int, - (char const *contents, int fd, char const *file)); -# endif -_GL_CXXALIASWARN (symlinkat); -#elif defined GNULIB_POSIXCHECK -# undef symlinkat -# if HAVE_RAW_DECL_SYMLINKAT -_GL_WARN_ON_USE (symlinkat, "symlinkat is not portable - " - "use gnulib module symlinkat for portability"); -# endif -#endif - - -#if 0 -/* Change the size of the file designated by FILENAME to become equal to LENGTH. - Return 0 if successful, otherwise -1 and errno set. - See the POSIX:2008 specification - . */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef truncate -# define truncate rpl_truncate -# endif -_GL_FUNCDECL_RPL (truncate, int, (const char *filename, off_t length) - _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (truncate, int, (const char *filename, off_t length)); -# else -# if !1 -_GL_FUNCDECL_SYS (truncate, int, (const char *filename, off_t length) - _GL_ARG_NONNULL ((1))); -# endif -_GL_CXXALIAS_SYS (truncate, int, (const char *filename, off_t length)); -# endif -_GL_CXXALIASWARN (truncate); -#elif defined GNULIB_POSIXCHECK -# undef truncate -# if HAVE_RAW_DECL_TRUNCATE -_GL_WARN_ON_USE (truncate, "truncate is unportable - " - "use gnulib module truncate for portability"); -# endif -#endif - - -#if 0 -/* Store at most BUFLEN characters of the pathname of the terminal FD is - open on in BUF. Return 0 on success, otherwise an error number. */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef ttyname_r -# define ttyname_r rpl_ttyname_r -# endif -_GL_FUNCDECL_RPL (ttyname_r, int, - (int fd, char *buf, size_t buflen) _GL_ARG_NONNULL ((2))); -_GL_CXXALIAS_RPL (ttyname_r, int, - (int fd, char *buf, size_t buflen)); -# else -# if !1 -_GL_FUNCDECL_SYS (ttyname_r, int, - (int fd, char *buf, size_t buflen) _GL_ARG_NONNULL ((2))); -# endif -_GL_CXXALIAS_SYS (ttyname_r, int, - (int fd, char *buf, size_t buflen)); -# endif -_GL_CXXALIASWARN (ttyname_r); -#elif defined GNULIB_POSIXCHECK -# undef ttyname_r -# if HAVE_RAW_DECL_TTYNAME_R -_GL_WARN_ON_USE (ttyname_r, "ttyname_r is not portable - " - "use gnulib module ttyname_r for portability"); -# endif -#endif - - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef unlink -# define unlink rpl_unlink -# endif -_GL_FUNCDECL_RPL (unlink, int, (char const *file) _GL_ARG_NONNULL ((1))); -_GL_CXXALIAS_RPL (unlink, int, (char const *file)); -# else -_GL_CXXALIAS_SYS (unlink, int, (char const *file)); -# endif -_GL_CXXALIASWARN (unlink); -#elif defined GNULIB_POSIXCHECK -# undef unlink -# if HAVE_RAW_DECL_UNLINK -_GL_WARN_ON_USE (unlink, "unlink is not portable - " - "use gnulib module unlink for portability"); -# endif -#endif - - -#if 0 -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef unlinkat -# define unlinkat rpl_unlinkat -# endif -_GL_FUNCDECL_RPL (unlinkat, int, (int fd, char const *file, int flag) - _GL_ARG_NONNULL ((2))); -_GL_CXXALIAS_RPL (unlinkat, int, (int fd, char const *file, int flag)); -# else -# if !1 -_GL_FUNCDECL_SYS (unlinkat, int, (int fd, char const *file, int flag) - _GL_ARG_NONNULL ((2))); -# endif -_GL_CXXALIAS_SYS (unlinkat, int, (int fd, char const *file, int flag)); -# endif -_GL_CXXALIASWARN (unlinkat); -#elif defined GNULIB_POSIXCHECK -# undef unlinkat -# if HAVE_RAW_DECL_UNLINKAT -_GL_WARN_ON_USE (unlinkat, "unlinkat is not portable - " - "use gnulib module openat for portability"); -# endif -#endif - - -#if 0 -/* Pause the execution of the current thread for N microseconds. - Returns 0 on completion, or -1 on range error. - See the POSIX:2001 specification - . */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef usleep -# define usleep rpl_usleep -# endif -_GL_FUNCDECL_RPL (usleep, int, (useconds_t n)); -_GL_CXXALIAS_RPL (usleep, int, (useconds_t n)); -# else -# if !1 -_GL_FUNCDECL_SYS (usleep, int, (useconds_t n)); -# endif -/* Need to cast, because on Haiku, the first parameter is - unsigned int n. */ -_GL_CXXALIAS_SYS_CAST (usleep, int, (useconds_t n)); -# endif -_GL_CXXALIASWARN (usleep); -#elif defined GNULIB_POSIXCHECK -# undef usleep -# if HAVE_RAW_DECL_USLEEP -_GL_WARN_ON_USE (usleep, "usleep is unportable - " - "use gnulib module usleep for portability"); -# endif -#endif - - -#if 0 -/* Write up to COUNT bytes starting at BUF to file descriptor FD. - See the POSIX:2008 specification - . */ -# if 0 -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) -# undef write -# define write rpl_write -# endif -_GL_FUNCDECL_RPL (write, ssize_t, (int fd, const void *buf, size_t count) - _GL_ARG_NONNULL ((2))); -_GL_CXXALIAS_RPL (write, ssize_t, (int fd, const void *buf, size_t count)); -# else -/* Need to cast, because on mingw, the third parameter is - unsigned int count - and the return type is 'int'. */ -_GL_CXXALIAS_SYS_CAST (write, ssize_t, (int fd, const void *buf, size_t count)); -# endif -_GL_CXXALIASWARN (write); -#endif - -_GL_INLINE_HEADER_END - -#endif /* _GL_UNISTD_H */ -#endif /* _GL_INCLUDING_UNISTD_H */ -#endif /* _GL_UNISTD_H */ diff --git a/third_party/make/variable.c b/third_party/make/variable.c index 2b1c53214..3e7a6cbec 100644 --- a/third_party/make/variable.c +++ b/third_party/make/variable.c @@ -1,5 +1,5 @@ /* Internals of variables for GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,25 +12,31 @@ 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 . */ +this program. If not, see . */ -#include "libc/runtime/runtime.h" -#include "third_party/make/makeint.inc" +#include "makeint.h" -#include "third_party/make/filedef.h" -#include "third_party/make/dep.h" -#include "third_party/make/job.h" -#include "third_party/make/commands.h" -#include "third_party/make/variable.h" -#include "third_party/make/rule.h" -#include "third_party/make/hash.h" +#include + +#include "filedef.h" +#include "debug.h" +#include "dep.h" +#include "job.h" +#include "commands.h" +#include "variable.h" +#include "os.h" +#include "rule.h" +#include "hash.h" + +/* Incremented every time we enter target_environment(). */ +unsigned long long env_recursion = 0; /* Incremented every time we add or remove a global variable. */ -static unsigned long variable_changenum; +static unsigned long variable_changenum = 0; /* Chain of all pattern-specific variables. */ -static struct pattern_var *pattern_vars; +static struct pattern_var *pattern_vars = NULL; /* Pointer to the last struct in the pack of a specific size, from 1 to 255.*/ @@ -47,7 +53,7 @@ struct pattern_var * create_pattern_var (const char *target, const char *suffix) { size_t len = strlen (target); - struct pattern_var *p = xcalloc (1, sizeof (struct pattern_var)); + struct pattern_var *p = xcalloc (sizeof (struct pattern_var)); if (pattern_vars != 0) { @@ -94,10 +100,10 @@ create_pattern_var (const char *target, const char *suffix) /* Look up a target in the pattern-specific variable list. */ static struct pattern_var * -lookup_pattern_var (struct pattern_var *start, const char *target) +lookup_pattern_var (struct pattern_var *start, const char *target, + size_t targlen) { struct pattern_var *p; - size_t targlen = strlen (target); for (p = start ? start->next : pattern_vars; p != 0; p = p->next) { @@ -206,6 +212,34 @@ define_variable_in_set (const char *name, size_t length, var_slot = (struct variable **) hash_find_slot (&set->table, &var_key); v = *var_slot; +#ifdef VMS + /* VMS does not populate envp[] with DCL symbols and logical names which + historically are mapped to environment variables. + If the variable is not yet defined, then we need to check if getenv() + can find it. Do not do this for origin == o_env to avoid infinite + recursion */ + if (HASH_VACANT (v) && (origin != o_env)) + { + struct variable * vms_variable; + char * vname = alloca (length + 1); + char * vvalue; + + strncpy (vname, name, length); + vvalue = getenv(vname); + + /* Values starting with '$' are probably foreign commands. + We want to treat them as Shell aliases and not look them up here */ + if ((vvalue != NULL) && (vvalue[0] != '$')) + { + vms_variable = lookup_variable(name, length); + /* Refresh the slot */ + var_slot = (struct variable **) hash_find_slot (&set->table, + &var_key); + v = *var_slot; + } + } +#endif + if (env_overrides && origin == o_env) origin = o_env_override; @@ -235,7 +269,7 @@ define_variable_in_set (const char *name, size_t length, /* Create a new variable definition and add it to the hash table. */ - v = xcalloc (1, sizeof (struct variable)); + v = xcalloc (sizeof (struct variable)); v->name = xstrndup (name, length); v->length = (unsigned int) length; hash_insert_at (&set->table, v, var_slot); @@ -250,6 +284,8 @@ define_variable_in_set (const char *name, size_t length, v->export = v_default; v->exportable = 1; + /* Check the nul-terminated variable name. */ + name = v->name; if (*name != '_' && (*name < 'A' || *name > 'Z') && (*name < 'a' || *name > 'z')) v->exportable = 0; @@ -344,13 +380,12 @@ lookup_special_var (struct variable *var) { static unsigned long last_changenum = 0; - /* This one actually turns out to be very hard, due to the way the parser records targets. The way it works is that target information is collected - internally until make knows the target is completely specified. It unitl - it sees that some new construct (a new target or variable) is defined that - it knows the previous one is done. In short, this means that if you do - this: + internally until make knows the target is completely specified. Only when + it sees that some new construct (a new target or variable) is defined does + make know that the previous one is done. In short, this means that if + you do this: all: @@ -400,8 +435,7 @@ lookup_special_var (struct variable *var) p = &var->value[off]; } - memcpy (p, v->name, l); - p += l; + p = mempcpy (p, v->name, l); *(p++) = ' '; } *(p-1) = '\0'; @@ -435,15 +469,95 @@ lookup_variable (const char *name, size_t length) const struct variable_set *set = setlist->set; struct variable *v; - v = (struct variable *) hash_find_item ((struct hash_table *) &set->table, &var_key); + v = hash_find_item ((struct hash_table *) &set->table, &var_key); if (v && (!is_parent || !v->private_var)) return v->special ? lookup_special_var (v) : v; is_parent |= setlist->next_is_parent; } +#ifdef VMS + /* VMS doesn't populate envp[] with DCL symbols and logical names, which + historically are mapped to environment variables and returned by + getenv(). */ + { + char *vname = alloca (length + 1); + char *value; + strncpy (vname, name, length); + vname[length] = 0; + value = getenv (vname); + if (value != 0) + { + char *sptr; + int scnt; + + sptr = value; + scnt = 0; + + while ((sptr = strchr (sptr, '$'))) + { + scnt++; + sptr++; + } + + if (scnt > 0) + { + char *nvalue; + char *nptr; + + nvalue = alloca (strlen (value) + scnt + 1); + sptr = value; + nptr = nvalue; + + while (*sptr) + { + if (*sptr == '$') + { + *nptr++ = '$'; + *nptr++ = '$'; + } + else + { + *nptr++ = *sptr; + } + sptr++; + } + + *nptr = '\0'; + return define_variable (vname, length, nvalue, o_env, 1); + + } + + return define_variable (vname, length, value, o_env, 1); + } + } +#endif /* VMS */ + return 0; } +/* Lookup a variable whose name is a string starting at NAME + and with LENGTH chars. NAME need not be null-terminated. + Returns address of the 'struct variable' containing all info + on the variable, or nil if no such variable is defined. */ + +struct variable * +lookup_variable_for_file (const char *name, size_t length, struct file *file) +{ + struct variable *var; + struct variable_set_list *savev; + + if (file == NULL) + return lookup_variable (name, length); + + savev = current_variable_set_list; + current_variable_set_list = file->variables; + + var = lookup_variable (name, length); + + current_variable_set_list = savev; + + return var; +} /* Lookup a variable whose name is a string starting at NAME and with LENGTH chars in set SET. NAME need not be null-terminated. @@ -459,7 +573,7 @@ lookup_variable_in_set (const char *name, size_t length, var_key.name = (char *) name; var_key.length = (unsigned int) length; - return (struct variable *) hash_find_item ((struct hash_table *) &set->table, &var_key); + return hash_find_item ((struct hash_table *) &set->table, &var_key); } /* Initialize FILE's variable set list. If FILE already has a variable set @@ -513,8 +627,9 @@ initialize_file_variables (struct file *file, int reading) if (!reading && !file->pat_searched) { struct pattern_var *p; + const size_t targlen = strlen (file->name); - p = lookup_pattern_var (0, file->name); + p = lookup_pattern_var (0, file->name, targlen); if (p != 0) { struct variable_set_list *global = current_variable_set_list; @@ -553,7 +668,7 @@ initialize_file_variables (struct file *file, int reading) v->export = p->variable.export; v->private_var = p->variable.private_var; } - while ((p = lookup_pattern_var (p, file->name)) != 0); + while ((p = lookup_pattern_var (p, file->name, targlen)) != 0); current_variable_set_list = global; } @@ -750,15 +865,93 @@ define_automatic_variables (void) ? "" : "-", (remote_description == 0 || remote_description[0] == '\0') ? "" : remote_description); - define_variable_cname ("LANDLOCKMAKE_VERSION", - LANDLOCKMAKE_VERSION, o_default, 0); define_variable_cname ("MAKE_VERSION", buf, o_default, 0); define_variable_cname ("MAKE_HOST", make_host, o_default, 0); +#ifdef __MSDOS__ + /* Allow to specify a special shell just for Make, + and use $COMSPEC as the default $SHELL when appropriate. */ + { + static char shell_str[] = "SHELL"; + const int shlen = sizeof (shell_str) - 1; + struct variable *mshp = lookup_variable ("MAKESHELL", 9); + struct variable *comp = lookup_variable ("COMSPEC", 7); + + /* $(MAKESHELL) overrides $(SHELL) even if -e is in effect. */ + if (mshp) + (void) define_variable (shell_str, shlen, + mshp->value, o_env_override, 0); + else if (comp) + { + /* $(COMSPEC) shouldn't override $(SHELL). */ + struct variable *shp = lookup_variable (shell_str, shlen); + + if (!shp) + (void) define_variable (shell_str, shlen, comp->value, o_env, 0); + } + } +#elif defined(__EMX__) + { + static char shell_str[] = "SHELL"; + const int shlen = sizeof (shell_str) - 1; + struct variable *shell = lookup_variable (shell_str, shlen); + struct variable *replace = lookup_variable ("MAKESHELL", 9); + + /* if $MAKESHELL is defined in the environment assume o_env_override */ + if (replace && *replace->value && replace->origin == o_env) + replace->origin = o_env_override; + + /* if $MAKESHELL is not defined use $SHELL but only if the variable + did not come from the environment */ + if (!replace || !*replace->value) + if (shell && *shell->value && (shell->origin == o_env + || shell->origin == o_env_override)) + { + /* overwrite whatever we got from the environment */ + free (shell->value); + shell->value = xstrdup (default_shell); + shell->origin = o_default; + } + + /* Some people do not like cmd to be used as the default + if $SHELL is not defined in the Makefile. + With -DNO_CMD_DEFAULT you can turn off this behaviour */ +# ifndef NO_CMD_DEFAULT + /* otherwise use $COMSPEC */ + if (!replace || !*replace->value) + replace = lookup_variable ("COMSPEC", 7); + + /* otherwise use $OS2_SHELL */ + if (!replace || !*replace->value) + replace = lookup_variable ("OS2_SHELL", 9); +# else +# warning NO_CMD_DEFAULT: GNU Make will not use CMD.EXE as default shell +# endif + + if (replace && *replace->value) + /* overwrite $SHELL */ + (void) define_variable (shell_str, shlen, replace->value, + replace->origin, 0); + else + /* provide a definition if there is none */ + (void) define_variable (shell_str, shlen, default_shell, + o_default, 0); + } + +#endif + /* This won't override any definition, but it will provide one if there isn't one there. */ v = define_variable_cname ("SHELL", default_shell, o_default, 0); +#ifdef __MSDOS__ + v->export = v_export; /* Export always SHELL. */ +#endif + /* On MSDOS we do use SHELL from environment, since it isn't a standard + environment variable on MSDOS, so whoever sets it, does that on purpose. + On OS/2 we do not use SHELL from environment but we have already handled + that problem above. */ +#if !defined(__MSDOS__) && !defined(__EMX__) /* Don't let SHELL come from the environment. */ if (*v->value == '\0' || v->origin == o_env || v->origin == o_env_override) { @@ -766,6 +959,7 @@ define_automatic_variables (void) v->origin = o_file; v->value = xstrdup (default_shell); } +#endif /* Make sure MAKEFILES gets exported if it is set. */ v = define_variable_cname ("MAKEFILES", "", o_default, 0); @@ -773,6 +967,24 @@ define_automatic_variables (void) /* Define the magic D and F variables in terms of the automatic variables they are variations of. */ + +#if defined(__MSDOS__) || defined(WINDOWS32) + /* For consistency, remove the trailing backslash as well as slash. */ + define_variable_cname ("@D", "$(patsubst %/,%,$(patsubst %\\,%,$(dir $@)))", + o_automatic, 1); + define_variable_cname ("%D", "$(patsubst %/,%,$(patsubst %\\,%,$(dir $%)))", + o_automatic, 1); + define_variable_cname ("*D", "$(patsubst %/,%,$(patsubst %\\,%,$(dir $*)))", + o_automatic, 1); + define_variable_cname ("export) + { + case v_export: + break; + + case v_noexport: + return 0; + + case v_ifset: + if (v->origin == o_default) + return 0; + break; + + case v_default: + if (v->origin == o_default || v->origin == o_automatic) + /* Only export default variables by explicit request. */ + return 0; + + /* The variable doesn't have a name that can be exported. */ + if (! v->exportable) + return 0; + + if (! export_all_variables + && v->origin != o_command + && v->origin != o_env && v->origin != o_env_override) + return 0; + break; + } + + return 1; +} + /* Create a new environment for FILE's commands. If FILE is nil, this is for the 'shell' function. - The child's MAKELEVEL variable is incremented. */ + The child's MAKELEVEL variable is incremented. + If recursive is true then we're running a recursive make, else not. */ char ** -target_environment (struct file *file) +target_environment (struct file *file, int recursive) { struct variable_set_list *set_list; struct variable_set_list *s; struct hash_table table; struct variable **v_slot; struct variable **v_end; - struct variable makelevel_key; char **result_0; char **result; + const char *invalid = NULL; + /* If we got no value from the environment then never add the default. */ + int added_SHELL = shell_var.value == 0; + int found_makelevel = 0; + int found_mflags = 0; + int found_makeflags = 0; - if (file == 0) - set_list = current_variable_set_list; - else + /* If file is NULL we're creating the target environment for $(shell ...) + Remember this so we can just ignore recursion. */ + if (!file) + ++env_recursion; + + /* We need to update makeflags if (a) we're not recurive, (b) jobserver_auth + is enabled, and (c) we need to add invalidation. */ + if (!recursive && jobserver_auth) + invalid = jobserver_get_invalid_auth (); + + if (file) set_list = file->variables; + else + set_list = current_variable_set_list; hash_init (&table, VARIABLE_BUCKETS, variable_hash_1, variable_hash_2, variable_hash_cmp); - /* Run through all the variable sets in the list, - accumulating variables in TABLE. */ + /* Run through all the variable sets in the list, accumulating variables + in TABLE. We go from most specific to least, so the first variable we + encounter is the keeper. */ for (s = set_list; s != 0; s = s->next) { struct variable_set *set = s->set; + const int islocal = s == set_list; + const int isglobal = set == &global_variable_set; + v_slot = (struct variable **) set->table.ht_vec; v_end = v_slot + set->table.ht_size; for ( ; v_slot < v_end; v_slot++) if (! HASH_VACANT (*v_slot)) { - struct variable **new_slot; + struct variable **evslot; struct variable *v = *v_slot; - /* If this is a per-target variable and it hasn't been touched - already then look up the global version and take its export - value. */ - if (v->per_target && v->export == v_default) + if (!islocal && v->private_var) + continue; + + evslot = (struct variable **) hash_find_slot (&table, v); + + if (HASH_VACANT (*evslot)) { - struct variable *gv; - - gv = lookup_variable_in_set (v->name, strlen (v->name), - &global_variable_set); - if (gv) - v->export = gv->export; + /* We'll always add target-specific variables, since we may + discover that they should be exported later: we'll check + again below. For global variables only add them if they're + exportable. */ + if (!isglobal || should_export (v)) + hash_insert_at (&table, v, evslot); } - - switch (v->export) - { - case v_default: - if (v->origin == o_default || v->origin == o_automatic) - /* Only export default variables by explicit request. */ - continue; - - /* The variable doesn't have a name that can be exported. */ - if (! v->exportable) - continue; - - if (! export_all_variables - && v->origin != o_command - && v->origin != o_env && v->origin != o_env_override) - continue; - break; - - case v_export: - break; - - case v_noexport: - { - /* If this is the SHELL variable and it's not exported, - then add the value from our original environment, if - the original environment defined a value for SHELL. */ - if (streq (v->name, "SHELL") && shell_var.value) - { - v = &shell_var; - break; - } - continue; - } - - case v_ifset: - if (v->origin == o_default) - continue; - break; - } - - new_slot = (struct variable **) hash_find_slot (&table, v); - if (HASH_VACANT (*new_slot)) - hash_insert_at (&table, v, new_slot); + else if ((*evslot)->export == v_default) + /* We already have a variable but we don't know its status. */ + (*evslot)->export = v->export; } } - makelevel_key.name = (char *)MAKELEVEL_NAME; - makelevel_key.length = MAKELEVEL_LENGTH; - hash_delete (&table, &makelevel_key); - - result = result_0 = xmalloc ((table.ht_fill + 2) * sizeof (char *)); + result = result_0 = xmalloc ((table.ht_fill + 3) * sizeof (char *)); v_slot = (struct variable **) table.ht_vec; v_end = v_slot + table.ht_size; @@ -898,36 +1124,131 @@ target_environment (struct file *file) if (! HASH_VACANT (*v_slot)) { struct variable *v = *v_slot; + char *value = v->value; + char *cp = NULL; + + /* This might be here because it was a target-specific variable that + we didn't know the status of when we added it. */ + if (! should_export (v)) + continue; /* If V is recursively expanded and didn't come from the environment, expand its value. If it came from the environment, it should - go back into the environment unchanged. */ - if (v->recursive - && v->origin != o_env && v->origin != o_env_override) + go back into the environment unchanged... except MAKEFLAGS. */ + if (v->recursive && ((v->origin != o_env && v->origin != o_env_override) + || streq (v->name, MAKEFLAGS_NAME))) + value = cp = recursively_expand_for_file (v, file); + + /* If this is the SHELL variable remember we already added it. */ + if (!added_SHELL && streq (v->name, "SHELL")) { - char *value = recursively_expand_for_file (v, file); - *result++ = xstrdup (concat (3, v->name, "=", value)); - free (value); + added_SHELL = 1; + goto setit; } - else + + /* If this is MAKELEVEL, update it. */ + if (!found_makelevel && streq (v->name, MAKELEVEL_NAME)) { - *result++ = xstrdup (concat (3, v->name, "=", v->value)); + char val[INTSTR_LENGTH + 1]; + sprintf (val, "%u", makelevel + 1); + free (cp); + value = cp = xstrdup (val); + found_makelevel = 1; + goto setit; } + + /* If we need to reset jobserver, check for MAKEFLAGS / MFLAGS. */ + if (invalid) + { + if (!found_makeflags && streq (v->name, MAKEFLAGS_NAME)) + { + char *mf; + char *vars; + found_makeflags = 1; + + if (!strstr (value, " --" JOBSERVER_AUTH_OPT "=")) + goto setit; + + /* The invalid option must come before variable overrides. */ + vars = strstr (value, " -- "); + if (!vars) + mf = xstrdup (concat (2, value, invalid)); + else + { + size_t lf = vars - value; + size_t li = strlen (invalid); + mf = xmalloc (strlen (value) + li + 1); + strcpy (mempcpy (mempcpy (mf, value, lf), invalid, li), + vars); + } + free (cp); + value = cp = mf; + if (found_mflags) + invalid = NULL; + goto setit; + } + + if (!found_mflags && streq (v->name, "MFLAGS")) + { + const char *mf; + found_mflags = 1; + + if (!strstr (value, " --" JOBSERVER_AUTH_OPT "=")) + goto setit; + + if (v->origin != o_env) + goto setit; + mf = concat (2, value, invalid); + free (cp); + value = cp = xstrdup (mf); + if (found_makeflags) + invalid = NULL; + goto setit; + } + } + +#ifdef WINDOWS32 + if (streq (v->name, "Path") || streq (v->name, "PATH")) + { + if (!cp) + cp = xstrdup (value); + value = convert_Path_to_windows32 (cp, ';'); + goto setit; + } +#endif + + setit: + *result++ = xstrdup (concat (3, v->name, "=", value)); + free (cp); } - *result = xmalloc (100); - sprintf (*result, "%s=%u", MAKELEVEL_NAME, makelevel + 1); - *++result = 0; + if (!added_SHELL) + *result++ = xstrdup (concat (3, shell_var.name, "=", shell_var.value)); + + if (!found_makelevel) + { + char val[MAKELEVEL_LENGTH + 1 + INTSTR_LENGTH + 1]; + sprintf (val, "%s=%u", MAKELEVEL_NAME, makelevel + 1); + *result++ = xstrdup (val); + } + + *result = NULL; hash_free (&table, 0); + if (!file) + --env_recursion; + return result_0; } static struct variable * -set_special_var (struct variable *var) +set_special_var (struct variable *var, enum variable_origin origin) { - if (streq (var->name, RECIPEPREFIX_NAME)) + if (streq (var->name, MAKEFLAGS_NAME)) + reset_makeflags (origin); + + else if (streq (var->name, RECIPEPREFIX_NAME)) { /* The user is resetting the command introduction prefix. This has to happen immediately, so that subsequent rules are interpreted @@ -969,7 +1290,7 @@ do_variable_definition (const floc *flocp, const char *varname, const char *value, enum variable_origin origin, enum variable_flavor flavor, int target_var) { - const char *p; + const char *newval; char *alloc_value = NULL; struct variable *v; int append = 0; @@ -979,25 +1300,41 @@ do_variable_definition (const floc *flocp, const char *varname, switch (flavor) { - default: - case f_bogus: - /* Should not be possible. */ - abort (); case f_simple: /* A simple variable definition "var := value". Expand the value. We have to allocate memory since otherwise it'll clobber the variable buffer, and we may still need that if we're looking at a target-specific variable. */ - p = alloc_value = allocated_variable_expand (value); + newval = alloc_value = allocated_variable_expand (value); break; + case f_expand: + { + /* A POSIX "var :::= value" assignment. Expand the value, then it + becomes a recursive variable. After expansion convert all '$' + tokens to '$$' to resolve to '$' when recursively expanded. */ + char *t = allocated_variable_expand (value); + char *np = alloc_value = xmalloc (strlen (t) * 2 + 1); + char *op = t; + while (op[0] != '\0') + { + if (op[0] == '$') + *(np++) = '$'; + *(np++) = *(op++); + } + *np = '\0'; + free (t); + newval = alloc_value; + break; + } case f_shell: { /* A shell definition "var != value". Expand value, pass it to the shell, and store the result in recursively-expanded var. */ char *q = allocated_variable_expand (value); - p = alloc_value = shell_result (q); + alloc_value = shell_result (q); free (q); flavor = f_recursive; + newval = alloc_value; break; } case f_conditional: @@ -1013,7 +1350,7 @@ do_variable_definition (const floc *flocp, const char *varname, case f_recursive: /* A recursive variable definition "var = value". The value is used verbatim. */ - p = value; + newval = value; break; case f_append: case f_append_value: @@ -1038,15 +1375,16 @@ do_variable_definition (const floc *flocp, const char *varname, { /* There was no old value. This becomes a normal recursive definition. */ - p = value; + newval = value; flavor = f_recursive; } else { /* Paste the old and new values together in VALUE. */ - size_t oldlen, vallen; + size_t oldlen, vallen, alloclen; const char *val; + char *cp; char *tp = NULL; val = value; @@ -1071,31 +1409,175 @@ do_variable_definition (const floc *flocp, const char *varname, } oldlen = strlen (v->value); - p = alloc_value = xmalloc (oldlen + 1 + vallen + 1); + alloclen = oldlen + 1 + vallen + 1; + cp = alloc_value = xmalloc (alloclen); if (oldlen) { - memcpy (alloc_value, v->value, oldlen); - alloc_value[oldlen] = ' '; - ++oldlen; + char *s; + if (streq (varname, MAKEFLAGS_NAME) + && (s = strstr (v->value, " -- "))) + /* We found a separator in MAKEFLAGS. Ignore variable + assignments: set_special_var() will reconstruct things. */ + cp = mempcpy (cp, v->value, s - v->value); + else + cp = mempcpy (cp, v->value, oldlen); + *(cp++) = ' '; } - memcpy (&alloc_value[oldlen], val, vallen + 1); - + memcpy (cp, val, vallen + 1); free (tp); + newval = alloc_value; } - break; } + break; + case f_bogus: + default: + /* Should not be possible. */ + abort (); } + assert (newval); + +#ifdef __MSDOS__ + /* Many Unix Makefiles include a line saying "SHELL=/bin/sh", but + non-Unix systems don't conform to this default configuration (in + fact, most of them don't even have '/bin'). On the other hand, + $SHELL in the environment, if set, points to the real pathname of + the shell. + Therefore, we generally won't let lines like "SHELL=/bin/sh" from + the Makefile override $SHELL from the environment. But first, we + look for the basename of the shell in the directory where SHELL= + points, and along the $PATH; if it is found in any of these places, + we define $SHELL to be the actual pathname of the shell. Thus, if + you have bash.exe installed as d:/unix/bash.exe, and d:/unix is on + your $PATH, then SHELL=/usr/local/bin/bash will have the effect of + defining SHELL to be "d:/unix/bash.exe". */ + if ((origin == o_file || origin == o_override) + && strcmp (varname, "SHELL") == 0) + { + PATH_VAR (shellpath); + extern char * __dosexec_find_on_path (const char *, char *[], char *); + + /* See if we can find "/bin/sh.exe", "/bin/sh.com", etc. */ + if (__dosexec_find_on_path (p, NULL, shellpath)) + { + char *tp; + + for (tp = shellpath; *tp; tp++) + if (*tp == '\\') + *tp = '/'; + + v = define_variable_loc (varname, strlen (varname), + shellpath, origin, flavor == f_recursive, + flocp); + } + else + { + const char *shellbase, *bslash; + struct variable *pathv = lookup_variable ("PATH", 4); + char *path_string; + char *fake_env[2]; + size_t pathlen = 0; + + shellbase = strrchr (newval, '/'); + bslash = strrchr (newval, '\\'); + if (!shellbase || bslash > shellbase) + shellbase = bslash; + if (!shellbase && newval[1] == ':') + shellbase = newval + 1; + if (shellbase) + shellbase++; + else + shellbase = newval; + + /* Search for the basename of the shell (with standard + executable extensions) along the $PATH. */ + if (pathv) + pathlen = strlen (pathv->value); + path_string = xmalloc (5 + pathlen + 2 + 1); + /* On MSDOS, current directory is considered as part of $PATH. */ + sprintf (path_string, "PATH=.;%s", pathv ? pathv->value : ""); + fake_env[0] = path_string; + fake_env[1] = 0; + if (__dosexec_find_on_path (shellbase, fake_env, shellpath)) + { + char *tp; + + for (tp = shellpath; *tp; tp++) + if (*tp == '\\') + *tp = '/'; + + v = define_variable_loc (varname, strlen (varname), + shellpath, origin, + flavor == f_recursive, flocp); + } + else + v = lookup_variable (varname, strlen (varname)); + + free (path_string); + } + } + else +#endif /* __MSDOS__ */ +#ifdef WINDOWS32 + if ((origin == o_file || origin == o_override || origin == o_command) + && streq (varname, "SHELL")) + { + extern const char *default_shell; + + /* Call shell locator function. If it returns TRUE, then + set no_default_sh_exe to indicate sh was found and + set new value for SHELL variable. */ + + if (find_and_set_default_shell (newval)) + { + v = define_variable_in_set (varname, strlen (varname), default_shell, + origin, flavor == f_recursive, + (target_var + ? current_variable_set_list->set + : NULL), + flocp); + no_default_sh_exe = 0; + } + else + { + char *tp = alloc_value; + + alloc_value = allocated_variable_expand (newval); + + if (find_and_set_default_shell (alloc_value)) + { + v = define_variable_in_set (varname, strlen (varname), newval, + origin, flavor == f_recursive, + (target_var + ? current_variable_set_list->set + : NULL), + flocp); + no_default_sh_exe = 0; + } + else + v = lookup_variable (varname, strlen (varname)); + + free (tp); + } + } + else + v = NULL; + + /* If not $SHELL, or if $SHELL points to a program we didn't find, + just process this variable "as usual". */ + if (!v) +#endif + /* If we are defining variables inside an $(eval ...), we might have a different variable context pushed, not the global context (maybe we're inside a $(call ...) or something. Since this function is only ever invoked in places where we want to define globally visible variables, make sure we define this variable in the global set. */ - v = define_variable_in_set (varname, strlen (varname), p, - origin, flavor == f_recursive, + v = define_variable_in_set (varname, strlen (varname), newval, origin, + flavor == f_recursive || flavor == f_expand, (target_var ? current_variable_set_list->set : NULL), flocp); @@ -1104,13 +1586,13 @@ do_variable_definition (const floc *flocp, const char *varname, done: free (alloc_value); - return v->special ? set_special_var (v) : v; + return v->special ? set_special_var (v, origin) : v; } /* Parse P (a null-terminated string) as a variable definition. If it is not a variable definition, return NULL and the contents of *VAR - are undefined, except NAME is set to the first non-space character or NIL. + are undefined, except NAME points to the first non-space character or EOS. If it is a variable definition, return a pointer to the char after the assignment token and set the following fields (only) of *VAR: @@ -1122,15 +1604,17 @@ do_variable_definition (const floc *flocp, const char *varname, */ char * -parse_variable_definition (const char *p, struct variable *var) +parse_variable_definition (const char *str, struct variable *var) { - int wspace = 0; - const char *e = NULL; + const char *p = str; + const char *end = NULL; NEXT_TOKEN (p); var->name = (char *)p; var->length = 0; + /* Walk through STR until we find a valid assignment operator. Each time + through this loop P points to the next character to consider. */ while (1) { int c = *p++; @@ -1139,26 +1623,112 @@ parse_variable_definition (const char *p, struct variable *var) if (STOP_SET (c, MAP_COMMENT|MAP_NUL)) return NULL; + if (ISBLANK (c)) + { + /* Variable names can't contain spaces so if this is the second set + of spaces we know it's not a variable assignment. */ + if (end) + return NULL; + end = p - 1; + NEXT_TOKEN (p); + continue; + } + + /* If we found = we're done! */ + if (c == '=') + { + if (!end) + end = p - 1; + var->flavor = f_recursive; + break; + } + + if (c == ':') + { + if (!end) + end = p - 1; + + /* We need to distinguish :=, ::=, and :::=, and : outside of an + assignment (which means this is not a variable definition). */ + c = *p++; + if (c == '=') + { + var->flavor = f_simple; + break; + } + if (c == ':') + { + c = *p++; + if (c == '=') + { + var->flavor = f_simple; + break; + } + if (c == ':' && *p++ == '=') + { + var->flavor = f_expand; + break; + } + } + return NULL; + } + + /* See if it's one of the other two-byte operators. */ + if (*p == '=') + { + switch (c) + { + case '+': + var->flavor = f_append; + break; + case '?': + var->flavor = f_conditional; + break; + case '!': + var->flavor = f_shell; + break; + default: + goto other; + } + + if (!end) + end = p - 1; + ++p; + break; + } + + other: + /* We found a char which is not part of an assignment operator. + If we've seen whitespace, then we know this is not a variable + assignment since variable names cannot contain whitespace. */ + if (end) + return NULL; + if (c == '$') { - /* This begins a variable expansion reference. Make sure we don't - treat chars inside the reference as assignment tokens. */ + /* Skip any variable reference, to ensure we don't treat chars + inside the reference as assignment operators. */ char closeparen; unsigned int count; c = *p++; - if (c == '(') - closeparen = ')'; - else if (c == '{') - closeparen = '}'; - else if (c == '\0') - return NULL; - else - /* '$$' or '$X'. Either way, nothing special to do here. */ - continue; + switch (c) + { + case '(': + closeparen = ')'; + break; + case '{': + closeparen = '}'; + break; + case '\0': + return NULL; + default: + /* '$$' or '$X': skip it. */ + continue; + } - /* P now points past the opening paren or brace. - Count parens or braces until it is matched. */ + /* P now points past the opening paren or brace. Count parens or + braces until we find the closing paren/brace. */ for (count = 1; *p != '\0'; ++p) { if (*p == closeparen && --count == 0) @@ -1169,82 +1739,12 @@ parse_variable_definition (const char *p, struct variable *var) if (*p == c) ++count; } - continue; } - - /* If we find whitespace skip it, and remember we found it. */ - if (ISBLANK (c)) - { - wspace = 1; - e = p - 1; - NEXT_TOKEN (p); - c = *p; - if (c == '\0') - return NULL; - ++p; - } - - - if (c == '=') - { - var->flavor = f_recursive; - if (! e) - e = p - 1; - break; - } - - /* Match assignment variants (:=, +=, ?=, !=) */ - if (*p == '=') - { - switch (c) - { - case ':': - var->flavor = f_simple; - break; - case '+': - var->flavor = f_append; - break; - case '?': - var->flavor = f_conditional; - break; - case '!': - var->flavor = f_shell; - break; - default: - /* If we skipped whitespace, non-assignments means no var. */ - if (wspace) - return NULL; - - /* Might be assignment, or might be $= or #=. Check. */ - continue; - } - if (! e) - e = p - 1; - ++p; - break; - } - - /* Check for POSIX ::= syntax */ - if (c == ':') - { - /* A colon other than :=/::= is not a variable defn. */ - if (*p != ':' || p[1] != '=') - return NULL; - - /* POSIX allows ::= to be the same as GNU make's := */ - var->flavor = f_simple; - if (! e) - e = p - 1; - p += 2; - break; - } - - /* If we skipped whitespace, non-assignments means no var. */ - if (wspace) - return NULL; } - var->length = (unsigned int) (e - var->name); + /* We found a valid variable assignment: END points to the char after the + end of the variable name and P points to the char after the =. */ + var->length = (unsigned int) (end - var->name); var->value = next_token (p); return (char *)p; } @@ -1310,6 +1810,44 @@ try_variable_definition (const floc *flocp, const char *line, return vp; } + +/* These variables are internal to make, and so considered "defined" for the + purposes of warn_undefined even if they are not really defined. */ + +struct defined_vars + { + const char *name; + size_t len; + }; + +static const struct defined_vars defined_vars[] = { + { STRING_SIZE_TUPLE ("MAKECMDGOALS") }, + { STRING_SIZE_TUPLE ("MAKE_RESTARTS") }, + { STRING_SIZE_TUPLE ("MAKE_TERMOUT") }, + { STRING_SIZE_TUPLE ("MAKE_TERMERR") }, + { STRING_SIZE_TUPLE ("MAKEOVERRIDES") }, + { STRING_SIZE_TUPLE (".DEFAULT") }, + { STRING_SIZE_TUPLE ("-*-command-variables-*-") }, + { STRING_SIZE_TUPLE ("-*-eval-flags-*-") }, + { STRING_SIZE_TUPLE ("VPATH") }, + { STRING_SIZE_TUPLE ("GPATH") }, + { NULL, 0 } +}; + +void +warn_undefined (const char *name, size_t len) +{ + if (warn_undefined_variables_flag) + { + const struct defined_vars *dp; + for (dp = defined_vars; dp->name != NULL; ++dp) + if (dp->len == len && memcmp (dp->name, name, len) == 0) + return; + + error (reading_file, len, _("warning: undefined variable '%.*s'"), + (int)len, name); + } +} /* Print information for variable V, prefixing it with PREFIX. */ @@ -1344,7 +1882,6 @@ print_variable (const void *item, void *arg) origin = _("'override' directive"); break; case o_invalid: - default: abort (); } fputs ("# ", stdout); @@ -1468,7 +2005,7 @@ print_target_variables (const struct file *file) size_t l = strlen (file->name); char *t = alloca (l + 3); - strcpy (t, file->name); + memcpy (t, file->name, l); t[l] = ':'; t[l+1] = ' '; t[l+2] = '\0'; @@ -1476,3 +2013,25 @@ print_target_variables (const struct file *file) hash_map_arg (&file->variables->set->table, print_noauto_variable, t); } } + +#ifdef WINDOWS32 +void +sync_Path_environment () +{ + static char *environ_path = NULL; + char *oldpath = environ_path; + char *path = allocated_variable_expand ("PATH=$(PATH)"); + + if (!path) + return; + + /* Convert the value of PATH into something WINDOWS32 world can grok. + Note: convert_Path_to_windows32 must see only the value of PATH, + and see it from its first character, to do its tricky job. */ + convert_Path_to_windows32 (path + CSTRLEN ("PATH="), ';'); + + environ_path = path; + putenv (environ_path); + free (oldpath); +} +#endif diff --git a/third_party/make/variable.h b/third_party/make/variable.h index c7884e0f0..244da4f86 100644 --- a/third_party/make/variable.h +++ b/third_party/make/variable.h @@ -1,5 +1,5 @@ /* Definitions for using variables in GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,9 +12,11 @@ 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 . */ +this program. If not, see . */ -#include "third_party/make/hash.h" +#include "hash.h" + +struct file; /* Codes in a variable definition saying where the definition came from. Increasing numeric values signify less-overridable definitions. */ @@ -35,12 +37,21 @@ enum variable_flavor f_bogus, /* Bogus (error) */ f_simple, /* Simple definition (:= or ::=) */ f_recursive, /* Recursive definition (=) */ + f_expand, /* POSIX :::= assignment */ f_append, /* Appending definition (+=) */ f_conditional, /* Conditional definition (?=) */ f_shell, /* Shell assignment (!=) */ f_append_value /* Append unexpanded value */ }; +enum variable_export +{ + v_default = 0, /* Decide in target_environment. */ + v_export, /* Export this variable. */ + v_noexport, /* Don't export this variable. */ + v_ifset /* Export it if it has a non-default value. */ +}; + /* Structure that represents one variable definition. Each bucket of the hash table is a chain of these, chained through 'next'. */ @@ -73,12 +84,7 @@ struct variable enum variable_origin origin ENUM_BITFIELD (3); /* Variable origin. */ enum variable_export - { - v_export, /* Export this variable. */ - v_noexport, /* Don't export this variable. */ - v_ifset, /* Export it if it has a non-default value. */ - v_default /* Decide in target_environment. */ - } export ENUM_BITFIELD (2); + export ENUM_BITFIELD (2); /* Export control. */ }; /* Structure that represents a variable set. */ @@ -108,6 +114,7 @@ struct pattern_var struct variable variable; }; +extern unsigned long long env_recursion; extern char *variable_buffer; extern struct variable_set_list *current_variable_set_list; extern struct variable *default_goal_var; @@ -126,6 +133,7 @@ char *allocated_variable_expand_for_file (const char *line, struct file *file); allocated_variable_expand_for_file (line, (struct file *) 0) char *expand_argument (const char *str, const char *end); char *variable_expand_string (char *line, const char *string, size_t length); +char *initialize_variable_output (void); void install_variable_buffer (char **bufp, size_t *lenp); void restore_variable_buffer (char *buf, size_t len); @@ -174,6 +182,8 @@ void define_new_function(const floc *flocp, const char *name, unsigned int min, unsigned int max, unsigned int flags, gmk_func_ptr func); struct variable *lookup_variable (const char *name, size_t length); +struct variable *lookup_variable_for_file (const char *name, size_t length, + struct file *file); struct variable *lookup_variable_in_set (const char *name, size_t length, const struct variable_set *set); @@ -183,6 +193,7 @@ struct variable *define_variable_in_set (const char *name, size_t length, int recursive, struct variable_set *set, const floc *flocp); +void warn_undefined (const char* name, size_t length); /* Define a variable in the current variable set. */ @@ -221,16 +232,7 @@ void undefine_variable_in_set (const char *name, size_t length, #define undefine_variable_global(n,l,o) \ undefine_variable_in_set((n),(l),(o),NULL) -/* Warn that NAME is an undefined variable. */ - -#define warn_undefined(n,l) do{\ - if (warn_undefined_variables_flag) \ - error (reading_file, (l), \ - _("warning: undefined variable '%.*s'"), \ - (int)(l), (n)); \ - }while(0) - -char **target_environment (struct file *file); +char **target_environment (struct file *file, int recursive); struct pattern_var *create_pattern_var (const char *target, const char *suffix); diff --git a/third_party/make/version.c b/third_party/make/version.c index e793c75aa..42d03671f 100644 --- a/third_party/make/version.c +++ b/third_party/make/version.c @@ -1,5 +1,5 @@ -/* Record version and build host architecture for GNU make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +/* Record version and build host architecture for GNU Make. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,18 +12,18 @@ 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 . */ +this program. If not, see . */ /* We use instead of "config.h" so that a compilation using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h (which it would do because makeint.h was found in $srcdir). */ -#include "third_party/make/config.h" +#include "config.h" #ifndef MAKE_HOST # define MAKE_HOST "unknown" #endif -const char *version_string = VERSION; +const char *version_string = PACKAGE_VERSION; const char *make_host = MAKE_HOST; /* diff --git a/third_party/make/vpath.c b/third_party/make/vpath.c index 836537e90..522fbd73f 100644 --- a/third_party/make/vpath.c +++ b/third_party/make/vpath.c @@ -1,5 +1,5 @@ /* Implementation of pattern-matching file search paths for GNU Make. -Copyright (C) 1988-2020 Free Software Foundation, Inc. +Copyright (C) 1988-2023 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -12,11 +12,11 @@ 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 . */ +this program. If not, see . */ -#include "third_party/make/makeint.inc" -#include "third_party/make/filedef.h" -#include "third_party/make/variable.h" +#include "makeint.h" +#include "filedef.h" +#include "variable.h" /* Structure used to represent a selective VPATH searchpath. */ @@ -65,19 +65,10 @@ build_vpath_lists (void) vpaths = new; - /* If there is a VPATH variable with a nonnull value, construct the - general VPATH list from it. We use variable_expand rather than just - calling lookup_variable so that it will be recursively expanded. */ + /* If there is a VPATH variable with a nonnull expanded value, construct the + general VPATH list from it. */ - { - /* Turn off --warn-undefined-variables while we expand SHELL and IFS. */ - int save = warn_undefined_variables_flag; - warn_undefined_variables_flag = 0; - - p = variable_expand ("$(strip $(VPATH))"); - - warn_undefined_variables_flag = save; - } + p = variable_expand ("$(strip $(VPATH))"); if (*p != '\0') { @@ -98,19 +89,10 @@ build_vpath_lists (void) vpaths = save_vpaths; } - /* If there is a GPATH variable with a nonnull value, construct the - GPATH list from it. We use variable_expand rather than just - calling lookup_variable so that it will be recursively expanded. */ + /* If there is a GPATH variable with a nonnull expanded value, construct the + GPATH list from it. */ - { - /* Turn off --warn-undefined-variables while we expand SHELL and IFS. */ - int save = warn_undefined_variables_flag; - warn_undefined_variables_flag = 0; - - p = variable_expand ("$(strip $(GPATH))"); - - warn_undefined_variables_flag = save; - } + p = variable_expand ("$(strip $(GPATH))"); if (*p != '\0') { @@ -236,8 +218,7 @@ construct_vpath_list (char *pattern, char *dirpath) also define HAVE_DOS_PATHS would like us to recognize colons after the drive letter in the likes of "D:/foo/bar:C:/xyzzy". */ - && (*p != PATH_SEPARATOR_CHAR - || (p == v + 1 && (p[1] == '/' || p[1] == '\\'))) + && (*p != PATH_SEPARATOR_CHAR || (p == v + 1 && ISDIRSEP (p[1]))) #else && *p != PATH_SEPARATOR_CHAR #endif @@ -274,7 +255,7 @@ construct_vpath_list (char *pattern, char *dirpath) entry, to where the nil-pointer terminator goes. Usually this is maxelem - 1. If not, shrink down. */ if (elem < (maxelem - 1)) - vpath = xrealloc (vpath, (elem+1) * sizeof (const char *)); + vpath = xrealloc ((void *)vpath, (elem+1) * sizeof (const char *)); /* Put the nil-pointer terminator on the end of the VPATH list. */ vpath[elem] = NULL; @@ -376,15 +357,19 @@ selective_vpath_search (struct vpath *path, const char *file, size_t vlen = strlen (vpath[i]); /* Put the next VPATH entry into NAME at P and increment P past it. */ - memcpy (p, vpath[i], vlen); - p += vlen; + p = mempcpy (p, vpath[i], vlen); /* Add the directory prefix already in *FILE. */ if (name_dplen > 0) { +#ifndef VMS *p++ = '/'; - memcpy (p, file, name_dplen); - p += name_dplen; +#else + /* VMS: if this is not in VMS format, treat as Unix format */ + if ((*p != ':') && (*p != ']') && (*p != '>')) + *p++ = '/'; +#endif + p = mempcpy (p, file, name_dplen); } #ifdef HAVE_DOS_PATHS @@ -393,12 +378,23 @@ selective_vpath_search (struct vpath *path, const char *file, p[-1] = '/'; #endif /* Now add the name-within-directory at the end of NAME. */ +#ifndef VMS if (p != name && p[-1] != '/') { *p = '/'; memcpy (p + 1, filename, flen + 1); } else +#else + /* VMS use a slash if no directory terminator present */ + if (p != name && p[-1] != '/' && p[-1] != ':' && + p[-1] != '>' && p[-1] != ']') + { + *p = '/'; + memcpy (p + 1, filename, flen + 1); + } + else +#endif memcpy (p, filename, flen + 1); /* Check if the file is mentioned in a makefile. If *FILE is not @@ -440,13 +436,22 @@ selective_vpath_search (struct vpath *path, const char *file, { /* That file wasn't mentioned in the makefile. See if it actually exists. */ - /* Clobber a null into the name at the last slash. - Now NAME is the name of the directory to look in. */ - *p = '\0'; - /* We know the directory is in the hash table now because either - construct_vpath_list or the code just above put it there. - Does the file we seek exist in it? */ - exists_in_cache = exists = dir_file_exists_p (name, filename); + +#ifdef VMS + /* For VMS syntax just use the original vpath */ + if (*p != '/') + exists_in_cache = exists = dir_file_exists_p (vpath[i], filename); + else +#endif + { + /* Clobber a null into the name at the last slash. + Now NAME is the name of the directory to look in. */ + *p = '\0'; + /* We know the directory is in the hash table now because either + construct_vpath_list or the code just above put it there. + Does the file we seek exist in it? */ + exists_in_cache = exists = dir_file_exists_p (name, filename); + } } if (exists) @@ -459,8 +464,14 @@ selective_vpath_search (struct vpath *path, const char *file, struct stat st; +#ifndef VMS /* Put the slash back in NAME. */ *p = '/'; +#else + /* If the slash was removed, put it back */ + if (*p == 0) + *p = '/'; +#endif if (exists_in_cache) /* Makefile-mentioned file need not exist. */ { @@ -554,6 +565,8 @@ vpath_search (const char *file, FILE_TIMESTAMP *mtime_ptr, return 0; } + + /* Print the data base of VPATH search paths. */ diff --git a/third_party/make/xalloc-die.c b/third_party/make/xalloc-die.c deleted file mode 100644 index c7a62a5f0..000000000 --- a/third_party/make/xalloc-die.c +++ /dev/null @@ -1,41 +0,0 @@ -/* Report a memory allocation failure and exit. - - Copyright (C) 1997-2000, 2002-2004, 2006, 2009-2020 Free Software - Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -#include "libc/runtime/runtime.h" -#include "third_party/make/config.h" - -#include "third_party/make/xalloc.h" - - -#include "third_party/make/error.h" -#include "third_party/make/exitfail.h" - -#include "third_party/make/gettext.h" -#define _(msgid) gettext (msgid) - -void -xalloc_die (void) -{ - error (exit_failure, 0, "%s", _("memory exhausted")); - - /* _Noreturn cannot be given to error, since it may return if - its first argument is 0. To help compilers understand the - xalloc_die does not return, call abort. Also, the abort is a - safety feature if exit_failure is 0 (which shouldn't happen). */ - abort (); -} diff --git a/third_party/make/xalloc-oversized.h b/third_party/make/xalloc-oversized.h deleted file mode 100644 index ed09c7001..000000000 --- a/third_party/make/xalloc-oversized.h +++ /dev/null @@ -1,58 +0,0 @@ -/* xalloc-oversized.h -- memory allocation size checking - - Copyright (C) 1990-2000, 2003-2004, 2006-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -#ifndef XALLOC_OVERSIZED_H_ -#define XALLOC_OVERSIZED_H_ - - -/* True if N * S would overflow in a size_t calculation, - or would generate a value larger than PTRDIFF_MAX. - This expands to a constant expression if N and S are both constants. - By gnulib convention, SIZE_MAX represents overflow in size - calculations, so the conservative size_t-based dividend to use here - is SIZE_MAX - 1. */ -#define __xalloc_oversized(n, s) \ - ((size_t) (PTRDIFF_MAX < SIZE_MAX ? PTRDIFF_MAX : SIZE_MAX - 1) / (s) < (n)) - -#if PTRDIFF_MAX < SIZE_MAX -typedef ptrdiff_t __xalloc_count_type; -#else -typedef size_t __xalloc_count_type; -#endif - -/* Return 1 if an array of N objects, each of size S, cannot exist - reliably due to size or ptrdiff_t arithmetic overflow. S must be - positive and N must be nonnegative. This is a macro, not a - function, so that it works correctly even when SIZE_MAX < N. */ - -#if 7 <= __GNUC__ -# define xalloc_oversized(n, s) \ - __builtin_mul_overflow_p (n, s, (__xalloc_count_type) 1) -#elif 5 <= __GNUC__ && !defined __ICC && !__STRICT_ANSI__ -# define xalloc_oversized(n, s) \ - (__builtin_constant_p (n) && __builtin_constant_p (s) \ - ? __xalloc_oversized (n, s) \ - : ({ __xalloc_count_type __xalloc_count; \ - __builtin_mul_overflow (n, s, &__xalloc_count); })) - -/* Other compilers use integer division; this may be slower but is - more portable. */ -#else -# define xalloc_oversized(n, s) __xalloc_oversized (n, s) -#endif - -#endif /* !XALLOC_OVERSIZED_H_ */ diff --git a/third_party/make/xalloc.h b/third_party/make/xalloc.h deleted file mode 100644 index 6b813fa00..000000000 --- a/third_party/make/xalloc.h +++ /dev/null @@ -1,261 +0,0 @@ -/* xalloc.h -- malloc with out-of-memory checking - - Copyright (C) 1990-2000, 2003-2004, 2006-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -#ifndef XALLOC_H_ -#define XALLOC_H_ - -#include "libc/limits.h" - -#include "third_party/make/xalloc-oversized.h" - -#ifndef _GL_INLINE_HEADER_BEGIN - #error "Please include config.h first." -#endif -_GL_INLINE_HEADER_BEGIN -#ifndef XALLOC_INLINE -# define XALLOC_INLINE _GL_INLINE -#endif - -#ifdef __cplusplus -extern "C" { -#endif - - -#if ! defined __clang__ && \ - (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) -# define _GL_ATTRIBUTE_ALLOC_SIZE(args) __attribute__ ((__alloc_size__ args)) -#else -# define _GL_ATTRIBUTE_ALLOC_SIZE(args) -#endif - -/* This function is always triggered when memory is exhausted. - It must be defined by the application, either explicitly - or by using gnulib's xalloc-die module. This is the - function to call when one wants the program to die because of a - memory allocation failure. */ -extern _Noreturn void xalloc_die (void); - -void *xmalloc (size_t s) - _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((1)); -void *xzalloc (size_t s) - _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((1)); -void *xcalloc (size_t n, size_t s) - _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((1, 2)); -void *xrealloc (void *p, size_t s) - _GL_ATTRIBUTE_ALLOC_SIZE ((2)); -void *x2realloc (void *p, size_t *pn); -void *xmemdup (void const *p, size_t s) - _GL_ATTRIBUTE_ALLOC_SIZE ((2)); -char *xstrdup (char const *str) - _GL_ATTRIBUTE_MALLOC; - -/* In the following macros, T must be an elementary or structure/union or - typedef'ed type, or a pointer to such a type. To apply one of the - following macros to a function pointer or array type, you need to typedef - it first and use the typedef name. */ - -/* Allocate an object of type T dynamically, with error checking. */ -/* extern t *XMALLOC (typename t); */ -#define XMALLOC(t) ((t *) xmalloc (sizeof (t))) - -/* Allocate memory for N elements of type T, with error checking. */ -/* extern t *XNMALLOC (size_t n, typename t); */ -#define XNMALLOC(n, t) \ - ((t *) (sizeof (t) == 1 ? xmalloc (n) : xnmalloc (n, sizeof (t)))) - -/* Allocate an object of type T dynamically, with error checking, - and zero it. */ -/* extern t *XZALLOC (typename t); */ -#define XZALLOC(t) ((t *) xzalloc (sizeof (t))) - -/* Allocate memory for N elements of type T, with error checking, - and zero it. */ -/* extern t *XCALLOC (size_t n, typename t); */ -#define XCALLOC(n, t) \ - ((t *) (sizeof (t) == 1 ? xzalloc (n) : xcalloc (n, sizeof (t)))) - - -/* Allocate an array of N objects, each with S bytes of memory, - dynamically, with error checking. S must be nonzero. */ - -XALLOC_INLINE void *xnmalloc (size_t n, size_t s) - _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((1, 2)); -XALLOC_INLINE void * -xnmalloc (size_t n, size_t s) -{ - if (xalloc_oversized (n, s)) - xalloc_die (); - return xmalloc (n * s); -} - -/* Change the size of an allocated block of memory P to an array of N - objects each of S bytes, with error checking. S must be nonzero. */ - -XALLOC_INLINE void *xnrealloc (void *p, size_t n, size_t s) - _GL_ATTRIBUTE_ALLOC_SIZE ((2, 3)); -XALLOC_INLINE void * -xnrealloc (void *p, size_t n, size_t s) -{ - if (xalloc_oversized (n, s)) - xalloc_die (); - return xrealloc (p, n * s); -} - -/* If P is null, allocate a block of at least *PN such objects; - otherwise, reallocate P so that it contains more than *PN objects - each of S bytes. S must be nonzero. Set *PN to the new number of - objects, and return the pointer to the new block. *PN is never set - to zero, and the returned pointer is never null. - - Repeated reallocations are guaranteed to make progress, either by - allocating an initial block with a nonzero size, or by allocating a - larger block. - - In the following implementation, nonzero sizes are increased by a - factor of approximately 1.5 so that repeated reallocations have - O(N) overall cost rather than O(N**2) cost, but the - specification for this function does not guarantee that rate. - - Here is an example of use: - - int *p = NULL; - size_t used = 0; - size_t allocated = 0; - - void - append_int (int value) - { - if (used == allocated) - p = x2nrealloc (p, &allocated, sizeof *p); - p[used++] = value; - } - - This causes x2nrealloc to allocate a block of some nonzero size the - first time it is called. - - To have finer-grained control over the initial size, set *PN to a - nonzero value before calling this function with P == NULL. For - example: - - int *p = NULL; - size_t used = 0; - size_t allocated = 0; - size_t allocated1 = 1000; - - void - append_int (int value) - { - if (used == allocated) - { - p = x2nrealloc (p, &allocated1, sizeof *p); - allocated = allocated1; - } - p[used++] = value; - } - - */ - -XALLOC_INLINE void * -x2nrealloc (void *p, size_t *pn, size_t s) -{ - size_t n = *pn; - - if (! p) - { - if (! n) - { - /* The approximate size to use for initial small allocation - requests, when the invoking code specifies an old size of - zero. This is the largest "small" request for the GNU C - library malloc. */ - enum { DEFAULT_MXFAST = 64 * sizeof (size_t) / 4 }; - - n = DEFAULT_MXFAST / s; - n += !n; - } - if (xalloc_oversized (n, s)) - xalloc_die (); - } - else - { - /* Set N = floor (1.5 * N) + 1 so that progress is made even if N == 0. - Check for overflow, so that N * S stays in both ptrdiff_t and - size_t range. The check may be slightly conservative, but an - exact check isn't worth the trouble. */ - if ((PTRDIFF_MAX < SIZE_MAX ? PTRDIFF_MAX : SIZE_MAX) / 3 * 2 / s - <= n) - xalloc_die (); - n += n / 2 + 1; - } - - *pn = n; - return xrealloc (p, n * s); -} - -/* Return a pointer to a new buffer of N bytes. This is like xmalloc, - except it returns char *. */ - -XALLOC_INLINE char *xcharalloc (size_t n) - _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((1)); -XALLOC_INLINE char * -xcharalloc (size_t n) -{ - return XNMALLOC (n, char); -} - -#ifdef __cplusplus -} - -/* C++ does not allow conversions from void * to other pointer types - without a cast. Use templates to work around the problem when - possible. */ - -template inline T * -xrealloc (T *p, size_t s) -{ - return (T *) xrealloc ((void *) p, s); -} - -template inline T * -xnrealloc (T *p, size_t n, size_t s) -{ - return (T *) xnrealloc ((void *) p, n, s); -} - -template inline T * -x2realloc (T *p, size_t *pn) -{ - return (T *) x2realloc ((void *) p, pn); -} - -template inline T * -x2nrealloc (T *p, size_t *pn, size_t s) -{ - return (T *) x2nrealloc ((void *) p, pn, s); -} - -template inline T * -xmemdup (T const *p, size_t s) -{ - return (T *) xmemdup ((void const *) p, s); -} - -#endif - -_GL_INLINE_HEADER_END - -#endif /* !XALLOC_H_ */ diff --git a/third_party/make/xconcat-filename.c b/third_party/make/xconcat-filename.c deleted file mode 100644 index 3aad7842a..000000000 --- a/third_party/make/xconcat-filename.c +++ /dev/null @@ -1,41 +0,0 @@ -/* Construct a full filename from a directory and a relative filename. - Copyright (C) 2001-2004, 2006-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 3 of the License, or 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 . */ - -/* Written by Bruno Haible . */ - -#include "third_party/make/config.h" - -/* Specification. */ -#include "third_party/make/concat-filename.h" - -#include "third_party/make/xalloc.h" - -/* Concatenate a directory filename, a relative filename and an optional - suffix. The directory may end with the directory separator. The second - argument may not start with the directory separator (it is relative). - Return a freshly allocated filename. */ -char * -xconcatenated_filename (const char *directory, const char *filename, - const char *suffix) -{ - char *result; - - result = concatenated_filename (directory, filename, suffix); - if (result == NULL) - xalloc_die (); - - return result; -} diff --git a/third_party/make/xmalloc.c b/third_party/make/xmalloc.c deleted file mode 100644 index f60f85e34..000000000 --- a/third_party/make/xmalloc.c +++ /dev/null @@ -1,122 +0,0 @@ -/* xmalloc.c -- malloc with out of memory checking - - Copyright (C) 1990-2000, 2002-2006, 2008-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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 . */ - -#include "libc/mem/mem.h" -#include "libc/str/str.h" -#include "third_party/make/config.h" - -#define XALLOC_INLINE _GL_EXTERN_INLINE - -#include "third_party/make/xalloc.h" - - -/* 1 if calloc is known to be compatible with GNU calloc. This - matters if we are not also using the calloc module, which defines - HAVE_CALLOC_GNU and supports the GNU API even on non-GNU platforms. */ -#if defined HAVE_CALLOC_GNU || (defined __GLIBC__ && !defined __UCLIBC__) -enum { HAVE_GNU_CALLOC = 1 }; -#else -enum { HAVE_GNU_CALLOC = 0 }; -#endif - -/* Allocate N bytes of memory dynamically, with error checking. */ - -void * -xmalloc (size_t n) -{ - void *p = malloc (n); - if (!p && n != 0) - xalloc_die (); - return p; -} - -/* Change the size of an allocated block of memory P to N bytes, - with error checking. */ - -void * -xrealloc (void *p, size_t n) -{ - if (!n && p) - { - /* The GNU and C99 realloc behaviors disagree here. Act like - GNU, even if the underlying realloc is C99. */ - free (p); - return NULL; - } - - p = realloc (p, n); - if (!p && n) - xalloc_die (); - return p; -} - -/* If P is null, allocate a block of at least *PN bytes; otherwise, - reallocate P so that it contains more than *PN bytes. *PN must be - nonzero unless P is null. Set *PN to the new block's size, and - return the pointer to the new block. *PN is never set to zero, and - the returned pointer is never null. */ - -void * -x2realloc (void *p, size_t *pn) -{ - return x2nrealloc (p, pn, 1); -} - -/* Allocate N bytes of zeroed memory dynamically, with error checking. - There's no need for xnzalloc (N, S), since it would be equivalent - to xcalloc (N, S). */ - -void * -xzalloc (size_t n) -{ - return xcalloc (n, 1); -} - -/* Allocate zeroed memory for N elements of S bytes, with error - checking. S must be nonzero. */ - -void * -xcalloc (size_t n, size_t s) -{ - void *p; - /* Test for overflow, since objects with size greater than - PTRDIFF_MAX cause pointer subtraction to go awry. Omit size-zero - tests if HAVE_GNU_CALLOC, since GNU calloc never returns NULL if - successful. */ - if (xalloc_oversized (n, s) - || (! (p = calloc (n, s)) && (HAVE_GNU_CALLOC || n != 0))) - xalloc_die (); - return p; -} - -/* Clone an object P of size S, with error checking. There's no need - for xnmemdup (P, N, S), since xmemdup (P, N * S) works without any - need for an arithmetic overflow check. */ - -void * -xmemdup (void const *p, size_t s) -{ - return memcpy (xmalloc (s), p, s); -} - -/* Clone STRING. */ - -char * -xstrdup (char const *string) -{ - return xmemdup (string, strlen (string) + 1); -}