Index: head/UPDATING =================================================================== --- head/UPDATING (revision 284463) +++ head/UPDATING (revision 284464) @@ -1,1255 +1,1259 @@ Updating Information for FreeBSD current users. This file is maintained and copyrighted by M. Warner Losh . See end of file for further details. For commonly done items, please see the COMMON ITEMS: section later in the file. These instructions assume that you basically know what you are doing. If not, then please consult the FreeBSD handbook: http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/makeworld.html Items affecting the ports and packages system can be found in /usr/ports/UPDATING. Please read that file before running portupgrade. NOTE: FreeBSD has switched from gcc to clang. If you have trouble bootstrapping from older versions of FreeBSD, try WITHOUT_CLANG and WITH_GCC to bootstrap to the tip of head, and then rebuild without this option. The bootstrap process from older version of current across the gcc/clang cutover is a bit fragile. NOTE TO PEOPLE WHO THINK THAT FreeBSD 11.x IS SLOW: FreeBSD 11.x has many debugging features turned on, in both the kernel and userland. These features attempt to detect incorrect use of system primitives, and encourage loud failure through extra sanity checking and fail stop semantics. They also substantially impact system performance. If you want to do performance measurement, benchmarking, and optimization, you'll want to turn them off. This includes various WITNESS- related kernel options, INVARIANTS, malloc debugging flags in userland, and various verbose features in the kernel. Many developers choose to disable these features on build machines to maximize performance. (To completely disable malloc debugging, define MALLOC_PRODUCTION in /etc/make.conf, or to merely disable the most expensive debugging functionality run "ln -s 'abort:false,junk:false' /etc/malloc.conf".) +20150616: + FreeBSD's old make (fmake) has been removed from the system. It is + available as the devel/fmake port or via pkg install fmake. + 20150615: The fix for the issue described in the 20150614 sendmail entry below has been been committed in revision 284436. The work around described in that entry is no longer needed unless the default setting is overridden by a confDH_PARAMETERS configuration setting of '5' or pointing to a 512 bit DH parameter file. 20150614: ALLOW_DEPRECATED_ATF_TOOLS/ATFFILE support has been removed from atf.test.mk (included from bsd.test.mk). Please upgrade devel/atf and devel/kyua to version 0.20+ and adjust any calling code to work with Kyuafile and kyua. 20150614: The import of openssl to address the FreeBSD-SA-15:10.openssl security advisory includes a change which rejects handshakes with DH parameters below 768 bits. sendmail releases prior to 8.15.2 (not yet released), defaulted to a 512 bit DH parameter setting for client connections. To work around this interoperability, sendmail can be configured to use a 2048 bit DH parameter by: 1. Edit /etc/mail/`hostname`.mc 2. If a setting for confDH_PARAMETERS does not exist or exists and is set to a string beginning with '5', replace it with '2'. 3. If a setting for confDH_PARAMETERS exists and is set to a file path, create a new file with: openssl dhparam -out /path/to/file 2048 4. Rebuild the .cf file: cd /etc/mail/; make; make install 5. Restart sendmail: cd /etc/mail/; make restart A sendmail patch is coming, at which time this file will be updated. 20150604: Generation of legacy formatted entries have been disabled by default in pwd_mkdb(8), as all base system consumers of the legacy formatted entries were converted to use the new format by default when the new, machine independent format have been added and supported since FreeBSD 5.x. Please see the pwd_mkdb(8) manual page for further details. 20150525: Clang and llvm have been upgraded to 3.6.1 release. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using 3.5.0 or higher. 20150521: TI platform code switched to using vendor DTS files and this update may break existing systems running on Beaglebone, Beaglebone Black, and Pandaboard: - dtb files should be regenerated/reinstalled. Filenames are the same but content is different now - GPIO addressing was changed, now each GPIO bank (32 pins per bank) has its own /dev/gpiocX device, e.g. pin 121 on /dev/gpioc0 in old addressing scheme is now pin 25 on /dev/gpioc3. - Pandaboard: /etc/ttys should be updated, serial console device is now /dev/ttyu2, not /dev/ttyu0 20150501: soelim(1) from gnu/usr.bin/groff has been replaced by usr.bin/soelim. If you need the GNU extension from groff soelim(1), install groff from package: pkg install groff, or via ports: textproc/groff. 20150423: chmod, chflags, chown and chgrp now affect symlinks in -R mode as defined in symlink(7); previously symlinks were silently ignored. 20150415: The const qualifier has been removed from iconv(3) to comply with POSIX. The ports tree is aware of this from r384038 onwards. 20150416: Libraries specified by LIBADD in Makefiles must have a corresponding DPADD_ variable to ensure correct dependencies. This is now enforced in src.libnames.mk. 20150324: From legacy ata(4) driver was removed support for SATA controllers supported by more functional drivers ahci(4), siis(4) and mvs(4). Kernel modules ataahci and ataadaptec were removed completely, replaced by ahci and mvs modules respectively. 20150315: Clang, llvm and lldb have been upgraded to 3.6.0 release. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using 3.5.0 or higher. 20150307: The 32-bit PowerPC kernel has been changed to a position-independent executable. This can only be booted with a version of loader(8) newer than January 31, 2015, so make sure to update both world and kernel before rebooting. 20150217: If you are running a -CURRENT kernel since r273872 (Oct 30th, 2014), but before r278950, the RNG was not seeded properly. Immediately upgrade the kernel to r278950 or later and regenerate any keys (e.g. ssh keys or openssl keys) that were generated w/ a kernel from that range. This does not affect programs that directly used /dev/random or /dev/urandom. All userland uses of arc4random(3) are affected. 20150210: The autofs(4) ABI was changed in order to restore binary compatibility with 10.1-RELEASE. The automountd(8) daemon needs to be rebuilt to work with the new kernel. 20150131: The powerpc64 kernel has been changed to a position-independent executable. This can only be booted with a new version of loader(8), so make sure to update both world and kernel before rebooting. 20150118: Clang and llvm have been upgraded to 3.5.1 release. This is a bugfix only release, no new features have been added. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using 3.5.0. 20150107: ELF tools addr2line, elfcopy (strip), nm, size, and strings are now taken from the ELF Tool Chain project rather than GNU binutils. They should be drop-in replacements, with the addition of arm64 support. The WITHOUT_ELFTOOLCHAIN_TOOLS= knob may be used to obtain the binutils tools, if necessary. 20150105: The default Unbound configuration now enables remote control using a local socket. Users who have already enabled the local_unbound service should regenerate their configuration by running "service local_unbound setup" as root. 20150102: The GNU texinfo and GNU info pages have been removed. To be able to view GNU info pages please install texinfo from ports. 20141231: Clang, llvm and lldb have been upgraded to 3.5.0 release. As of this release, a prerequisite for building clang, llvm and lldb is a C++11 capable compiler and C++11 standard library. This means that to be able to successfully build the cross-tools stage of buildworld, with clang as the bootstrap compiler, your system compiler or cross compiler should either be clang 3.3 or later, or gcc 4.8 or later, and your system C++ library should be libc++, or libdstdc++ from gcc 4.8 or later. On any standard FreeBSD 10.x or 11.x installation, where clang and libc++ are on by default (that is, on x86 or arm), this should work out of the box. On 9.x installations where clang is enabled by default, e.g. on x86 and powerpc, libc++ will not be enabled by default, so libc++ should be built (with clang) and installed first. If both clang and libc++ are missing, build clang first, then use it to build libc++. On 8.x and earlier installations, upgrade to 9.x first, and then follow the instructions for 9.x above. Sparc64 and mips users are unaffected, as they still use gcc 4.2.1 by default, and do not build clang. Many embedded systems are resource constrained, and will not be able to build clang in a reasonable time, or in some cases at all. In those cases, cross building bootable systems on amd64 is a workaround. This new version of clang introduces a number of new warnings, of which the following are most likely to appear: -Wabsolute-value This warns in two cases, for both C and C++: * When the code is trying to take the absolute value of an unsigned quantity, which is effectively a no-op, and almost never what was intended. The code should be fixed, if at all possible. If you are sure that the unsigned quantity can be safely cast to signed, without loss of information or undefined behavior, you can add an explicit cast, or disable the warning. * When the code is trying to take an absolute value, but the called abs() variant is for the wrong type, which can lead to truncation. If you want to disable the warning instead of fixing the code, please make sure that truncation will not occur, or it might lead to unwanted side-effects. -Wtautological-undefined-compare and -Wundefined-bool-conversion These warn when C++ code is trying to compare 'this' against NULL, while 'this' should never be NULL in well-defined C++ code. However, there is some legacy (pre C++11) code out there, which actively abuses this feature, which was less strictly defined in previous C++ versions. Squid and openjdk do this, for example. The warning can be turned off for C++98 and earlier, but compiling the code in C++11 mode might result in unexpected behavior; for example, the parts of the program that are unreachable could be optimized away. 20141222: The old NFS client and server (kernel options NFSCLIENT, NFSSERVER) kernel sources have been removed. The .h files remain, since some utilities include them. This will need to be fixed later. If "mount -t oldnfs ..." is attempted, it will fail. If the "-o" option on mountd(8), nfsd(8) or nfsstat(1) is used, the utilities will report errors. 20141121: The handling of LOCAL_LIB_DIRS has been altered to skip addition of directories to top level SUBDIR variable when their parent directory is included in LOCAL_DIRS. Users with build systems with such hierarchies and without SUBDIR entries in the parent directory Makefiles should add them or add the directories to LOCAL_DIRS. 20141109: faith(4) and faithd(8) have been removed from the base system. Faith has been obsolete for a very long time. 20141104: vt(4), the new console driver, is enabled by default. It brings support for Unicode and double-width characters, as well as support for UEFI and integration with the KMS kernel video drivers. You may need to update your console settings in /etc/rc.conf, most probably the keymap. During boot, /etc/rc.d/syscons will indicate what you need to do. vt(4) still has issues and lacks some features compared to syscons(4). See the wiki for up-to-date information: https://wiki.freebsd.org/Newcons If you want to keep using syscons(4), you can do so by adding the following line to /boot/loader.conf: kern.vty=sc 20141102: pjdfstest has been integrated into kyua as an opt-in test suite. Please see share/doc/pjdfstest/README for more details on how to execute it. 20141009: gperf has been removed from the base system for architectures that use clang. Ports that require gperf will obtain it from the devel/gperf port. 20140923: pjdfstest has been moved from tools/regression/pjdfstest to contrib/pjdfstest . 20140922: At svn r271982, The default linux compat kernel ABI has been adjusted to 2.6.18 in support of the linux-c6 compat ports infrastructure update. If you wish to continue using the linux-f10 compat ports, add compat.linux.osrelease=2.6.16 to your local sysctl.conf. Users are encouraged to update their linux-compat packages to linux-c6 during their next update cycle. 20140729: The ofwfb driver, used to provide a graphics console on PowerPC when using vt(4), no longer allows mmap() of all physical memory. This will prevent Xorg on PowerPC with some ATI graphics cards from initializing properly unless x11-servers/xorg-server is updated to 1.12.4_8 or newer. 20140723: The xdev targets have been converted to using TARGET and TARGET_ARCH instead of XDEV and XDEV_ARCH. 20140719: The default unbound configuration has been modified to address issues with reverse lookups on networks that use private address ranges. If you use the local_unbound service, run "service local_unbound setup" as root to regenerate your configuration, then "service local_unbound reload" to load the new configuration. 20140709: The GNU texinfo and GNU info pages are not built and installed anymore, WITH_INFO knob has been added to allow to built and install them again. UPDATE: see 20150102 entry on texinfo's removal 20140708: The GNU readline library is now an INTERNALLIB - that is, it is statically linked into consumers (GDB and variants) in the base system, and the shared library is no longer installed. The devel/readline port is available for third party software that requires readline. 20140702: The Itanium architecture (ia64) has been removed from the list of known architectures. This is the first step in the removal of the architecture. 20140701: Commit r268115 has added NFSv4.1 server support, merged from projects/nfsv4.1-server. Since this includes changes to the internal interfaces between the NFS related modules, a full build of the kernel and modules will be necessary. __FreeBSD_version has been bumped. 20140629: The WITHOUT_VT_SUPPORT kernel config knob has been renamed WITHOUT_VT. (The other _SUPPORT knobs have a consistent meaning which differs from the behaviour controlled by this knob.) 20140619: Maximal length of the serial number in CTL was increased from 16 to 64 chars, that breaks ABI. All CTL-related tools, such as ctladm and ctld, need to be rebuilt to work with a new kernel. 20140606: The libatf-c and libatf-c++ major versions were downgraded to 0 and 1 respectively to match the upstream numbers. They were out of sync because, when they were originally added to FreeBSD, the upstream versions were not respected. These libraries are private and not yet built by default, so renumbering them should be a non-issue. However, unclean source trees will yield broken test programs once the operator executes "make delete-old-libs" after a "make installworld". Additionally, the atf-sh binary was made private by moving it into /usr/libexec/. Already-built shell test programs will keep the path to the old binary so they will break after "make delete-old" is run. If you are using WITH_TESTS=yes (not the default), wipe the object tree and rebuild from scratch to prevent spurious test failures. This is only needed once: the misnumbered libraries and misplaced binaries have been added to OptionalObsoleteFiles.inc so they will be removed during a clean upgrade. 20140512: Clang and llvm have been upgraded to 3.4.1 release. 20140508: We bogusly installed src.opts.mk in /usr/share/mk. This file should be removed to avoid issues in the future (and has been added to ObsoleteFiles.inc). 20140505: /etc/src.conf now affects only builds of the FreeBSD src tree. In the past, it affected all builds that used the bsd.*.mk files. The old behavior was a bug, but people may have relied upon it. To get this behavior back, you can .include /etc/src.conf from /etc/make.conf (which is still global and isn't changed). This also changes the behavior of incremental builds inside the tree of individual directories. Set MAKESYSPATH to ".../share/mk" to do that. Although this has survived make universe and some upgrade scenarios, other upgrade scenarios may have broken. At least one form of temporary breakage was fixed with MAKESYSPATH settings for buildworld as well... In cases where MAKESYSPATH isn't working with this setting, you'll need to set it to the full path to your tree. One side effect of all this cleaning up is that bsd.compiler.mk is no longer implicitly included by bsd.own.mk. If you wish to use COMPILER_TYPE, you must now explicitly include bsd.compiler.mk as well. 20140430: The lindev device has been removed since /dev/full has been made a standard device. __FreeBSD_version has been bumped. 20140424: The knob WITHOUT_VI was added to the base system, which controls building ex(1), vi(1), etc. Older releases of FreeBSD required ex(1) in order to reorder files share/termcap and didn't build ex(1) as a build tool, so building/installing with WITH_VI is highly advised for build hosts for older releases. This issue has been fixed in stable/9 and stable/10 in r277022 and r276991, respectively. 20140418: The YES_HESIOD knob has been removed. It has been obsolete for a decade. Please move to using WITH_HESIOD instead or your builds will silently lack HESIOD. 20140405: The uart(4) driver has been changed with respect to its handling of the low-level console. Previously the uart(4) driver prevented any process from changing the baudrate or the CLOCAL and HUPCL control flags. By removing the restrictions, operators can make changes to the serial console port without having to reboot. However, when getty(8) is started on the serial device that is associated with the low-level console, a misconfigured terminal line in /etc/ttys will now have a real impact. Before upgrading the kernel, make sure that /etc/ttys has the serial console device configured as 3wire without baudrate to preserve the previous behaviour. E.g: ttyu0 "/usr/libexec/getty 3wire" vt100 on secure 20140306: Support for libwrap (TCP wrappers) in rpcbind was disabled by default to improve performance. To re-enable it, if needed, run rpcbind with command line option -W. 20140226: Switched back to the GPL dtc compiler due to updates in the upstream dts files not being supported by the BSDL dtc compiler. You will need to rebuild your kernel toolchain to pick up the new compiler. Core dumps may result while building dtb files during a kernel build if you fail to do so. Set WITHOUT_GPL_DTC if you require the BSDL compiler. 20140216: Clang and llvm have been upgraded to 3.4 release. 20140216: The nve(4) driver has been removed. Please use the nfe(4) driver for NVIDIA nForce MCP Ethernet adapters instead. 20140212: An ABI incompatibility crept into the libc++ 3.4 import in r261283. This could cause certain C++ applications using shared libraries built against the previous version of libc++ to crash. The incompatibility has now been fixed, but any C++ applications or shared libraries built between r261283 and r261801 should be recompiled. 20140204: OpenSSH will now ignore errors caused by kernel lacking of Capsicum capability mode support. Please note that enabling the feature in kernel is still highly recommended. 20140131: OpenSSH is now built with sandbox support, and will use sandbox as the default privilege separation method. This requires Capsicum capability mode support in kernel. 20140128: The libelf and libdwarf libraries have been updated to newer versions from upstream. Shared library version numbers for these two libraries were bumped. Any ports or binaries requiring these two libraries should be recompiled. __FreeBSD_version is bumped to 1100006. 20140110: If a Makefile in a tests/ directory was auto-generating a Kyuafile instead of providing an explicit one, this would prevent such Makefile from providing its own Kyuafile in the future during NO_CLEAN builds. This has been fixed in the Makefiles but manual intervention is needed to clean an objdir if you use NO_CLEAN: # find /usr/obj -name Kyuafile | xargs rm -f 20131213: The behavior of gss_pseudo_random() for the krb5 mechanism has changed, for applications requesting a longer random string than produced by the underlying enctype's pseudo-random() function. In particular, the random string produced from a session key of enctype aes256-cts-hmac-sha1-96 or aes256-cts-hmac-sha1-96 will be different at the 17th octet and later, after this change. The counter used in the PRF+ construction is now encoded as a big-endian integer in accordance with RFC 4402. __FreeBSD_version is bumped to 1100004. 20131108: The WITHOUT_ATF build knob has been removed and its functionality has been subsumed into the more generic WITHOUT_TESTS. If you were using the former to disable the build of the ATF libraries, you should change your settings to use the latter. 20131025: The default version of mtree is nmtree which is obtained from NetBSD. The output is generally the same, but may vary slightly. If you found you need identical output adding "-F freebsd9" to the command line should do the trick. For the time being, the old mtree is available as fmtree. 20131014: libbsdyml has been renamed to libyaml and moved to /usr/lib/private. This will break ports-mgmt/pkg. Rebuild the port, or upgrade to pkg 1.1.4_8 and verify bsdyml not linked in, before running "make delete-old-libs": # make -C /usr/ports/ports-mgmt/pkg build deinstall install clean or # pkg install pkg; ldd /usr/local/sbin/pkg | grep bsdyml 20131010: The rc.d/jail script has been updated to support jail(8) configuration file. The "jail__*" rc.conf(5) variables for per-jail configuration are automatically converted to /var/run/jail..conf before the jail(8) utility is invoked. This is transparently backward compatible. See below about some incompatibilities and rc.conf(5) manual page for more details. These variables are now deprecated in favor of jail(8) configuration file. One can use "rc.d/jail config " command to generate a jail(8) configuration file in /var/run/jail..conf without running the jail(8) utility. The default pathname of the configuration file is /etc/jail.conf and can be specified by using $jail_conf or $jail__conf variables. Please note that jail_devfs_ruleset accepts an integer at this moment. Please consider to rewrite the ruleset name with an integer. 20130930: BIND has been removed from the base system. If all you need is a local resolver, simply enable and start the local_unbound service instead. Otherwise, several versions of BIND are available in the ports tree. The dns/bind99 port is one example. With this change, nslookup(1) and dig(1) are no longer in the base system. Users should instead use host(1) and drill(1) which are in the base system. Alternatively, nslookup and dig can be obtained by installing the dns/bind-tools port. 20130916: With the addition of unbound(8), a new unbound user is now required during installworld. "mergemaster -p" can be used to add the user prior to installworld, as documented in the handbook. 20130911: OpenSSH is now built with DNSSEC support, and will by default silently trust signed SSHFP records. This can be controlled with the VerifyHostKeyDNS client configuration setting. DNSSEC support can be disabled entirely with the WITHOUT_LDNS option in src.conf. 20130906: The GNU Compiler Collection and C++ standard library (libstdc++) are no longer built by default on platforms where clang is the system compiler. You can enable them with the WITH_GCC and WITH_GNUCXX options in src.conf. 20130905: The PROCDESC kernel option is now part of the GENERIC kernel configuration and is required for the rwhod(8) to work. If you are using custom kernel configuration, you should include 'options PROCDESC'. 20130905: The API and ABI related to the Capsicum framework was modified in backward incompatible way. The userland libraries and programs have to be recompiled to work with the new kernel. This includes the following libraries and programs, but the whole buildworld is advised: libc, libprocstat, dhclient, tcpdump, hastd, hastctl, kdump, procstat, rwho, rwhod, uniq. 20130903: AES-NI intrinsic support has been added to gcc. The AES-NI module has been updated to use this support. A new gcc is required to build the aesni module on both i386 and amd64. 20130821: The PADLOCK_RNG and RDRAND_RNG kernel options are now devices. Thus "device padlock_rng" and "device rdrand_rng" should be used instead of "options PADLOCK_RNG" & "options RDRAND_RNG". 20130813: WITH_ICONV has been split into two feature sets. WITH_ICONV now enables just the iconv* functionality and is now on by default. WITH_LIBICONV_COMPAT enables the libiconv api and link time compatability. Set WITHOUT_ICONV to build the old way. If you have been using WITH_ICONV before, you will very likely need to turn on WITH_LIBICONV_COMPAT. 20130806: INVARIANTS option now enables DEBUG for code with OpenSolaris and Illumos origin, including ZFS. If you have INVARIANTS in your kernel configuration, then there is no need to set DEBUG or ZFS_DEBUG explicitly. DEBUG used to enable witness(9) tracking of OpenSolaris (mostly ZFS) locks if WITNESS option was set. Because that generated a lot of witness(9) reports and all of them were believed to be false positives, this is no longer done. New option OPENSOLARIS_WITNESS can be used to achieve the previous behavior. 20130806: Timer values in IPv6 data structures now use time_uptime instead of time_second. Although this is not a user-visible functional change, userland utilities which directly use them---ndp(8), rtadvd(8), and rtsold(8) in the base system---need to be updated to r253970 or later. 20130802: find -delete can now delete the pathnames given as arguments, instead of only files found below them or if the pathname did not contain any slashes. Formerly, the following error message would result: find: -delete: : relative path potentially not safe Deleting the pathnames given as arguments can be prevented without error messages using -mindepth 1 or by changing directory and passing "." as argument to find. This works in the old as well as the new version of find. 20130726: Behavior of devfs rules path matching has been changed. Pattern is now always matched against fully qualified devfs path and slash characters must be explicitly matched by slashes in pattern (FNM_PATHNAME). Rulesets involving devfs subdirectories must be reviewed. 20130716: The default ARM ABI has changed to the ARM EABI. The old ABI is incompatible with the ARM EABI and all programs and modules will need to be rebuilt to work with a new kernel. To keep using the old ABI ensure the WITHOUT_ARM_EABI knob is set. NOTE: Support for the old ABI will be removed in the future and users are advised to upgrade. 20130709: pkg_install has been disconnected from the build if you really need it you should add WITH_PKGTOOLS in your src.conf(5). 20130709: Most of network statistics structures were changed to be able keep 64-bits counters. Thus all tools, that work with networking statistics, must be rebuilt (netstat(1), bsnmpd(1), etc.) 20130629: Fix targets that run multiple make's to use && rather than ; so that subsequent steps depend on success of previous. NOTE: if building 'universe' with -j* on stable/8 or stable/9 it would be better to start the build using bmake, to avoid overloading the machine. 20130618: Fix a bug that allowed a tracing process (e.g. gdb) to write to a memory-mapped file in the traced process's address space even if neither the traced process nor the tracing process had write access to that file. 20130615: CVS has been removed from the base system. An exact copy of the code is available from the devel/cvs port. 20130613: Some people report the following error after the switch to bmake: make: illegal option -- J usage: make [-BPSXeiknpqrstv] [-C directory] [-D variable] ... *** [buildworld] Error code 2 this likely due to an old instance of make in ${MAKEPATH} (${MAKEOBJDIRPREFIX}${.CURDIR}/make.${MACHINE}) which src/Makefile will use that blindly, if it exists, so if you see the above error: rm -rf `make -V MAKEPATH` should resolve it. 20130516: Use bmake by default. Whereas before one could choose to build with bmake via -DWITH_BMAKE one must now use -DWITHOUT_BMAKE to use the old make. The goal is to remove these knobs for 10-RELEASE. It is worth noting that bmake (like gmake) treats the command line as the unit of failure, rather than statements within the command line. Thus '(cd some/where && dosomething)' is safer than 'cd some/where; dosomething'. The '()' allows consistent behavior in parallel build. 20130429: Fix a bug that allows NFS clients to issue READDIR on files. 20130426: The WITHOUT_IDEA option has been removed because the IDEA patent expired. 20130426: The sysctl which controls TRIM support under ZFS has been renamed from vfs.zfs.trim_disable -> vfs.zfs.trim.enabled and has been enabled by default. 20130425: The mergemaster command now uses the default MAKEOBJDIRPREFIX rather than creating it's own in the temporary directory in order allow access to bootstrapped versions of tools such as install and mtree. When upgrading from version of FreeBSD where the install command does not support -l, you will need to install a new mergemaster command if mergemaster -p is required. This can be accomplished with the command (cd src/usr.sbin/mergemaster && make install). 20130404: Legacy ATA stack, disabled and replaced by new CAM-based one since FreeBSD 9.0, completely removed from the sources. Kernel modules atadisk and atapi*, user-level tools atacontrol and burncd are removed. Kernel option `options ATA_CAM` is now permanently enabled and removed. 20130319: SOCK_CLOEXEC and SOCK_NONBLOCK flags have been added to socket(2) and socketpair(2). Software, in particular Kerberos, may automatically detect and use these during building. The resulting binaries will not work on older kernels. 20130308: CTL_DISABLE has also been added to the sparc64 GENERIC (for further information, see the respective 20130304 entry). 20130304: Recent commits to callout(9) changed the size of struct callout, so the KBI is probably heavily disturbed. Also, some functions in callout(9)/sleep(9)/sleepqueue(9)/condvar(9) KPIs were replaced by macros. Every kernel module using it won't load, so rebuild is requested. The ctl device has been re-enabled in GENERIC for i386 and amd64, but does not initialize by default (because of the new CTL_DISABLE option) to save memory. To re-enable it, remove the CTL_DISABLE option from the kernel config file or set kern.cam.ctl.disable=0 in /boot/loader.conf. 20130301: The ctl device has been disabled in GENERIC for i386 and amd64. This was done due to the extra memory being allocated at system initialisation time by the ctl driver which was only used if a CAM target device was created. This makes a FreeBSD system unusable on 128MB or less of RAM. 20130208: A new compression method (lz4) has been merged to -HEAD. Please refer to zpool-features(7) for more information. Please refer to the "ZFS notes" section of this file for information on upgrading boot ZFS pools. 20130129: A BSD-licensed patch(1) variant has been added and is installed as bsdpatch, being the GNU version the default patch. To inverse the logic and use the BSD-licensed one as default, while having the GNU version installed as gnupatch, rebuild and install world with the WITH_BSD_PATCH knob set. 20130121: Due to the use of the new -l option to install(1) during build and install, you must take care not to directly set the INSTALL make variable in your /etc/make.conf, /etc/src.conf, or on the command line. If you wish to use the -C flag for all installs you may be able to add INSTALL+=-C to /etc/make.conf or /etc/src.conf. 20130118: The install(1) option -M has changed meaning and now takes an argument that is a file or path to append logs to. In the unlikely event that -M was the last option on the command line and the command line contained at least two files and a target directory the first file will have logs appended to it. The -M option served little practical purpose in the last decade so its use is expected to be extremely rare. 20121223: After switching to Clang as the default compiler some users of ZFS on i386 systems started to experience stack overflow kernel panics. Please consider using 'options KSTACK_PAGES=4' in such configurations. 20121222: GEOM_LABEL now mangles label names read from file system metadata. Mangling affect labels containing spaces, non-printable characters, '%' or '"'. Device names in /etc/fstab and other places may need to be updated. 20121217: By default, only the 10 most recent kernel dumps will be saved. To restore the previous behaviour (no limit on the number of kernel dumps stored in the dump directory) add the following line to /etc/rc.conf: savecore_flags="" 20121201: With the addition of auditdistd(8), a new auditdistd user is now required during installworld. "mergemaster -p" can be used to add the user prior to installworld, as documented in the handbook. 20121117: The sin6_scope_id member variable in struct sockaddr_in6 is now filled by the kernel before passing the structure to the userland via sysctl or routing socket. This means the KAME-specific embedded scope id in sin6_addr.s6_addr[2] is always cleared in userland application. This behavior can be controlled by net.inet6.ip6.deembed_scopeid. __FreeBSD_version is bumped to 1000025. 20121105: On i386 and amd64 systems WITH_CLANG_IS_CC is now the default. This means that the world and kernel will be compiled with clang and that clang will be installed as /usr/bin/cc, /usr/bin/c++, and /usr/bin/cpp. To disable this behavior and revert to building with gcc, compile with WITHOUT_CLANG_IS_CC. Really old versions of current may need to bootstrap WITHOUT_CLANG first if the clang build fails (its compatibility window doesn't extend to the 9 stable branch point). 20121102: The IPFIREWALL_FORWARD kernel option has been removed. Its functionality now turned on by default. 20121023: The ZERO_COPY_SOCKET kernel option has been removed and split into SOCKET_SEND_COW and SOCKET_RECV_PFLIP. NB: SOCKET_SEND_COW uses the VM page based copy-on-write mechanism which is not safe and may result in kernel crashes. NB: The SOCKET_RECV_PFLIP mechanism is useless as no current driver supports disposeable external page sized mbuf storage. Proper replacements for both zero-copy mechanisms are under consideration and will eventually lead to complete removal of the two kernel options. 20121023: The IPv4 network stack has been converted to network byte order. The following modules need to be recompiled together with kernel: carp(4), divert(4), gif(4), siftr(4), gre(4), pf(4), ipfw(4), ng_ipfw(4), stf(4). 20121022: Support for non-MPSAFE filesystems was removed from VFS. The VFS_VERSION was bumped, all filesystem modules shall be recompiled. 20121018: All the non-MPSAFE filesystems have been disconnected from the build. The full list includes: codafs, hpfs, ntfs, nwfs, portalfs, smbfs, xfs. 20121016: The interface cloning API and ABI has changed. The following modules need to be recompiled together with kernel: ipfw(4), pfsync(4), pflog(4), usb(4), wlan(4), stf(4), vlan(4), disc(4), edsc(4), if_bridge(4), gif(4), tap(4), faith(4), epair(4), enc(4), tun(4), if_lagg(4), gre(4). 20121015: The sdhci driver was split in two parts: sdhci (generic SD Host Controller logic) and sdhci_pci (actual hardware driver). No kernel config modifications are required, but if you load sdhc as a module you must switch to sdhci_pci instead. 20121014: Import the FUSE kernel and userland support into base system. 20121013: The GNU sort(1) program has been removed since the BSD-licensed sort(1) has been the default for quite some time and no serious problems have been reported. The corresponding WITH_GNU_SORT knob has also gone. 20121006: The pfil(9) API/ABI for AF_INET family has been changed. Packet filtering modules: pf(4), ipfw(4), ipfilter(4) need to be recompiled with new kernel. 20121001: The net80211(4) ABI has been changed to allow for improved driver PS-POLL and power-save support. All wireless drivers need to be recompiled to work with the new kernel. 20120913: The random(4) support for the VIA hardware random number generator (`PADLOCK') is no longer enabled unconditionally. Add the padlock_rng device in the custom kernel config if needed. The GENERIC kernels on i386 and amd64 do include the device, so the change only affects the custom kernel configurations. 20120908: The pf(4) packet filter ABI has been changed. pfctl(8) and snmp_pf module need to be recompiled to work with new kernel. 20120828: A new ZFS feature flag "com.delphix:empty_bpobj" has been merged to -HEAD. Pools that have empty_bpobj in active state can not be imported read-write with ZFS implementations that do not support this feature. For more information read the zpool-features(5) manual page. 20120727: The sparc64 ZFS loader has been changed to no longer try to auto- detect ZFS providers based on diskN aliases but now requires these to be explicitly listed in the OFW boot-device environment variable. 20120712: The OpenSSL has been upgraded to 1.0.1c. Any binaries requiring libcrypto.so.6 or libssl.so.6 must be recompiled. Also, there are configuration changes. Make sure to merge /etc/ssl/openssl.cnf. 20120712: The following sysctls and tunables have been renamed for consistency with other variables: kern.cam.da.da_send_ordered -> kern.cam.da.send_ordered kern.cam.ada.ada_send_ordered -> kern.cam.ada.send_ordered 20120628: The sort utility has been replaced with BSD sort. For now, GNU sort is also available as "gnusort" or the default can be set back to GNU sort by setting WITH_GNU_SORT. In this case, BSD sort will be installed as "bsdsort". 20120611: A new version of ZFS (pool version 5000) has been merged to -HEAD. Starting with this version the old system of ZFS pool versioning is superseded by "feature flags". This concept enables forward compatibility against certain future changes in functionality of ZFS pools. The first read-only compatible "feature flag" for ZFS pools is named "com.delphix:async_destroy". For more information read the new zpool-features(5) manual page. Please refer to the "ZFS notes" section of this file for information on upgrading boot ZFS pools. 20120417: The malloc(3) implementation embedded in libc now uses sources imported as contrib/jemalloc. The most disruptive API change is to /etc/malloc.conf. If your system has an old-style /etc/malloc.conf, delete it prior to installworld, and optionally re-create it using the new format after rebooting. See malloc.conf(5) for details (specifically the TUNING section and the "opt.*" entries in the MALLCTL NAMESPACE section). 20120328: Big-endian MIPS TARGET_ARCH values no longer end in "eb". mips64eb is now spelled mips64. mipsn32eb is now spelled mipsn32. mipseb is now spelled mips. This is to aid compatibility with third-party software that expects this naming scheme in uname(3). Little-endian settings are unchanged. If you are updating a big-endian mips64 machine from before this change, you may need to set MACHINE_ARCH=mips64 in your environment before the new build system will recognize your machine. 20120306: Disable by default the option VFS_ALLOW_NONMPSAFE for all supported platforms. 20120229: Now unix domain sockets behave "as expected" on nullfs(5). Previously nullfs(5) did not pass through all behaviours to the underlying layer, as a result if we bound to a socket on the lower layer we could connect only to the lower path; if we bound to the upper layer we could connect only to the upper path. The new behavior is one can connect to both the lower and the upper paths regardless what layer path one binds to. 20120211: The getifaddrs upgrade path broken with 20111215 has been restored. If you have upgraded in between 20111215 and 20120209 you need to recompile libc again with your kernel. You still need to recompile world to be able to configure CARP but this restriction already comes from 20111215. 20120114: The set_rcvar() function has been removed from /etc/rc.subr. All base and ports rc.d scripts have been updated, so if you have a port installed with a script in /usr/local/etc/rc.d you can either hand-edit the rcvar= line, or reinstall the port. An easy way to handle the mass-update of /etc/rc.d: rm /etc/rc.d/* && mergemaster -i 20120109: panic(9) now stops other CPUs in the SMP systems, disables interrupts on the current CPU and prevents other threads from running. This behavior can be reverted using the kern.stop_scheduler_on_panic tunable/sysctl. The new behavior can be incompatible with kern.sync_on_panic. 20111215: The carp(4) facility has been changed significantly. Configuration of the CARP protocol via ifconfig(8) has changed, as well as format of CARP events submitted to devd(8) has changed. See manual pages for more information. The arpbalance feature of carp(4) is currently not supported anymore. Size of struct in_aliasreq, struct in6_aliasreq has changed. User utilities using SIOCAIFADDR, SIOCAIFADDR_IN6, e.g. ifconfig(8), need to be recompiled. 20111122: The acpi_wmi(4) status device /dev/wmistat has been renamed to /dev/wmistat0. 20111108: The option VFS_ALLOW_NONMPSAFE option has been added in order to explicitely support non-MPSAFE filesystems. It is on by default for all supported platform at this present time. 20111101: The broken amd(4) driver has been replaced with esp(4) in the amd64, i386 and pc98 GENERIC kernel configuration files. 20110930: sysinstall has been removed 20110923: The stable/9 branch created in subversion. This corresponds to the RELENG_9 branch in CVS. COMMON ITEMS: General Notes ------------- Avoid using make -j when upgrading. While generally safe, there are sometimes problems using -j to upgrade. If your upgrade fails with -j, please try again without -j. From time to time in the past there have been problems using -j with buildworld and/or installworld. This is especially true when upgrading between "distant" versions (eg one that cross a major release boundary or several minor releases, or when several months have passed on the -current branch). Sometimes, obscure build problems are the result of environment poisoning. This can happen because the make utility reads its environment when searching for values for global variables. To run your build attempts in an "environmental clean room", prefix all make commands with 'env -i '. See the env(1) manual page for more details. When upgrading from one major version to another it is generally best to upgrade to the latest code in the currently installed branch first, then do an upgrade to the new branch. This is the best-tested upgrade path, and has the highest probability of being successful. Please try this approach before reporting problems with a major version upgrade. When upgrading a live system, having a root shell around before installing anything can help undo problems. Not having a root shell around can lead to problems if pam has changed too much from your starting point to allow continued authentication after the upgrade. ZFS notes --------- When upgrading the boot ZFS pool to a new version, always follow these two steps: 1.) recompile and reinstall the ZFS boot loader and boot block (this is part of "make buildworld" and "make installworld") 2.) update the ZFS boot block on your boot drive The following example updates the ZFS boot block on the first partition (freebsd-boot) of a GPT partitioned drive ada0: "gpart bootcode -p /boot/gptzfsboot -i 1 ada0" Non-boot pools do not need these updates. To build a kernel ----------------- If you are updating from a prior version of FreeBSD (even one just a few days old), you should follow this procedure. It is the most failsafe as it uses a /usr/obj tree with a fresh mini-buildworld, make kernel-toolchain make -DALWAYS_CHECK_MAKE buildkernel KERNCONF=YOUR_KERNEL_HERE make -DALWAYS_CHECK_MAKE installkernel KERNCONF=YOUR_KERNEL_HERE To test a kernel once --------------------- If you just want to boot a kernel once (because you are not sure if it works, or if you want to boot a known bad kernel to provide debugging information) run make installkernel KERNCONF=YOUR_KERNEL_HERE KODIR=/boot/testkernel nextboot -k testkernel To just build a kernel when you know that it won't mess you up -------------------------------------------------------------- This assumes you are already running a CURRENT system. Replace ${arch} with the architecture of your machine (e.g. "i386", "arm", "amd64", "ia64", "pc98", "sparc64", "powerpc", "mips", etc). cd src/sys/${arch}/conf config KERNEL_NAME_HERE cd ../compile/KERNEL_NAME_HERE make depend make make install If this fails, go to the "To build a kernel" section. To rebuild everything and install it on the current system. ----------------------------------------------------------- # Note: sometimes if you are running current you gotta do more than # is listed here if you are upgrading from a really old current. make buildworld make kernel KERNCONF=YOUR_KERNEL_HERE [1] [3] mergemaster -Fp [5] make installworld mergemaster -Fi [4] make delete-old [6] To cross-install current onto a separate partition -------------------------------------------------- # In this approach we use a separate partition to hold # current's root, 'usr', and 'var' directories. A partition # holding "/", "/usr" and "/var" should be about 2GB in # size. make buildworld make buildkernel KERNCONF=YOUR_KERNEL_HERE make installworld DESTDIR=${CURRENT_ROOT} -DDB_FROM_SRC make distribution DESTDIR=${CURRENT_ROOT} # if newfs'd make installkernel KERNCONF=YOUR_KERNEL_HERE DESTDIR=${CURRENT_ROOT} cp /etc/fstab ${CURRENT_ROOT}/etc/fstab # if newfs'd To upgrade in-place from stable to current ---------------------------------------------- make buildworld [9] make kernel KERNCONF=YOUR_KERNEL_HERE [8] [1] [3] mergemaster -Fp [5] make installworld mergemaster -Fi [4] make delete-old [6] Make sure that you've read the UPDATING file to understand the tweaks to various things you need. At this point in the life cycle of current, things change often and you are on your own to cope. The defaults can also change, so please read ALL of the UPDATING entries. Also, if you are tracking -current, you must be subscribed to freebsd-current@freebsd.org. Make sure that before you update your sources that you have read and understood all the recent messages there. If in doubt, please track -stable which has much fewer pitfalls. [1] If you have third party modules, such as vmware, you should disable them at this point so they don't crash your system on reboot. [3] From the bootblocks, boot -s, and then do fsck -p mount -u / mount -a cd src adjkerntz -i # if CMOS is wall time Also, when doing a major release upgrade, it is required that you boot into single user mode to do the installworld. [4] Note: This step is non-optional. Failure to do this step can result in a significant reduction in the functionality of the system. Attempting to do it by hand is not recommended and those that pursue this avenue should read this file carefully, as well as the archives of freebsd-current and freebsd-hackers mailing lists for potential gotchas. The -U option is also useful to consider. See mergemaster(8) for more information. [5] Usually this step is a noop. However, from time to time you may need to do this if you get unknown user in the following step. It never hurts to do it all the time. You may need to install a new mergemaster (cd src/usr.sbin/mergemaster && make install) after the buildworld before this step if you last updated from current before 20130425 or from -stable before 20130430. [6] This only deletes old files and directories. Old libraries can be deleted by "make delete-old-libs", but you have to make sure that no program is using those libraries anymore. [8] In order to have a kernel that can run the 4.x binaries needed to do an installworld, you must include the COMPAT_FREEBSD4 option in your kernel. Failure to do so may leave you with a system that is hard to boot to recover. A similar kernel option COMPAT_FREEBSD5 is required to run the 5.x binaries on more recent kernels. And so on for COMPAT_FREEBSD6 and COMPAT_FREEBSD7. Make sure that you merge any new devices from GENERIC since the last time you updated your kernel config file. [9] When checking out sources, you must include the -P flag to have cvs prune empty directories. If CPUTYPE is defined in your /etc/make.conf, make sure to use the "?=" instead of the "=" assignment operator, so that buildworld can override the CPUTYPE if it needs to. MAKEOBJDIRPREFIX must be defined in an environment variable, and not on the command line, or in /etc/make.conf. buildworld will warn if it is improperly defined. FORMAT: This file contains a list, in reverse chronological order, of major breakages in tracking -current. It is not guaranteed to be a complete list of such breakages, and only contains entries since October 10, 2007. If you need to see UPDATING entries from before that date, you will need to fetch an UPDATING file from an older FreeBSD release. Copyright information: Copyright 1998-2009 M. Warner Losh. All Rights Reserved. Redistribution, publication, translation and use, with or without modification, in full or in part, in any form or format of this document are permitted without further permission from the author. THIS DOCUMENT IS PROVIDED BY WARNER LOSH ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WARNER LOSH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Contact Warner Losh if you have any questions about your use of this document. $FreeBSD$ Index: head/share/mk/src.opts.mk =================================================================== --- head/share/mk/src.opts.mk (revision 284463) +++ head/share/mk/src.opts.mk (revision 284464) @@ -1,399 +1,398 @@ # $FreeBSD$ # # Option file for FreeBSD /usr/src builds. # # Users define WITH_FOO and WITHOUT_FOO on the command line or in /etc/src.conf # and /etc/make.conf files. These translate in the build system to MK_FOO={yes,no} # with sensible (usually) defaults. # # Makefiles must include bsd.opts.mk after defining specific MK_FOO options that # are applicable for that Makefile (typically there are none, but sometimes there # are exceptions). Recursive makes usually add MK_FOO=no for options that they wish # to omit from that make. # # Makefiles must include bsd.mkopt.mk before they test the value of any MK_FOO # variable. # # Makefiles may also assume that this file is included by src.opts.mk should it # need variables defined there prior to the end of the Makefile where # bsd.{subdir,lib.bin}.mk is traditionally included. # # The old-style YES_FOO and NO_FOO are being phased out. No new instances of them # should be added. Old instances should be removed since they were just to # bridge the gap between FreeBSD 4 and FreeBSD 5. # # Makefiles should never test WITH_FOO or WITHOUT_FOO directly (although an # exception is made for _WITHOUT_SRCONF which turns off this mechanism # completely inside bsd.*.mk files). # .if !target(____) ____: .include # # Define MK_* variables (which are either "yes" or "no") for users # to set via WITH_*/WITHOUT_* in /etc/src.conf and override in the # make(1) environment. # These should be tested with `== "no"' or `!= "no"' in makefiles. # The NO_* variables should only be set by makefiles for variables # that haven't been converted over. # # These options are used by src the builds __DEFAULT_YES_OPTIONS = \ ACCT \ ACPI \ AMD \ APM \ AT \ ATM \ AUDIT \ AUTHPF \ AUTOFS \ BHYVE \ BINUTILS \ BINUTILS_BOOTSTRAP \ BLUETOOTH \ BOOT \ BOOTPARAMD \ BOOTPD \ BSD_CPIO \ BSDINSTALL \ BSNMP \ BZIP2 \ CALENDAR \ CAPSICUM \ CASPER \ CCD \ CDDL \ CPP \ CROSS_COMPILER \ CRYPT \ CTM \ CUSE \ CXX \ DICT \ DMAGENT \ DYNAMICROOT \ ED_CRYPTO \ EE \ ELFTOOLCHAIN_TOOLS \ EXAMPLES \ FDT \ FILE \ FINGER \ FLOPPY \ FMTREE \ FORTH \ FP_LIBC \ FREEBSD_UPDATE \ FTP \ GAMES \ GCOV \ GDB \ GNU \ GNU_GREP_COMPAT \ GPIO \ GPL_DTC \ GROFF \ HAST \ HTML \ HYPERV \ ICONV \ INET \ INET6 \ INETD \ IPFILTER \ IPFW \ ISCSI \ JAIL \ KDUMP \ KVM \ LDNS \ LDNS_UTILS \ LEGACY_CONSOLE \ LIB32 \ LIBPTHREAD \ LIBTHR \ LOCALES \ LOCATE \ LPR \ LS_COLORS \ LZMA_SUPPORT \ MAIL \ MAILWRAPPER \ MAKE \ MANDOCDB \ NDIS \ NETCAT \ NETGRAPH \ NLS_CATALOGS \ NS_CACHING \ NTP \ OPENSSL \ PAM \ PC_SYSINSTALL \ PF \ PKGBOOTSTRAP \ PMC \ PORTSNAP \ PPP \ QUOTAS \ RADIUS_SUPPORT \ RCMDS \ RBOOTD \ RCS \ RESCUE \ ROUTED \ SENDMAIL \ SETUID_LOGIN \ SHAREDOCS \ SOURCELESS \ SOURCELESS_HOST \ SOURCELESS_UCODE \ SVNLITE \ SYSCONS \ SYSINSTALL \ TALK \ TCP_WRAPPERS \ TCSH \ TELNET \ TESTS \ TEXTPROC \ TFTP \ TIMED \ UNBOUND \ USB \ UTMPX \ VI \ VT \ WIRELESS \ WPA_SUPPLICANT_EAPOL \ ZFS \ ZONEINFO __DEFAULT_NO_OPTIONS = \ BSD_GREP \ CLANG_EXTRAS \ EISA \ - FMAKE \ HESIOD \ LLDB \ NAND \ OFED \ OPENLDAP \ OPENSSH_NONE_CIPHER \ SHARED_TOOLCHAIN \ SORT_THREADS \ SVN # # Default behaviour of some options depends on the architecture. Unfortunately # this means that we have to test TARGET_ARCH (the buildworld case) as well # as MACHINE_ARCH (the non-buildworld case). Normally TARGET_ARCH is not # used at all in bsd.*.mk, but we have to make an exception here if we want # to allow defaults for some things like clang to vary by target architecture. # Additional, per-target behavior should be rarely added only after much # gnashing of teeth and grinding of gears. # .if defined(TARGET_ARCH) __T=${TARGET_ARCH} .else __T=${MACHINE_ARCH} .endif .if defined(TARGET) __TT=${TARGET} .else __TT=${MACHINE} .endif .include .if !${COMPILER_FEATURES:Mc++11} # If the compiler is not C++11 capable, disable clang and use gcc instead. __DEFAULT_YES_OPTIONS+=GCC GCC_BOOTSTRAP GNUCXX __DEFAULT_NO_OPTIONS+=CLANG CLANG_BOOTSTRAP CLANG_FULL CLANG_IS_CC .elif ${__T} == "aarch64" || ${__T} == "amd64" || ${__T} == "i386" # On x86 and arm64, clang is enabled, and will be installed as the default cc. __DEFAULT_YES_OPTIONS+=CLANG CLANG_BOOTSTRAP CLANG_FULL CLANG_IS_CC __DEFAULT_NO_OPTIONS+=GCC GCC_BOOTSTRAP GNUCXX .elif ${__TT} == "arm" # On arm, clang is enabled, and it is installed as the default cc, but # since gcc is unable to build the full clang, disable it by default. __DEFAULT_YES_OPTIONS+=CLANG CLANG_BOOTSTRAP CLANG_IS_CC __DEFAULT_NO_OPTIONS+=CLANG_FULL GCC GCC_BOOTSTRAP GNUCXX .elif ${__T:Mpowerpc*} # On powerpc, clang is enabled, but gcc is installed as the default cc. __DEFAULT_YES_OPTIONS+=CLANG CLANG_FULL GCC GCC_BOOTSTRAP GNUCXX __DEFAULT_NO_OPTIONS+=CLANG_BOOTSTRAP CLANG_IS_CC .else # Everything else disables clang, and uses gcc instead. __DEFAULT_YES_OPTIONS+=GCC GCC_BOOTSTRAP GNUCXX __DEFAULT_NO_OPTIONS+=CLANG CLANG_BOOTSTRAP CLANG_FULL CLANG_IS_CC .endif .if ${__T} == "aarch64" BROKEN_OPTIONS+=BINUTILS BINUTILS_BOOTSTRAP GCC GCC_BOOTSTRAP GDB .endif # LLVM lacks support for FreeBSD 64-bit atomic operations for ARMv4/ARMv5 .if ${__T} == "arm" || ${__T} == "armeb" BROKEN_OPTIONS+=LLDB .endif .include # # MK_* options that default to "yes" if the compiler is a C++11 compiler. # .for var in \ LIBCPLUSPLUS .if !defined(MK_${var}) .if ${COMPILER_FEATURES:Mc++11} .if defined(WITHOUT_${var}) MK_${var}:= no .else MK_${var}:= yes .endif .else .if defined(WITH_${var}) MK_${var}:= yes .else MK_${var}:= no .endif .endif .endif .endfor # # Force some options off if their dependencies are off. # Order is somewhat important. # .if ${MK_LIBPTHREAD} == "no" MK_LIBTHR:= no .endif .if ${MK_LDNS} == "no" MK_LDNS_UTILS:= no MK_UNBOUND:= no .endif .if ${MK_SOURCELESS} == "no" MK_SOURCELESS_HOST:= no MK_SOURCELESS_UCODE:= no .endif .if ${MK_CDDL} == "no" MK_ZFS:= no MK_CTF:= no .endif .if ${MK_CRYPT} == "no" MK_OPENSSL:= no MK_OPENSSH:= no MK_KERBEROS:= no .endif .if ${MK_CXX} == "no" MK_CLANG:= no MK_GROFF:= no MK_GNUCXX:= no .endif .if ${MK_MAIL} == "no" MK_MAILWRAPPER:= no MK_SENDMAIL:= no MK_DMAGENT:= no .endif .if ${MK_NETGRAPH} == "no" MK_ATM:= no MK_BLUETOOTH:= no .endif .if ${MK_OPENSSL} == "no" MK_OPENSSH:= no MK_KERBEROS:= no .endif .if ${MK_PF} == "no" MK_AUTHPF:= no .endif .if ${MK_TEXTPROC} == "no" MK_GROFF:= no .endif .if ${MK_CROSS_COMPILER} == "no" MK_BINUTILS_BOOTSTRAP:= no MK_CLANG_BOOTSTRAP:= no MK_GCC_BOOTSTRAP:= no .endif .if ${MK_TOOLCHAIN} == "no" MK_BINUTILS:= no MK_CLANG:= no MK_GCC:= no MK_GDB:= no MK_INCLUDES:= no .endif .if ${MK_CLANG} == "no" MK_CLANG_EXTRAS:= no MK_CLANG_FULL:= no .endif # # Set defaults for the MK_*_SUPPORT variables. # # # MK_*_SUPPORT options which default to "yes" unless their corresponding # MK_* variable is set to "no". # .for var in \ BZIP2 \ GNU \ INET \ INET6 \ KERBEROS \ KVM \ NETGRAPH \ PAM \ TESTS \ WIRELESS .if defined(WITHOUT_${var}_SUPPORT) || ${MK_${var}} == "no" MK_${var}_SUPPORT:= no .else MK_${var}_SUPPORT:= yes .endif .endfor # # MK_* options whose default value depends on another option. # .for vv in \ GSSAPI/KERBEROS \ MAN_UTILS/MAN .if defined(WITH_${vv:H}) MK_${vv:H}:= yes .elif defined(WITHOUT_${vv:H}) MK_${vv:H}:= no .else MK_${vv:H}:= ${MK_${vv:T}} .endif .endfor .if !${COMPILER_FEATURES:Mc++11} MK_LLDB:= no .endif # gcc 4.8 and newer supports libc++, so suppress gnuc++ in that case. # while in theory we could build it with that, we don't want to do # that since it creates too much confusion for too little gain. .if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} >= 40800 MK_GNUCXX:=no MK_GCC:=no .endif .endif # !target(____) Index: head/usr.bin/make/make.1 =================================================================== --- head/usr.bin/make/make.1 (revision 284463) +++ head/usr.bin/make/make.1 (nonexistent) @@ -1,1843 +0,0 @@ -.\" Copyright (c) 1990, 1993 -.\" The Regents of the University of California. All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. Neither the name of the University nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" @(#)make.1 8.8 (Berkeley) 6/13/95 -.\" $FreeBSD$ -.\" -.Dd May 30, 2012 -.Dt MAKE 1 -.Os -.Sh NAME -.Nm make -.Nd maintain program dependencies -.Sh SYNOPSIS -.Nm -.Op Fl ABPSXeiknpqrstv -.Op Fl C Ar directory -.Op Fl D Ar variable -.Op Fl d Ar flags -.Op Fl E Ar variable -.Op Fl f Ar makefile -.Op Fl I Ar directory -.Bk -words -.Op Fl j Ar max_jobs -.Op Fl m Ar directory -.Ek -.Op Fl V Ar variable -.Op Fl x Ar warning_options -.Op Ar variable Ns No = Ns Ar value -.Op Ar target ... -.Sh DESCRIPTION -The -.Nm -utility is a program designed to simplify the maintenance of other programs. -Its input is a list of specifications -describing dependency relationships between the generation of -files and programs. -.Pp -First of all, the initial list of specifications will be read -from the system makefile, -.Pa sys.mk , -unless inhibited with the -.Fl r -option. -The standard -.Pa sys.mk -as shipped with -.Fx -also handles -.Xr make.conf 5 , -the default path to which -can be altered via the -.Nm -variable -.Va __MAKE_CONF . -.Pp -Then the first of -.Pa BSDmakefile , -.Pa makefile , -and -.Pa Makefile -that can be found in the current directory, object directory (see -.Va .OBJDIR ) , -or search path (see the -.Fl I -option) -will be read for the main list of dependency specifications. -A different makefile or list of them can be supplied via the -.Fl f -option(s). -Finally, if the file -.Pa .depend -can be found in any of the aforesaid locations, it will also be read (see -.Xr mkdep 1 ) . -.Pp -When -.Nm -searches for a makefile, its name takes precedence over its location. -For instance, -.Pa BSDmakefile -in the object directory will be favored over -.Pa Makefile -in the current directory. -.Pp -The options are as follows: -.Bl -tag -width Ds -.It Fl A -Make archive errors non-fatal, causing -.Nm -to just skip the remainder -or all of the archive and continue after printing a message. -.It Fl B -Try to be backwards compatible by executing a single shell per command and -by executing the commands to make the sources of a dependency line in sequence. -This is turned on by default unless -.Fl j -is used. -.It Fl C Ar directory -Change to -.Ar directory -before reading the makefiles or doing anything else. -If multiple -.Fl C -options are specified, each is interpreted relative to the previous one: -.Fl C Pa / Fl C Pa etc -is equivalent to -.Fl C Pa /etc . -.It Fl D Ar variable -Define -.Ar variable -to be 1, in the global context. -.It Fl d Ar flags -Turn on debugging, and specify which portions of -.Nm -are to print debugging information. -Argument -.Ar flags -is one or more of the following: -.Bl -tag -width Ds -.It Ar A -Print all possible debugging information; -equivalent to specifying all of the debugging flags. -.It Ar a -Print debugging information about archive searching and caching. -.It Ar c -Print debugging information about conditional evaluation. -.It Ar d -Print debugging information about directory searching and caching. -.It Ar f -Print debugging information about the execution of for loops. -.It Ar "g1" -Print the input graph before making anything. -.It Ar "g2" -Print the input graph after making everything, or before exiting -on error. -.It Ar j -Print debugging information about running multiple shells. -.It Ar l -Print commands in Makefiles regardless of whether or not they are prefixed -by @ or other "quiet" flags. -Also known as "loud" behavior. -.It Ar m -Print debugging information about making targets, including modification -dates. -.It Ar s -Print debugging information about suffix-transformation rules. -.It Ar t -Print debugging information about target list maintenance. -.It Ar v -Print debugging information about variable assignment. -.El -.It Fl E Ar variable -Specify a variable whose environment value (if any) will override -macro assignments within makefiles. -.It Fl e -Specify that environment values override macro assignments within -makefiles for all variables. -.It Fl f Ar makefile -Specify a makefile to read instead of the default one. -If -.Ar makefile -is not an absolute pathname, -.Nm -will search for it as described above. -In case -.Ar makefile -is -.Sq Fl , -standard input is read. -Multiple -.Fl f -options can be supplied, -and the makefiles will be read in that order. -Unlike the other command-line options, -.Fl f -is neither stored in -.Va .MAKEFLAGS -nor pushed down to sub-makes via -.Ev MAKEFLAGS . -See below for more details on these variables. -.It Fl I Ar directory -Specify a directory in which to search for makefiles and included makefiles. -Multiple -.Fl I -options can be specified to form a search path. -The system makefile directory (or directories, see the -.Fl m -option) is automatically appended at the tail of this path. -.It Fl i -Ignore non-zero exit of shell commands in the makefile. -Equivalent to specifying -.Sq Ic \- -before each command line in the makefile. -.It Fl j Ar max_jobs -Specify the maximum number of jobs that -.Nm -may have running at any one time. -Turns compatibility mode off, unless the -.Fl B -flag is also specified. -.It Fl k -Continue processing after errors are encountered, but only on those targets -that do not depend on the target whose creation caused the error. -.It Fl m Ar directory -Specify a directory in which to search for -the system makefile and makefiles included via the <...> style. -Multiple -.Fl m -options can be specified to form a search path. -This path will override the default system include path, -.Pa /usr/share/mk . -The system include path will always be appended to the search path used -for "..."-style inclusions and makefile searches (see the -.Fl I -option). -.Pp -If a file or directory name in the -.Fl m -argument (or the -.Ev MAKESYSPATH -environment variable) starts with the string -.Qq \&.../ -then -.Nm -will search for the specified file or directory named in the remaining part -of the argument string. -The search starts with the current directory of the Makefile and then works -upward towards the root of the filesystem. -If the search is successful, -then the resulting directory replaces the -.Qq \&.../ -specification in the -.Fl m -argument. -If used, this feature allows -.Nm -to easily search in the current source tree for customized sys.mk files -(e.g. by using -.Qq \&.../mk/sys.mk -as an argument). -Note that a -.Fl C -that are earlier on the command line affect where -.Fl m Qq \&.../ -searches. -.It Fl n -Display the commands that would have been executed, but do not actually -execute them. -.It Fl P -Collate the output of a given job and display it only when the job finishes, -instead of mixing the output of parallel jobs together. -This option has no effect unless -.Fl j -is used too. -.It Fl p -Only print the input graph, not executing any commands. -The output is the same as -.Fl d Ar g1 . -When combined with -.Fl f Pa /dev/null , -only the builtin rules of -.Nm -are displayed. -.It Fl Q -Be extra quiet. -For multi-job makes, this will cause file banners not to be generated. -.It Fl q -Do not execute any commands, but exit 0 if the specified targets are -up-to-date and 1, otherwise. -.It Fl r -Do not process the system makefile. -.It Fl S -Stop processing when an error is encountered. -Default behaviour. -This is needed to negate the -.Fl k -option during recursive builds. -.It Fl s -Do not echo any commands as they are executed. -Equivalent to specifying -.Sq Ic @ -before each command line in the makefile. -.It Fl t -Rather than re-building a target as specified in the makefile, create it -or update its modification time to make it appear up-to-date. -.It Fl V Ar variable -Print -.Nm Ns 's -idea of the value of -.Ar variable , -in the global context. -Do not build any targets. -Multiple instances of this option may be specified; -the variables will be printed one per line, -with a blank line for each null or undefined variable. -If -.Ar variable -contains a -.Sq Ic $ -then the value will be expanded before printing. -.It Fl v -Be extra verbose. -Print any extra information. -.It Fl X -When using the -.Fl V -option to print the values of variables, -do not recursively expand the values. -.It Ar variable Ns No = Ns Ar value -Set the value of the variable -.Ar variable -to -.Ar value . -.It Fl x Ar warning_options -Specify extended warning options. -This option may be specified several times. -A -.Ar warning_option -can be prefixed with -.Dq Li no -in which case the warning is switched off. -The currently available options are: -.Bl -tag -width indent -.It Li dirsyntax -Warn if anything except blanks and comments follows an -.Ic .endif -or -.Ic .else -directive. -.El -.Pp -See also the -.Ic .WARN -special target. -.El -.Pp -There are seven different types of lines in a makefile: file dependency -specifications, shell commands, variable assignments, include statements, -conditional directives, for loops, and comments. -.Pp -In general, lines may be continued from one line to the next by ending -them with a backslash -.Pq Ql \e . -The trailing newline character and initial whitespace on the following -line are compressed into a single space. -.Sh FILE DEPENDENCY SPECIFICATIONS -Dependency lines consist of one or more targets, an operator, and zero -or more sources. -This creates a relationship where the targets -.Dq depend -on the sources -and are usually created from them. -The exact relationship between the target and the source is determined -by the operator that separates them. -The three operators are as follows: -.Bl -tag -width flag -.It Ic \&: -A target is considered out-of-date if its modification time is less than -those of any of its sources. -Sources for a target accumulate over dependency lines when this operator -is used. -The target is removed if -.Nm -is interrupted. -.It Ic \&! -Targets are always re-created, but not until all sources have been -examined and re-created as necessary. -Sources for a target accumulate over dependency lines when this operator -is used. -The target is removed if -.Nm -is interrupted. -.It Ic :: -If no sources are specified, the target is always re-created. -Otherwise, a target is considered out-of-date if any of its sources has -been modified more recently than the target. -Sources for a target do not accumulate over dependency lines when this -operator is used. -The target will not be removed if -.Nm -is interrupted. -.El -.Pp -Targets and sources may contain the shell wildcard expressions -.Ql \&? , -.Ql * , -.Ql [] -and -.Ql {} . -The expressions -.Ql \&? , -.Ql * -and -.Ql [] -may only be used as part of the final -component of the target or source, and must be used to describe existing -files. -The expression -.Ql {} -need not necessarily be used to describe existing files. -Expansion is in directory order, not alphabetically as done in the shell. -.Sh SHELL COMMANDS -Each target may have associated with it a series of shell commands, normally -used to create the target. -Each of the commands in this script -.Em must -be preceded by a tab. -While any target may appear on a dependency line, only one of these -dependencies may be followed by a creation script, unless the -.Sq Ic :: -operator is used. -.Pp -If the first characters of the command line are -.Sq Ic @ , -.Sq Ic \- , -and/or -.Sq Ic + , -the command is treated specially. -A -.Sq Ic @ -causes the command not to be echoed before it is executed. -A -.Sq Ic \- -causes any non-zero exit status of the command line to be ignored. -A -.Sq Ic + -causes the command to be executed even if -.Fl n -is specified on the command line. -.Sh VARIABLE ASSIGNMENTS -Variables in -.Nm -are much like variables in the shell, and, by tradition, -consist of all upper-case letters. -The five operators that can be used to assign values to variables are as -follows: -.Bl -tag -width Ds -.It Ic = -Assign the value to the variable. -Any previous value is overridden. -.It Ic += -Append the value to the current value of the variable. -.It Ic ?= -Assign the value to the variable if it is not already defined. -.It Ic := -Assign with expansion, i.e., expand the value before assigning it -to the variable. -Normally, expansion is not done until the variable is referenced. -.It Ic != -Expand the value and pass it to the shell for execution and assign -the result to the variable. -Any newlines in the result are replaced with spaces. -.El -.Pp -Any whitespace before the assigned -.Ar value -is removed; if the value is being appended, a single space is inserted -between the previous contents of the variable and the appended value. -.Pp -Variables are expanded by surrounding the variable name with either -curly braces -.Pq Ql {} -or parentheses -.Pq Ql () -and preceding it with -a dollar sign -.Pq Ql $ . -If the variable name contains only a single letter, the surrounding -braces or parentheses are not required. -This shorter form is not recommended. -.Pp -Variable substitution occurs at two distinct times, depending on where -the variable is being used. -Variables in dependency lines are expanded as the line is read. -Variables in shell commands are expanded when the shell command is -executed. -.Pp -The four different classes of variables (in order of increasing precedence) -are: -.Bl -tag -width Ds -.It Environment variables -Variables defined as part of -.Nm Ns 's -environment. -.It Global variables -Variables defined in the makefile or in included makefiles. -.It Command line variables -Variables defined as part of the command line and variables -obtained from the -.Ev MAKEFLAGS -environment variable or the -.Ic .MAKEFLAGS -target. -.It Local variables -Variables that are defined specific to a certain target. -.El -.Pp -If the name of an environment variable appears in a makefile -on the left-hand side of an assignment, -a global variable with the same name is created, and the latter -shadows the former as per their relative precedences. -The environment is not changed in this case, and the change -is not exported to programs executed by -.Nm . -However, a command-line variable actually replaces -the environment variable of the same name if the latter exists, -which is visible to child programs. -.Pp -There are seven local variables in -.Nm : -.Bl -tag -width ".ARCHIVE" -.It Va .ALLSRC -The list of all sources for this target; also known as -.Sq Va > . -.It Va .ARCHIVE -The name of the archive file; also known as -.Sq Va \&! . -.It Va .IMPSRC -The name/path of the source from which the target is to be transformed -(the -.Dq implied -source); also known as -.Sq Va < . -.It Va .MEMBER -The name of the archive member; also known as -.Sq Va % . -.It Va .OODATE -The list of sources for this target that were deemed out-of-date; also -known as -.Sq Va \&? . -.It Va .PREFIX -The file prefix of the file, containing only the file portion, no suffix -or preceding directory components; also known as -.Sq Va * . -.It Va .TARGET -The name of the target; also known as -.Sq Va @ . -.El -.Pp -The shorter forms -.Sq Va @ , -.Sq Va \&! , -.Sq Va < , -.Sq Va % , -.Sq Va \&? , -.Sq Va > , -and -.Sq Va * -are permitted for backward -compatibility and are not recommended. -The six variables -.Sq Va @F , -.Sq Va @D , -.Sq Va -.It Ic .include Ar \*qfile\*q -Include the specified makefile. -Variables between the angle brackets -or double quotes are expanded to form the file name. -If angle brackets -are used, the included makefile is expected to be in the system -makefile directory. -If double quotes are used, the including -makefile's directory and any directories specified using the -.Fl I -option are searched before the system -makefile directory. -.It Ic .sinclude Ar -.It Ic .sinclude Ar \*qfile\*q -Like -.Ic .include , -but silently ignored if the file cannot be found and opened. -.It Ic .undef Ar variable -Un-define the specified global variable. -Only global variables may be un-defined. -.It Ic .error Ar message -Terminate processing of the makefile immediately. -The filename of the -makefile, the line on which the error was encountered and the specified -message are printed to the standard error output and -.Nm -terminates with exit code 1. -Variables in the message are expanded. -.It Ic .warning Ar message -Emit a warning message. -The filename of the makefile, -the line on which the warning was encountered, -and the specified message are printed to the standard error output. -Variables in the message are expanded. -.El -.Pp -Conditionals are used to determine which parts of the Makefile -to process. -They are used similarly to the conditionals supported -by the C pre-processor. -The following conditionals are supported: -.Bl -tag -width Ds -.It Xo -.Ic .if -.Oo \&! Oc Ns Ar expression -.Op Ar operator expression ... -.Xc -Test the value of an expression. -.It Xo -.Ic .ifdef -.Oo \&! Oc Ns Ar variable -.Op Ar operator variable ... -.Xc -Test the value of a variable. -.It Xo -.Ic .ifndef -.Oo \&! Oc Ns Ar variable -.Op Ar operator variable ... -.Xc -Test the value of a variable. -.It Xo -.Ic .ifmake -.Oo \&! Oc Ns Ar target -.Op Ar operator target ... -.Xc -Test the target being built. -.It Xo -.Ic .ifnmake -.Oo \&! Oc Ns Ar target -.Op Ar operator target ... -.Xc -Test the target being built. -.It Ic .else -Reverse the sense of the last conditional. -.It Xo -.Ic .elif -.Oo \&! Oc Ns Ar expression -.Op Ar operator expression ... -.Xc -A combination of -.Ic .else -followed by -.Ic .if . -.It Xo -.Ic .elifdef -.Oo \&! Oc Ns Ar variable -.Op Ar operator variable ... -.Xc -A combination of -.Ic .else -followed by -.Ic .ifdef . -.It Xo -.Ic .elifndef -.Oo \&! Oc Ns Ar variable -.Op Ar operator variable ... -.Xc -A combination of -.Ic .else -followed by -.Ic .ifndef . -.It Xo -.Ic .elifmake -.Oo \&! Oc Ns Ar target -.Op Ar operator target ... -.Xc -A combination of -.Ic .else -followed by -.Ic .ifmake . -.It Xo -.Ic .elifnmake -.Oo \&! Oc Ns Ar target -.Op Ar operator target ... -.Xc -A combination of -.Ic .else -followed by -.Ic .ifnmake . -.It Ic .endif -End the body of the conditional. -.El -.Pp -The -.Ar operator -may be any one of the following: -.Bl -tag -width "Cm XX" -.It Cm || -Logical -.Tn OR -.It Cm && -Logical -.Tn AND ; -of higher precedence than -.Sq Ic || . -.El -.Pp -As in C, -.Nm -will only evaluate a conditional as far as is necessary to determine -its value. -Parentheses may be used to change the order of evaluation. -The boolean operator -.Sq Ic !\& -may be used to logically negate an entire -conditional. -It is of higher precedence than -.Sq Ic && . -.Pp -The value of -.Ar expression -may be any of the following: -.Bl -tag -width Ic -.It Ic defined -Takes a variable name as an argument and evaluates to true if the variable -has been defined. -.It Ic make -Takes a target name as an argument and evaluates to true if the target -was specified as part of -.Nm Ns 's -command line or was declared the default target (either implicitly or -explicitly, see -.Va .MAIN ) -before the line containing the conditional. -.It Ic empty -Takes a variable, with possible modifiers, and evaluates to true if -the expansion of the variable would result in an empty string. -.It Ic exists -Takes a file name as an argument and evaluates to true if the file exists. -The file is searched for on the system search path (see -.Va .PATH ) . -.It Ic target -Takes a target name as an argument and evaluates to true if the target -has been defined. -.El -.Pp -An -.Ar expression -may also be a numeric or string comparison: -in this case, the left-hand side -.Ar must be -a variable expansion, whereas the right-hand side can be a -constant or a variable expansion. -Variable expansion is performed on both sides, after which the resulting -values are compared. -A value is interpreted as hexadecimal if it is -preceded by 0x, otherwise it is decimal; octal numbers are not supported. -.Pp -String comparison can only use the -.Sq Ic == -or -.Sq Ic != -operators, whereas numeric values (both integer and floating point) -can also be compared using the -.Sq Ic > , -.Sq Ic >= , -.Sq Ic < -and -.Sq Ic <= -operators. -.Pp -If no relational operator (and right-hand value) are given, an implicit -.Sq Ic != 0 -is used. -However be very careful in using this feature especially -when the left-hand side variable expansion returns a string. -.Pp -When -.Nm -is evaluating one of these conditional expressions, and it encounters -a word it does not recognize, either the -.Dq make -or -.Dq defined -expression is applied to it, depending on the form of the conditional. -If the form is -.Ic .if , -.Ic .ifdef -or -.Ic .ifndef , -the -.Dq defined -expression is applied. -Similarly, if the form is -.Ic .ifmake -or -.Ic .ifnmake , -the -.Dq make -expression is applied. -.Pp -If the conditional evaluates to true the parsing of the makefile continues -as before. -If it evaluates to false, the following lines are skipped. -In both cases this continues until a -.Ic .else -or -.Ic .endif -is found. -.Pp -For loops are typically used to apply a set of rules to a list of files. -The syntax of a for loop is: -.Pp -.Bl -tag -width indent -compact -.It Ic .for Ar variable Ic in Ar expression -.It -.It Ic .endfor -.El -.Pp -After the for -.Ar expression -is evaluated, it is split into words. -The -iteration -.Ar variable -is successively set to each word, and substituted in the -.Ic make-rules -inside the body of the for loop. -.Sh COMMENTS -Comments begin with a hash -.Pq Ql # -character, anywhere but in a shell -command line, and continue to the end of the line. -.Sh SPECIAL SOURCES -.Bl -tag -width Ic -.It Ic .IGNORE -Ignore any errors from the commands associated with this target, exactly -as if they all were preceded by a dash -.Pq Ql \- . -.It Ic .MAKE -Execute the commands associated with this target even if the -.Fl n -or -.Fl t -options were specified. -Normally used to mark recursive -.Nm Ns 's . -.It Ic .NOTMAIN -Normally -.Nm -selects the first target it encounters as the default target to be built -if no target was specified. -This source prevents this target from being selected. -.It Ic .OPTIONAL -If a target is marked with this attribute and -.Nm -cannot figure out how to create it, it will ignore this fact and assume -the file is not needed or already exists. -.It Ic .PRECIOUS -When -.Nm -is interrupted, it removes any partially made targets. -This source prevents the target from being removed. -.It Ic .SILENT -Do not echo any of the commands associated with this target, exactly -as if they all were preceded by an at sign -.Pq Ql @ . -.It Ic .USE -Turn the target into -.Nm Ns 's -version of a macro. -When the target is used as a source for another target, the other target -acquires the commands, sources, and attributes (except for -.Ic .USE ) -of the -source. -If the target already has commands, the -.Ic .USE -target's commands are appended -to them. -.It Ic .WAIT -If special -.Ic .WAIT -source appears in a dependency line, the sources that precede it are -made before the sources that succeed it in the line. -Loops are not being -detected and targets that form loops will be silently ignored. -.El -.Sh SPECIAL TARGETS -Special targets may not be included with other targets, i.e., they must be -the only target specified. -.Bl -tag -width Ic -.It Ic .BEGIN -Any command lines attached to this target are executed before anything -else is done. -.It Ic .DEFAULT -This is sort of a -.Ic .USE -rule for any target (that was used only as a -source) that -.Nm -cannot figure out any other way to create. -Only the shell script is used. -The -.Ic .IMPSRC -variable of a target that inherits -.Ic .DEFAULT Ns 's -commands is set -to the target's own name. -.It Ic .END -Any command lines attached to this target are executed after everything -else is done. -.It Ic .IGNORE -Mark each of the sources with the -.Ic .IGNORE -attribute. -If no sources are specified, this is the equivalent of specifying the -.Fl i -option. -.It Ic .INCLUDES -A list of suffixes that indicate files that can be included in a source -file. -The suffix must have already been declared with -.Ic .SUFFIXES ; -any suffix so declared will have the directories on its search path (see -.Ic .PATH ) -placed in the -.Va .INCLUDES -special variable, each preceded by a -.Fl I -flag. -.It Ic .INTERRUPT -If -.Nm -is interrupted, the commands for this target will be executed. -.It Ic .LIBS -This does for libraries what -.Ic .INCLUDES -does for include files, except that the flag used is -.Fl L . -.It Ic .MAIN -If no target is specified when -.Nm -is invoked, this target will be built. -This is always set, either -explicitly, or implicitly when -.Nm -selects the default target, to give the user a way to refer to the default -target on the command line. -.It Ic .MAKEFILEDEPS -Enable the -.Dq Remaking Makefiles -functionality, as explained in the -.Sx REMAKING MAKEFILES -section below. -.It Ic .MAKEFLAGS -This target provides a way to specify flags for -.Nm -when the makefile is used. -The flags are as if typed to the shell, though the -.Fl f -option will have -no effect. -Flags (except for -.Fl f ) -and variable assignments specified as the source -for this target are also appended to the -.Va .MAKEFLAGS -internal variable. -Please note the difference between this target and the -.Va .MAKEFLAGS -internal variable: specifying an option or variable -assignment as the source for this target will affect -.Em both -the current makefile and all processes that -.Nm -executes. -.It Ic .MFLAGS -Same as above, for backward compatibility. -.\" XXX: NOT YET!!!! -.\" .It Ic .NOTPARALLEL -.\" The named targets are executed in non parallel mode. If no targets are -.\" specified, then all targets are executed in non parallel mode. -.It Ic .NOTPARALLEL -Disable parallel mode. -.It Ic .NO_PARALLEL -Same as above, for compatibility with other -.Nm pmake -variants. -.It Ic .ORDER -The named targets are made in sequence. -.\" XXX: NOT YET!!!! -.\" .It Ic .PARALLEL -.\" The named targets are executed in parallel mode. If no targets are -.\" specified, then all targets are executed in parallel mode. -.It Ic .PATH -The sources are directories which are to be searched for files not -found in the current directory. -If no sources are specified, any previously specified directories are -deleted. -Where possible, use of -.Ic .PATH -is preferred over use of the -.Va VPATH -variable. -.It Ic .PATH\fIsuffix\fR -The sources are directories which are to be searched for suffixed files -not found in the current directory. -The -.Nm -utility -first searches the suffixed search path, before reverting to the default -path if the file is not found there. -This form is required for -.Ic .LIBS -and -.Ic .INCLUDES -to work. -.It Ic .PHONY -Apply the -.Ic .PHONY -attribute to any specified sources. -Targets with this attribute are always -considered to be out of date. -.It Ic .POSIX -Adjust -.Nm Ap s -behavior to match the applicable -.Tn POSIX -specifications. -(Note this disables the -.Dq Remaking Makefiles -feature.) -.It Ic .PRECIOUS -Apply the -.Ic .PRECIOUS -attribute to any specified sources. -If no sources are specified, the -.Ic .PRECIOUS -attribute is applied to every -target in the file. -.It Ic .SHELL -Select another shell. -The sources of this target have the format -.Ar key Ns = Ns Ar value . -The -.Ar key -is one of: -.Bl -tag -width ".Va hasErrCtl" -.It Va path -Specify the path to the new shell. -.It Va name -Specify the name of the new shell. -This may be either one of the three builtin shells (see below) or any -other name. -.It Va quiet -Specify the shell command to turn echoing off. -.It Va echo -Specify the shell command to turn echoing on. -.It Va filter -Usually shells print the echo off command before turning echoing off. -This is the exact string that will be printed by the shell and is used -to filter the shell output to remove the echo off command. -.It Va echoFlag -The shell option that turns echoing on. -.It Va errFlag -The shell option to turn on error checking. -If error checking is on, the shell should exit if a command returns -a non-zero status. -.It Va hasErrCtl -True if the shell has error control. -.It Va check -If -.Va hasErrCtl -is true then this is the shell command to turn error checking on. -If -.Va hasErrCtl -is false then this is a command template to echo commands for which error -checking is disabled. -The template must contain a -.Ql %s . -.It Va ignore -If -.Va hasErrCtl -is true, this is the shell command to turn error checking off. -If -.Va hasErrCtl -is false, this is a command template to execute a command so that errors -are ignored. -The template must contain a -.Ql %s . -.It Va meta -This is a string of meta characters of the shell. -.It Va builtins -This is a string holding all the shell's builtin commands separated by blanks. -The -.Va meta -and -.Va builtins -strings are used in compat mode. -When a command line contains neither a meta -character nor starts with a shell builtin, it is executed directly without -invoking a shell. -When one of these strings (or both) is empty all commands are executed -through a shell. -.It Va unsetenv -If true, remove the -.Ev ENV -environment variable before executing any command. -This is useful for the Korn-shell -.Pq Nm ksh . -.El -.Pp -Values that are strings must be surrounded by double quotes. -Boolean values are specified as -.Ql T -or -.Ql Y -(in either case) to mean true. -Any other value is taken to mean false. -.Pp -There are several uses of the -.Ic .SHELL -target: -.Bl -bullet -.It -Selecting one of the builtin shells. -This is done by just specifying the name of the shell with the -.Va name -keyword. -It is also possible to modify the parameters of the builtin shell by just -specifying other keywords (except for -.Va path ) . -.It -Using another executable for one of the builtin shells. -This is done by specifying the path to the executable with the -.Va path -keyword. -If the last component is the same as the name of the builtin shell, no -name needs to be specified; if it is different, the name must be given: -.Bd -literal -offset indent -\&.SHELL: path="/usr/local/bin/sh" -.Ed -.Pp -selects the builtin shell -.Dq Li sh -but will execute it from -.Pa /usr/local/bin/sh . -Like in the previous case, it is possible to modify parameters of the builtin -shell by just specifying them. -.It -Using an entirely different shell. -This is done by specifying all keywords. -.El -.Pp -The builtin shells are -.Dq Li sh , -.Dq Li csh -and -.Dq Li ksh . -Because -.Fx -has no -.Nm ksh -in -.Pa /bin , -it is unwise to specify -.Va name Ns = Ns Qq Li ksh -without also specifying a path. -.It Ic .SILENT -Apply the -.Ic .SILENT -attribute to any specified sources. -If no sources are specified, the -.Ic .SILENT -attribute is applied to every -command in the file. -.It Ic .SUFFIXES -Each source specifies a suffix to -.Nm . -If no sources are specified, any previous specified suffixes are deleted. -.It Ic .WARN -Each source specifies a warning flag as previously described for the -.Fl x -command line option. -Warning flags specified on the command line take precedence over flags -specified in the makefile. -Also, command line warning flags are pushed to sub-makes through the -.Ev MAKEFLAGS -environment variables so that a warning flag specified on the command -line will influence all sub-makes. -Several flags can be specified on a single -.Ic .WARN -target by separating them with blanks. -.El -.Sh REMAKING MAKEFILES -If the special target -.Ic .MAKEFILEDEPS -exists in the Makefile, -.Nm -enables the -.Dq Remaking Makefiles -feature. -After reading Makefile and all the files that are included using -.Ic .include -or -.Ic .sinclude -directives (source Makefiles) -.Nm -considers each source Makefile as a target and tries to rebuild it. -Both explicit and implicit rules are checked and all source Makefiles -are updated if necessary. If any of the source Makefiles were rebuilt, -.Nm -restarts from clean state. -.Pp -To prevent infinite loops the following source Makefile targets are ignored: -.Bl -bullet -.It -.Ic :: -targets that have no prerequisites -.It -.Ic \&! -targets -.It -targets that have -.Ic .PHONY -or -.Ic .EXEC -attributes -.It -targets without prerequisites and without commands -.El -.Pp -When remaking a source Makefile options -.Ic -t -(touch target), -.Ic -q -(query mode), and -.Ic -n -(no exec) do not take effect, unless source Makefile is specified -explicitly as a target in -.Nm -command line. -.Pp -Additionally, system makefiles and -.Ic .depend -are not considered as Makefiles that can be rebuilt. -.Sh ENVIRONMENT -The -.Nm -utility uses the following environment variables, if they exist: -.Ev MACHINE , -.Ev MAKE , -.Ev MAKEFLAGS , -.Ev MAKEOBJDIR , -.Ev MAKEOBJDIRPREFIX , -and -.Ev MAKESYSPATH . -.Sh FILES -.Bl -tag -width /usr/share/doc/psd/12.make -compact -.It Pa .depend -list of dependencies -.It Pa Makefile -list of dependencies -.It Pa makefile -list of dependencies -.It Pa obj -object directory -.It Pa sys.mk -system makefile -.It Pa /usr/share/mk -default system makefile directory -.It Pa /usr/share/doc/psd/12.make -PMake tutorial -.It Pa /usr/obj -default -.Ev MAKEOBJDIRPREFIX -directory. -.It Pa /etc/make.conf -default path to -.Xr make.conf 5 -.El -.Sh EXAMPLES -List all included makefiles in order visited: -.Pp -.Dl "make -V .MAKEFILE_LIST | tr \e\ \e\en" -.Sh COMPATIBILITY -Older versions of -.Nm -used -.Ev MAKE -instead of -.Ev MAKEFLAGS . -This was removed for -.Tn POSIX -compatibility. -The internal variable -.Va MAKE -is set to the same value as -.Va .MAKE ; -support for this may be removed in the future. -.Pp -The use of the -.Cm :L -and -.Cm :U -modifiers are deprecated -in -.Fx 10.0 -and the more portable (among Pmake decedents) -.Cm :tl -and -.Cm :tu -should be used instead. -.Pp -Most of the more esoteric features of -.Nm -should probably be avoided for greater compatibility. -.Sh SEE ALSO -.Xr mkdep 1 , -.Xr make.conf 5 -.Rs -.%T "PMake - A Tutorial" -.Re -in -.Pa /usr/share/doc/psd/12.make -.Sh HISTORY -A -.Nm -command appeared in PWB UNIX. -.Sh BUGS -The determination of -.Va .OBJDIR -is contorted to the point of absurdity. -.Pp -In the presence of several -.Ic .MAIN -special targets, -.Nm -silently ignores all but the first. -.Pp -.Va .TARGETS -is not set to the default target when -.Nm -is invoked without a target name and no -.Ic .MAIN -special target exists. -.Pp -The evaluation of -.Ar expression -in a test is very simple-minded. -Currently, the only form that works is -.Ql .if ${VAR} op something . -For instance, you should write tests as -.Ql .if ${VAR} == "string" -not the other way around, which would give you an error. -.Pp -For loops are expanded before tests, so a fragment such as: -.Bd -literal -offset indent -\&.for ARCH in ${SHARED_ARCHS} -\&.if ${ARCH} == ${MACHINE} - ... -\&.endif -\&.endfor -.Ed -.Pp -will not work, and should be rewritten as: -.Bd -literal -offset indent -\&.for ARCH in ${SHARED_ARCHS} -\&.if ${MACHINE} == ${ARCH} - ... -\&.endif -\&.endfor -.Ed -.Pp -The parsing code is broken with respect to handling a semicolon -after a colon, so a fragment like this will fail: -.Bd -literal -offset indent -HDRS= foo.h bar.h - -all: -\&.for h in ${HDRS:S;^;${.CURDIR}/;} - ... -\&.endfor -.Ed -.Pp -A trailing backslash in a variable value defined on the command line causes -the delimiting space in the -.Ev MAKEFLAGS -environment variable to be preceded by that backslash. -That causes a submake to not treat that space as a word delimiter. -Fixing this requires a larger rewrite of the code handling command line -macros and assignments to -.Va .MAKEFLAGS . Property changes on: head/usr.bin/make/make.1 ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/shell.c =================================================================== --- head/usr.bin/make/shell.c (revision 284463) +++ head/usr.bin/make/shell.c (nonexistent) @@ -1,472 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1988, 1989 by Adam de Boor - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include - -#include "parse.h" -#include "pathnames.h" -#include "shell.h" -#include "util.h" - -/* - * Descriptions for various shells. What the list of builtins should contain - * is debatable: either all builtins or only those which may specified on - * a single line without use of meta-characters. For correct makefiles that - * contain only correct command lines there is no difference. But if a command - * line, for example, is: 'if -foo bar' and there is an executable named 'if' - * in the path, the first possibility would execute that 'if' while in the - * second case the shell would give an error. Histerically only a small - * subset of the builtins and no reserved words where given in the list which - * corresponds roughly to the first variant. So go with this but add missing - * words. - */ -#define CSH_BUILTINS \ - "alias cd eval exec exit read set ulimit unalias " \ - "umask unset wait" - -#define SH_BUILTINS \ - "alias cd eval exec exit read set ulimit unalias " \ - "umask unset wait" - -#define CSH_META "#=|^(){};&<>*?[]:$`\\@\n" -#define SH_META "#=|^(){};&<>*?[]:$`\\\n" - -static const char *const shells_init[] = { - /* - * CSH description. The csh can do echo control by playing - * with the setting of the 'echo' shell variable. Sadly, - * however, it is unable to do error control nicely. - */ - "name=csh path='" PATH_DEFSHELLDIR "/csh' " - "quiet='unset verbose' echo='set verbose' filter='unset verbose' " - "hasErrCtl=N check='echo \"%s\"\n' ignore='csh -c \"%s || exit 0\"' " - "echoFlag=v errFlag=e " - "meta='" CSH_META "' builtins='" CSH_BUILTINS "'", - - /* - * SH description. Echo control is also possible and, under - * sun UNIX anyway, one can even control error checking. - */ - "name=sh path='" PATH_DEFSHELLDIR "/sh' " - "quiet='set -' echo='set -v' filter='set -' " - "hasErrCtl=Y check='set -e' ignore='set +e' " - "echoFlag=v errFlag=e " - "meta='" SH_META "' builtins='" SH_BUILTINS "'", - - /* - * KSH description. The Korn shell has a superset of - * the Bourne shell's functionality. There are probably builtins - * missing here. - */ - "name=ksh path='" PATH_DEFSHELLDIR "/ksh' " - "quiet='set -' echo='set -v' filter='set -' " - "hasErrCtl=Y check='set -e' ignore='set +e' " - "echoFlag=v errFlag=e " - "meta='" SH_META "' builtins='" SH_BUILTINS "' unsetenv=T", - - NULL -}; - -/* - * This is the shell to which we pass all commands in the Makefile. - * It is set by the Job_ParseShell function. - */ -struct Shell *commandShell; - -/* - * This is the list of all known shells. - */ -static struct Shells shells = TAILQ_HEAD_INITIALIZER(shells); - -void ShellDump(const struct Shell *) __unused; - -/** - * Helper function for sorting the builtin list alphabetically. - */ -static int -sort_builtins(const void *p1, const void *p2) -{ - - return (strcmp(*(const char* const*)p1, *(const char* const*)p2)); -} - -/** - * Free a shell structure and all associated strings. - */ -static void -ShellFree(struct Shell *sh) -{ - - if (sh != NULL) { - free(sh->name); - free(sh->path); - free(sh->echoOff); - free(sh->echoOn); - free(sh->noPrint); - free(sh->errCheck); - free(sh->ignErr); - free(sh->echo); - free(sh->exit); - ArgArray_Done(&sh->builtins); - free(sh->meta); - free(sh); - } -} - -/** - * Dump a shell specification to stderr. - */ -void -ShellDump(const struct Shell *sh) -{ - int i; - - fprintf(stderr, "Shell %p:\n", sh); - fprintf(stderr, " name='%s' path='%s'\n", sh->name, sh->path); - fprintf(stderr, " hasEchoCtl=%d echoOff='%s' echoOn='%s'\n", - sh->hasEchoCtl, sh->echoOff, sh->echoOn); - fprintf(stderr, " noPrint='%s'\n", sh->noPrint); - fprintf(stderr, " hasErrCtl=%d errCheck='%s' ignErr='%s'\n", - sh->hasErrCtl, sh->errCheck, sh->ignErr); - fprintf(stderr, " echo='%s' exit='%s'\n", sh->echo, sh->exit); - fprintf(stderr, " builtins=%d\n", sh->builtins.argc - 1); - for (i = 1; i < sh->builtins.argc; i++) - fprintf(stderr, " '%s'", sh->builtins.argv[i]); - fprintf(stderr, "\n meta='%s'\n", sh->meta); - fprintf(stderr, " unsetenv=%d\n", sh->unsetenv); -} - -/** - * Parse a shell specification line and return the new Shell structure. - * In case of an error a message is printed and NULL is returned. - */ -static struct Shell * -ShellParseSpec(const char *spec, Boolean *fullSpec) -{ - ArgArray aa; - struct Shell *sh; - char *eq; - char *keyw; - int arg; - - *fullSpec = FALSE; - - sh = emalloc(sizeof(*sh)); - memset(sh, 0, sizeof(*sh)); - ArgArray_Init(&sh->builtins); - - /* - * Parse the specification by keyword but skip the first word - */ - brk_string(&aa, spec, TRUE); - - for (arg = 1; arg < aa.argc; arg++) { - /* - * Split keyword and value - */ - keyw = aa.argv[arg]; - if ((eq = strchr(keyw, '=')) == NULL) { - Parse_Error(PARSE_FATAL, "missing '=' in shell " - "specification keyword '%s'", keyw); - ArgArray_Done(&aa); - ShellFree(sh); - return (NULL); - } - *eq++ = '\0'; - - if (strcmp(keyw, "path") == 0) { - free(sh->path); - sh->path = estrdup(eq); - } else if (strcmp(keyw, "name") == 0) { - free(sh->name); - sh->name = estrdup(eq); - } else if (strcmp(keyw, "quiet") == 0) { - free(sh->echoOff); - sh->echoOff = estrdup(eq); - *fullSpec = TRUE; - } else if (strcmp(keyw, "echo") == 0) { - free(sh->echoOn); - sh->echoOn = estrdup(eq); - *fullSpec = TRUE; - } else if (strcmp(keyw, "filter") == 0) { - free(sh->noPrint); - sh->noPrint = estrdup(eq); - *fullSpec = TRUE; - } else if (strcmp(keyw, "echoFlag") == 0) { - free(sh->echo); - sh->echo = estrdup(eq); - *fullSpec = TRUE; - } else if (strcmp(keyw, "errFlag") == 0) { - free(sh->exit); - sh->exit = estrdup(eq); - *fullSpec = TRUE; - } else if (strcmp(keyw, "hasErrCtl") == 0) { - sh->hasErrCtl = (*eq == 'Y' || *eq == 'y' || - *eq == 'T' || *eq == 't'); - *fullSpec = TRUE; - } else if (strcmp(keyw, "check") == 0) { - free(sh->errCheck); - sh->errCheck = estrdup(eq); - *fullSpec = TRUE; - } else if (strcmp(keyw, "ignore") == 0) { - free(sh->ignErr); - sh->ignErr = estrdup(eq); - *fullSpec = TRUE; - } else if (strcmp(keyw, "builtins") == 0) { - ArgArray_Done(&sh->builtins); - brk_string(&sh->builtins, eq, TRUE); - qsort(sh->builtins.argv + 1, sh->builtins.argc - 1, - sizeof(char *), sort_builtins); - *fullSpec = TRUE; - } else if (strcmp(keyw, "meta") == 0) { - free(sh->meta); - sh->meta = estrdup(eq); - *fullSpec = TRUE; - } else if (strcmp(keyw, "unsetenv") == 0) { - sh->unsetenv = (*eq == 'Y' || *eq == 'y' || - *eq == 'T' || *eq == 't'); - *fullSpec = TRUE; - } else { - Parse_Error(PARSE_FATAL, "unknown keyword in shell " - "specification '%s'", keyw); - ArgArray_Done(&aa); - ShellFree(sh); - return (NULL); - } - } - ArgArray_Done(&aa); - - /* - * Some checks (could be more) - */ - if (*fullSpec) { - if ((sh->echoOn != NULL) ^ (sh->echoOff != NULL)) { - Parse_Error(PARSE_FATAL, "Shell must have either both " - "echoOff and echoOn or none of them"); - ShellFree(sh); - return (NULL); - } - - if (sh->echoOn != NULL && sh->echoOff != NULL) - sh->hasEchoCtl = TRUE; - } - - return (sh); -} - -/** - * Parse the builtin shell specifications and put them into the shell - * list. Then select the default shell to be the current shell. This - * is called from main() before any parsing (including MAKEFLAGS and - * command line) is done. - */ -void -Shell_Init(void) -{ - int i; - struct Shell *sh; - Boolean fullSpec; - - for (i = 0; shells_init[i] != NULL; i++) { - sh = ShellParseSpec(shells_init[i], &fullSpec); - TAILQ_INSERT_TAIL(&shells, sh, link); - if (strcmp(sh->name, DEFSHELLNAME) == 0) - commandShell = sh; - } -} - -/** - * Find a matching shell in 'shells' given its final component. - * - * Results: - * A pointer to a freshly allocated Shell structure with the contents - * from static description or NULL if no shell with the given name - * is found. - */ -static struct Shell * -ShellMatch(const char *name) -{ - struct Shell *sh; - - TAILQ_FOREACH(sh, &shells, link) - if (strcmp(sh->name, name) == 0) - return (sh); - - return (NULL); -} - -/** - * Parse a shell specification and set up commandShell appropriately. - * - * Results: - * TRUE if the specification was correct. FALSE otherwise. - * - * Side Effects: - * commandShell points to a Shell structure. - * created from the shell spec). - * - * Notes: - * A shell specification consists of a .SHELL target, with dependency - * operator, followed by a series of blank-separated words. Double - * quotes can be used to use blanks in words. A backslash escapes - * anything (most notably a double-quote and a space) and - * provides the functionality it does in C. Each word consists of - * keyword and value separated by an equal sign. There should be no - * unnecessary spaces in the word. The keywords are as follows: - * name Name of shell. - * path Location of shell. Overrides "name" if given - * quiet Command to turn off echoing. - * echo Command to turn echoing on - * filter Result of turning off echoing that shouldn't be - * printed. - * echoFlag Flag to turn echoing on at the start - * errFlag Flag to turn error checking on at the start - * hasErrCtl True if shell has error checking control - * check Command to turn on error checking if hasErrCtl - * is TRUE or template of command to echo a command - * for which error checking is off if hasErrCtl is - * FALSE. - * ignore Command to turn off error checking if hasErrCtl - * is TRUE or template of command to execute a - * command so as to ignore any errors it returns if - * hasErrCtl is FALSE. - * builtins A space separated list of builtins. If one - * of these builtins is detected when make wants - * to execute a command line, the command line is - * handed to the shell. Otherwise make may try to - * execute the command directly. If this list is empty - * it is assumed, that the command must always be - * handed over to the shell. - * meta The shell meta characters. If this is not specified - * or empty, commands are alway passed to the shell. - * Otherwise they are not passed when they contain - * neither a meta character nor a builtin command. - * unsetenv Unsetenv("ENV") before executing anything. - */ -Boolean -Shell_Parse(const char line[]) -{ - Boolean fullSpec; - struct Shell *sh; - struct Shell *match; - - /* parse the specification */ - if ((sh = ShellParseSpec(line, &fullSpec)) == NULL) - return (FALSE); - - if (sh->path == NULL) { - /* - * If no path was given, the user wants one of the pre-defined - * shells, yes? So we find the one s/he wants with the help of - * JobMatchShell and set things up the right way. - */ - if (sh->name == NULL) { - Parse_Error(PARSE_FATAL, - "Neither path nor name specified"); - ShellFree(sh); - return (FALSE); - } - if (fullSpec) { - /* - * XXX May want to merge sh into match. But this - * require ShellParseSpec to return information - * which attributes actuall have been specified. - */ - Parse_Error(PARSE_FATAL, "No path specified"); - ShellFree(sh); - return (FALSE); - } - if ((match = ShellMatch(sh->name)) == NULL) { - Parse_Error(PARSE_FATAL, "%s: no matching shell", - sh->name); - ShellFree(sh); - return (FALSE); - } - ShellFree(sh); - commandShell = match; - - return (TRUE); - } - - /* - * The user provided a path. If s/he gave nothing else - * (fullSpec is FALSE), try and find a matching shell in the - * ones we know of. Else we just take the specification at its - * word and copy it to a new location. In either case, we need - * to record the path the user gave for the shell. - */ - if (sh->name == NULL) { - /* get the base name as the name */ - if ((sh->name = strrchr(sh->path, '/')) == NULL) { - sh->name = estrdup(sh->path); - } else { - sh->name = estrdup(sh->name + 1); - } - } - - if (!fullSpec) { - if ((match = ShellMatch(sh->name)) == NULL) { - Parse_Error(PARSE_FATAL, - "%s: no matching shell", sh->name); - ShellFree(sh); - return (FALSE); - } - - /* set the patch on the matching shell */ - free(match->path); - match->path = sh->path; - sh->path = NULL; - - ShellFree(sh); - commandShell = match; - return (TRUE); - } - - TAILQ_INSERT_HEAD(&shells, sh, link); - - /* set the new shell */ - commandShell = sh; - return (TRUE); -} Property changes on: head/usr.bin/make/shell.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/targ.h =================================================================== --- head/usr.bin/make/targ.h (revision 284463) +++ head/usr.bin/make/targ.h (nonexistent) @@ -1,73 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef targ_h_6ded1830 -#define targ_h_6ded1830 - -#include - -/* - * The TARG_ constants are used when calling the Targ_FindNode and - * Targ_FindList functions in targ.c. They simply tell the functions what to - * do if the desired node(s) is (are) not found. If the TARG_CREATE constant - * is given, a new, empty node will be created for the target, placed in the - * table of all targets and its address returned. If TARG_NOCREATE is given, - * a NULL pointer will be returned. - */ -#define TARG_CREATE 0x01 /* create node if not found */ -#define TARG_NOCREATE 0x00 /* don't create it */ - -struct GNode; -struct Lst; - -void Targ_Init(void); -struct GNode *Targ_NewGN(const char *); -struct GNode *Targ_FindNode(const char *, int); -void Targ_FindList(struct Lst *, struct Lst *, int); -Boolean Targ_Ignore(struct GNode *); -Boolean Targ_Silent(struct GNode *); -Boolean Targ_Precious(struct GNode *); -void Targ_SetMain(struct GNode *); -int Targ_PrintCmd(void *, void *); -char *Targ_FmtTime(time_t); -void Targ_PrintType(int); -void Targ_PrintGraph(int); - -#endif /* targ_h_6ded1830 */ Property changes on: head/usr.bin/make/targ.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/parse.h =================================================================== --- head/usr.bin/make/parse.h (revision 284463) +++ head/usr.bin/make/parse.h (nonexistent) @@ -1,86 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef parse_h_470eeb9a -#define parse_h_470eeb9a - -#include - -#include "util.h" - -struct GNode; -struct Lst; - -/* - * Error levels for parsing. PARSE_FATAL means the process cannot continue - * once the makefile has been parsed. PARSE_WARNING means it can. Passed - * as the first argument to Parse_Error. - */ -#define PARSE_WARNING 2 -#define PARSE_FATAL 1 - -/* - * Definitions for the "local" variables. Used only for clarity. - */ -#define TARGET "@" /* Target of dependency */ -#define OODATE "?" /* All out-of-date sources */ -#define ALLSRC ">" /* All sources */ -#define IMPSRC "<" /* Source implied by transformation */ -#define PREFIX "*" /* Common prefix */ -#define ARCHIVE "!" /* Archive in "archive(member)" syntax */ -#define MEMBER "%" /* Member in "archive(member)" syntax */ - -#define FTARGET "@F" /* file part of TARGET */ -#define DTARGET "@D" /* directory part of TARGET */ -#define FIMPSRC " - -#include "str.h" -#include "util.h" - -/** - * Shell Specifications: - * - * Some special stuff goes on if a shell doesn't have error control. In such - * a case, errCheck becomes a printf template for echoing the command, - * should echoing be on and ignErr becomes another printf template for - * executing the command while ignoring the return status. If either of these - * strings is empty when hasErrCtl is FALSE, the command will be executed - * anyway as is and if it causes an error, so be it. - */ -struct Shell { - TAILQ_ENTRY(Shell) link; /* link all shell descriptions */ - - /* - * the name of the shell. For Bourne and C shells, this is used - * only to find the shell description when used as the single - * source of a .SHELL target. - */ - char *name; - - char *path; /* full path to the shell */ - - /* True if both echoOff and echoOn defined */ - Boolean hasEchoCtl; - - char *echoOff; /* command to turn off echo */ - char *echoOn; /* command to turn it back on */ - - /* - * What the shell prints, and its length, when given the - * echo-off command. This line will not be printed when - * received from the shell. This is usually the command which - * was executed to turn off echoing - */ - char *noPrint; - - /* set if can control error checking for individual commands */ - Boolean hasErrCtl; - - /* string to turn error checking on */ - char *errCheck; - - /* string to turn off error checking */ - char *ignErr; - - char *echo; /* command line flag: echo commands */ - char *exit; /* command line flag: exit on error */ - - ArgArray builtins; /* ordered list of shell builtins */ - char *meta; /* shell meta characters */ - - Boolean unsetenv; /* unsetenv("ENV") before exec */ -}; -TAILQ_HEAD(Shells, Shell); - -extern struct Shell *commandShell; - -void Shell_Init(void); -Boolean Shell_Parse(const char []); - -#endif /* shell_h_6002e3b8 */ Property changes on: head/usr.bin/make/shell.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/lst.c =================================================================== --- head/usr.bin/make/lst.c (revision 284463) +++ head/usr.bin/make/lst.c (nonexistent) @@ -1,344 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/*- - * lst.c -- - * Routines to maintain a linked list of objects. - */ - -#include -#include - -#include "lst.h" -#include "util.h" - -/** - * Lst_Append - * Create a new node and add it to the given list after the given node. - * - * Arguments: - * l affected list - * ln node after which to append the datum - * d said datum - * - * Side Effects: - * A new LstNode is created and linked in to the List. The lastPtr - * field of the List will be altered if ln is the last node in the - * list. lastPtr and firstPtr will alter if the list was empty and - * ln was NULL. - */ -void -Lst_Append(Lst *list, LstNode *ln, void *d) -{ - LstNode *nLNode; - - nLNode = emalloc(sizeof(*nLNode)); - nLNode->datum = d; - - if (ln == NULL) { - nLNode->nextPtr = nLNode->prevPtr = NULL; - list->firstPtr = list->lastPtr = nLNode; - } else { - nLNode->prevPtr = ln; - nLNode->nextPtr = ln->nextPtr; - - ln->nextPtr = nLNode; - if (nLNode->nextPtr != NULL) { - nLNode->nextPtr->prevPtr = nLNode; - } - - if (ln == list->lastPtr) { - list->lastPtr = nLNode; - } - } -} - -/** - * Lst_Concat - * Concatenate two lists. New elements are created to hold the data - * elements, if specified, but the elements themselves are not copied. - * If the elements should be duplicated to avoid confusion with another - * list, the Lst_Duplicate function should be called first. - * - * Arguments: - * list1 The list to which list2 is to be appended - * list2 The list to append to list1 - * flags LST_CONCNEW if LstNode's should be duplicated - * LST_CONCLINK if should just be relinked - * - * Side Effects: - * New elements are created and appended the first list. - */ -void -Lst_Concat(Lst *list1, Lst *list2, int flags) -{ - LstNode *ln; /* original LstNode */ - LstNode *nln; /* new LstNode */ - LstNode *last; /* the last element in the list. Keeps - * bookkeeping until the end */ - - if (list2->firstPtr == NULL) - return; - - if (flags == LST_CONCLINK) { - /* - * Link the first element of the second list to the last - * element of the first list. If the first list isn't empty, - * we then link the last element of the list to the first - * element of the second list. The last element of the second - * list, if it exists, then becomes the last element of the - * first list. - */ - list2->firstPtr->prevPtr = list1->lastPtr; - if (list1->lastPtr != NULL) - list1->lastPtr->nextPtr = list2->firstPtr; - else - list1->firstPtr = list2->firstPtr; - list1->lastPtr = list2->lastPtr; - - Lst_Init(list2); - } else { - /* - * The loop simply goes through the entire second list creating - * new LstNodes and filling in the nextPtr, and prevPtr to fit - * into list1 and its datum field from the datum field of the - * corresponding element in list2. The 'last' node follows the - * last of the new nodes along until the entire list2 has been - * appended. Only then does the bookkeeping catch up with the - * changes. During the first iteration of the loop, if 'last' - * is NULL, the first list must have been empty so the - * newly-created node is made the first node of the list. - */ - for (last = list1->lastPtr, ln = list2->firstPtr; - ln != NULL; - ln = ln->nextPtr) { - nln = emalloc(sizeof(*nln)); - nln->datum = ln->datum; - if (last != NULL) { - last->nextPtr = nln; - } else { - list1->firstPtr = nln; - } - nln->prevPtr = last; - last = nln; - } - - /* - * Finish bookkeeping. The last new element becomes the last - * element of list one. - */ - list1->lastPtr = last; - last->nextPtr = NULL; - } -} - -/** - * Lst_DeQueue - * Remove and return the datum at the head of the given list. - * - * Results: - * The datum in the node at the head or (ick) NULL if the list - * is empty. - * - * Side Effects: - * The head node is removed from the list. - */ -void * -Lst_DeQueue(Lst *l) -{ - void *rd; - LstNode *tln; - - tln = Lst_First(l); - if (tln == NULL) { - return (NULL); - } - - rd = tln->datum; - Lst_Remove(l, tln); - return (rd); -} - -/** - * Lst_Destroy - * Destroy a list and free all its resources. If the freeProc is - * given, it is called with the datum from each node in turn before - * the node is freed. - * - * Side Effects: - * The given list is freed in its entirety. - */ -void -Lst_Destroy(Lst *list, FreeProc *freeProc) -{ - LstNode *ln; - - if (list->firstPtr == NULL) - return; - - if (freeProc != NOFREE) { - while ((ln = list->firstPtr) != NULL) { - list->firstPtr = ln->nextPtr; - (*freeProc)(ln->datum); - free(ln); - } - } else { - while ((ln = list->firstPtr) != NULL) { - list->firstPtr = ln->nextPtr; - free(ln); - } - } - list->lastPtr = NULL; -} - -/** - * Lst_Duplicate - * Duplicate an entire list. If a function to copy a void * is - * given, the individual client elements will be duplicated as well. - * - * Arguments: - * dst the destination list (initialized) - * src the list to duplicate - * copyProc A function to duplicate each void - */ -void -Lst_Duplicate(Lst *dst, Lst *src, DuplicateProc *copyProc) -{ - LstNode *ln; - - ln = src->firstPtr; - while (ln != NULL) { - if (copyProc != NOCOPY) - Lst_AtEnd(dst, (*copyProc)(ln->datum)); - else - Lst_AtEnd(dst, ln->datum); - ln = ln->nextPtr; - } -} - -/** - * Lst_Insert - * Insert a new node with the given piece of data before the given - * node in the given list. - * - * Parameters: - * l list to manipulate - * ln node before which to insert d - * d datum to be inserted - * - * Side Effects: - * the firstPtr field will be changed if ln is the first node in the - * list. - */ -void -Lst_Insert(Lst *list, LstNode *ln, void *d) -{ - LstNode *nLNode; /* new lnode for d */ - - nLNode = emalloc(sizeof(*nLNode)); - nLNode->datum = d; - - if (ln == NULL) { - nLNode->prevPtr = nLNode->nextPtr = NULL; - list->firstPtr = list->lastPtr = nLNode; - } else { - nLNode->prevPtr = ln->prevPtr; - nLNode->nextPtr = ln; - - if (nLNode->prevPtr != NULL) { - nLNode->prevPtr->nextPtr = nLNode; - } - ln->prevPtr = nLNode; - - if (ln == list->firstPtr) { - list->firstPtr = nLNode; - } - } -} - -LstNode * -Lst_Member(Lst *list, void *d) -{ - LstNode *lNode; - - lNode = list->firstPtr; - if (lNode == NULL) { - return (NULL); - } - - do { - if (lNode->datum == d) { - return (lNode); - } - lNode = lNode->nextPtr; - } while (lNode != NULL && lNode != list->firstPtr); - - return (NULL); -} - -/** - * Lst_Remove - * Remove the given node from the given list. - * - * Side Effects: - * The list's firstPtr will be set to NULL if ln is the last - * node on the list. firsPtr and lastPtr will be altered if ln is - * either the first or last node, respectively, on the list. - */ -void -Lst_Remove(Lst *list, LstNode *ln) -{ - /* - * unlink it from the list - */ - if (ln->nextPtr != NULL) - /* unlink from the backward chain */ - ln->nextPtr->prevPtr = ln->prevPtr; - else - /* this was the last element */ - list->lastPtr = ln->prevPtr; - - if (ln->prevPtr != NULL) - /* unlink from the forward chain */ - ln->prevPtr->nextPtr = ln->nextPtr; - else - /* this was the first element */ - list->firstPtr = ln->nextPtr; - - /* - * note that the datum is unmolested. The caller must free it as - * necessary and as expected. - */ - free(ln); -} Property changes on: head/usr.bin/make/lst.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/lst.h =================================================================== --- head/usr.bin/make/lst.h (revision 284463) +++ head/usr.bin/make/lst.h (nonexistent) @@ -1,175 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1988, 1989 by Adam de Boor - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)lst.h 8.2 (Berkeley) 4/28/95 - * $FreeBSD$ - */ - -#ifndef lst_h_38f3ead1 -#define lst_h_38f3ead1 - -/*- - * lst.h -- - * Header for using the list library - */ - -/* - * Structure of a list node. - */ -struct LstNode { - struct LstNode *prevPtr; /* previous element in list */ - struct LstNode *nextPtr; /* next in list */ - void *datum; /* datum associated with this element */ -}; -typedef struct LstNode LstNode; - -/* - * The list itself - */ -struct Lst { - LstNode *firstPtr; /* first node in list */ - LstNode *lastPtr; /* last node in list */ -}; -typedef struct Lst Lst; - -typedef void *DuplicateProc(void *); -typedef void FreeProc(void *); - -/* - * NOFREE can be used as the freeProc to Lst_Destroy when the elements are - * not to be freed. - * NOCOPY performs similarly when given as the copyProc to Lst_Duplicate. - */ -#define NOFREE ((FreeProc *)NULL) -#define NOCOPY ((DuplicateProc *)NULL) - -#define LST_CONCNEW 0 /* create new LstNode's when using Lst_Concat */ -#define LST_CONCLINK 1 /* relink LstNode's when using Lst_Concat */ - -/* - * Creation/destruction functions - */ -/* Create a new list */ -#define Lst_Init(LST) do { \ - (LST)->firstPtr = NULL; \ - (LST)->lastPtr = NULL; \ - } while (0) -#define Lst_Initializer(NAME) { NULL, NULL } - -/* Duplicate an existing list */ -void Lst_Duplicate(Lst *, Lst *, DuplicateProc *); - -/* Destroy an old one */ -void Lst_Destroy(Lst *, FreeProc *); - -/* - * Functions to modify a list - */ -/* Insert an element before another */ -void Lst_Insert(Lst *, LstNode *, void *); -/* Insert an element after another */ -void Lst_Append(Lst *, LstNode *, void *); -/* Place an element at the front of a lst. */ -#define Lst_AtFront(LST, D) (Lst_Insert((LST), Lst_First(LST), (D))) -/* Place an element at the end of a lst. */ -#define Lst_AtEnd(LST, D) (Lst_Append((LST), Lst_Last(LST), (D))) -/* Remove an element */ -void Lst_Remove(Lst *, LstNode *); -/* Replace a node with a new value */ -#define Lst_Replace(NODE, D) ((void)((NODE)->datum = (D))) -/* Concatenate two lists */ -void Lst_Concat(Lst *, Lst *, int); - -/* - * Node-specific functions - */ -/* Return first element in list */ -#define Lst_First(LST) ((Lst_Valid(LST) && !Lst_IsEmpty(LST)) \ - ? (LST)->firstPtr : NULL) -/* Return last element in list */ -#define Lst_Last(LST) ((Lst_Valid(LST) && !Lst_IsEmpty(LST)) \ - ? (LST)->lastPtr : NULL) -/* Return successor to given element */ -#define Lst_Succ(NODE) (((NODE) == NULL) ? NULL : (NODE)->nextPtr) -#define LST_NEXT(NODE) ((NODE)->nextPtr) -/* Get datum from LstNode */ -#define Lst_Datum(NODE) ((NODE)->datum) - -/* - * Functions for entire lists - */ - -/* - * See if the given datum is on the list. Returns the LstNode containing - * the datum - */ -LstNode *Lst_Member(Lst *, void *); - -/* Loop through a list. Note, that you may not delete the list element. */ -#define LST_FOREACH(PTR, LST) \ - for ((PTR) = (LST)->firstPtr; (PTR) != NULL; (PTR) = (PTR)->nextPtr) - -/* - * for using the list as a queue - */ -/* Place an element at tail of queue */ -#define Lst_EnQueue(LST, D) (Lst_Valid(LST) \ - ? Lst_Append((LST), Lst_Last(LST), (D)) \ - : (void)0) -/* Remove an element from head of queue */ -void *Lst_DeQueue(Lst *); - -/* - * LstValid (L) -- - * Return TRUE if the list L is valid - */ -#define Lst_Valid(L) (((L) == NULL) ? FALSE : TRUE) - -/* - * LstNodeValid (LN, L) -- - * Return TRUE if the LstNode LN is valid with respect to L - */ -#define Lst_NodeValid(LN, L) (((LN) == NULL) ? FALSE : TRUE) - -/* - * Lst_IsEmpty(L) -- - * TRUE if the list L is empty. - */ -#define Lst_IsEmpty(L) (!Lst_Valid(L) || (L)->firstPtr == NULL) - -#endif /* lst_h_38f3ead1 */ Property changes on: head/usr.bin/make/lst.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/str.c =================================================================== --- head/usr.bin/make/str.c (revision 284463) +++ head/usr.bin/make/str.c (nonexistent) @@ -1,559 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)str.c 5.8 (Berkeley) 6/1/90 - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include - -#include "buf.h" -#include "str.h" -#include "util.h" - -/** - * Initialize the argument array object. The array is initially - * eight positions, and will be expanded as necessary. The first - * position is set to NULL since everything ignores it. We allocate - * (size + 1) since we need space for the terminating NULL. The - * buffer is set to NULL, since no common buffer is allocated yet. - */ -void -ArgArray_Init(ArgArray *aa) -{ - - aa->size = 8; - aa->argv = emalloc((aa->size + 1) * sizeof(char *)); - aa->argc = 0; - aa->argv[aa->argc++] = NULL; - aa->len = 0; - aa->buffer = NULL; -} - -/** - * Cleanup the memory allocated for in the argument array object. - */ -void -ArgArray_Done(ArgArray *aa) -{ - - if (aa->buffer == NULL) { - int i; - /* args are individually allocated */ - for (i = 0; i < aa->argc; ++i) { - if (aa->argv[i]) { - free(aa->argv[i]); - aa->argv[i] = NULL; - } - } - } else { - /* args are part of a single allocation */ - free(aa->buffer); - aa->buffer = NULL; - } - free(aa->argv); - aa->argv = NULL; - aa->argc = 0; - aa->size = 0; -} - -/*- - * str_concat -- - * concatenate the two strings, inserting a space or slash between them. - * - * returns -- - * the resulting string in allocated space. - */ -char * -str_concat(const char *s1, const char *s2, int flags) -{ - int len1, len2; - char *result; - - /* get the length of both strings */ - len1 = strlen(s1); - len2 = strlen(s2); - - /* allocate length plus separator plus EOS */ - result = emalloc(len1 + len2 + 2); - - /* copy first string into place */ - memcpy(result, s1, len1); - - /* add separator character */ - if (flags & STR_ADDSPACE) { - result[len1] = ' '; - ++len1; - } else if (flags & STR_ADDSLASH) { - result[len1] = '/'; - ++len1; - } - - /* copy second string plus EOS into place */ - memcpy(result + len1, s2, len2 + 1); - - return (result); -} - -/** - * Fracture a string into an array of words (as delineated by tabs or - * spaces) taking quotation marks into account. Leading tabs/spaces - * are ignored. - */ -void -brk_string(ArgArray *aa, const char str[], Boolean expand) -{ - char inquote; - char *start; - char *arg; - - /* skip leading space chars. */ - for (; *str == ' ' || *str == '\t'; ++str) - continue; - - ArgArray_Init(aa); - - aa->buffer = estrdup(str); - - arg = aa->buffer; - start = arg; - inquote = '\0'; - - /* - * copy the string; at the same time, parse backslashes, - * quotes and build the argument list. - */ - for (;;) { - switch (str[0]) { - case '"': - case '\'': - if (inquote == '\0') { - inquote = str[0]; - if (expand) - break; - if (start == NULL) - start = arg; - } else if (inquote == str[0]) { - inquote = '\0'; - /* Don't miss "" or '' */ - if (start == NULL) - start = arg; - if (expand) - break; - } else { - /* other type of quote found */ - if (start == NULL) - start = arg; - } - *arg++ = str[0]; - break; - case ' ': - case '\t': - case '\n': - if (inquote) { - if (start == NULL) - start = arg; - *arg++ = str[0]; - break; - } - if (start == NULL) - break; - /* FALLTHROUGH */ - case '\0': - /* - * end of a token -- make sure there's enough argv - * space and save off a pointer. - */ - if (aa->argc == aa->size) { - aa->size *= 2; /* ramp up fast */ - aa->argv = erealloc(aa->argv, - (aa->size + 1) * sizeof(char *)); - } - - *arg++ = '\0'; - if (start == NULL) { - aa->argv[aa->argc] = start; - return; - } - if (str[0] == '\n' || str[0] == '\0') { - aa->argv[aa->argc++] = start; - aa->argv[aa->argc] = NULL; - return; - } else { - aa->argv[aa->argc++] = start; - start = NULL; - break; - } - case '\\': - if (start == NULL) - start = arg; - if (expand) { - switch (str[1]) { - case '\0': - case '\n': - /* hmmm; fix it up as best we can */ - *arg++ = '\\'; - break; - case 'b': - *arg++ = '\b'; - ++str; - break; - case 'f': - *arg++ = '\f'; - ++str; - break; - case 'n': - *arg++ = '\n'; - ++str; - break; - case 'r': - *arg++ = '\r'; - ++str; - break; - case 't': - *arg++ = '\t'; - ++str; - break; - default: - *arg++ = str[1]; - ++str; - break; - } - } else { - *arg++ = str[0]; - if (str[1] != '\0') { - ++str; - *arg++ = str[0]; - } - } - break; - default: - if (start == NULL) - start = arg; - *arg++ = str[0]; - break; - } - ++str; - } -} - -/* - * Quote a string for appending it to MAKEFLAGS. According to Posix the - * kind of quoting here is implementation-defined. This quoting must ensure - * that the parsing of MAKEFLAGS's contents in a sub-shell yields the same - * options, option arguments and macro definitions as in the calling make. - * We simply quote all blanks, which according to Posix are space and tab - * in the POSIX locale. Don't use isblank because in that case makes with - * different locale settings could not communicate. We must also quote - * backslashes obviously. - */ -char * -MAKEFLAGS_quote(const char *str) -{ - char *ret, *q; - const char *p; - - /* assume worst case - everything has to be quoted */ - ret = emalloc(strlen(str) * 2 + 1); - - p = str; - q = ret; - while (*p != '\0') { - switch (*p) { - - case ' ': - case '\t': - *q++ = '\\'; - break; - - default: - break; - } - *q++ = *p++; - } - *q++ = '\0'; - return (ret); -} - -void -MAKEFLAGS_break(ArgArray *aa, const char str[]) -{ - char *arg; - char *start; - - ArgArray_Init(aa); - - aa->buffer = strdup(str); - - arg = aa->buffer; - start = NULL; - - for (;;) { - switch (str[0]) { - case ' ': - case '\t': - /* word separator */ - if (start == NULL) { - /* not in a word */ - str++; - continue; - } - /* FALLTHRU */ - case '\0': - if (aa->argc == aa->size) { - aa->size *= 2; - aa->argv = erealloc(aa->argv, - (aa->size + 1) * sizeof(char *)); - } - - *arg++ = '\0'; - if (start == NULL) { - aa->argv[aa->argc] = start; - return; - } - if (str[0] == '\0') { - aa->argv[aa->argc++] = start; - aa->argv[aa->argc] = NULL; - return; - } else { - aa->argv[aa->argc++] = start; - start = NULL; - str++; - continue; - } - - case '\\': - if (str[1] == ' ' || str[1] == '\t') - str++; - break; - - default: - break; - } - if (start == NULL) - start = arg; - *arg++ = *str++; - } -} - -/* - * Str_Match -- - * - * See if a particular string matches a particular pattern. - * - * Results: Non-zero is returned if string matches pattern, 0 otherwise. The - * matching operation permits the following special characters in the - * pattern: *?\[] (see the man page for details on what these mean). - * - * Side effects: None. - */ -int -Str_Match(const char *string, const char *pattern) -{ - char c2; - - for (;;) { - /* - * See if we're at the end of both the pattern and the - * string. If, we succeeded. If we're at the end of the - * pattern but not at the end of the string, we failed. - */ - if (*pattern == 0) - return (!*string); - if (*string == 0 && *pattern != '*') - return (0); - /* - * Check for a "*" as the next pattern character. It matches - * any substring. We handle this by calling ourselves - * recursively for each postfix of string, until either we - * match or we reach the end of the string. - */ - if (*pattern == '*') { - pattern += 1; - if (*pattern == 0) - return (1); - while (*string != 0) { - if (Str_Match(string, pattern)) - return (1); - ++string; - } - return (0); - } - /* - * Check for a "?" as the next pattern character. It matches - * any single character. - */ - if (*pattern == '?') - goto thisCharOK; - /* - * Check for a "[" as the next pattern character. It is - * followed by a list of characters that are acceptable, or - * by a range (two characters separated by "-"). - */ - if (*pattern == '[') { - ++pattern; - for (;;) { - if ((*pattern == ']') || (*pattern == 0)) - return (0); - if (*pattern == *string) - break; - if (pattern[1] == '-') { - c2 = pattern[2]; - if (c2 == 0) - return (0); - if ((*pattern <= *string) && - (c2 >= *string)) - break; - if ((*pattern >= *string) && - (c2 <= *string)) - break; - pattern += 2; - } - ++pattern; - } - while ((*pattern != ']') && (*pattern != 0)) - ++pattern; - goto thisCharOK; - } - /* - * If the next pattern character is '/', just strip off the - * '/' so we do exact matching on the character that follows. - */ - if (*pattern == '\\') { - ++pattern; - if (*pattern == 0) - return (0); - } - /* - * There's no special character. Just make sure that the - * next characters of each string match. - */ - if (*pattern != *string) - return (0); -thisCharOK: ++pattern; - ++string; - } -} - - -/** - * Str_SYSVMatch - * Check word against pattern for a match (% is wild), - * - * Results: - * Returns the beginning position of a match or null. The number - * of characters matched is returned in len. - */ -const char * -Str_SYSVMatch(const char *word, const char *pattern, int *len) -{ - const char *m, *p, *w; - - p = pattern; - w = word; - - if (*w == '\0') { - /* Zero-length word cannot be matched against */ - *len = 0; - return (NULL); - } - - if (*p == '\0') { - /* Null pattern is the whole string */ - *len = strlen(w); - return (w); - } - - if ((m = strchr(p, '%')) != NULL) { - /* check that the prefix matches */ - for (; p != m && *w && *w == *p; w++, p++) - continue; - - if (p != m) - return (NULL); /* No match */ - - if (*++p == '\0') { - /* No more pattern, return the rest of the string */ - *len = strlen(w); - return (w); - } - } - - m = w; - - /* Find a matching tail */ - do - if (strcmp(p, w) == 0) { - *len = w - m; - return (m); - } - while (*w++ != '\0'); - - return (NULL); -} - - -/** - * Str_SYSVSubst - * Substitute '%' on the pattern with len characters from src. - * If the pattern does not contain a '%' prepend len characters - * from src. - * - * Side Effects: - * Places result on buf - */ -void -Str_SYSVSubst(Buffer *buf, const char *pat, const char *src, int len) -{ - const char *m; - - if ((m = strchr(pat, '%')) != NULL) { - /* Copy the prefix */ - Buf_AppendRange(buf, pat, m); - /* skip the % */ - pat = m + 1; - } - - /* Copy the pattern */ - Buf_AddBytes(buf, len, (const Byte *)src); - - /* append the rest */ - Buf_Append(buf, pat); -} Property changes on: head/usr.bin/make/str.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/str.h =================================================================== --- head/usr.bin/make/str.h (revision 284463) +++ head/usr.bin/make/str.h (nonexistent) @@ -1,81 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef str_h_44db59e6 -#define str_h_44db59e6 - -#include "util.h" - -struct Buffer; - -/** - * An array of c-strings. The pointers stored in argv, point to - * strings stored in buffer. - */ -typedef struct ArgArray { - int size; /* size of argv array */ - int argc; /* strings referenced in argv */ - char **argv; /* array of string pointers */ - size_t len; /* size of buffer */ - char *buffer; /* data buffer */ -} ArgArray; - -/* - * These constants are all used by the Str_Concat function to decide how the - * final string should look. If STR_ADDSPACE is given, a space will be - * placed between the two strings. If STR_ADDSLASH is given, a '/' will - * be used instead of a space. If neither is given, no intervening characters - * will be placed between the two strings in the final output. - */ -#define STR_ADDSPACE 0x01 /* add a space when Str_Concat'ing */ -#define STR_ADDSLASH 0x04 /* add a slash when Str_Concat'ing */ - -void ArgArray_Init(ArgArray *); -void ArgArray_Done(ArgArray *); - -char *str_concat(const char *, const char *, int); -void brk_string(ArgArray *, const char [], Boolean); -char *MAKEFLAGS_quote(const char *); -void MAKEFLAGS_break(ArgArray *, const char []); -int Str_Match(const char *, const char *); -const char *Str_SYSVMatch(const char *, const char *, int *); -void Str_SYSVSubst(struct Buffer *, const char *, const char *, int); - -#endif /* str_h_44db59e6 */ Property changes on: head/usr.bin/make/str.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/pathnames.h =================================================================== --- head/usr.bin/make/pathnames.h (revision 284463) +++ head/usr.bin/make/pathnames.h (nonexistent) @@ -1,56 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)pathnames.h 8.2 (Berkeley) 4/28/95 - * $FreeBSD$ - */ - -#ifndef pathnames_h_235b888a -#define pathnames_h_235b888a - -#ifndef PATH_OBJDIR -#define PATH_OBJDIR "obj" -#endif /* ! PATH_OBJDIR */ - -#ifndef PATH_OBJDIRPREFIX -#define PATH_OBJDIRPREFIX "/usr/obj" -#endif /* ! PATH_OBJDIRPREFIX */ - -#ifndef PATH_DEFSHELLDIR -#define PATH_DEFSHELLDIR "/bin" -#endif /* ! PATH_DEFSHELLDIR */ - -#ifndef PATH_DEFSYSMK -#define PATH_DEFSYSMK "sys.mk" -#endif /* ! PATH_DEFSYSMK */ - -#ifndef PATH_DEFSYSPATH -#define PATH_DEFSYSPATH "/usr/share/mk" -#endif /* ! PATH_DEFSYSPATH */ - -#endif /* pathnames_h_235b888a */ Property changes on: head/usr.bin/make/pathnames.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/hash_tables.c =================================================================== --- head/usr.bin/make/hash_tables.c (revision 284463) +++ head/usr.bin/make/hash_tables.c (nonexistent) @@ -1,130 +0,0 @@ -/* - * DO NOT EDIT - * $FreeBSD$ - * auto-generated from FreeBSD: src/usr.bin/make/parse.c,v 1.114 2008/03/12 14:50:58 obrien Exp - * DO NOT EDIT - */ -#include - -#include "hash_tables.h" - -/* - * d=2 - * n=40 - * m=19 - * c=2.09 - * maxlen=1 - * minklen=2 - * maxklen=9 - * minchar=97 - * maxchar=119 - * loop=0 - * numiter=1 - * seed= - */ - -static const signed char directive_g[] = { - 8, 0, 0, 5, 6, -1, 17, 15, 10, 6, - -1, -1, 10, 0, 0, -1, 18, 2, 3, 0, - 7, -1, -1, -1, 0, 14, -1, -1, 11, 16, - -1, -1, 0, -1, 0, 0, 17, 0, -1, 1, -}; - -static const u_char directive_T0[] = { - 26, 14, 19, 35, 10, 34, 18, 27, 1, 17, - 22, 37, 12, 12, 36, 21, 0, 6, 1, 25, - 9, 4, 19, -}; - -static const u_char directive_T1[] = { - 25, 22, 19, 0, 2, 18, 33, 18, 30, 4, - 30, 9, 21, 19, 16, 12, 35, 34, 4, 19, - 9, 33, 16, -}; - - -int -directive_hash(const u_char *key, size_t len) -{ - unsigned f0, f1; - const u_char *kp = key; - - if (len < 2 || len > 9) - return -1; - - for (f0=f1=0; kp < key + len; ++kp) { - if (*kp < 97 || *kp > 119) - return -1; - f0 += directive_T0[-97 + *kp]; - f1 += directive_T1[-97 + *kp]; - } - - f0 %= 40; - f1 %= 40; - - return (directive_g[f0] + directive_g[f1]) % 19; -} -/* - * d=2 - * n=74 - * m=35 - * c=2.09 - * maxlen=1 - * minklen=4 - * maxklen=13 - * minchar=46 - * maxchar=95 - * loop=0 - * numiter=4 - * seed= - */ - -static const signed char keyword_g[] = { - 12, 18, 7, 25, 30, 5, -1, -1, -1, 7, - -1, 0, 33, 0, 4, -1, -1, 13, 29, 0, - -1, 28, -1, 28, -1, 0, -1, 27, 4, 34, - -1, -1, -1, 30, 13, 10, -1, -1, 0, 10, - 24, -1, -1, -1, 0, 6, 0, 0, -1, 23, - -1, -1, -1, 0, -1, 23, -1, -1, 19, 4, - -1, 31, 12, 16, -1, 20, 22, 9, 0, -1, - -1, 9, 4, 0, -}; - -static const u_char keyword_T0[] = { - 34, 28, 50, 61, 14, 57, 48, 60, 20, 67, - 60, 63, 0, 24, 28, 2, 49, 64, 18, 23, - 36, 33, 40, 14, 38, 42, 71, 49, 2, 53, - 53, 37, 7, 29, 24, 21, 12, 50, 59, 10, - 43, 23, 0, 44, 47, 6, 46, 22, 48, 64, -}; - -static const u_char keyword_T1[] = { - 18, 67, 39, 60, 7, 70, 2, 26, 31, 18, - 73, 47, 61, 17, 38, 50, 22, 52, 13, 55, - 56, 32, 63, 4, 64, 55, 49, 21, 47, 67, - 33, 66, 60, 73, 30, 68, 69, 32, 72, 4, - 28, 49, 51, 15, 66, 68, 43, 67, 46, 56, -}; - - -int -keyword_hash(const u_char *key, size_t len) -{ - unsigned f0, f1; - const u_char *kp = key; - - if (len < 4 || len > 13) - return -1; - - for (f0=f1=0; *kp; ++kp) { - if (*kp < 46 || *kp > 95) - return -1; - f0 += keyword_T0[-46 + *kp]; - f1 += keyword_T1[-46 + *kp]; - } - - f0 %= 74; - f1 %= 74; - - return (keyword_g[f0] + keyword_g[f1]) % 35; -} Property changes on: head/usr.bin/make/hash_tables.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/buf.c =================================================================== --- head/usr.bin/make/buf.c (revision 284463) +++ head/usr.bin/make/buf.c (nonexistent) @@ -1,291 +0,0 @@ -/*- - * Copyright (c) 2005 Max Okumoto - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1988, 1989 by Adam de Boor - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)buf.c 8.1 (Berkeley) 6/6/93 - */ - -#include -__FBSDID("$FreeBSD$"); - -/* - * buf.c - * Functions for automatically-expanded buffers. - */ - -#include -#include - -#include "buf.h" -#include "util.h" - -/** - * Returns the number of bytes in the buffer. Doesn't include the - * null-terminating byte. - */ -size_t -Buf_Size(const Buffer *buf) -{ - - return (buf->end - buf->buf); -} - -/** - * Returns a reference to the data contained in the buffer. - * - * @note Adding data to the Buffer object may invalidate the reference. - */ -char * -Buf_Data(const Buffer *bp) -{ - - return (bp->buf); -} - -/** - * Expand the buffer to hold the number of additional bytes, plus - * space to store a terminating NULL byte. - */ -static inline void -BufExpand(Buffer *bp, size_t nb) -{ - size_t len = Buf_Size(bp); - size_t size; - - if (bp->size < len + nb + 1) { - size = bp->size + MAX(nb + 1, BUF_ADD_INC); - bp->size = size; - bp->buf = erealloc(bp->buf, size); - bp->end = bp->buf + len; - } -} - -/** - * Add a single byte to the buffer. - */ -void -Buf_AddByte(Buffer *bp, Byte byte) -{ - - BufExpand(bp, 1); - - *bp->end = byte; - bp->end++; - *bp->end = '\0'; -} - -/** - * Add bytes to the buffer. - */ -void -Buf_AddBytes(Buffer *bp, size_t len, const Byte *bytes) -{ - - BufExpand(bp, len); - - memcpy(bp->end, bytes, len); - bp->end += len; - *bp->end = '\0'; -} - -/** - * Get a reference to the internal buffer. - * - * len: - * Pointer to where we return the number of bytes in the internal buffer. - * - * Returns: - * return A pointer to the data. - */ -Byte * -Buf_GetAll(Buffer *bp, size_t *len) -{ - - if (len != NULL) - *len = Buf_Size(bp); - - return (bp->buf); -} - -/** - * Get the contents of a buffer and destroy the buffer. If the buffer - * is NULL, return NULL. - * - * Returns: - * the pointer to the data. - */ -char * -Buf_Peel(Buffer *bp) -{ - char *ret; - - if (bp == NULL) - return (NULL); - ret = bp->buf; - free(bp); - return (ret); -} - -/** - * Initialize a buffer. If no initial size is given, a reasonable - * default is used. - * - * Returns: - * A buffer object to be given to other functions in this library. - * - * Side Effects: - * Space is allocated for the Buffer object and a internal buffer. - */ -Buffer * -Buf_Init(size_t size) -{ - Buffer *bp; /* New Buffer */ - - if (size <= 0) - size = BUF_DEF_SIZE; - - bp = emalloc(sizeof(*bp)); - bp->size = size; - bp->buf = emalloc(size); - bp->end = bp->buf; - *bp->end = '\0'; - - return (bp); -} - -/** - * Destroy a buffer, and optionally free its data, too. - * - * Side Effects: - * Space for the Buffer object and possibly the internal buffer - * is de-allocated. - */ -void -Buf_Destroy(Buffer *buf, Boolean freeData) -{ - - if (freeData) - free(buf->buf); - free(buf); -} - -/** - * Replace the last byte in a buffer. If the buffer was empty - * initially, then a new byte will be added. - */ -void -Buf_ReplaceLastByte(Buffer *bp, Byte byte) -{ - - if (bp->end == bp->buf) { - Buf_AddByte(bp, byte); - } else { - *(bp->end - 1) = byte; - } -} - -/** - * Append characters in str to Buffer object - */ -void -Buf_Append(Buffer *bp, const char str[]) -{ - - Buf_AddBytes(bp, strlen(str), str); -} - -/** - * Append characters in buf to Buffer object - */ -void -Buf_AppendBuf(Buffer *bp, const Buffer *buf) -{ - - Buf_AddBytes(bp, Buf_Size(buf), buf->buf); -} - -/** - * Append characters between str and end to Buffer object. - */ -void -Buf_AppendRange(Buffer *bp, const char str[], const char *end) -{ - - Buf_AddBytes(bp, end - str, str); -} - -/** - * Convert newlines in buffer to spaces. The trailing newline is - * removed. - */ -void -Buf_StripNewlines(Buffer *bp) -{ - char *ptr = bp->end; - - /* - * If there is anything in the buffer, remove the last - * newline character. - */ - if (ptr != bp->buf) { - if (*(ptr - 1) == '\n') { - /* shorten buffer */ - *(ptr - 1) = '\0'; - --bp->end; - } - --ptr; - } - - /* Convert newline characters to a space characters. */ - while (ptr != bp->buf) { - if (*ptr == '\n') { - *ptr = ' '; - } - --ptr; - } -} -/** - * Clear the contents of the buffer. - */ -void -Buf_Clear(Buffer *bp) -{ - - bp->end = bp->buf; - *bp->end = '\0'; -} Property changes on: head/usr.bin/make/buf.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/config.h =================================================================== --- head/usr.bin/make/config.h (revision 284463) +++ head/usr.bin/make/config.h (nonexistent) @@ -1,111 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1988, 1989 by Adam de Boor - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)config.h 8.2 (Berkeley) 4/28/95 - * $FreeBSD$ - */ - -#ifndef config_h_efe0765e -#define config_h_efe0765e - -/* - * DEFMAXJOBS - * This control the default concurrency. On no occasion will more - * than DEFMAXJOBS targets be created at once. - */ -#define DEFMAXJOBS 1 - -/* - * INCLUDES - * LIBRARIES - * These control the handling of the .INCLUDES and .LIBS variables. - * If INCLUDES is defined, the .INCLUDES variable will be filled - * from the search paths of those suffixes which are marked by - * .INCLUDES dependency lines. Similarly for LIBRARIES and .LIBS - * See suff.c for more details. - */ -#define INCLUDES -#define LIBRARIES - -/* - * LIBSUFF - * Is the suffix used to denote libraries and is used by the Suff module - * to find the search path on which to seek any -l targets. - * - * RECHECK - * If defined, Make_Update will check a target for its current - * modification time after it has been re-made, setting it to the - * starting time of the make only if the target still doesn't exist. - * Unfortunately, under NFS the modification time often doesn't - * get updated in time, so a target will appear to not have been - * re-made, causing later targets to appear up-to-date. On systems - * that don't have this problem, you should defined this. Under - * NFS you probably should not, unless you aren't exporting jobs. - */ -#define LIBSUFF ".a" -#define RECHECK - -/* - * SYSVINCLUDE - * Recognize system V like include directives [include "filename"] - * SYSVVARSUB - * Recognize system V like ${VAR:x=y} variable substitutions - */ -#define SYSVINCLUDE -#define SYSVVARSUB - -/* - * SUNSHCMD - * Recognize SunOS and Solaris: - * VAR :sh= CMD # Assign VAR to the command substitution of CMD - * ${VAR:sh} # Return the command substitution of the value - * # of ${VAR} - */ -#define SUNSHCMD - -#if !defined(__svr4__) && !defined(__SVR4) && !defined(__ELF__) -# ifndef RANLIBMAG -# define RANLIBMAG "__.SYMDEF" -# endif -#else -# ifndef RANLIBMAG -# define RANLIBMAG "/" -# endif -#endif - -#endif /* config_h_efe0765e */ Property changes on: head/usr.bin/make/config.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/hash_tables.h =================================================================== --- head/usr.bin/make/hash_tables.h (revision 284463) +++ head/usr.bin/make/hash_tables.h (nonexistent) @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2005 Max Okumoto. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifndef hash_tables_h_ -#define hash_tables_h_ - -#include - -int directive_hash(const u_char *, size_t); -int keyword_hash(const u_char *, size_t); - -#endif Property changes on: head/usr.bin/make/hash_tables.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/buf.h =================================================================== --- head/usr.bin/make/buf.h (revision 284463) +++ head/usr.bin/make/buf.h (nonexistent) @@ -1,92 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1988, 1989 by Adam de Boor - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)buf.h 8.2 (Berkeley) 4/28/95 - * $FreeBSD$ - */ - -#ifndef buf_h_a61a6812 -#define buf_h_a61a6812 - -/*- - * buf.h -- - * Header for users of the buf library. - */ - -#include - -#include "util.h" - -/* - * There are several places where expandable buffers are used (parse.c and - * var.c). This constant is merely the starting point for those buffers. If - * lines tend to be much shorter than this, it would be best to reduce BSIZE. - * If longer, it should be increased. Reducing it will cause more copying to - * be done for longer lines, but will save space for shorter ones. In any - * case, it ought to be a power of two simply because most storage allocation - * schemes allocate in powers of two. - */ -#define MAKE_BSIZE 256 /* starting size for expandable buffers */ - -#define BUF_DEF_SIZE 256 /* Default buffer size */ -#define BUF_ADD_INC 256 /* Expansion increment when Adding */ - -typedef char Byte; - -typedef struct Buffer { - size_t size; /* Current size of the buffer */ - Byte *buf; /* The buffer itself */ - Byte *end; /* Place to write to */ -} Buffer; - -void Buf_AddByte(Buffer *, Byte); -void Buf_AddBytes(Buffer *, size_t, const Byte *); -void Buf_Append(Buffer *, const char []); -void Buf_AppendBuf(Buffer *, const Buffer *); -void Buf_AppendRange(Buffer *, const char [], const char *); -void Buf_Clear(Buffer *); -char *Buf_Data(const Buffer *); -void Buf_Destroy(Buffer *, Boolean); -Byte *Buf_GetAll(Buffer *, size_t *); -Buffer *Buf_Init(size_t); -char *Buf_Peel(Buffer *); -void Buf_ReplaceLastByte(Buffer *, Byte); -size_t Buf_Size(const Buffer *); -void Buf_StripNewlines(Buffer *); - -#endif /* buf_h_a61a6812 */ Property changes on: head/usr.bin/make/buf.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/Makefile =================================================================== --- head/usr.bin/make/Makefile (revision 284463) +++ head/usr.bin/make/Makefile (nonexistent) @@ -1,120 +0,0 @@ -# @(#)Makefile 5.2 (Berkeley) 12/28/90 -# $Id: Makefile,v 1.6 1994/06/30 05:33:39 cgd Exp $ -# $FreeBSD$ - -.include - -PROG= make -CFLAGS+=-I${.CURDIR} -SRCS= arch.c buf.c cond.c dir.c for.c hash.c hash_tables.c job.c \ - lst.c main.c make.c parse.c proc.c shell.c str.c suff.c targ.c \ - util.c var.c - -.if !defined(MK_SHARED_TOOLCHAIN) || ${MK_SHARED_TOOLCHAIN} == "no" -NO_SHARED?= YES -.endif - -# Version has the RYYYYMMDDX format, where R is from RELENG_ -CFLAGS+=-DMAKE_VERSION=\"10201205300\" - -# There is no obvious performance improvement currently. -# CFLAGS+=-DUSE_KQUEUE - -# Make object files which depend on preprocessor symbols defined in -# the Makefile which are not compilation options but rather configuration -# options dependend on the Makefile. main.c needs MAKE_VERSION while -# shell.c uses DEFSHELLNAME. This will cause recompilation in the case -# the definition is changed in the makefile. It will of course not cause -# recompilation if one does 'make MAKE_SHELL=csh'. -main.o shell.o: ${MAKEFILE} - -# Directive and keyword tables. We use hash tables. These hash tables have been -# generated with mph (ports/devel/mph) -# If you change the directives or keywords (adding, deleting, reordering) you -# need to create new tables and hash functions (directive_hash, keyword_hash). -# -# The following changes have been made to the generated code: -# -# o prefix the names of the g, T0 and T1 arrays with 'directive_' -# resp. 'keyword_'. -# -# o make the type of the tables 'const [un]signed char' (if you change -# anything make sure that the numbers fit into a char). -# -# o make the hash function use the length for termination, -# not the trailing '\0', via the -l flag in emitc and some editing -# (only for directive_hash). - -LOCALBASE ?= /usr/local -MPH ?= ${LOCALBASE}/bin/mph -EMITC ?= ${LOCALBASE}/bin/emitc - -.PRECIOUS: hash - -hash: - ( echo '/*' ; \ - echo ' * DO NOT EDIT' ; \ - echo ' * $$''FreeBSD$$' ; \ - echo -n ' * auto-generated from ' ; \ - sed -nEe '/\$$FreeBSD/s/^.*\$$(.*)\$$.*$$/\1/p' \ - ${.CURDIR}/parse.c ; \ - echo ' * DO NOT EDIT' ; \ - echo ' */' ; \ - echo '#include ' ; \ - echo ; \ - echo '#include "hash_tables.h"' ; \ - echo ; \ - cat ${.CURDIR}/parse.c | sed \ - -e '1,/DIRECTIVES-START-TAG/d' \ - -e '/DIRECTIVES-END-TAG/,$$d' \ - -e 's/^[^"]*"\([^"]*\)".*$$/\1/' | \ - ${MPH} -d2 -m1 | ${EMITC} -l -s | \ - sed \ - -e 's/^static int g\[\]/static const signed char directive_g[]/' \ - -e 's/^static int T0\[\]/static const u_char directive_T0[]/' \ - -e 's/^static int T1\[\]/static const u_char directive_T1[]/' \ - -e '/^#define uchar unsigned char/d' \ - -e 's/uchar/u_char/g' \ - -e 's/^hash(/directive_hash(/' \ - -e 's/; \*kp;/; kp < key + len;/' \ - -e 's/int len)/size_t len)/' \ - -e 's/= T0\[/= directive_T0\[/' \ - -e 's/= T1\[/= directive_T1\[/' \ - -e 's/g\[f/directive_g[f/g' ; \ - cat ${.CURDIR}/parse.c | sed \ - -e '1,/KEYWORD-START-TAG/d' \ - -e '/KEYWORD-END-TAG/,$$d' \ - -e 's/^[^"]*"\([^"]*\)".*$$/\1/' | \ - ${MPH} -d2 -m1 | ${EMITC} -l -s | \ - sed \ - -e 's/^static int g\[\]/static const signed char keyword_g[]/' \ - -e 's/^static int T0\[\]/static const u_char keyword_T0[]/' \ - -e 's/^static int T1\[\]/static const u_char keyword_T1[]/' \ - -e '/^#define uchar unsigned char/d' \ - -e 's/uchar/u_char/g' \ - -e 's/^hash(/keyword_hash(/' \ - -e 's/int len)/size_t len)/' \ - -e 's/= T0\[/= keyword_T0\[/' \ - -e 's/= T1\[/= keyword_T1\[/' \ - -e 's/g\[f/keyword_g[f/g' \ - ) > ${.CURDIR}/hash_tables.c - -# Set the shell which make(1) uses. Bourne is the default, but a decent -# Korn shell works fine, and much faster. Using the C shell for this -# will almost certainly break everything, but it's Unix tradition to -# allow you to shoot yourself in the foot if you want to :-) - -MAKE_SHELL?= sh -.if ${MAKE_SHELL} == "csh" || ${MAKE_SHELL} == "sh" || ${MAKE_SHELL} == "ksh" -CFLAGS+= -DDEFSHELLNAME=\"${MAKE_SHELL}\" -.else -.error "MAKE_SHELL must be set to one of \"csh\", \"sh\" or \"ksh\"." -.endif - -# if we are here we don't want this called 'make' -PROG= fmake -CLEANFILES+= fmake.1 -fmake.1: make.1 - ${CP} ${.ALLSRC} ${.TARGET} - -.include Property changes on: head/usr.bin/make/Makefile ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/job.c =================================================================== --- head/usr.bin/make/job.c (revision 284463) +++ head/usr.bin/make/job.c (nonexistent) @@ -1,3391 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1988, 1989 by Adam de Boor - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)job.c 8.2 (Berkeley) 3/19/94 - */ - -#include -__FBSDID("$FreeBSD$"); - -/*- - * job.c -- - * handle the creation etc. of our child processes. - * - * Interface: - * Job_Make Start the creation of the given target. - * - * Job_CatchChildren - * Check for and handle the termination of any children. - * This must be called reasonably frequently to keep the - * whole make going at a decent clip, since job table - * entries aren't removed until their process is caught - * this way. Its single argument is TRUE if the function - * should block waiting for a child to terminate. - * - * Job_CatchOutput Print any output our children have produced. Should - * also be called fairly frequently to keep the user - * informed of what's going on. If no output is waiting, - * it will block for a time given by the SEL_* constants, - * below, or until output is ready. - * - * Job_Init Called to intialize this module. in addition, any - * commands attached to the .BEGIN target are executed - * before this function returns. Hence, the makefile must - * have been parsed before this function is called. - * - * Job_Full Return TRUE if the job table is filled. - * - * Job_Empty Return TRUE if the job table is completely empty. - * - * Job_Finish Perform any final processing which needs doing. This - * includes the execution of any commands which have - * been/were attached to the .END target. It should only - * be called when the job table is empty. - * - * Job_AbortAll Abort all currently running jobs. It doesn't handle - * output or do anything for the jobs, just kills them. - * It should only be called in an emergency, as it were. - * - * Job_CheckCommands - * Verify that the commands for a target are ok. Provide - * them if necessary and possible. - * - * Job_Touch Update a target without really updating it. - * - * Job_Wait Wait for all currently-running jobs to finish. - * - * compat.c -- - * The routines in this file implement the full-compatibility - * mode of PMake. Most of the special functionality of PMake - * is available in this mode. Things not supported: - * - different shells. - * - friendly variable substitution. - * - * Interface: - * Compat_Run Initialize things for this module and recreate - * thems as need creatin' - */ - -#include -#include -#include -#include -#ifdef USE_KQUEUE -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "arch.h" -#include "buf.h" -#include "config.h" -#include "dir.h" -#include "globals.h" -#include "GNode.h" -#include "job.h" -#include "make.h" -#include "parse.h" -#include "proc.h" -#include "shell.h" -#include "str.h" -#include "suff.h" -#include "targ.h" -#include "util.h" -#include "var.h" - -#define TMPPAT "makeXXXXXXXXXX" - -#ifndef USE_KQUEUE -/* - * The SEL_ constants determine the maximum amount of time spent in select - * before coming out to see if a child has finished. SEL_SEC is the number of - * seconds and SEL_USEC is the number of micro-seconds - */ -#define SEL_SEC 2 -#define SEL_USEC 0 -#endif /* !USE_KQUEUE */ - -/* - * Job Table definitions. - * - * The job "table" is kept as a linked Lst in 'jobs', with the number of - * active jobs maintained in the 'nJobs' variable. At no time will this - * exceed the value of 'maxJobs', initialized by the Job_Init function. - * - * When a job is finished, the Make_Update function is called on each of the - * parents of the node which was just remade. This takes care of the upward - * traversal of the dependency graph. - */ -#define JOB_BUFSIZE 1024 -typedef struct Job { - pid_t pid; /* The child's process ID */ - - struct GNode *node; /* The target the child is making */ - - /* - * A LstNode for the first command to be saved after the job completes. - * This is NULL if there was no "..." in the job's commands. - */ - LstNode *tailCmds; - - /* - * An FILE* for writing out the commands. This is only - * used before the job is actually started. - */ - FILE *cmdFILE; - - /* - * A word of flags which determine how the module handles errors, - * echoing, etc. for the job - */ - short flags; /* Flags to control treatment of job */ -#define JOB_IGNERR 0x001 /* Ignore non-zero exits */ -#define JOB_SILENT 0x002 /* no output */ -#define JOB_SPECIAL 0x004 /* Target is a special one. i.e. run it locally - * if we can't export it and maxLocal is 0 */ -#define JOB_IGNDOTS 0x008 /* Ignore "..." lines when processing - * commands */ -#define JOB_FIRST 0x020 /* Job is first job for the node */ -#define JOB_RESTART 0x080 /* Job needs to be completely restarted */ -#define JOB_RESUME 0x100 /* Job needs to be resumed b/c it stopped, - * for some reason */ -#define JOB_CONTINUING 0x200 /* We are in the process of resuming this job. - * Used to avoid infinite recursion between - * JobFinish and JobRestart */ - - /* union for handling shell's output */ - union { - /* - * This part is used when usePipes is true. - * The output is being caught via a pipe and the descriptors - * of our pipe, an array in which output is line buffered and - * the current position in that buffer are all maintained for - * each job. - */ - struct { - /* - * Input side of pipe associated with - * job's output channel - */ - int op_inPipe; - - /* - * Output side of pipe associated with job's - * output channel - */ - int op_outPipe; - - /* - * Buffer for storing the output of the - * job, line by line - */ - char op_outBuf[JOB_BUFSIZE + 1]; - - /* Current position in op_outBuf */ - int op_curPos; - } o_pipe; - - /* - * If usePipes is false the output is routed to a temporary - * file and all that is kept is the name of the file and the - * descriptor open to the file. - */ - struct { - /* Name of file to which shell output was rerouted */ - char of_outFile[PATH_MAX]; - - /* - * Stream open to the output file. Used to funnel all - * from a single job to one file while still allowing - * multiple shell invocations - */ - int of_outFd; - } o_file; - - } output; /* Data for tracking a shell's output */ - - TAILQ_ENTRY(Job) link; /* list link */ -} Job; - -#define outPipe output.o_pipe.op_outPipe -#define inPipe output.o_pipe.op_inPipe -#define outBuf output.o_pipe.op_outBuf -#define curPos output.o_pipe.op_curPos -#define outFile output.o_file.of_outFile -#define outFd output.o_file.of_outFd - -TAILQ_HEAD(JobList, Job); - -/* - * error handling variables - */ -static int aborting = 0; /* why is the make aborting? */ -#define ABORT_ERROR 1 /* Because of an error */ -#define ABORT_INTERRUPT 2 /* Because it was interrupted */ -#define ABORT_WAIT 3 /* Waiting for jobs to finish */ - -/* - * XXX: Avoid SunOS bug... FILENO() is fp->_file, and file - * is a char! So when we go above 127 we turn negative! - */ -#define FILENO(a) ((unsigned)fileno(a)) - -/* - * post-make command processing. The node postCommands is really just the - * .END target but we keep it around to avoid having to search for it - * all the time. - */ -static GNode *postCommands; - -/* - * The number of commands actually printed for a target. Should this - * number be 0, no shell will be executed. - */ -static int numCommands; - -/* - * Return values from JobStart. - */ -#define JOB_RUNNING 0 /* Job is running */ -#define JOB_ERROR 1 /* Error in starting the job */ -#define JOB_FINISHED 2 /* The job is already finished */ -#define JOB_STOPPED 3 /* The job is stopped */ - -/* - * The maximum number of jobs that may run. This is initialize from the - * -j argument for the leading make and from the FIFO for sub-makes. - */ -static int maxJobs; - -static int nJobs; /* The number of children currently running */ - -/* The structures that describe them */ -static struct JobList jobs = TAILQ_HEAD_INITIALIZER(jobs); - -static Boolean jobFull; /* Flag to tell when the job table is full. It - * is set TRUE when (1) the total number of - * running jobs equals the maximum allowed */ -#ifdef USE_KQUEUE -static int kqfd; /* File descriptor obtained by kqueue() */ -#else -static fd_set outputs; /* Set of descriptors of pipes connected to - * the output channels of children */ -#endif - -static GNode *lastNode; /* The node for which output was most recently - * produced. */ -static const char *targFmt; /* Format string to use to head output from a - * job when it's not the most-recent job heard - * from */ -static char *targPrefix = NULL; /* What we print at the start of targFmt */ - -#define TARG_FMT "%s %s ---\n" /* Default format */ -#define MESSAGE(fp, gn) \ - fprintf(fp, targFmt, targPrefix, gn->name); - -/* - * When JobStart attempts to run a job but isn't allowed to - * or when Job_CatchChildren detects a job that has - * been stopped somehow, the job is placed on the stoppedJobs queue to be run - * when the next job finishes. - * - * Lst of Job structures describing jobs that were stopped due to - * concurrency limits or externally - */ -static struct JobList stoppedJobs = TAILQ_HEAD_INITIALIZER(stoppedJobs); - -static int fifoFd; /* Fd of our job fifo */ -static char fifoName[] = "/tmp/make_fifo_XXXXXXXXX"; -static int fifoMaster; - -static volatile sig_atomic_t interrupted; - - -#if defined(USE_PGRP) && defined(SYSV) -# define KILL(pid, sig) killpg(-(pid), (sig)) -#else -# if defined(USE_PGRP) -# define KILL(pid, sig) killpg((pid), (sig)) -# else -# define KILL(pid, sig) kill((pid), (sig)) -# endif -#endif - -/* - * Grmpf... There is no way to set bits of the wait structure - * anymore with the stupid W*() macros. I liked the union wait - * stuff much more. So, we devise our own macros... This is - * really ugly, use dramamine sparingly. You have been warned. - */ -#define W_SETMASKED(st, val, fun) \ - { \ - int sh = (int)~0; \ - int mask = fun(sh); \ - \ - for (sh = 0; ((mask >> sh) & 1) == 0; sh++) \ - continue; \ - *(st) = (*(st) & ~mask) | ((val) << sh); \ - } - -#define W_SETTERMSIG(st, val) W_SETMASKED(st, val, WTERMSIG) -#define W_SETEXITSTATUS(st, val) W_SETMASKED(st, val, WEXITSTATUS) - -static void JobRestart(Job *); -static int JobStart(GNode *, int, Job *); -static void JobDoOutput(Job *, Boolean); -static void JobInterrupt(int, int); -static void JobRestartJobs(void); -static int Compat_RunCommand(LstNode *, struct GNode *); - -static GNode *curTarg = NULL; -static GNode *ENDNode; - -/** - * Create a fifo file with a uniq filename, and returns a file - * descriptor to that fifo. - */ -static int -mkfifotemp(char *template) -{ - char *start; - char *pathend; - char *ptr; - const unsigned char padchar[] = - "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - - if (template[0] == '\0') { - errno = EINVAL; /* bad input string */ - return (-1); - } - - /* Find end of template string. */ - pathend = strchr(template, '\0'); - ptr = pathend - 1; - - /* - * Starting from the end of the template replace spaces with 'X' in - * them with random characters until there are no more 'X'. - */ - while (ptr >= template && *ptr == 'X') { - uint32_t rand_num = -#if __FreeBSD_version < 800041 - arc4random() % (sizeof(padchar) - 1); -#else - arc4random_uniform(sizeof(padchar) - 1); -#endif - *ptr-- = padchar[rand_num]; - } - start = ptr + 1; - - /* Check the target directory. */ - for (; ptr > template; --ptr) { - if (*ptr == '/') { - struct stat sbuf; - - *ptr = '\0'; - if (stat(template, &sbuf) != 0) - return (-1); - - if (!S_ISDIR(sbuf.st_mode)) { - errno = ENOTDIR; - return (-1); - } - *ptr = '/'; - break; - } - } - - for (;;) { - if (mkfifo(template, 0600) == 0) { - int fd; - - if ((fd = open(template, O_RDWR, 0600)) < 0) { - unlink(template); - return (-1); - } else { - return (fd); - } - } else { - if (errno != EEXIST) { - return (-1); - } - } - - /* - * If we have a collision, cycle through the space of - * filenames. - */ - for (ptr = start;;) { - char *pad; - - if (*ptr == '\0' || ptr == pathend) - return (-1); - - pad = strchr(padchar, *ptr); - if (pad == NULL || *++pad == '\0') { - *ptr++ = padchar[0]; - } else { - *ptr++ = *pad; - break; - } - } - } - /*NOTREACHED*/ -} - -static void -catch_child(int sig __unused) -{ -} - -/** - */ -void -Proc_Init(void) -{ - /* - * Catch SIGCHLD so that we get kicked out of select() when we - * need to look at a child. This is only known to matter for the - * -j case (perhaps without -P). - * - * XXX this is intentionally misplaced. - */ - struct sigaction sa; - - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; - sa.sa_handler = catch_child; - sigaction(SIGCHLD, &sa, NULL); -} - -/** - * Wait for child process to terminate. - */ -static int -ProcWait(ProcStuff *ps) -{ - pid_t pid; - int status; - - /* - * Wait for the process to exit. - */ - for (;;) { - pid = wait(&status); - if (pid == -1 && errno != EINTR) { - Fatal("error in wait: %d", pid); - /* NOTREACHED */ - } - if (pid == ps->child_pid) { - break; - } - if (interrupted) { - break; - } - } - - return (status); -} - -/** - * JobCatchSignal - * Got a signal. Set global variables and hope that someone will - * handle it. - */ -static void -JobCatchSig(int signo) -{ - - interrupted = signo; -} - -/** - * JobPassSig -- - * Pass a signal on to all local jobs if - * USE_PGRP is defined, then die ourselves. - * - * Side Effects: - * We die by the same signal. - */ -static void -JobPassSig(int signo) -{ - Job *job; - sigset_t nmask, omask; - struct sigaction act; - - sigemptyset(&nmask); - sigaddset(&nmask, signo); - sigprocmask(SIG_SETMASK, &nmask, &omask); - - DEBUGF(JOB, ("JobPassSig(%d) called.\n", signo)); - TAILQ_FOREACH(job, &jobs, link) { - DEBUGF(JOB, ("JobPassSig passing signal %d to child %jd.\n", - signo, (intmax_t)job->pid)); - KILL(job->pid, signo); - } - - /* - * Deal with proper cleanup based on the signal received. We only run - * the .INTERRUPT target if the signal was in fact an interrupt. - * The other three termination signals are more of a "get out *now*" - * command. - */ - if (signo == SIGINT) { - JobInterrupt(TRUE, signo); - } else if (signo == SIGHUP || signo == SIGTERM || signo == SIGQUIT) { - JobInterrupt(FALSE, signo); - } - - /* - * Leave gracefully if SIGQUIT, rather than core dumping. - */ - if (signo == SIGQUIT) { - signo = SIGINT; - } - - /* - * Send ourselves the signal now we've given the message to everyone - * else. Note we block everything else possible while we're getting - * the signal. This ensures that all our jobs get continued when we - * wake up before we take any other signal. - * XXX this comment seems wrong. - */ - act.sa_handler = SIG_DFL; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - sigaction(signo, &act, NULL); - - DEBUGF(JOB, ("JobPassSig passing signal to self, mask = %x.\n", - ~0 & ~(1 << (signo - 1)))); - signal(signo, SIG_DFL); - - KILL(getpid(), signo); - - signo = SIGCONT; - TAILQ_FOREACH(job, &jobs, link) { - DEBUGF(JOB, ("JobPassSig passing signal %d to child %jd.\n", - signo, (intmax_t)job->pid)); - KILL(job->pid, signo); - } - - sigprocmask(SIG_SETMASK, &omask, NULL); - sigprocmask(SIG_SETMASK, &omask, NULL); - act.sa_handler = JobPassSig; - sigaction(signo, &act, NULL); -} - -/** - * JobPrintCommand -- - * Put out another command for the given job. If the command starts - * with an @ or a - we process it specially. In the former case, - * so long as the -s and -n flags weren't given to make, we stick - * a shell-specific echoOff command in the script. In the latter, - * we ignore errors for the entire job, unless the shell has error - * control. - * If the command is just "..." we take all future commands for this - * job to be commands to be executed once the entire graph has been - * made and return non-zero to signal that the end of the commands - * was reached. These commands are later attached to the postCommands - * node and executed by Job_Finish when all things are done. - * This function is called from JobStart via LST_FOREACH. - * - * Results: - * Always 0, unless the command was "..." - * - * Side Effects: - * If the command begins with a '-' and the shell has no error control, - * the JOB_IGNERR flag is set in the job descriptor. - * If the command is "..." and we're not ignoring such things, - * tailCmds is set to the successor node of the cmd. - * numCommands is incremented if the command is actually printed. - */ -static int -JobPrintCommand(LstNode *cmdNode, Job *job) -{ - Boolean noSpecials; /* true if we shouldn't worry about - * inserting special commands into - * the input stream. */ - Boolean shutUp = FALSE; /* true if we put a no echo command - * into the command file */ - Boolean errOff = FALSE; /* true if we turned error checking - * off before printing the command - * and need to turn it back on */ - const char *cmdTemplate;/* Template to use when printing the command */ - char *cmd; /* Expanded command */ - - noSpecials = (noExecute && !(job->node->type & OP_MAKE)); - -#define DBPRINTF(fmt, arg) \ - DEBUGF(JOB, (fmt, arg)); \ - fprintf(job->cmdFILE, fmt, arg); \ - fflush(job->cmdFILE); - - /* - * For debugging, we replace each command with the result of expanding - * the variables in the command. - */ - cmd = Buf_Peel(Var_Subst(Lst_Datum(cmdNode), job->node, FALSE)); - if (strcmp(cmd, "...") == 0) { - free(cmd); - job->node->type |= OP_SAVE_CMDS; - if ((job->flags & JOB_IGNDOTS) == 0) { - job->tailCmds = Lst_Succ(cmdNode); - return (1); - } - return (0); - } - Lst_Replace(cmdNode, cmd); - - /* - * Check for leading @', -' or +'s to control echoing, error checking, - * and execution on -n. - */ - while (*cmd == '@' || *cmd == '-' || *cmd == '+') { - switch (*cmd) { - - case '@': - shutUp = DEBUG(LOUD) ? FALSE : TRUE; - break; - - case '-': - errOff = TRUE; - break; - - case '+': - if (noSpecials) { - /* - * We're not actually exececuting anything... - * but this one needs to be - use compat mode - * just for it. - */ - Compat_RunCommand(cmdNode, job->node); - return (0); - } - break; - } - cmd++; - } - - while (isspace((unsigned char)*cmd)) - cmd++; - - /* - * Ignore empty commands - */ - if (*cmd == '\0') { - return (0); - } - - cmdTemplate = "%s\n"; - numCommands += 1; - - if (shutUp) { - if (!(job->flags & JOB_SILENT) && !noSpecials && - commandShell->hasEchoCtl) { - DBPRINTF("%s\n", commandShell->echoOff); - } else { - shutUp = FALSE; - } - } - - if (errOff) { - if (!(job->flags & JOB_IGNERR) && !noSpecials) { - if (commandShell->hasErrCtl) { - /* - * We don't want the error-control commands - * showing up either, so we turn off echoing - * while executing them. We could put another - * field in the shell structure to tell - * JobDoOutput to look for this string too, - * but why make it any more complex than - * it already is? - */ - if (!(job->flags & JOB_SILENT) && !shutUp && - commandShell->hasEchoCtl) { - DBPRINTF("%s\n", commandShell->echoOff); - DBPRINTF("%s\n", commandShell->ignErr); - DBPRINTF("%s\n", commandShell->echoOn); - } else { - DBPRINTF("%s\n", commandShell->ignErr); - } - } else if (commandShell->ignErr && - *commandShell->ignErr != '\0') { - /* - * The shell has no error control, so we need to - * be weird to get it to ignore any errors from - * the command. If echoing is turned on, we turn - * it off and use the errCheck template to echo - * the command. Leave echoing off so the user - * doesn't see the weirdness we go through to - * ignore errors. Set cmdTemplate to use the - * weirdness instead of the simple "%s\n" - * template. - */ - if (!(job->flags & JOB_SILENT) && !shutUp && - commandShell->hasEchoCtl) { - DBPRINTF("%s\n", commandShell->echoOff); - DBPRINTF(commandShell->errCheck, cmd); - shutUp = TRUE; - } - cmdTemplate = commandShell->ignErr; - /* - * The error ignoration (hee hee) is already - * taken care of by the ignErr template, so - * pretend error checking is still on. - */ - errOff = FALSE; - } else { - errOff = FALSE; - } - } else { - errOff = FALSE; - } - } - - DBPRINTF(cmdTemplate, cmd); - - if (errOff) { - /* - * If echoing is already off, there's no point in issuing the - * echoOff command. Otherwise we issue it and pretend it was on - * for the whole command... - */ - if (!shutUp && !(job->flags & JOB_SILENT) && - commandShell->hasEchoCtl) { - DBPRINTF("%s\n", commandShell->echoOff); - shutUp = TRUE; - } - DBPRINTF("%s\n", commandShell->errCheck); - } - if (shutUp) { - DBPRINTF("%s\n", commandShell->echoOn); - } - return (0); -} - -/** - * JobClose -- - * Called to close both input and output pipes when a job is finished. - * - * Side Effects: - * The file descriptors associated with the job are closed. - */ -static void -JobClose(Job *job) -{ - - if (usePipes) { -#if !defined(USE_KQUEUE) - FD_CLR(job->inPipe, &outputs); -#endif - if (job->outPipe != job->inPipe) { - close(job->outPipe); - } - JobDoOutput(job, TRUE); - close(job->inPipe); - } else { - close(job->outFd); - JobDoOutput(job, TRUE); - } -} - -/** - * JobFinish -- - * Do final processing for the given job including updating - * parents and starting new jobs as available/necessary. Note - * that we pay no attention to the JOB_IGNERR flag here. - * This is because when we're called because of a noexecute flag - * or something, jstat.w_status is 0 and when called from - * Job_CatchChildren, the status is zeroed if it s/b ignored. - * - * Side Effects: - * Some nodes may be put on the toBeMade queue. - * Final commands for the job are placed on postCommands. - * - * If we got an error and are aborting (aborting == ABORT_ERROR) and - * the job list is now empty, we are done for the day. - * If we recognized an error (makeErrors !=0), we set the aborting flag - * to ABORT_ERROR so no more jobs will be started. - */ -static void -JobFinish(Job *job, int *status) -{ - Boolean done; - LstNode *ln; - - if (WIFEXITED(*status)) { - int job_status = WEXITSTATUS(*status); - - JobClose(job); - /* - * Deal with ignored errors in -B mode. We need to - * print a message telling of the ignored error as - * well as setting status.w_status to 0 so the next - * command gets run. To do this, we set done to be - * TRUE if in -B mode and the job exited non-zero. - */ - if (job_status == 0) { - done = FALSE; - } else { - if (job->flags & JOB_IGNERR) { - done = TRUE; - } else { - /* - * If it exited non-zero and either we're - * doing things our way or we're not ignoring - * errors, the job is finished. Similarly, if - * the shell died because of a signal the job - * is also finished. In these cases, finish - * out the job's output before printing the - * exit status... - */ - done = TRUE; - if (job->cmdFILE != NULL && - job->cmdFILE != stdout) { - fclose(job->cmdFILE); - } - - } - } - } else if (WIFSIGNALED(*status)) { - if (WTERMSIG(*status) == SIGCONT) { - /* - * No need to close things down or anything. - */ - done = FALSE; - } else { - /* - * If it exited non-zero and either we're - * doing things our way or we're not ignoring - * errors, the job is finished. Similarly, if - * the shell died because of a signal the job - * is also finished. In these cases, finish - * out the job's output before printing the - * exit status... - */ - JobClose(job); - if (job->cmdFILE != NULL && - job->cmdFILE != stdout) { - fclose(job->cmdFILE); - } - done = TRUE; - } - } else { - /* - * No need to close things down or anything. - */ - done = FALSE; - } - - if (WIFEXITED(*status)) { - if (done || DEBUG(JOB)) { - FILE *out; - - if (compatMake && - !usePipes && - (job->flags & JOB_IGNERR)) { - /* - * If output is going to a file and this job - * is ignoring errors, arrange to have the - * exit status sent to the output file as - * well. - */ - out = fdopen(job->outFd, "w"); - if (out == NULL) - Punt("Cannot fdopen"); - } else { - out = stdout; - } - - DEBUGF(JOB, ("Process %jd exited.\n", - (intmax_t)job->pid)); - - if (WEXITSTATUS(*status) == 0) { - if (DEBUG(JOB)) { - if (usePipes && job->node != lastNode) { - MESSAGE(out, job->node); - lastNode = job->node; - } - fprintf(out, - "*** [%s] Completed successfully\n", - job->node->name); - } - } else { - if (usePipes && job->node != lastNode) { - MESSAGE(out, job->node); - lastNode = job->node; - } - fprintf(out, "*** [%s] Error code %d%s\n", - job->node->name, - WEXITSTATUS(*status), - (job->flags & JOB_IGNERR) ? - " (ignored)" : ""); - - if (job->flags & JOB_IGNERR) { - *status = 0; - } - } - - fflush(out); - } - } else if (WIFSIGNALED(*status)) { - if (done || DEBUG(JOB) || (WTERMSIG(*status) == SIGCONT)) { - FILE *out; - - if (compatMake && - !usePipes && - (job->flags & JOB_IGNERR)) { - /* - * If output is going to a file and this job - * is ignoring errors, arrange to have the - * exit status sent to the output file as - * well. - */ - out = fdopen(job->outFd, "w"); - if (out == NULL) - Punt("Cannot fdopen"); - } else { - out = stdout; - } - - if (WTERMSIG(*status) == SIGCONT) { - /* - * If the beastie has continued, shift the - * Job from the stopped list to the running - * one (or re-stop it if concurrency is - * exceeded) and go and get another child. - */ - if (job->flags & (JOB_RESUME | JOB_RESTART)) { - if (usePipes && job->node != lastNode) { - MESSAGE(out, job->node); - lastNode = job->node; - } - fprintf(out, "*** [%s] Continued\n", - job->node->name); - } - if (!(job->flags & JOB_CONTINUING)) { - DEBUGF(JOB, ("Warning: process %jd was not " - "continuing.\n", (intmax_t) job->pid)); - } - job->flags &= ~JOB_CONTINUING; - TAILQ_INSERT_TAIL(&jobs, job, link); - nJobs += 1; - DEBUGF(JOB, ("Process %jd is continuing locally.\n", - (intmax_t) job->pid)); - if (nJobs == maxJobs) { - jobFull = TRUE; - DEBUGF(JOB, ("Job queue is full.\n")); - } - fflush(out); - return; - - } else { - if (usePipes && job->node != lastNode) { - MESSAGE(out, job->node); - lastNode = job->node; - } - fprintf(out, - "*** [%s] Signal %d\n", job->node->name, - WTERMSIG(*status)); - fflush(out); - } - } - } else { - /* STOPPED */ - FILE *out; - - if (compatMake && !usePipes && (job->flags & JOB_IGNERR)) { - /* - * If output is going to a file and this job - * is ignoring errors, arrange to have the - * exit status sent to the output file as - * well. - */ - out = fdopen(job->outFd, "w"); - if (out == NULL) - Punt("Cannot fdopen"); - } else { - out = stdout; - } - - DEBUGF(JOB, ("Process %jd stopped.\n", (intmax_t) job->pid)); - if (usePipes && job->node != lastNode) { - MESSAGE(out, job->node); - lastNode = job->node; - } - fprintf(out, "*** [%s] Stopped -- signal %d\n", - job->node->name, WSTOPSIG(*status)); - job->flags |= JOB_RESUME; - TAILQ_INSERT_TAIL(&stoppedJobs, job, link); - fflush(out); - return; - } - - /* - * Now handle the -B-mode stuff. If the beast still isn't finished, - * try and restart the job on the next command. If JobStart says it's - * ok, it's ok. If there's an error, this puppy is done. - */ - if (compatMake && WIFEXITED(*status) && - Lst_Succ(job->node->compat_command) != NULL) { - switch (JobStart(job->node, job->flags & JOB_IGNDOTS, job)) { - case JOB_RUNNING: - done = FALSE; - break; - case JOB_ERROR: - done = TRUE; - W_SETEXITSTATUS(status, 1); - break; - case JOB_FINISHED: - /* - * If we got back a JOB_FINISHED code, JobStart has - * already called Make_Update and freed the job - * descriptor. We set done to false here to avoid fake - * cycles and double frees. JobStart needs to do the - * update so we can proceed up the graph when given - * the -n flag.. - */ - done = FALSE; - break; - default: - break; - } - } else { - done = TRUE; - } - - if (done && aborting != ABORT_ERROR && - aborting != ABORT_INTERRUPT && *status == 0) { - /* - * As long as we aren't aborting and the job didn't return a - * non-zero status that we shouldn't ignore, we call - * Make_Update to update the parents. In addition, any saved - * commands for the node are placed on the .END target. - */ - for (ln = job->tailCmds; ln != NULL; ln = LST_NEXT(ln)) { - Lst_AtEnd(&postCommands->commands, - Buf_Peel( - Var_Subst(Lst_Datum(ln), job->node, FALSE))); - } - - job->node->made = MADE; - Make_Update(job->node); - free(job); - - } else if (*status != 0) { - makeErrors++; - free(job); - } - - JobRestartJobs(); - - /* - * Set aborting if any error. - */ - if (makeErrors && !keepgoing && aborting != ABORT_INTERRUPT) { - /* - * If we found any errors in this batch of children and the -k - * flag wasn't given, we set the aborting flag so no more jobs - * get started. - */ - aborting = ABORT_ERROR; - } - - if (aborting == ABORT_ERROR && Job_Empty()) { - /* - * If we are aborting and the job table is now empty, we finish. - */ - Finish(makeErrors); - } -} - -/** - * Job_Touch - * Touch the given target. Called by JobStart when the -t flag was - * given. Prints messages unless told to be silent. - * - * Side Effects: - * The data modification of the file is changed. In addition, if the - * file did not exist, it is created. - */ -void -Job_Touch(GNode *gn, Boolean silent) -{ - int streamID; /* ID of stream opened to do the touch */ - struct utimbuf times; /* Times for utime() call */ - - if (gn->type & (OP_JOIN | OP_USE | OP_EXEC | OP_OPTIONAL)) { - /* - * .JOIN, .USE, .ZEROTIME and .OPTIONAL targets are "virtual" - * targets and, as such, shouldn't really be created. - */ - return; - } - - if (!silent) { - fprintf(stdout, "touch %s\n", gn->name); - fflush(stdout); - } - - if (noExecute) { - return; - } - - if (gn->type & OP_ARCHV) { - Arch_Touch(gn); - } else if (gn->type & OP_LIB) { - Arch_TouchLib(gn); - } else { - char *file = gn->path ? gn->path : gn->name; - - times.actime = times.modtime = now; - if (utime(file, ×) < 0) { - streamID = open(file, O_RDWR | O_CREAT, 0666); - - if (streamID >= 0) { - char c; - - /* - * Read and write a byte to the file to change - * the modification time, then close the file. - */ - if (read(streamID, &c, 1) == 1) { - lseek(streamID, (off_t)0, SEEK_SET); - write(streamID, &c, 1); - } - - close(streamID); - } else { - fprintf(stdout, "*** couldn't touch %s: %s", - file, strerror(errno)); - fflush(stdout); - } - } - } -} - -/** - * Job_CheckCommands - * Make sure the given node has all the commands it needs. - * - * Results: - * TRUE if the commands list is/was ok. - * - * Side Effects: - * The node will have commands from the .DEFAULT rule added to it - * if it needs them. - */ -Boolean -Job_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...)) -{ - - if (OP_NOP(gn->type) && Lst_IsEmpty(&gn->commands) && - (gn->type & OP_LIB) == 0) { - /* - * No commands. Look for .DEFAULT rule from which we might infer - * commands. - */ - if (DEFAULT != NULL && !Lst_IsEmpty(&DEFAULT->commands)) { - /* - * Make only looks for a .DEFAULT if the node was - * never the target of an operator, so that's what we - * do too. If a .DEFAULT was given, we substitute its - * commands for gn's commands and set the IMPSRC - * variable to be the target's name The DEFAULT node - * acts like a transformation rule, in that gn also - * inherits any attributes or sources attached to - * .DEFAULT itself. - */ - Make_HandleUse(DEFAULT, gn); - Var_Set(IMPSRC, Var_Value(TARGET, gn), gn); - - } else if (Dir_MTime(gn) == 0) { - /* - * The node wasn't the target of an operator we have - * no .DEFAULT rule to go on and the target doesn't - * already exist. There's nothing more we can do for - * this branch. If the -k flag wasn't given, we stop - * in our tracks, otherwise we just don't update - * this node's parents so they never get examined. - */ - static const char msg[] = - "make: don't know how to make"; - - if (gn->type & OP_OPTIONAL) { - fprintf(stdout, "%s %s(ignored)\n", - msg, gn->name); - fflush(stdout); - } else if (keepgoing) { - fprintf(stdout, "%s %s(continuing)\n", - msg, gn->name); - fflush(stdout); - return (FALSE); - } else { -#ifndef WITHOUT_OLD_JOKE - if (strcmp(gn->name,"love") == 0) - (*abortProc)("Not war."); - else -#endif - (*abortProc)("%s %s. Stop", - msg, gn->name); - return (FALSE); - } - } - } - return (TRUE); -} - -/** - * JobExec - * Execute the shell for the given job. Called from JobStart and - * JobRestart. - * - * Side Effects: - * A shell is executed, outputs is altered and the Job structure added - * to the job table. - */ -static void -JobExec(Job *job, char **argv) -{ - ProcStuff ps; - - if (DEBUG(JOB)) { - int i; - - DEBUGF(JOB, ("Running %s\n", job->node->name)); - DEBUGF(JOB, ("\tCommand: ")); - for (i = 0; argv[i] != NULL; i++) { - DEBUGF(JOB, ("%s ", argv[i])); - } - DEBUGF(JOB, ("\n")); - } - - /* - * Some jobs produce no output and it's disconcerting to have - * no feedback of their running (since they produce no output, the - * banner with their name in it never appears). This is an attempt to - * provide that feedback, even if nothing follows it. - */ - if (lastNode != job->node && (job->flags & JOB_FIRST) && - !(job->flags & JOB_SILENT)) { - MESSAGE(stdout, job->node); - lastNode = job->node; - } - - ps.in = FILENO(job->cmdFILE); - if (usePipes) { - /* - * Set up the child's output to be routed through the - * pipe we've created for it. - */ - ps.out = job->outPipe; - } else { - /* - * We're capturing output in a file, so we duplicate - * the descriptor to the temporary file into the - * standard output. - */ - ps.out = job->outFd; - } - ps.err = STDERR_FILENO; - - ps.merge_errors = 1; - ps.pgroup = 1; - ps.searchpath = 0; - - ps.argv = argv; - ps.argv_free = 0; - - /* - * Fork. Warning since we are doing vfork() instead of fork(), - * do not allocate memory in the child process! - */ - if ((ps.child_pid = vfork()) == -1) { - Punt("Cannot fork"); - - - } else if (ps.child_pid == 0) { - /* - * Child - */ - if (fifoFd >= 0) - close(fifoFd); - - Proc_Exec(&ps); - /* NOTREACHED */ - } - - /* - * Parent - */ - job->pid = ps.child_pid; - - if (usePipes && (job->flags & JOB_FIRST)) { - /* - * The first time a job is run for a node, we set the - * current position in the buffer to the beginning and - * mark another stream to watch in the outputs mask. - */ -#ifdef USE_KQUEUE - struct kevent kev[2]; -#endif - job->curPos = 0; - -#if defined(USE_KQUEUE) - EV_SET(&kev[0], job->inPipe, EVFILT_READ, EV_ADD, 0, 0, job); - EV_SET(&kev[1], job->pid, EVFILT_PROC, - EV_ADD | EV_ONESHOT, NOTE_EXIT, 0, NULL); - if (kevent(kqfd, kev, 2, NULL, 0, NULL) != 0) { - /* - * kevent() will fail if the job is already - * finished - */ - if (errno != EINTR && errno != EBADF && errno != ESRCH) - Punt("kevent: %s", strerror(errno)); - } -#else - FD_SET(job->inPipe, &outputs); -#endif /* USE_KQUEUE */ - } - - if (job->cmdFILE != NULL && job->cmdFILE != stdout) { - fclose(job->cmdFILE); - job->cmdFILE = NULL; - } - - /* - * Now the job is actually running, add it to the table. - */ - nJobs += 1; - TAILQ_INSERT_TAIL(&jobs, job, link); - if (nJobs == maxJobs) { - jobFull = TRUE; - } -} - -/** - * JobMakeArgv - * Create the argv needed to execute the shell for a given job. - */ -static void -JobMakeArgv(Job *job, char **argv) -{ - int argc; - static char args[10]; /* For merged arguments */ - - argv[0] = commandShell->name; - argc = 1; - - if ((commandShell->exit && *commandShell->exit != '-') || - (commandShell->echo && *commandShell->echo != '-')) { - /* - * At least one of the flags doesn't have a minus before it, so - * merge them together. Have to do this because the *(&(@*#*&#$# - * Bourne shell thinks its second argument is a file to source. - * Grrrr. Note the ten-character limitation on the combined - * arguments. - */ - sprintf(args, "-%s%s", (job->flags & JOB_IGNERR) ? "" : - commandShell->exit ? commandShell->exit : "", - (job->flags & JOB_SILENT) ? "" : - commandShell->echo ? commandShell->echo : ""); - - if (args[1]) { - argv[argc] = args; - argc++; - } - } else { - if (!(job->flags & JOB_IGNERR) && commandShell->exit) { - argv[argc] = commandShell->exit; - argc++; - } - if (!(job->flags & JOB_SILENT) && commandShell->echo) { - argv[argc] = commandShell->echo; - argc++; - } - } - argv[argc] = NULL; -} - -/** - * JobRestart - * Restart a job that stopped for some reason. The job must be neither - * on the jobs nor on the stoppedJobs list. - * - * Side Effects: - * jobFull will be set if the job couldn't be run. - */ -static void -JobRestart(Job *job) -{ - - if (job->flags & JOB_RESTART) { - /* - * Set up the control arguments to the shell. This is based on - * the flags set earlier for this job. If the JOB_IGNERR flag - * is clear, the 'exit' flag of the commandShell is used to - * cause it to exit upon receiving an error. If the JOB_SILENT - * flag is clear, the 'echo' flag of the commandShell is used - * to get it to start echoing as soon as it starts - * processing commands. - */ - char *argv[4]; - - JobMakeArgv(job, argv); - - DEBUGF(JOB, ("Restarting %s...", job->node->name)); - if (nJobs >= maxJobs && !(job->flags & JOB_SPECIAL)) { - /* - * Not allowed to run -- put it back on the hold - * queue and mark the table full - */ - DEBUGF(JOB, ("holding\n")); - TAILQ_INSERT_HEAD(&stoppedJobs, job, link); - jobFull = TRUE; - DEBUGF(JOB, ("Job queue is full.\n")); - return; - } else { - /* - * Job may be run locally. - */ - DEBUGF(JOB, ("running locally\n")); - } - JobExec(job, argv); - - } else { - /* - * The job has stopped and needs to be restarted. - * Why it stopped, we don't know... - */ - DEBUGF(JOB, ("Resuming %s...", job->node->name)); - if ((nJobs < maxJobs || ((job->flags & JOB_SPECIAL) && - maxJobs == 0)) && nJobs != maxJobs) { - /* - * If we haven't reached the concurrency limit already - * (or the job must be run and maxJobs is 0), it's ok - * to resume it. - */ - Boolean error; - int status; - - error = (KILL(job->pid, SIGCONT) != 0); - - if (!error) { - /* - * Make sure the user knows we've continued - * the beast and actually put the thing in the - * job table. - */ - job->flags |= JOB_CONTINUING; - status = 0; - W_SETTERMSIG(&status, SIGCONT); - JobFinish(job, &status); - - job->flags &= ~(JOB_RESUME|JOB_CONTINUING); - DEBUGF(JOB, ("done\n")); - } else { - Error("couldn't resume %s: %s", - job->node->name, strerror(errno)); - status = 0; - W_SETEXITSTATUS(&status, 1); - JobFinish(job, &status); - } - } else { - /* - * Job cannot be restarted. Mark the table as full and - * place the job back on the list of stopped jobs. - */ - DEBUGF(JOB, ("table full\n")); - TAILQ_INSERT_HEAD(&stoppedJobs, job, link); - jobFull = TRUE; - DEBUGF(JOB, ("Job queue is full.\n")); - } - } -} - -/** - * JobStart - * Start a target-creation process going for the target described - * by the graph node gn. - * - * Results: - * JOB_ERROR if there was an error in the commands, JOB_FINISHED - * if there isn't actually anything left to do for the job and - * JOB_RUNNING if the job has been started. - * - * Side Effects: - * A new Job node is created and added to the list of running - * jobs. PMake is forked and a child shell created. - */ -static int -JobStart(GNode *gn, int flags, Job *previous) -{ - Job *job; /* new job descriptor */ - char *argv[4]; /* Argument vector to shell */ - Boolean cmdsOK; /* true if the nodes commands were all right */ - Boolean noExec; /* Set true if we decide not to run the job */ - int tfd; /* File descriptor for temp file */ - LstNode *ln; - char tfile[PATH_MAX]; - const char *tdir; - - if (interrupted) { - JobPassSig(interrupted); - return (JOB_ERROR); - } - if (previous != NULL) { - previous->flags &= ~(JOB_FIRST | JOB_IGNERR | JOB_SILENT); - job = previous; - } else { - job = emalloc(sizeof(Job)); - flags |= JOB_FIRST; - } - - job->node = gn; - job->tailCmds = NULL; - - /* - * Set the initial value of the flags for this job based on the global - * ones and the node's attributes... Any flags supplied by the caller - * are also added to the field. - */ - job->flags = 0; - if (Targ_Ignore(gn)) { - job->flags |= JOB_IGNERR; - } - if (Targ_Silent(gn)) { - job->flags |= JOB_SILENT; - } - job->flags |= flags; - - /* - * Check the commands now so any attributes from .DEFAULT have a chance - * to migrate to the node. - */ - if (!compatMake && (job->flags & JOB_FIRST)) { - cmdsOK = Job_CheckCommands(gn, Error); - } else { - cmdsOK = TRUE; - } - - if ((tdir = getenv("TMPDIR")) == NULL) - tdir = _PATH_TMP; - - /* - * If the -n flag wasn't given, we open up OUR (not the child's) - * temporary file to stuff commands in it. The thing is rd/wr so we - * don't need to reopen it to feed it to the shell. If the -n flag - * *was* given, we just set the file to be stdout. Cute, huh? - */ - if ((gn->type & OP_MAKE) || (!noExecute && !touchFlag)) { - /* - * We're serious here, but if the commands were bogus, we're - * also dead... - */ - if (!cmdsOK) { - DieHorribly(); - } - - snprintf(tfile, sizeof(tfile), "%s/%s", tdir, TMPPAT); - if ((tfd = mkstemp(tfile)) == -1) - Punt("Cannot create temp file: %s", strerror(errno)); - job->cmdFILE = fdopen(tfd, "w+"); - eunlink(tfile); - if (job->cmdFILE == NULL) { - close(tfd); - Punt("Could not open %s", tfile); - } - fcntl(FILENO(job->cmdFILE), F_SETFD, 1); - /* - * Send the commands to the command file, flush all its - * buffers then rewind and remove the thing. - */ - noExec = FALSE; - - /* - * Used to be backwards; replace when start doing multiple - * commands per shell. - */ - if (compatMake) { - /* - * Be compatible: If this is the first time for this - * node, verify its commands are ok and open the - * commands list for sequential access by later - * invocations of JobStart. Once that is done, we take - * the next command off the list and print it to the - * command file. If the command was an ellipsis, note - * that there's nothing more to execute. - */ - if (job->flags & JOB_FIRST) - gn->compat_command = Lst_First(&gn->commands); - else - gn->compat_command = - Lst_Succ(gn->compat_command); - - if (gn->compat_command == NULL || - JobPrintCommand(gn->compat_command, job)) - noExec = TRUE; - - if (noExec && !(job->flags & JOB_FIRST)) { - /* - * If we're not going to execute anything, the - * job is done and we need to close down the - * various file descriptors we've opened for - * output, then call JobDoOutput to catch the - * final characters or send the file to the - * screen... Note that the i/o streams are only - * open if this isn't the first job. Note also - * that this could not be done in - * Job_CatchChildren b/c it wasn't clear if - * there were more commands to execute or not... - */ - JobClose(job); - } - } else { - /* - * We can do all the commands at once. hooray for sanity - */ - numCommands = 0; - LST_FOREACH(ln, &gn->commands) { - if (JobPrintCommand(ln, job)) - break; - } - - /* - * If we didn't print out any commands to the shell - * script, there's not much point in executing the - * shell, is there? - */ - if (numCommands == 0) { - noExec = TRUE; - } - } - - } else if (noExecute) { - /* - * Not executing anything -- just print all the commands to - * stdout in one fell swoop. This will still set up - * job->tailCmds correctly. - */ - if (lastNode != gn) { - MESSAGE(stdout, gn); - lastNode = gn; - } - job->cmdFILE = stdout; - - /* - * Only print the commands if they're ok, but don't die if - * they're not -- just let the user know they're bad and keep - * going. It doesn't do any harm in this case and may do - * some good. - */ - if (cmdsOK) { - LST_FOREACH(ln, &gn->commands) { - if (JobPrintCommand(ln, job)) - break; - } - } - /* - * Don't execute the shell, thank you. - */ - noExec = TRUE; - - } else { - /* - * Just touch the target and note that no shell should be - * executed. Set cmdFILE to stdout to make life easier. Check - * the commands, too, but don't die if they're no good -- it - * does no harm to keep working up the graph. - */ - job->cmdFILE = stdout; - Job_Touch(gn, job->flags & JOB_SILENT); - noExec = TRUE; - } - - /* - * If we're not supposed to execute a shell, don't. - */ - if (noExec) { - /* - * Unlink and close the command file if we opened one - */ - if (job->cmdFILE != stdout) { - if (job->cmdFILE != NULL) - fclose(job->cmdFILE); - } else { - fflush(stdout); - } - - /* - * We only want to work our way up the graph if we aren't here - * because the commands for the job were no good. - */ - if (cmdsOK) { - if (aborting == 0) { - for (ln = job->tailCmds; ln != NULL; - ln = LST_NEXT(ln)) { - Lst_AtEnd(&postCommands->commands, - Buf_Peel(Var_Subst(Lst_Datum(ln), - job->node, FALSE))); - } - job->node->made = MADE; - Make_Update(job->node); - } - free(job); - return(JOB_FINISHED); - } else { - free(job); - return(JOB_ERROR); - } - } else { - fflush(job->cmdFILE); - } - - /* - * Set up the control arguments to the shell. This is based on the flags - * set earlier for this job. - */ - JobMakeArgv(job, argv); - - /* - * If we're using pipes to catch output, create the pipe by which we'll - * get the shell's output. If we're using files, print out that we're - * starting a job and then set up its temporary-file name. - */ - if (!compatMake || (job->flags & JOB_FIRST)) { - if (usePipes) { - int fd[2]; - - if (pipe(fd) == -1) - Punt("Cannot create pipe: %s", strerror(errno)); - job->inPipe = fd[0]; - job->outPipe = fd[1]; - fcntl(job->inPipe, F_SETFD, 1); - fcntl(job->outPipe, F_SETFD, 1); - } else { - fprintf(stdout, "Remaking `%s'\n", gn->name); - fflush(stdout); - snprintf(job->outFile, sizeof(job->outFile), "%s/%s", - tdir, TMPPAT); - if ((job->outFd = mkstemp(job->outFile)) == -1) - Punt("cannot create temp file: %s", - strerror(errno)); - fcntl(job->outFd, F_SETFD, 1); - } - } - - if (nJobs >= maxJobs && !(job->flags & JOB_SPECIAL) && maxJobs != 0) { - /* - * We've hit the limit of concurrency, so put the job on hold - * until some other job finishes. Note that the special jobs - * (.BEGIN, .INTERRUPT and .END) may be run even when the - * limit has been reached (e.g. when maxJobs == 0). - */ - jobFull = TRUE; - - DEBUGF(JOB, ("Can only run job locally.\n")); - job->flags |= JOB_RESTART; - TAILQ_INSERT_TAIL(&stoppedJobs, job, link); - } else { - if (nJobs >= maxJobs) { - /* - * If we're running this job as a special case - * (see above), at least say the table is full. - */ - jobFull = TRUE; - DEBUGF(JOB, ("Local job queue is full.\n")); - } - JobExec(job, argv); - } - return (JOB_RUNNING); -} - -static char * -JobOutput(Job *job, char *cp, char *endp, int msg) -{ - char *ecp; - - if (commandShell->noPrint) { - ecp = strstr(cp, commandShell->noPrint); - while (ecp != NULL) { - if (cp != ecp) { - *ecp = '\0'; - if (msg && job->node != lastNode) { - MESSAGE(stdout, job->node); - lastNode = job->node; - } - /* - * The only way there wouldn't be a newline - * after this line is if it were the last in - * the buffer. However, since the non-printable - * comes after it, there must be a newline, so - * we don't print one. - */ - fprintf(stdout, "%s", cp); - fflush(stdout); - } - cp = ecp + strlen(commandShell->noPrint); - if (cp != endp) { - /* - * Still more to print, look again after - * skipping the whitespace following the - * non-printable command.... - */ - cp++; - while (*cp == ' ' || *cp == '\t' || - *cp == '\n') { - cp++; - } - ecp = strstr(cp, commandShell->noPrint); - } else { - return (cp); - } - } - } - return (cp); -} - -/** - * JobDoOutput - * This function is called at different times depending on - * whether the user has specified that output is to be collected - * via pipes or temporary files. In the former case, we are called - * whenever there is something to read on the pipe. We collect more - * output from the given job and store it in the job's outBuf. If - * this makes up a line, we print it tagged by the job's identifier, - * as necessary. - * If output has been collected in a temporary file, we open the - * file and read it line by line, transferring it to our own - * output channel until the file is empty. At which point we - * remove the temporary file. - * In both cases, however, we keep our figurative eye out for the - * 'noPrint' line for the shell from which the output came. If - * we recognize a line, we don't print it. If the command is not - * alone on the line (the character after it is not \0 or \n), we - * do print whatever follows it. - * - * Side Effects: - * curPos may be shifted as may the contents of outBuf. - */ -static void -JobDoOutput(Job *job, Boolean finish) -{ - Boolean gotNL = FALSE; /* true if got a newline */ - Boolean fbuf; /* true if our buffer filled up */ - int nr; /* number of bytes read */ - int i; /* auxiliary index into outBuf */ - int max; /* limit for i (end of current data) */ - int nRead; /* (Temporary) number of bytes read */ - FILE *oFILE; /* Stream pointer to shell's output file */ - char inLine[132]; - - if (usePipes) { - /* - * Read as many bytes as will fit in the buffer. - */ - end_loop: - gotNL = FALSE; - fbuf = FALSE; - - nRead = read(job->inPipe, &job->outBuf[job->curPos], - JOB_BUFSIZE - job->curPos); - /* - * Check for interrupt here too, because the above read may - * block when the child process is stopped. In this case the - * interrupt will unblock it (we don't use SA_RESTART). - */ - if (interrupted) - JobPassSig(interrupted); - - if (nRead < 0) { - DEBUGF(JOB, ("JobDoOutput(piperead)")); - nr = 0; - } else { - nr = nRead; - } - - /* - * If we hit the end-of-file (the job is dead), we must flush - * its remaining output, so pretend we read a newline if - * there's any output remaining in the buffer. - * Also clear the 'finish' flag so we stop looping. - */ - if (nr == 0 && job->curPos != 0) { - job->outBuf[job->curPos] = '\n'; - nr = 1; - finish = FALSE; - } else if (nr == 0) { - finish = FALSE; - } - - /* - * Look for the last newline in the bytes we just got. If there - * is one, break out of the loop with 'i' as its index and - * gotNL set TRUE. - */ - max = job->curPos + nr; - for (i = job->curPos + nr - 1; i >= job->curPos; i--) { - if (job->outBuf[i] == '\n') { - gotNL = TRUE; - break; - } else if (job->outBuf[i] == '\0') { - /* - * Why? - */ - job->outBuf[i] = ' '; - } - } - - if (!gotNL) { - job->curPos += nr; - if (job->curPos == JOB_BUFSIZE) { - /* - * If we've run out of buffer space, we have - * no choice but to print the stuff. sigh. - */ - fbuf = TRUE; - i = job->curPos; - } - } - if (gotNL || fbuf) { - /* - * Need to send the output to the screen. Null terminate - * it first, overwriting the newline character if there - * was one. So long as the line isn't one we should - * filter (according to the shell description), we print - * the line, preceded by a target banner if this target - * isn't the same as the one for which we last printed - * something. The rest of the data in the buffer are - * then shifted down to the start of the buffer and - * curPos is set accordingly. - */ - job->outBuf[i] = '\0'; - if (i >= job->curPos) { - char *cp; - - cp = JobOutput(job, job->outBuf, - &job->outBuf[i], FALSE); - - /* - * There's still more in that buffer. This time, - * though, we know there's no newline at the - * end, so we add one of our own free will. - */ - if (*cp != '\0') { - if (job->node != lastNode) { - MESSAGE(stdout, job->node); - lastNode = job->node; - } - fprintf(stdout, "%s%s", cp, - gotNL ? "\n" : ""); - fflush(stdout); - } - } - if (i < max - 1) { - /* shift the remaining characters down */ - memcpy(job->outBuf, &job->outBuf[i + 1], - max - (i + 1)); - job->curPos = max - (i + 1); - - } else { - /* - * We have written everything out, so we just - * start over from the start of the buffer. - * No copying. No nothing. - */ - job->curPos = 0; - } - } - if (finish) { - /* - * If the finish flag is true, we must loop until we hit - * end-of-file on the pipe. This is guaranteed to happen - * eventually since the other end of the pipe is now - * closed (we closed it explicitly and the child has - * exited). When we do get an EOF, finish will be set - * FALSE and we'll fall through and out. - */ - goto end_loop; - } - - } else { - /* - * We've been called to retrieve the output of the job from the - * temporary file where it's been squirreled away. This consists - * of opening the file, reading the output line by line, being - * sure not to print the noPrint line for the shell we used, - * then close and remove the temporary file. Very simple. - * - * Change to read in blocks and do FindSubString type things - * as for pipes? That would allow for "@echo -n..." - */ - oFILE = fopen(job->outFile, "r"); - if (oFILE != NULL) { - fprintf(stdout, "Results of making %s:\n", - job->node->name); - fflush(stdout); - - while (fgets(inLine, sizeof(inLine), oFILE) != NULL) { - char *cp, *endp, *oendp; - - cp = inLine; - oendp = endp = inLine + strlen(inLine); - if (endp[-1] == '\n') { - *--endp = '\0'; - } - cp = JobOutput(job, inLine, endp, FALSE); - - /* - * There's still more in that buffer. This time, - * though, we know there's no newline at the - * end, so we add one of our own free will. - */ - fprintf(stdout, "%s", cp); - fflush(stdout); - if (endp != oendp) { - fprintf(stdout, "\n"); - fflush(stdout); - } - } - fclose(oFILE); - eunlink(job->outFile); - } - } -} - -/** - * Job_CatchChildren - * Handle the exit of a child. Called from Make_Make. - * - * Side Effects: - * The job descriptor is removed from the list of children. - * - * Notes: - * We do waits, blocking or not, according to the wisdom of our - * caller, until there are no more children to report. For each - * job, call JobFinish to finish things off. This will take care of - * putting jobs on the stoppedJobs queue. - */ -void -Job_CatchChildren(Boolean block) -{ - pid_t pid; /* pid of dead child */ - Job *job; /* job descriptor for dead child */ - int status; /* Exit/termination status */ - - /* - * Don't even bother if we know there's no one around. - */ - if (nJobs == 0) { - return; - } - - for (;;) { - pid = waitpid(-1, &status, - (block ? 0 : WNOHANG) | WUNTRACED); - if (pid <= 0) - break; - - DEBUGF(JOB, ("Process %jd exited or stopped.\n", - (intmax_t)pid)); - - TAILQ_FOREACH(job, &jobs, link) { - if (job->pid == pid) - break; - } - - if (job == NULL) { - if (WIFSIGNALED(status) && - (WTERMSIG(status) == SIGCONT)) { - TAILQ_FOREACH(job, &jobs, link) { - if (job->pid == pid) - break; - } - if (job == NULL) { - Error("Resumed child (%jd) " - "not in table", (intmax_t)pid); - continue; - } - TAILQ_REMOVE(&stoppedJobs, job, link); - } else { - Error("Child (%jd) not in table?", - (intmax_t)pid); - continue; - } - } else { - TAILQ_REMOVE(&jobs, job, link); - nJobs -= 1; - if (fifoFd >= 0 && maxJobs > 1) { - write(fifoFd, "+", 1); - maxJobs--; - if (nJobs >= maxJobs) - jobFull = TRUE; - else - jobFull = FALSE; - } else { - DEBUGF(JOB, ("Job queue is no longer full.\n")); - jobFull = FALSE; - } - } - - JobFinish(job, &status); - } - if (interrupted) - JobPassSig(interrupted); -} - -/** - * Job_CatchOutput - * Catch the output from our children, if we're using - * pipes do so. Otherwise just block time until we get a - * signal(most likely a SIGCHLD) since there's no point in - * just spinning when there's nothing to do and the reaping - * of a child can wait for a while. - * - * Side Effects: - * Output is read from pipes if we're piping. - * ----------------------------------------------------------------------- - */ -void -#ifdef USE_KQUEUE -Job_CatchOutput(int flag __unused) -#else -Job_CatchOutput(int flag) -#endif -{ - int nfds; -#ifdef USE_KQUEUE -#define KEV_SIZE 4 - struct kevent kev[KEV_SIZE]; - int i; -#else - struct timeval timeout; - fd_set readfds; - Job *job; -#endif - - fflush(stdout); - - if (usePipes) { -#ifdef USE_KQUEUE - if ((nfds = kevent(kqfd, NULL, 0, kev, KEV_SIZE, NULL)) == -1) { - if (errno != EINTR) - Punt("kevent: %s", strerror(errno)); - if (interrupted) - JobPassSig(interrupted); - } else { - for (i = 0; i < nfds; i++) { - if (kev[i].flags & EV_ERROR) { - warnc(kev[i].data, "kevent"); - continue; - } - switch (kev[i].filter) { - case EVFILT_READ: - JobDoOutput(kev[i].udata, FALSE); - break; - case EVFILT_PROC: - /* - * Just wake up and let - * Job_CatchChildren() collect the - * terminated job. - */ - break; - } - } - } -#else - readfds = outputs; - timeout.tv_sec = SEL_SEC; - timeout.tv_usec = SEL_USEC; - if (flag && jobFull && fifoFd >= 0) - FD_SET(fifoFd, &readfds); - - nfds = select(FD_SETSIZE, &readfds, (fd_set *)NULL, - (fd_set *)NULL, &timeout); - if (nfds <= 0) { - if (interrupted) - JobPassSig(interrupted); - return; - } - if (fifoFd >= 0 && FD_ISSET(fifoFd, &readfds)) { - if (--nfds <= 0) - return; - } - job = TAILQ_FIRST(&jobs); - while (nfds != 0 && job != NULL) { - if (FD_ISSET(job->inPipe, &readfds)) { - JobDoOutput(job, FALSE); - nfds--; - } - job = TAILQ_NEXT(job, link); - } -#endif /* !USE_KQUEUE */ - } -} - -/** - * Job_Make - * Start the creation of a target. Basically a front-end for - * JobStart used by the Make module. - * - * Side Effects: - * Another job is started. - */ -void -Job_Make(GNode *gn) -{ - - JobStart(gn, 0, NULL); -} - -void -Job_SetPrefix(void) -{ - - if (targPrefix) { - free(targPrefix); - } else if (!Var_Exists(MAKE_JOB_PREFIX, VAR_GLOBAL)) { - Var_SetGlobal(MAKE_JOB_PREFIX, "---"); - } - targPrefix = Var_Subst("${" MAKE_JOB_PREFIX "}", VAR_GLOBAL, 0)->buf; -} - -/** - * Job_Init - * Initialize the process module, given a maximum number of jobs. - * - * Side Effects: - * lists and counters are initialized - */ -void -Job_Init(int maxproc) -{ - GNode *begin; /* node for commands to do at the very start */ - const char *env; - struct sigaction sa; - - fifoFd = -1; - env = getenv("MAKE_JOBS_FIFO"); - - if (env == NULL && maxproc > 1) { - /* - * We did not find the environment variable so we are the - * leader. Create the fifo, open it, write one char per - * allowed job into the pipe. - */ - fifoFd = mkfifotemp(fifoName); - if (fifoFd < 0) { - env = NULL; - } else { - fifoMaster = 1; - fcntl(fifoFd, F_SETFL, O_NONBLOCK); - env = fifoName; - setenv("MAKE_JOBS_FIFO", env, 1); - while (maxproc-- > 0) { - write(fifoFd, "+", 1); - } - /* The master make does not get a magic token */ - jobFull = TRUE; - maxJobs = 0; - } - - } else if (env != NULL) { - /* - * We had the environment variable so we are a slave. - * Open fifo and give ourselves a magic token which represents - * the token our parent make has grabbed to start his make - * process. Otherwise the sub-makes would gobble up tokens and - * the proper number of tokens to specify to -j would depend - * on the depth of the tree and the order of execution. - */ - fifoFd = open(env, O_RDWR, 0); - if (fifoFd >= 0) { - fcntl(fifoFd, F_SETFL, O_NONBLOCK); - maxJobs = 1; - jobFull = FALSE; - } - } - if (fifoFd < 0) { - maxJobs = maxproc; - jobFull = FALSE; - } else { - } - nJobs = 0; - - aborting = 0; - makeErrors = 0; - - lastNode = NULL; - if ((maxJobs == 1 && fifoFd < 0) || !beVerbose || is_posix || beQuiet) { - /* - * If only one job can run at a time, there's no need for a - * banner, no is there? - */ - targFmt = ""; - } else { - targFmt = TARG_FMT; - } - - /* - * Catch the four signals that POSIX specifies if they aren't ignored. - * JobCatchSignal will just set global variables and hope someone - * else is going to handle the interrupt. - */ - sa.sa_handler = JobCatchSig; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - - if (signal(SIGINT, SIG_IGN) != SIG_IGN) { - sigaction(SIGINT, &sa, NULL); - } - if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { - sigaction(SIGHUP, &sa, NULL); - } - if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) { - sigaction(SIGQUIT, &sa, NULL); - } - if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { - sigaction(SIGTERM, &sa, NULL); - } - /* - * There are additional signals that need to be caught and passed if - * either the export system wants to be told directly of signals or if - * we're giving each job its own process group (since then it won't get - * signals from the terminal driver as we own the terminal) - */ -#if defined(USE_PGRP) - if (signal(SIGTSTP, SIG_IGN) != SIG_IGN) { - sigaction(SIGTSTP, &sa, NULL); - } - if (signal(SIGTTOU, SIG_IGN) != SIG_IGN) { - sigaction(SIGTTOU, &sa, NULL); - } - if (signal(SIGTTIN, SIG_IGN) != SIG_IGN) { - sigaction(SIGTTIN, &sa, NULL); - } - if (signal(SIGWINCH, SIG_IGN) != SIG_IGN) { - sigaction(SIGWINCH, &sa, NULL); - } -#endif - -#ifdef USE_KQUEUE - if ((kqfd = kqueue()) == -1) { - Punt("kqueue: %s", strerror(errno)); - } -#endif - - begin = Targ_FindNode(".BEGIN", TARG_NOCREATE); - - if (begin != NULL) { - JobStart(begin, JOB_SPECIAL, (Job *)NULL); - while (nJobs) { - Job_CatchOutput(0); - Job_CatchChildren(!usePipes); - } - } - postCommands = Targ_FindNode(".END", TARG_CREATE); -} - -/** - * Job_Full - * See if the job table is full. It is considered full if it is OR - * if we are in the process of aborting OR if we have - * reached/exceeded our local quota. This prevents any more jobs - * from starting up. - * - * Results: - * TRUE if the job table is full, FALSE otherwise - */ -Boolean -Job_Full(void) -{ - char c; - int i; - - if (aborting) - return (aborting); - if (fifoFd >= 0 && jobFull) { - i = read(fifoFd, &c, 1); - if (i > 0) { - maxJobs++; - jobFull = FALSE; - } - } - return (jobFull); -} - -/** - * Job_Empty - * See if the job table is empty. Because the local concurrency may - * be set to 0, it is possible for the job table to become empty, - * while the list of stoppedJobs remains non-empty. In such a case, - * we want to restart as many jobs as we can. - * - * Results: - * TRUE if it is. FALSE if it ain't. - */ -Boolean -Job_Empty(void) -{ - if (nJobs == 0) { - if (!TAILQ_EMPTY(&stoppedJobs) && !aborting) { - /* - * The job table is obviously not full if it has no - * jobs in it...Try and restart the stopped jobs. - */ - jobFull = FALSE; - JobRestartJobs(); - return (FALSE); - } else { - return (TRUE); - } - } else { - return (FALSE); - } -} - -/** - * JobInterrupt - * Handle the receipt of an interrupt. - * - * Side Effects: - * All children are killed. Another job will be started if the - * .INTERRUPT target was given. - */ -static void -JobInterrupt(int runINTERRUPT, int signo) -{ - Job *job; /* job descriptor in that element */ - GNode *interrupt; /* the node describing the .INTERRUPT target */ - - aborting = ABORT_INTERRUPT; - - TAILQ_FOREACH(job, &jobs, link) { - if (!Targ_Precious(job->node)) { - char *file = (job->node->path == NULL ? - job->node->name : job->node->path); - - if (!noExecute && eunlink(file) != -1) { - Error("*** %s removed", file); - } - } - if (job->pid) { - DEBUGF(JOB, ("JobInterrupt passing signal to child " - "%jd.\n", (intmax_t)job->pid)); - KILL(job->pid, signo); - } - } - - if (runINTERRUPT && !touchFlag) { - /* - * clear the interrupted flag because we would get an - * infinite loop otherwise. - */ - interrupted = 0; - - interrupt = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); - if (interrupt != NULL) { - ignoreErrors = FALSE; - - JobStart(interrupt, JOB_IGNDOTS, (Job *)NULL); - while (nJobs) { - Job_CatchOutput(0); - Job_CatchChildren(!usePipes); - } - } - } - if (fifoMaster) - unlink(fifoName); -} - -/** - * Job_Finish - * Do final processing such as the running of the commands - * attached to the .END target. - * - * Results: - * None. - */ -void -Job_Finish(void) -{ - - if (postCommands != NULL && !Lst_IsEmpty(&postCommands->commands)) { - if (makeErrors) { - Error("Errors reported so .END ignored"); - } else { - JobStart(postCommands, JOB_SPECIAL | JOB_IGNDOTS, NULL); - - while (nJobs) { - Job_CatchOutput(0); - Job_CatchChildren(!usePipes); - } - } - } - if (fifoFd >= 0) { - close(fifoFd); - fifoFd = -1; - if (fifoMaster) - unlink(fifoName); - } -} - -/** - * Job_Wait - * Waits for all running jobs to finish and returns. Sets 'aborting' - * to ABORT_WAIT to prevent other jobs from starting. - * - * Side Effects: - * Currently running jobs finish. - */ -void -Job_Wait(void) -{ - - aborting = ABORT_WAIT; - while (nJobs != 0) { - Job_CatchOutput(0); - Job_CatchChildren(!usePipes); - } - aborting = 0; -} - -/** - * Job_AbortAll - * Abort all currently running jobs without handling output or anything. - * This function is to be called only in the event of a major - * error. Most definitely NOT to be called from JobInterrupt. - * - * Side Effects: - * All children are killed, not just the firstborn - */ -void -Job_AbortAll(void) -{ - Job *job; /* the job descriptor in that element */ - int foo; - - aborting = ABORT_ERROR; - - if (nJobs) { - TAILQ_FOREACH(job, &jobs, link) { - /* - * kill the child process with increasingly drastic - * signals to make darn sure it's dead. - */ - KILL(job->pid, SIGINT); - KILL(job->pid, SIGKILL); - } - } - - /* - * Catch as many children as want to report in at first, then give up - */ - while (waitpid(-1, &foo, WNOHANG) > 0) - ; -} - -/** - * JobRestartJobs - * Tries to restart stopped jobs if there are slots available. - * Note that this tries to restart them regardless of pending errors. - * It's not good to leave stopped jobs lying around! - * - * Side Effects: - * Resumes(and possibly migrates) jobs. - */ -static void -JobRestartJobs(void) -{ - Job *job; - - while (!jobFull && (job = TAILQ_FIRST(&stoppedJobs)) != NULL) { - DEBUGF(JOB, ("Job queue is not full. " - "Restarting a stopped job.\n")); - TAILQ_REMOVE(&stoppedJobs, job, link); - JobRestart(job); - } -} - -/** - * Cmd_Exec - * Execute the command in cmd, and return the output of that command - * in a string. - * - * Results: - * A string containing the output of the command, or the empty string - * If error is not NULL, it contains the reason for the command failure - * Any output sent to stderr in the child process is passed to stderr, - * and not captured in the string. - * - * Side Effects: - * The string must be freed by the caller. - */ -Buffer * -Cmd_Exec(const char *cmd, const char **error) -{ - int fds[2]; /* Pipe streams */ - int status; /* command exit status */ - Buffer *buf; /* buffer to store the result */ - ssize_t rcnt; - ProcStuff ps; - - *error = NULL; - buf = Buf_Init(0); - - /* - * Open a pipe for fetching its output - */ - if (pipe(fds) == -1) { - *error = "Couldn't create pipe for \"%s\""; - return (buf); - } - - /* Set close-on-exec on read side of pipe. */ - fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC); - - ps.in = STDIN_FILENO; - ps.out = fds[1]; - ps.err = STDERR_FILENO; - - ps.merge_errors = 0; - ps.pgroup = 0; - ps.searchpath = 0; - - /* Set up arguments for shell */ - ps.argv = emalloc(4 * sizeof(char *)); - ps.argv[0] = strdup(commandShell->name); - ps.argv[1] = strdup("-c"); - ps.argv[2] = strdup(cmd); - ps.argv[3] = NULL; - ps.argv_free = 1; - - /* - * Fork. Warning since we are doing vfork() instead of fork(), - * do not allocate memory in the child process! - */ - if ((ps.child_pid = vfork()) == -1) { - *error = "Couldn't exec \"%s\""; - return (buf); - - } else if (ps.child_pid == 0) { - /* - * Child - */ - Proc_Exec(&ps); - /* NOTREACHED */ - } - - free(ps.argv[2]); - free(ps.argv[1]); - free(ps.argv[0]); - free(ps.argv); - - close(fds[1]); /* No need for the writing half of the pipe. */ - - do { - char result[BUFSIZ]; - - rcnt = read(fds[0], result, sizeof(result)); - if (rcnt != -1) - Buf_AddBytes(buf, (size_t)rcnt, (Byte *)result); - } while (rcnt > 0 || (rcnt == -1 && errno == EINTR)); - - if (rcnt == -1) - *error = "Error reading shell's output for \"%s\""; - - /* - * Close the input side of the pipe. - */ - close(fds[0]); - - status = ProcWait(&ps); - - if (status) - *error = "\"%s\" returned non-zero status"; - - Buf_StripNewlines(buf); - - return (buf); -} - - -/* - * Interrupt handler - set flag and defer handling to the main code - */ -static void -CompatCatchSig(int signo) -{ - - interrupted = signo; -} - -/*- - *----------------------------------------------------------------------- - * CompatInterrupt -- - * Interrupt the creation of the current target and remove it if - * it ain't precious. - * - * Results: - * None. - * - * Side Effects: - * The target is removed and the process exits. If .INTERRUPT exists, - * its commands are run first WITH INTERRUPTS IGNORED.. - * - *----------------------------------------------------------------------- - */ -static void -CompatInterrupt(int signo) -{ - GNode *gn; - sigset_t nmask, omask; - LstNode *ln; - - sigemptyset(&nmask); - sigaddset(&nmask, SIGINT); - sigaddset(&nmask, SIGTERM); - sigaddset(&nmask, SIGHUP); - sigaddset(&nmask, SIGQUIT); - sigprocmask(SIG_SETMASK, &nmask, &omask); - - /* prevent recursion in evaluation of .INTERRUPT */ - interrupted = 0; - - if (curTarg != NULL && !Targ_Precious(curTarg)) { - const char *file = Var_Value(TARGET, curTarg); - - if (!noExecute && eunlink(file) != -1) { - printf("*** %s removed\n", file); - } - } - - /* - * Run .INTERRUPT only if hit with interrupt signal - */ - if (signo == SIGINT) { - gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); - if (gn != NULL) { - LST_FOREACH(ln, &gn->commands) { - if (Compat_RunCommand(ln, gn)) - break; - } - } - } - - sigprocmask(SIG_SETMASK, &omask, NULL); - - if (signo == SIGQUIT) - exit(signo); - signal(signo, SIG_DFL); - kill(getpid(), signo); -} - -/** - * shellneed - * - * Results: - * Returns NULL if a specified line must be executed by the shell, - * and an argument vector if it can be run via execvp(). - * - * Side Effects: - * Uses brk_string so destroys the contents of argv. - */ -static char ** -shellneed(ArgArray *aa, char *cmd) -{ - char **p; - int ret; - - if (commandShell->meta == NULL || commandShell->builtins.argc <= 1) - /* use shell */ - return (NULL); - - if (strpbrk(cmd, commandShell->meta) != NULL) - return (NULL); - - /* - * Break the command into words to form an argument - * vector we can execute. - */ - brk_string(aa, cmd, TRUE); - for (p = commandShell->builtins.argv + 1; *p != 0; p++) { - if ((ret = strcmp(aa->argv[1], *p)) == 0) { - /* found - use shell */ - ArgArray_Done(aa); - return (NULL); - } - if (ret < 0) { - /* not found */ - break; - } - } - return (aa->argv + 1); -} - -/** - * Execute the next command for a target. If the command returns an - * error, the node's made field is set to ERROR and creation stops. - * The node from which the command came is also given. This is used - * to execute the commands in compat mode and when executing commands - * with the '+' flag in non-compat mode. In these modes each command - * line should be executed by its own shell. We do some optimisation here: - * if the shell description defines both a string of meta characters and - * a list of builtins and the command line neither contains a meta character - * nor starts with one of the builtins then we execute the command directly - * without invoking a shell. - * - * Results: - * 0 if the command succeeded, 1 if an error occurred. - * - * Side Effects: - * The node's 'made' field may be set to ERROR. - */ -static int -Compat_RunCommand(LstNode *cmdNode, GNode *gn) -{ - ArgArray aa; - char *cmd; /* Expanded command */ - Boolean silent; /* Don't print command */ - Boolean doit; /* Execute even in -n */ - Boolean errCheck; /* Check errors */ - int reason; /* Reason for child's death */ - int status; /* Description of child's death */ - char **av; /* Argument vector for thing to exec */ - ProcStuff ps; - - silent = gn->type & OP_SILENT; - errCheck = !(gn->type & OP_IGNORE); - doit = FALSE; - - cmd = Buf_Peel(Var_Subst(Lst_Datum(cmdNode), gn, FALSE)); - if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) { - Lst_AtEnd(&ENDNode->commands, cmd); - return (0); - } else if (strcmp(cmd, "...") == 0) { - free(cmd); - gn->type |= OP_SAVE_CMDS; - return (0); - } - Lst_Replace(cmdNode, cmd); - - while (*cmd == '@' || *cmd == '-' || *cmd == '+') { - switch (*cmd) { - - case '@': - silent = DEBUG(LOUD) ? FALSE : TRUE; - break; - - case '-': - errCheck = FALSE; - break; - - case '+': - doit = TRUE; - break; - } - cmd++; - } - - while (isspace((unsigned char)*cmd)) - cmd++; - - /* - * Ignore empty commands - */ - if (*cmd == '\0') { - return (0); - } - - /* - * Print the command before echoing if we're not supposed to be quiet - * for this one. We also print the command if -n given, but not if '+'. - */ - if (!silent || (noExecute && !doit)) { - printf("%s\n", cmd); - fflush(stdout); - } - - /* - * If we're not supposed to execute any commands, this is as far as - * we go... - */ - if (!doit && noExecute) { - return (0); - } - - ps.in = STDIN_FILENO; - ps.out = STDOUT_FILENO; - ps.err = STDERR_FILENO; - - ps.merge_errors = 0; - ps.pgroup = 0; - ps.searchpath = 1; - - if ((av = shellneed(&aa, cmd)) == NULL) { - /* - * Shell meta character or shell builtin found - pass - * command to shell. We give the shell the -e flag as - * well as -c if it is supposed to exit when it hits an error. - */ - ps.argv = emalloc(4 * sizeof(char *)); - ps.argv[0] = strdup(commandShell->path); - ps.argv[1] = strdup(errCheck ? "-ec" : "-c"); - ps.argv[2] = strdup(cmd); - ps.argv[3] = NULL; - ps.argv_free = 1; - } else { - ps.argv = av; - ps.argv_free = 0; - } - ps.errCheck = errCheck; - - /* - * Warning since we are doing vfork() instead of fork(), - * do not allocate memory in the child process! - */ - if ((ps.child_pid = vfork()) == -1) { - Fatal("Could not fork"); - - } else if (ps.child_pid == 0) { - /* - * Child - */ - Proc_Exec(&ps); - /* NOTREACHED */ - - } else { - if (ps.argv_free) { - free(ps.argv[2]); - free(ps.argv[1]); - free(ps.argv[0]); - free(ps.argv); - } else { - ArgArray_Done(&aa); - } - - /* - * we need to print out the command associated with this - * Gnode in Targ_PrintCmd from Targ_PrintGraph when debugging - * at level g2, in main(), Fatal() and DieHorribly(), - * therefore do not free it when debugging. - */ - if (!DEBUG(GRAPH2)) { - free(Lst_Datum(cmdNode)); - Lst_Replace(cmdNode, NULL); - } - - /* - * The child is off and running. Now all we can do is wait... - */ - reason = ProcWait(&ps); - - if (interrupted) - CompatInterrupt(interrupted); - - /* - * Decode and report the reason child exited, then - * indicate how we handled it. - */ - if (WIFEXITED(reason)) { - status = WEXITSTATUS(reason); - if (status == 0) { - return (0); - } else { - printf("*** [%s] Error code %d", - gn->name, status); - } - } else if (WIFSTOPPED(reason)) { - status = WSTOPSIG(reason); - } else { - status = WTERMSIG(reason); - printf("*** [%s] Signal %d", - gn->name, status); - } - - if (ps.errCheck) { - gn->made = ERROR; - if (keepgoing) { - /* - * Abort the current - * target, but let - * others continue. - */ - printf(" (continuing)\n"); - } - return (status); - } else { - /* - * Continue executing - * commands for this target. - * If we return 0, this will - * happen... - */ - printf(" (ignored)\n"); - return (0); - } - } -} - -/*- - *----------------------------------------------------------------------- - * Compat_Make -- - * Make a target, given the parent, to abort if necessary. - * - * Side Effects: - * If an error is detected and not being ignored, the process exits. - * - *----------------------------------------------------------------------- - */ -int -Compat_Make(GNode *gn, GNode *pgn) -{ - LstNode *ln; - - if (gn->type & OP_USE) { - Make_HandleUse(gn, pgn); - - } else if (gn->made == UNMADE) { - /* - * First mark ourselves to be made, then apply whatever - * transformations the suffix module thinks are necessary. - * Once that's done, we can descend and make all our children. - * If any of them has an error but the -k flag was given, our - * 'make' field will be set FALSE again. This is our signal to - * not attempt to do anything but abort our parent as well. - */ - gn->make = TRUE; - gn->made = BEINGMADE; - Suff_FindDeps(gn); - LST_FOREACH(ln, &gn->children) - Compat_Make(Lst_Datum(ln), gn); - if (!gn->make) { - gn->made = ABORTED; - pgn->make = FALSE; - return (0); - } - - if (Lst_Member(&gn->iParents, pgn) != NULL) { - Var_Set(IMPSRC, Var_Value(TARGET, gn), pgn); - } - - /* - * All the children were made ok. Now cmtime contains the - * modification time of the newest child, we need to find out - * if we exist and when we were modified last. The criteria for - * datedness are defined by the Make_OODate function. - */ - DEBUGF(MAKE, ("Examining %s...", gn->name)); - if (!Make_OODate(gn)) { - gn->made = UPTODATE; - DEBUGF(MAKE, ("up-to-date.\n")); - return (0); - } else { - DEBUGF(MAKE, ("out-of-date.\n")); - } - - /* - * If the user is just seeing if something is out-of-date, - * exit now to tell him/her "yes". - */ - if (queryFlag) { - exit(1); - } - - /* - * We need to be re-made. We also have to make sure we've got - * a $? variable. To be nice, we also define the $> variable - * using Make_DoAllVar(). - */ - Make_DoAllVar(gn); - - /* - * Alter our type to tell if errors should be ignored or things - * should not be printed so Compat_RunCommand knows what to do. - */ - if (Targ_Ignore(gn)) { - gn->type |= OP_IGNORE; - } - if (Targ_Silent(gn)) { - gn->type |= OP_SILENT; - } - - if (Job_CheckCommands(gn, Fatal)) { - /* - * Our commands are ok, but we still have to worry - * about the -t flag... - */ - if (!touchFlag) { - curTarg = gn; - LST_FOREACH(ln, &gn->commands) { - if (Compat_RunCommand(ln, gn)) - break; - } - curTarg = NULL; - } else { - Job_Touch(gn, gn->type & OP_SILENT); - } - } else { - gn->made = ERROR; - } - - if (gn->made != ERROR) { - /* - * If the node was made successfully, mark it so, update - * its modification time and timestamp all its parents. - * Note that for .ZEROTIME targets, the timestamping - * isn't done. This is to keep its state from affecting - * that of its parent. - */ - gn->made = MADE; -#ifndef RECHECK - /* - * We can't re-stat the thing, but we can at least take - * care of rules where a target depends on a source that - * actually creates the target, but only if it has - * changed, e.g. - * - * parse.h : parse.o - * - * parse.o : parse.y - * yacc -d parse.y - * cc -c y.tab.c - * mv y.tab.o parse.o - * cmp -s y.tab.h parse.h || mv y.tab.h parse.h - * - * In this case, if the definitions produced by yacc - * haven't changed from before, parse.h won't have been - * updated and gn->mtime will reflect the current - * modification time for parse.h. This is something of a - * kludge, I admit, but it's a useful one.. - * - * XXX: People like to use a rule like - * - * FRC: - * - * To force things that depend on FRC to be made, so we - * have to check for gn->children being empty as well... - */ - if (!Lst_IsEmpty(&gn->commands) || - Lst_IsEmpty(&gn->children)) { - gn->mtime = now; - } -#else - /* - * This is what Make does and it's actually a good - * thing, as it allows rules like - * - * cmp -s y.tab.h parse.h || cp y.tab.h parse.h - * - * to function as intended. Unfortunately, thanks to - * the stateless nature of NFS (and the speed of this - * program), there are times when the modification time - * of a file created on a remote machine will not be - * modified before the stat() implied by the Dir_MTime - * occurs, thus leading us to believe that the file - * is unchanged, wreaking havoc with files that depend - * on this one. - * - * I have decided it is better to make too much than to - * make too little, so this stuff is commented out - * unless you're sure it's ok. - * -- ardeb 1/12/88 - */ - if (noExecute || Dir_MTime(gn) == 0) { - gn->mtime = now; - } - if (gn->cmtime > gn->mtime) - gn->mtime = gn->cmtime; - DEBUGF(MAKE, ("update time: %s\n", - Targ_FmtTime(gn->mtime))); -#endif - if (!(gn->type & OP_EXEC)) { - pgn->childMade = TRUE; - Make_TimeStamp(pgn, gn); - } - - } else if (keepgoing) { - pgn->make = FALSE; - - } else { - printf("\n\nStop in %s.\n", Var_Value(".CURDIR", gn)); - exit(1); - } - } else if (gn->made == ERROR) { - /* - * Already had an error when making this beastie. Tell the - * parent to abort. - */ - pgn->make = FALSE; - } else { - if (Lst_Member(&gn->iParents, pgn) != NULL) { - Var_Set(IMPSRC, Var_Value(TARGET, gn), pgn); - } - switch(gn->made) { - case BEINGMADE: - Error("Graph cycles through %s\n", gn->name); - gn->made = ERROR; - pgn->make = FALSE; - break; - case MADE: - if ((gn->type & OP_EXEC) == 0) { - pgn->childMade = TRUE; - Make_TimeStamp(pgn, gn); - } - break; - case UPTODATE: - if ((gn->type & OP_EXEC) == 0) { - Make_TimeStamp(pgn, gn); - } - break; - default: - break; - } - } - - return (0); -} - -/*- - * Install signal handlers for Compat_Run - */ -void -Compat_InstallSignalHandlers(void) -{ - - if (signal(SIGINT, SIG_IGN) != SIG_IGN) { - signal(SIGINT, CompatCatchSig); - } - if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { - signal(SIGTERM, CompatCatchSig); - } - if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { - signal(SIGHUP, CompatCatchSig); - } - if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) { - signal(SIGQUIT, CompatCatchSig); - } -} - -/*- - *----------------------------------------------------------------------- - * Compat_Run -- - * Start making again, given a list of target nodes. - * - * Results: - * None. - * - * Side Effects: - * Guess what? - * - *----------------------------------------------------------------------- - */ -void -Compat_Run(Lst *targs) -{ - GNode *gn = NULL; /* Current root target */ - LstNode *ln; - - Compat_InstallSignalHandlers(); - ENDNode = Targ_FindNode(".END", TARG_CREATE); - /* - * If the user has defined a .BEGIN target, execute the commands - * attached to it. - */ - if (!queryFlag) { - gn = Targ_FindNode(".BEGIN", TARG_NOCREATE); - if (gn != NULL) { - LST_FOREACH(ln, &gn->commands) { - if (Compat_RunCommand(ln, gn)) - break; - } - if (gn->made == ERROR) { - printf("\n\nStop.\n"); - exit(1); - } - } - } - - /* - * For each entry in the list of targets to create, call Compat_Make on - * it to create the thing. Compat_Make will leave the 'made' field of gn - * in one of several states: - * UPTODATE gn was already up-to-date - * MADE gn was recreated successfully - * ERROR An error occurred while gn was being created - * ABORTED gn was not remade because one of its inferiors - * could not be made due to errors. - */ - makeErrors = 0; - while (!Lst_IsEmpty(targs)) { - gn = Lst_DeQueue(targs); - Compat_Make(gn, gn); - - if (gn->made == UPTODATE) { - printf("`%s' is up to date.\n", gn->name); - } else if (gn->made == ABORTED) { - printf("`%s' not remade because of errors.\n", - gn->name); - makeErrors++; - } else if (gn->made == ERROR) { - makeErrors++; - } - } - - /* - * If the user has defined a .END target, run its commands. - */ - if (makeErrors == 0) { - LST_FOREACH(ln, &ENDNode->commands) { - if (Compat_RunCommand(ln, ENDNode)) - break; - } - } -} Property changes on: head/usr.bin/make/job.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/globals.h =================================================================== --- head/usr.bin/make/globals.h (revision 284463) +++ head/usr.bin/make/globals.h (nonexistent) @@ -1,116 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef globals_h_1c1edb96 -#define globals_h_1c1edb96 - -/* - * Global Variables - */ - -#include "lst.h" -#include "util.h" - -struct GNode; -struct Path; - -/* - * The list of target names specified on the command line. - * Used to resolve #if make(...) statements - */ -extern Lst create; - -/* The list of directories to search when looking for targets */ -extern struct Path dirSearchPath; - -/* The list of directories to search when looking for includes */ -extern struct Path parseIncPath; - -/* The system include path. */ -extern struct Path sysIncPath; - -extern int jobLimit; /* -j argument: maximum number of jobs */ -extern int makeErrors; /* Number of targets not remade due to errors */ -extern Boolean jobsRunning; /* True if jobs are running */ -extern Boolean compatMake; /* True if we are make compatible */ -extern Boolean ignoreErrors; /* True if should ignore all errors */ -extern Boolean beSilent; /* True if should print no commands */ -extern Boolean beVerbose; /* True if should print extra cruft */ -extern Boolean beQuiet; /* True if want quiet headers with -j */ -extern Boolean noExecute; /* True if should execute nothing */ -extern Boolean printGraphOnly; /* -p flag */ -extern Boolean allPrecious; /* True if every target is precious */ -extern Boolean is_posix; /* .POSIX target seen */ -extern Boolean mfAutoDeps; /* .MAKEFILEDEPS target seen */ -extern Boolean remakingMakefiles; /* True if remaking makefiles is in progress */ - -/* True if should continue on unaffected portions of the graph - * when have an error in one portion */ -extern Boolean keepgoing; - -/* TRUE if targets should just be 'touched'if out of date. Set by the -t flag */ -extern Boolean touchFlag; - -/* TRUE if should capture the output of subshells by means of pipes. - * Otherwise it is routed to temporary files from which it is retrieved - * when the shell exits */ -extern Boolean usePipes; - -/* TRUE if we aren't supposed to really make anything, just see if the - * targets are out-of-date */ -extern Boolean queryFlag; - -/* List of specific variables for which the environment should be - * searched before the global context */ -extern Lst envFirstVars; - -extern struct GNode *DEFAULT; /* .DEFAULT rule */ - -/* The time at the start of this whole process */ -extern time_t now; - -extern int debug; - -/* warning flags */ -extern uint32_t warn_cmd; /* positive warning flags on command line */ -extern uint32_t warn_nocmd; /* negative warning flags on command line */ -extern uint32_t warn_flags; /* current warning flags */ - -#endif /* globals_h_1c1edb96 */ Property changes on: head/usr.bin/make/globals.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/dir.c =================================================================== --- head/usr.bin/make/dir.c (revision 284463) +++ head/usr.bin/make/dir.c (nonexistent) @@ -1,1217 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1988, 1989 by Adam de Boor - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)dir.c 8.2 (Berkeley) 1/2/94 - */ - -#include -__FBSDID("$FreeBSD$"); - -/*- - * dir.c -- - * Directory searching using wildcards and/or normal names... - * Used both for source wildcarding in the Makefile and for finding - * implicit sources. - * - * The interface for this module is: - * Dir_Init Initialize the module. - * - * Dir_HasWildcards Returns TRUE if the name given it needs to - * be wildcard-expanded. - * - * Path_Expand Given a pattern and a path, return a Lst of names - * which match the pattern on the search path. - * - * Path_FindFile Searches for a file on a given search path. - * If it exists, the entire path is returned. - * Otherwise NULL is returned. - * - * Dir_FindHereOrAbove Search for a path in the current directory and - * then all the directories above it in turn until - * the path is found or we reach the root ("/"). - * - * Dir_MTime Return the modification time of a node. The file - * is searched for along the default search path. - * The path and mtime fields of the node are filled in. - * - * Path_AddDir Add a directory to a search path. - * - * Dir_MakeFlags Given a search path and a command flag, create - * a string with each of the directories in the path - * preceded by the command flag and all of them - * separated by a space. - * - * Dir_Destroy Destroy an element of a search path. Frees up all - * things that can be freed for the element as long - * as the element is no longer referenced by any other - * search path. - * - * Dir_ClearPath Resets a search path to the empty list. - * - * For debugging: - * Dir_PrintDirectories Print stats about the directory cache. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "arch.h" -#include "dir.h" -#include "globals.h" -#include "GNode.h" -#include "hash.h" -#include "lst.h" -#include "str.h" -#include "targ.h" -#include "util.h" - -/* - * A search path consists of a list of Dir structures. A Dir structure - * has in it the name of the directory and a hash table of all the files - * in the directory. This is used to cut down on the number of system - * calls necessary to find implicit dependents and their like. Since - * these searches are made before any actions are taken, we need not - * worry about the directory changing due to creation commands. If this - * hampers the style of some makefiles, they must be changed. - * - * A list of all previously-read directories is kept in the - * openDirectories list. This list is checked first before a directory - * is opened. - * - * The need for the caching of whole directories is brought about by - * the multi-level transformation code in suff.c, which tends to search - * for far more files than regular make does. In the initial - * implementation, the amount of time spent performing "stat" calls was - * truly astronomical. The problem with hashing at the start is, - * of course, that pmake doesn't then detect changes to these directories - * during the course of the make. Three possibilities suggest themselves: - * - * 1) just use stat to test for a file's existence. As mentioned - * above, this is very inefficient due to the number of checks - * engendered by the multi-level transformation code. - * 2) use readdir() and company to search the directories, keeping - * them open between checks. I have tried this and while it - * didn't slow down the process too much, it could severely - * affect the amount of parallelism available as each directory - * open would take another file descriptor out of play for - * handling I/O for another job. Given that it is only recently - * that UNIX OS's have taken to allowing more than 20 or 32 - * file descriptors for a process, this doesn't seem acceptable - * to me. - * 3) record the mtime of the directory in the Dir structure and - * verify the directory hasn't changed since the contents were - * hashed. This will catch the creation or deletion of files, - * but not the updating of files. However, since it is the - * creation and deletion that is the problem, this could be - * a good thing to do. Unfortunately, if the directory (say ".") - * were fairly large and changed fairly frequently, the constant - * rehashing could seriously degrade performance. It might be - * good in such cases to keep track of the number of rehashes - * and if the number goes over a (small) limit, resort to using - * stat in its place. - * - * An additional thing to consider is that pmake is used primarily - * to create C programs and until recently pcc-based compilers refused - * to allow you to specify where the resulting object file should be - * placed. This forced all objects to be created in the current - * directory. This isn't meant as a full excuse, just an explanation of - * some of the reasons for the caching used here. - * - * One more note: the location of a target's file is only performed - * on the downward traversal of the graph and then only for terminal - * nodes in the graph. This could be construed as wrong in some cases, - * but prevents inadvertent modification of files when the "installed" - * directory for a file is provided in the search path. - * - * Another data structure maintained by this module is an mtime - * cache used when the searching of cached directories fails to find - * a file. In the past, Path_FindFile would simply perform an access() - * call in such a case to determine if the file could be found using - * just the name given. When this hit, however, all that was gained - * was the knowledge that the file existed. Given that an access() is - * essentially a stat() without the copyout() call, and that the same - * filesystem overhead would have to be incurred in Dir_MTime, it made - * sense to replace the access() with a stat() and record the mtime - * in a cache for when Dir_MTime was actually called. - */ - -typedef struct Dir { - char *name; /* Name of directory */ - int refCount; /* No. of paths with this directory */ - int hits; /* No. of times a file has been found here */ - Hash_Table files; /* Hash table of files in directory */ - TAILQ_ENTRY(Dir) link; /* allDirs link */ -} Dir; - -/* - * A path is a list of pointers to directories. These directories are - * reference counted so a directory can be on more than one path. - */ -struct PathElement { - struct Dir *dir; /* pointer to the directory */ - TAILQ_ENTRY(PathElement) link; /* path link */ -}; - -/* main search path */ -struct Path dirSearchPath = TAILQ_HEAD_INITIALIZER(dirSearchPath); - -/* the list of all open directories */ -static TAILQ_HEAD(, Dir) openDirectories = - TAILQ_HEAD_INITIALIZER(openDirectories); - -/* - * Variables for gathering statistics on the efficiency of the hashing - * mechanism. - */ -static int hits; /* Found in directory cache */ -static int misses; /* Sad, but not evil misses */ -static int nearmisses; /* Found under search path */ -static int bigmisses; /* Sought by itself */ - -static Dir *dot; /* contents of current directory */ - -/* Results of doing a last-resort stat in Path_FindFile -- - * if we have to go to the system to find the file, we might as well - * have its mtime on record. - * XXX: If this is done way early, there's a chance other rules will - * have already updated the file, in which case we'll update it again. - * Generally, there won't be two rules to update a single file, so this - * should be ok, but... - */ -static Hash_Table mtimes; - -/*- - *----------------------------------------------------------------------- - * Dir_Init -- - * initialize things for this module - * - * Results: - * none - * - * Side Effects: - * none - *----------------------------------------------------------------------- - */ -void -Dir_Init(void) -{ - - Hash_InitTable(&mtimes, 0); -} - -/*- - *----------------------------------------------------------------------- - * Dir_InitDot -- - * initialize the "." directory - * - * Results: - * none - * - * Side Effects: - * some directories may be opened. - *----------------------------------------------------------------------- - */ -void -Dir_InitDot(void) -{ - - dot = Path_AddDir(NULL, "."); - if (dot == NULL) - err(1, "cannot open current directory"); - - /* - * We always need to have dot around, so we increment its - * reference count to make sure it's not destroyed. - */ - dot->refCount += 1; -} - -/*- - *----------------------------------------------------------------------- - * Dir_HasWildcards -- - * See if the given name has any wildcard characters in it. - * - * Results: - * returns TRUE if the word should be expanded, FALSE otherwise - * - * Side Effects: - * none - *----------------------------------------------------------------------- - */ -Boolean -Dir_HasWildcards(const char *name) -{ - const char *cp; - int wild = 0, brace = 0, bracket = 0; - - for (cp = name; *cp; cp++) { - switch (*cp) { - case '{': - brace++; - wild = 1; - break; - case '}': - brace--; - break; - case '[': - bracket++; - wild = 1; - break; - case ']': - bracket--; - break; - case '?': - case '*': - wild = 1; - break; - default: - break; - } - } - return (wild && bracket == 0 && brace == 0); -} - -/*- - *----------------------------------------------------------------------- - * DirMatchFiles -- - * Given a pattern and a Dir structure, see if any files - * match the pattern and add their names to the 'expansions' list if - * any do. This is incomplete -- it doesn't take care of patterns like - * src / *src / *.c properly (just *.c on any of the directories), but it - * will do for now. - * - * Results: - * Always returns 0 - * - * Side Effects: - * File names are added to the expansions lst. The directory will be - * fully hashed when this is done. - *----------------------------------------------------------------------- - */ -static int -DirMatchFiles(const char *pattern, const Dir *p, Lst *expansions) -{ - Hash_Search search; /* Index into the directory's table */ - Hash_Entry *entry; /* Current entry in the table */ - Boolean isDot; /* TRUE if the directory being searched is . */ - - isDot = (*p->name == '.' && p->name[1] == '\0'); - - for (entry = Hash_EnumFirst(&p->files, &search); - entry != NULL; - entry = Hash_EnumNext(&search)) { - /* - * See if the file matches the given pattern. Note we follow - * the UNIX convention that dot files will only be found if - * the pattern begins with a dot (note also that as a side - * effect of the hashing scheme, .* won't match . or .. - * since they aren't hashed). - */ - if (Str_Match(entry->name, pattern) && - ((entry->name[0] != '.') || - (pattern[0] == '.'))) { - Lst_AtEnd(expansions, (isDot ? estrdup(entry->name) : - str_concat(p->name, entry->name, STR_ADDSLASH))); - } - } - return (0); -} - -/*- - *----------------------------------------------------------------------- - * DirExpandCurly -- - * Expand curly braces like the C shell. Does this recursively. - * Note the special case: if after the piece of the curly brace is - * done there are no wildcard characters in the result, the result is - * placed on the list WITHOUT CHECKING FOR ITS EXISTENCE. The - * given arguments are the entire word to expand, the first curly - * brace in the word, the search path, and the list to store the - * expansions in. - * - * Results: - * None. - * - * Side Effects: - * The given list is filled with the expansions... - * - *----------------------------------------------------------------------- - */ -static void -DirExpandCurly(const char *word, const char *brace, struct Path *path, - Lst *expansions) -{ - const char *end; /* Character after the closing brace */ - const char *cp; /* Current position in brace clause */ - const char *start; /* Start of current piece of brace clause */ - int bracelevel; /* Number of braces we've seen. If we see a right brace - * when this is 0, we've hit the end of the clause. */ - char *file; /* Current expansion */ - int otherLen; /* The length of the other pieces of the expansion - * (chars before and after the clause in 'word') */ - char *cp2; /* Pointer for checking for wildcards in - * expansion before calling Dir_Expand */ - - start = brace + 1; - - /* - * Find the end of the brace clause first, being wary of nested brace - * clauses. - */ - for (end = start, bracelevel = 0; *end != '\0'; end++) { - if (*end == '{') - bracelevel++; - else if ((*end == '}') && (bracelevel-- == 0)) - break; - } - if (*end == '\0') { - Error("Unterminated {} clause \"%s\"", start); - return; - } else - end++; - - otherLen = brace - word + strlen(end); - - for (cp = start; cp < end; cp++) { - /* - * Find the end of this piece of the clause. - */ - bracelevel = 0; - while (*cp != ',') { - if (*cp == '{') - bracelevel++; - else if ((*cp == '}') && (bracelevel-- <= 0)) - break; - cp++; - } - /* - * Allocate room for the combination and install the - * three pieces. - */ - file = emalloc(otherLen + cp - start + 1); - if (brace != word) - strncpy(file, word, brace - word); - if (cp != start) - strncpy(&file[brace - word], start, cp - start); - strcpy(&file[(brace - word) + (cp - start)], end); - - /* - * See if the result has any wildcards in it. If we find one, - * call Dir_Expand right away, telling it to place the result - * on our list of expansions. - */ - for (cp2 = file; *cp2 != '\0'; cp2++) { - switch (*cp2) { - case '*': - case '?': - case '{': - case '[': - Path_Expand(file, path, expansions); - goto next; - default: - break; - } - } - if (*cp2 == '\0') { - /* - * Hit the end w/o finding any wildcards, so stick - * the expansion on the end of the list. - */ - Lst_AtEnd(expansions, file); - } else { - next: - free(file); - } - start = cp + 1; - } -} - -/*- - *----------------------------------------------------------------------- - * DirExpandInt -- - * Internal expand routine. Passes through the directories in the - * path one by one, calling DirMatchFiles for each. NOTE: This still - * doesn't handle patterns in directories... Works given a word to - * expand, a path to look in, and a list to store expansions in. - * - * Results: - * None. - * - * Side Effects: - * Things are added to the expansions list. - * - *----------------------------------------------------------------------- - */ -static void -DirExpandInt(const char *word, const struct Path *path, Lst *expansions) -{ - struct PathElement *pe; - - TAILQ_FOREACH(pe, path, link) - DirMatchFiles(word, pe->dir, expansions); -} - -/*- - *----------------------------------------------------------------------- - * Dir_Expand -- - * Expand the given word into a list of words by globbing it looking - * in the directories on the given search path. - * - * Results: - * A list of words consisting of the files which exist along the search - * path matching the given pattern is placed in expansions. - * - * Side Effects: - * Directories may be opened. Who knows? - *----------------------------------------------------------------------- - */ -void -Path_Expand(char *word, struct Path *path, Lst *expansions) -{ - LstNode *ln; - char *cp; - - DEBUGF(DIR, ("expanding \"%s\"...", word)); - - cp = strchr(word, '{'); - if (cp != NULL) - DirExpandCurly(word, cp, path, expansions); - else { - cp = strchr(word, '/'); - if (cp != NULL) { - /* - * The thing has a directory component -- find the - * first wildcard in the string. - */ - for (cp = word; *cp != '\0'; cp++) { - if (*cp == '?' || *cp == '[' || - *cp == '*' || *cp == '{') { - break; - } - } - if (*cp == '{') { - /* - * This one will be fun. - */ - DirExpandCurly(word, cp, path, expansions); - return; - } else if (*cp != '\0') { - /* - * Back up to the start of the component - */ - char *dirpath; - - while (cp > word && *cp != '/') - cp--; - if (cp != word) { - char sc; - - /* - * If the glob isn't in the first - * component, try and find all the - * components up to the one with a - * wildcard. - */ - sc = cp[1]; - cp[1] = '\0'; - dirpath = Path_FindFile(word, path); - cp[1] = sc; - /* - * dirpath is null if can't find the - * leading component - * XXX: Path_FindFile won't find internal - * components. i.e. if the path contains - * ../Etc/Object and we're looking for - * Etc, * it won't be found. Ah well. - * Probably not important. - */ - if (dirpath != NULL) { - char *dp = - &dirpath[strlen(dirpath) - - 1]; - struct Path tp = - TAILQ_HEAD_INITIALIZER(tp); - - if (*dp == '/') - *dp = '\0'; - Path_AddDir(&tp, dirpath); - DirExpandInt(cp + 1, &tp, - expansions); - Path_Clear(&tp); - } - } else { - /* - * Start the search from the local - * directory - */ - DirExpandInt(word, path, expansions); - } - } else { - /* - * Return the file -- this should never happen. - */ - DirExpandInt(word, path, expansions); - } - } else { - /* - * First the files in dot - */ - DirMatchFiles(word, dot, expansions); - - /* - * Then the files in every other directory on the path. - */ - DirExpandInt(word, path, expansions); - } - } - if (DEBUG(DIR)) { - LST_FOREACH(ln, expansions) - DEBUGF(DIR, ("%s ", (const char *)Lst_Datum(ln))); - DEBUGF(DIR, ("\n")); - } -} - -/** - * Path_FindFile - * Find the file with the given name along the given search path. - * - * Results: - * The path to the file or NULL. This path is guaranteed to be in a - * different part of memory than name and so may be safely free'd. - * - * Side Effects: - * If the file is found in a directory which is not on the path - * already (either 'name' is absolute or it is a relative path - * [ dir1/.../dirn/file ] which exists below one of the directories - * already on the search path), its directory is added to the end - * of the path on the assumption that there will be more files in - * that directory later on. Sometimes this is true. Sometimes not. - */ -char * -Path_FindFile(char *name, struct Path *path) -{ - char *p1; /* pointer into p->name */ - char *p2; /* pointer into name */ - char *file; /* the current filename to check */ - const struct PathElement *pe; /* current path member */ - char *cp; /* final component of the name */ - Boolean hasSlash; /* true if 'name' contains a / */ - struct stat stb; /* Buffer for stat, if necessary */ - Hash_Entry *entry; /* Entry for mtimes table */ - - /* - * Find the final component of the name and note whether it has a - * slash in it (the name, I mean) - */ - cp = strrchr(name, '/'); - if (cp != NULL) { - hasSlash = TRUE; - cp += 1; - } else { - hasSlash = FALSE; - cp = name; - } - - DEBUGF(DIR, ("Searching for %s...", name)); - /* - * No matter what, we always look for the file in the current directory - * before anywhere else and we *do not* add the ./ to it if it exists. - * This is so there are no conflicts between what the user specifies - * (fish.c) and what pmake finds (./fish.c). - */ - if ((!hasSlash || (cp - name == 2 && *name == '.')) && - (Hash_FindEntry(&dot->files, cp) != NULL)) { - DEBUGF(DIR, ("in '.'\n")); - hits += 1; - dot->hits += 1; - return (estrdup(name)); - } - - /* - * We look through all the directories on the path seeking one which - * contains the final component of the given name and whose final - * component(s) match the name's initial component(s). If such a beast - * is found, we concatenate the directory name and the final component - * and return the resulting string. If we don't find any such thing, - * we go on to phase two... - */ - TAILQ_FOREACH(pe, path, link) { - DEBUGF(DIR, ("%s...", pe->dir->name)); - if (Hash_FindEntry(&pe->dir->files, cp) != NULL) { - DEBUGF(DIR, ("here...")); - if (hasSlash) { - /* - * If the name had a slash, its initial - * components and p's final components must - * match. This is false if a mismatch is - * encountered before all of the initial - * components have been checked (p2 > name at - * the end of the loop), or we matched only - * part of one of the components of p - * along with all the rest of them (*p1 != '/'). - */ - p1 = pe->dir->name + strlen(pe->dir->name) - 1; - p2 = cp - 2; - while (p2 >= name && p1 >= pe->dir->name && - *p1 == *p2) { - p1 -= 1; p2 -= 1; - } - if (p2 >= name || (p1 >= pe->dir->name && - *p1 != '/')) { - DEBUGF(DIR, ("component mismatch -- " - "continuing...")); - continue; - } - } - file = str_concat(pe->dir->name, cp, STR_ADDSLASH); - DEBUGF(DIR, ("returning %s\n", file)); - pe->dir->hits += 1; - hits += 1; - return (file); - } else if (hasSlash) { - /* - * If the file has a leading path component and that - * component exactly matches the entire name of the - * current search directory, we assume the file - * doesn't exist and return NULL. - */ - for (p1 = pe->dir->name, p2 = name; *p1 && *p1 == *p2; - p1++, p2++) - continue; - if (*p1 == '\0' && p2 == cp - 1) { - if (*cp == '\0' || ISDOT(cp) || ISDOTDOT(cp)) { - DEBUGF(DIR, ("returning %s\n", name)); - return (estrdup(name)); - } else { - DEBUGF(DIR, ("must be here but isn't --" - " returning NULL\n")); - return (NULL); - } - } - } - } - - /* - * We didn't find the file on any existing members of the directory. - * If the name doesn't contain a slash, that means it doesn't exist. - * If it *does* contain a slash, however, there is still hope: it - * could be in a subdirectory of one of the members of the search - * path. (eg. /usr/include and sys/types.h. The above search would - * fail to turn up types.h in /usr/include, but it *is* in - * /usr/include/sys/types.h) If we find such a beast, we assume there - * will be more (what else can we assume?) and add all but the last - * component of the resulting name onto the search path (at the - * end). This phase is only performed if the file is *not* absolute. - */ - if (!hasSlash) { - DEBUGF(DIR, ("failed.\n")); - misses += 1; - return (NULL); - } - - if (*name != '/') { - Boolean checkedDot = FALSE; - - DEBUGF(DIR, ("failed. Trying subdirectories...")); - TAILQ_FOREACH(pe, path, link) { - if (pe->dir != dot) { - file = str_concat(pe->dir->name, - name, STR_ADDSLASH); - } else { - /* - * Checking in dot -- DON'T put a leading ./ - * on the thing. - */ - file = estrdup(name); - checkedDot = TRUE; - } - DEBUGF(DIR, ("checking %s...", file)); - - if (stat(file, &stb) == 0) { - DEBUGF(DIR, ("got it.\n")); - - /* - * We've found another directory to search. We - * know there's a slash in 'file' because we put - * one there. We nuke it after finding it and - * call Path_AddDir to add this new directory - * onto the existing search path. Once that's - * done, we restore the slash and triumphantly - * return the file name, knowing that should a - * file in this directory every be referenced - * again in such a manner, we will find it - * without having to do numerous numbers of - * access calls. Hurrah! - */ - cp = strrchr(file, '/'); - *cp = '\0'; - Path_AddDir(path, file); - *cp = '/'; - - /* - * Save the modification time so if - * it's needed, we don't have to fetch it again. - */ - DEBUGF(DIR, ("Caching %s for %s\n", - Targ_FmtTime(stb.st_mtime), file)); - entry = Hash_CreateEntry(&mtimes, file, - (Boolean *)NULL); - Hash_SetValue(entry, - (void *)(long)stb.st_mtime); - nearmisses += 1; - return (file); - } else { - free(file); - } - } - - DEBUGF(DIR, ("failed. ")); - - if (checkedDot) { - /* - * Already checked by the given name, since . was in - * the path, so no point in proceeding... - */ - DEBUGF(DIR, ("Checked . already, returning NULL\n")); - return (NULL); - } - } - - /* - * Didn't find it that way, either. Sigh. Phase 3. Add its directory - * onto the search path in any case, just in case, then look for the - * thing in the hash table. If we find it, grand. We return a new - * copy of the name. Otherwise we sadly return a NULL pointer. Sigh. - * Note that if the directory holding the file doesn't exist, this will - * do an extra search of the final directory on the path. Unless - * something weird happens, this search won't succeed and life will - * be groovy. - * - * Sigh. We cannot add the directory onto the search path because - * of this amusing case: - * $(INSTALLDIR)/$(FILE): $(FILE) - * - * $(FILE) exists in $(INSTALLDIR) but not in the current one. - * When searching for $(FILE), we will find it in $(INSTALLDIR) - * b/c we added it here. This is not good... - */ - DEBUGF(DIR, ("Looking for \"%s\"...", name)); - - bigmisses += 1; - entry = Hash_FindEntry(&mtimes, name); - if (entry != NULL) { - DEBUGF(DIR, ("got it (in mtime cache)\n")); - return (estrdup(name)); - } else if (stat (name, &stb) == 0) { - entry = Hash_CreateEntry(&mtimes, name, (Boolean *)NULL); - DEBUGF(DIR, ("Caching %s for %s\n", - Targ_FmtTime(stb.st_mtime), name)); - Hash_SetValue(entry, (void *)(long)stb.st_mtime); - return (estrdup(name)); - } else { - DEBUGF(DIR, ("failed. Returning NULL\n")); - return (NULL); - } -} - -/*- - *----------------------------------------------------------------------- - * Dir_FindHereOrAbove -- - * search for a path starting at a given directory and then working - * our way up towards the root. - * - * Input: - * here starting directory - * search_path the path we are looking for - * result the result of a successful search is placed here - * rlen the length of the result buffer - * (typically MAXPATHLEN + 1) - * - * Results: - * 0 on failure, 1 on success [in which case the found path is put - * in the result buffer]. - * - * Side Effects: - *----------------------------------------------------------------------- - */ -int -Dir_FindHereOrAbove(char *here, char *search_path, char *result, int rlen) -{ - struct stat st; - char dirbase[MAXPATHLEN + 1], *db_end; - char try[MAXPATHLEN + 1], *try_end; - - /* copy out our starting point */ - snprintf(dirbase, sizeof(dirbase), "%s", here); - db_end = dirbase + strlen(dirbase); - - /* loop until we determine a result */ - while (1) { - /* try and stat(2) it ... */ - snprintf(try, sizeof(try), "%s/%s", dirbase, search_path); - if (stat(try, &st) != -1) { - /* - * Success! If we found a file, chop off - * the filename so we return a directory. - */ - if ((st.st_mode & S_IFMT) != S_IFDIR) { - try_end = try + strlen(try); - while (try_end > try && *try_end != '/') - try_end--; - if (try_end > try) - *try_end = 0; /* chop! */ - } - - /* - * Done! - */ - snprintf(result, rlen, "%s", try); - return(1); - } - - /* - * Nope, we didn't find it. If we used up dirbase we've - * reached the root and failed. - */ - if (db_end == dirbase) - break; /* Failed! */ - - /* - * truncate dirbase from the end to move up a dir - */ - while (db_end > dirbase && *db_end != '/') - db_end--; - *db_end = 0; /* chop! */ - - } /* while (1) */ - - /* - * We failed... - */ - return(0); -} - -/*- - *----------------------------------------------------------------------- - * Dir_MTime -- - * Find the modification time of the file described by gn along the - * search path dirSearchPath. - * - * Results: - * The modification time or 0 if it doesn't exist - * - * Side Effects: - * The modification time is placed in the node's mtime slot. - * If the node didn't have a path entry before, and Path_FindFile - * found one for it, the full name is placed in the path slot. - *----------------------------------------------------------------------- - */ -int -Dir_MTime(GNode *gn) -{ - char *fullName; /* the full pathname of name */ - struct stat stb; /* buffer for finding the mod time */ - Hash_Entry *entry; - - if (gn->type & OP_ARCHV) - return (Arch_MTime(gn)); - - else if (gn->path == NULL) - fullName = Path_FindFile(gn->name, &dirSearchPath); - else - fullName = gn->path; - - if (fullName == NULL) - fullName = estrdup(gn->name); - - entry = Hash_FindEntry(&mtimes, fullName); - if (entry != NULL) { - /* - * Only do this once -- the second time folks are checking to - * see if the file was actually updated, so we need to - * actually go to the filesystem. - */ - DEBUGF(DIR, ("Using cached time %s for %s\n", - Targ_FmtTime((time_t)(long)Hash_GetValue(entry)), - fullName)); - stb.st_mtime = (time_t)(long)Hash_GetValue(entry); - Hash_DeleteEntry(&mtimes, entry); - } else if (stat(fullName, &stb) < 0) { - if (gn->type & OP_MEMBER) { - if (fullName != gn->path) - free(fullName); - return (Arch_MemMTime(gn)); - } else { - stb.st_mtime = 0; - } - } - if (fullName && gn->path == (char *)NULL) - gn->path = fullName; - - gn->mtime = stb.st_mtime; - return (gn->mtime); -} - -/*- - *----------------------------------------------------------------------- - * Path_AddDir -- - * Add the given name to the end of the given path. - * - * Results: - * none - * - * Side Effects: - * A structure is added to the list and the directory is - * read and hashed. - *----------------------------------------------------------------------- - */ -struct Dir * -Path_AddDir(struct Path *path, const char *name) -{ - Dir *d; /* pointer to new Path structure */ - DIR *dir; /* for reading directory */ - struct PathElement *pe; - struct dirent *dp; /* entry in directory */ - - /* check whether we know this directory */ - TAILQ_FOREACH(d, &openDirectories, link) { - if (strcmp(d->name, name) == 0) { - /* Found it. */ - if (path == NULL) - return (d); - - /* Check whether its already on the path. */ - TAILQ_FOREACH(pe, path, link) { - if (pe->dir == d) - return (d); - } - /* Add it to the path */ - d->refCount += 1; - pe = emalloc(sizeof(*pe)); - pe->dir = d; - TAILQ_INSERT_TAIL(path, pe, link); - return (d); - } - } - - DEBUGF(DIR, ("Caching %s...", name)); - - if ((dir = opendir(name)) == NULL) { - DEBUGF(DIR, (" cannot open\n")); - return (NULL); - } - - d = emalloc(sizeof(*d)); - d->name = estrdup(name); - d->hits = 0; - d->refCount = 1; - Hash_InitTable(&d->files, -1); - - while ((dp = readdir(dir)) != NULL) { -#if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */ - /* - * The sun directory library doesn't check for - * a 0 inode (0-inode slots just take up space), - * so we have to do it ourselves. - */ - if (dp->d_fileno == 0) - continue; -#endif /* sun && d_ino */ - - /* Skip the '.' and '..' entries by checking - * for them specifically instead of assuming - * readdir() reuturns them in that order when - * first going through a directory. This is - * needed for XFS over NFS filesystems since - * SGI does not guarantee that these are the - * first two entries returned from readdir(). - */ - if (ISDOT(dp->d_name) || ISDOTDOT(dp->d_name)) - continue; - - Hash_CreateEntry(&d->files, dp->d_name, (Boolean *)NULL); - } - closedir(dir); - - if (path != NULL) { - /* Add it to the path */ - d->refCount += 1; - pe = emalloc(sizeof(*pe)); - pe->dir = d; - TAILQ_INSERT_TAIL(path, pe, link); - } - - /* Add to list of all directories */ - TAILQ_INSERT_TAIL(&openDirectories, d, link); - - DEBUGF(DIR, ("done\n")); - - return (d); -} - -/** - * Path_Duplicate - * Duplicate a path. Ups the reference count for the directories. - */ -void -Path_Duplicate(struct Path *dst, const struct Path *src) -{ - struct PathElement *ped, *pes; - - TAILQ_FOREACH(pes, src, link) { - ped = emalloc(sizeof(*ped)); - ped->dir = pes->dir; - ped->dir->refCount++; - TAILQ_INSERT_TAIL(dst, ped, link); - } -} - -/** - * Path_MakeFlags - * Make a string by taking all the directories in the given search - * path and preceding them by the given flag. Used by the suffix - * module to create variables for compilers based on suffix search - * paths. - * - * Results: - * The string mentioned above. Note that there is no space between - * the given flag and each directory. The empty string is returned if - * Things don't go well. - */ -char * -Path_MakeFlags(const char *flag, const struct Path *path) -{ - char *str; /* the string which will be returned */ - char *tstr; /* the current directory preceded by 'flag' */ - char *nstr; - const struct PathElement *pe; - - str = estrdup(""); - - TAILQ_FOREACH(pe, path, link) { - tstr = str_concat(flag, pe->dir->name, 0); - nstr = str_concat(str, tstr, STR_ADDSPACE); - free(str); - free(tstr); - str = nstr; - } - - return (str); -} - -/** - * Path_Clear - * - * Destroy a path. This decrements the reference counts of all - * directories of this path and, if a reference count goes 0, - * destroys the directory object. - */ -void -Path_Clear(struct Path *path) -{ - struct PathElement *pe; - - while ((pe = TAILQ_FIRST(path)) != NULL) { - pe->dir->refCount--; - TAILQ_REMOVE(path, pe, link); - if (pe->dir->refCount == 0) { - TAILQ_REMOVE(&openDirectories, pe->dir, link); - Hash_DeleteTable(&pe->dir->files); - free(pe->dir->name); - free(pe->dir); - } - free(pe); - } -} - -/** - * Path_Concat - * - * Concatenate two paths, adding the second to the end of the first. - * Make sure to avoid duplicates. - * - * Side Effects: - * Reference counts for added dirs are upped. - */ -void -Path_Concat(struct Path *path1, const struct Path *path2) -{ - struct PathElement *p1, *p2; - - TAILQ_FOREACH(p2, path2, link) { - TAILQ_FOREACH(p1, path1, link) { - if (p1->dir == p2->dir) - break; - } - if (p1 == NULL) { - p1 = emalloc(sizeof(*p1)); - p1->dir = p2->dir; - p1->dir->refCount++; - TAILQ_INSERT_TAIL(path1, p1, link); - } - } -} - -/********** DEBUG INFO **********/ -void -Dir_PrintDirectories(void) -{ - const Dir *d; - - printf("#*** Directory Cache:\n"); - printf("# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n", - hits, misses, nearmisses, bigmisses, - (hits + bigmisses + nearmisses ? - hits * 100 / (hits + bigmisses + nearmisses) : 0)); - printf("# %-20s referenced\thits\n", "directory"); - TAILQ_FOREACH(d, &openDirectories, link) - printf("# %-20s %10d\t%4d\n", d->name, d->refCount, d->hits); -} - -void -Path_Print(const struct Path *path) -{ - const struct PathElement *p; - - TAILQ_FOREACH(p, path, link) - printf("%s ", p->dir->name); -} Property changes on: head/usr.bin/make/dir.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/for.c =================================================================== --- head/usr.bin/make/for.c (revision 284463) +++ head/usr.bin/make/for.c (nonexistent) @@ -1,267 +0,0 @@ -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)for.c 8.1 (Berkeley) 6/6/93 - */ - -#include -__FBSDID("$FreeBSD$"); - -/*- - * for.c -- - * Functions to handle loops in a makefile. - * - * Interface: - * For_Eval Evaluate the loop in the passed line. - * For_Run Run accumulated loop - * - */ - -#include -#include -#include - -#include "buf.h" -#include "for.h" -#include "globals.h" -#include "lst.h" -#include "parse.h" -#include "str.h" -#include "util.h" -#include "var.h" - -/* - * For statements are of the form: - * - * .for in - * ... - * .endfor - * - * The trick is to look for the matching end inside for for loop - * To do that, we count the current nesting level of the for loops. - * and the .endfor statements, accumulating all the statements between - * the initial .for loop and the matching .endfor; - * then we evaluate the for loop for each variable in the varlist. - */ - -static int forLevel = 0; /* Nesting level */ -static char *forVar; /* Iteration variable */ -static Buffer *forBuf; /* Commands in loop */ -static Lst forLst; /* List of items */ - -/** - * For_For - * Evaluate the for loop in the passed line. The line - * looks like this: - * .for in - * The line pointer points just behind the for. - * - * Results: - * TRUE: Syntax ok. - * FALSE: Syntax error. - */ -Boolean -For_For(char *line) -{ - char *ptr; - char *wrd; - char *sub; - Buffer *buf; - size_t varlen; - int i; - ArgArray words; - - ptr = line; - - /* - * Skip space between for and the variable. - */ - for (ptr++; *ptr && isspace((u_char)*ptr); ptr++) - ; - - /* - * Grab the variable - */ - for (wrd = ptr; *ptr && !isspace((u_char)*ptr); ptr++) - ; - - buf = Buf_Init(0); - Buf_AppendRange(buf, wrd, ptr); - forVar = Buf_GetAll(buf, &varlen); - - if (varlen == 0) { - Buf_Destroy(buf, TRUE); - Parse_Error(PARSE_FATAL, "missing variable in for"); - return (FALSE); - } - Buf_Destroy(buf, FALSE); - - /* - * Skip to 'in'. - */ - while (*ptr && isspace((u_char)*ptr)) - ptr++; - - /* - * Grab the `in' - */ - if (ptr[0] != 'i' || ptr[1] != 'n' || !isspace((u_char)ptr[2])) { - free(forVar); - Parse_Error(PARSE_FATAL, "missing `in' in for"); - fprintf(stderr, "%s\n", ptr); - return (FALSE); - } - ptr += 3; - - /* - * Skip to values - */ - while (*ptr && isspace((u_char)*ptr)) - ptr++; - - /* - * Make a list with the remaining words - */ - sub = Buf_Peel(Var_Subst(ptr, VAR_CMD, FALSE)); - brk_string(&words, sub, FALSE); - Lst_Init(&forLst); - for (i = 1; i < words.argc; i++) { - if (words.argv[i][0] != '\0') - Lst_AtFront(&forLst, estrdup(words.argv[i])); - } - ArgArray_Done(&words); - DEBUGF(FOR, ("For: Iterator %s List %s\n", forVar, sub)); - free(sub); - - forBuf = Buf_Init(0); - forLevel++; - return (TRUE); -} - -/** - * For_Eval - * Eat a line of the .for body looking for embedded .for loops - * and the .endfor - */ -Boolean -For_Eval(char *line) -{ - char *ptr; - - ptr = line; - - if (*ptr == '.') { - /* - * Need to check for 'endfor' and 'for' to find the end - * of our loop or to find embedded for loops. - */ - for (ptr++; *ptr != '\0' && isspace((u_char)*ptr); ptr++) - ; - - /* XXX the isspace is wrong */ - if (strncmp(ptr, "endfor", 6) == 0 && - (isspace((u_char)ptr[6]) || ptr[6] == '\0')) { - DEBUGF(FOR, ("For: end for %d\n", forLevel)); - if (forLevel == 0) { - /* should not be here */ - abort(); - } - forLevel--; - - } else if (strncmp(ptr, "for", 3) == 0 && - isspace((u_char)ptr[3])) { - forLevel++; - DEBUGF(FOR, ("For: new loop %d\n", forLevel)); - } - } - - if (forLevel != 0) { - /* - * Still in loop - append the line - */ - Buf_Append(forBuf, line); - Buf_AddByte(forBuf, (Byte)'\n'); - return (TRUE); - } - - return (FALSE); -} - -/*- - *----------------------------------------------------------------------- - * For_Run -- - * Run the for loop, imitating the actions of an include file - * - * Results: - * None. - * - * Side Effects: - * The values of the variables forLst, forVar and forBuf are freed. - * - *----------------------------------------------------------------------- - */ -void -For_Run(int lineno) -{ - Lst values; /* list of values for the variable */ - char *var; /* the variable's name */ - Buffer *buf; /* the contents of the for loop */ - const char *val; /* current value of loop variable */ - LstNode *ln; - char *str; - - if (forVar == NULL || forBuf == NULL) - return; - - /* copy the global variables to have them free for embedded fors */ - var = forVar; - buf = forBuf; - Lst_Init(&values); - Lst_Concat(&values, &forLst, LST_CONCLINK); - - forVar = NULL; - forBuf = NULL; - - LST_FOREACH(ln, &values) { - val = Lst_Datum(ln); - Var_SetGlobal(var, val); - - DEBUGF(FOR, ("--- %s = %s\n", var, val)); - str = Buf_Peel(Var_SubstOnly(var, Buf_Data(buf), FALSE)); - - Parse_FromString(str, lineno); - Var_Delete(var, VAR_GLOBAL); - } - - free(var); - Lst_Destroy(&values, free); - Buf_Destroy(buf, TRUE); -} Property changes on: head/usr.bin/make/for.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/arch.c =================================================================== --- head/usr.bin/make/arch.c (revision 284463) +++ head/usr.bin/make/arch.c (nonexistent) @@ -1,1224 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)arch.c 8.2 (Berkeley) 1/2/94 - */ - -#include -__FBSDID("$FreeBSD$"); - -/*- - * arch.c -- - * Functions to manipulate libraries, archives and their members. - * - * Once again, cacheing/hashing comes into play in the manipulation - * of archives. The first time an archive is referenced, all of its members' - * headers are read and hashed and the archive closed again. All hashed - * archives are kept on a list which is searched each time an archive member - * is referenced. - * - * The interface to this module is: - * Arch_ParseArchive Given an archive specification, return a list - * of GNode's, one for each member in the spec. - * FALSE is returned if the specification is - * invalid for some reason. - * - * Arch_Touch Alter the modification time of the archive - * member described by the given node to be - * the current time. - * - * Arch_TouchLib Update the modification time of the library - * described by the given node. This is special - * because it also updates the modification time - * of the library's table of contents. - * - * Arch_MTime Find the modification time of a member of - * an archive *in the archive*. The time is also - * placed in the member's GNode. Returns the - * modification time. - * - * Arch_MemTime Find the modification time of a member of - * an archive. Called when the member doesn't - * already exist. Looks in the archive for the - * modification time. Returns the modification - * time. - * - * Arch_FindLib Search for a library along a path. The - * library name in the GNode should be in - * -l format. - * - * Arch_LibOODate Special function to decide if a library node - * is out-of-date. - * - * Arch_Init Initialize this module. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "arch.h" -#include "buf.h" -#include "config.h" -#include "dir.h" -#include "globals.h" -#include "GNode.h" -#include "hash.h" -#include "make.h" -#include "parse.h" -#include "targ.h" -#include "util.h" -#include "var.h" - -typedef struct Arch { - char *name; /* Name of archive */ - - /* - * All the members of the archive described - * by key/value pairs - */ - Hash_Table members; - - TAILQ_ENTRY(Arch) link; /* link all cached archives */ -} Arch; - -/* Lst of archives we've already examined */ -static TAILQ_HEAD(, Arch) archives = TAILQ_HEAD_INITIALIZER(archives); - - -/* size of the name field in the archive member header */ -#define AR_NAMSIZ sizeof(((struct ar_hdr *)0)->ar_name) - -/* - * This structure is used while reading/writing an archive - */ -struct arfile { - FILE *fp; /* archive file */ - char *fname; /* name of the file */ - struct ar_hdr hdr; /* current header */ - char sname[AR_NAMSIZ + 1]; /* short name */ - char *member; /* (long) member name */ - size_t mlen; /* size of the above */ - char *nametab; /* name table */ - size_t nametablen; /* size of the table */ - int64_t time; /* from ar_date */ - uint64_t size; /* from ar_size */ - off_t pos; /* header pos of current entry */ -}; - -/* - * Name of the symbol table. The original BSD used "__.SYMDEF". Rumours go - * that this name may have a slash appended sometimes. Actually FreeBSD - * uses "/" which probably came from SVR4. - */ -#define SVR4_RANLIBMAG "/" -#define BSD_RANLIBMAG "__.SYMDEF" - -/* - * Name of the filename table. The 4.4BSD ar format did not use this, but - * puts long filenames directly between the member header and the object - * file. - */ -#define SVR4_NAMEMAG "//" -#define BSD_NAMEMAG "ARFILENAMES/" - -/* - * 44BSD long filename key. Use a local define here instead of relying - * on ar.h because we want this to continue working even when the - * definition is removed from ar.h. - */ -#define BSD_EXT1 "#1/" -#define BSD_EXT1LEN 3 - -/* if this is TRUE make archive errors fatal */ -Boolean arch_fatal = TRUE; - -/** - * ArchError - * An error happened while handling an archive. BSDmake traditionally - * ignored these errors. Now this is dependent on the global arch_fatal - * which, if true, makes these errors fatal and, if false, just emits an - * error message. - */ -#define ArchError(ARGS) do { \ - if (arch_fatal) \ - Fatal ARGS; \ - else \ - Error ARGS; \ - } while (0) - -/*- - *----------------------------------------------------------------------- - * Arch_ParseArchive -- - * Parse the archive specification in the given line and find/create - * the nodes for the specified archive members, placing their nodes - * on the given list, given the pointer to the start of the - * specification, a Lst on which to place the nodes, and a context - * in which to expand variables. - * - * Results: - * TRUE if it was a valid specification. The linePtr is updated - * to point to the first non-space after the archive spec. The - * nodes for the members are placed on the given list. - * - * Side Effects: - * Some nodes may be created. The given list is extended. - * - *----------------------------------------------------------------------- - */ -Boolean -Arch_ParseArchive(char **linePtr, Lst *nodeLst, GNode *ctxt) -{ - char *cp; /* Pointer into line */ - GNode *gn; /* New node */ - char *libName; /* Library-part of specification */ - char *memName; /* Member-part of specification */ - char *nameBuf; /* temporary place for node name */ - char saveChar; /* Ending delimiter of member-name */ - Boolean subLibName; /* TRUE if libName should have/had - * variable substitution performed on it */ - - libName = *linePtr; - - subLibName = FALSE; - - for (cp = libName; *cp != '(' && *cp != '\0'; cp++) { - if (*cp == '$') { - /* - * Variable spec, so call the Var module to parse the - * puppy so we can safely advance beyond it... - */ - size_t length = 0; - Boolean freeIt; - char *result; - - result = Var_Parse(cp, ctxt, TRUE, &length, &freeIt); - if (result == var_Error) { - return (FALSE); - } - subLibName = TRUE; - - if (freeIt) { - free(result); - } - cp += length - 1; - } - } - - *cp++ = '\0'; - if (subLibName) { - libName = Buf_Peel(Var_Subst(libName, ctxt, TRUE)); - } - - for (;;) { - /* - * First skip to the start of the member's name, mark that - * place and skip to the end of it (either white-space or - * a close paren). - */ - - /* - * TRUE if need to substitute in memName - */ - Boolean doSubst = FALSE; - - while (*cp != '\0' && *cp != ')' && - isspace((unsigned char)*cp)) { - cp++; - } - - memName = cp; - while (*cp != '\0' && *cp != ')' && - !isspace((unsigned char)*cp)) { - if (*cp == '$') { - /* - * Variable spec, so call the Var module to - * parse the puppy so we can safely advance - * beyond it... - */ - size_t length = 0; - Boolean freeIt; - char *result; - - result = Var_Parse(cp, ctxt, TRUE, - &length, &freeIt); - if (result == var_Error) { - return (FALSE); - } - doSubst = TRUE; - - if (freeIt) { - free(result); - } - cp += length; - } else { - cp++; - } - } - - /* - * If the specification ends without a closing parenthesis, - * chances are there's something wrong (like a missing - * backslash), so it's better to return failure than allow - * such things to happen - */ - if (*cp == '\0') { - printf("No closing parenthesis in archive " - "specification\n"); - return (FALSE); - } - - /* - * If we didn't move anywhere, we must be done - */ - if (cp == memName) { - break; - } - - saveChar = *cp; - *cp = '\0'; - - /* - * XXX: This should be taken care of intelligently by - * SuffExpandChildren, both for the archive and the member - * portions. - */ - /* - * If member contains variables, try and substitute for them. - * This will slow down archive specs with dynamic sources, of - * course, since we'll be (non-)substituting them three times, - * but them's the breaks -- we need to do this since - * SuffExpandChildren calls us, otherwise we could assume the - * thing would be taken care of later. - */ - if (doSubst) { - char *buf; - char *sacrifice; - char *oldMemName = memName; - size_t sz; - Buffer *buf1; - - /* - * Now form an archive spec and recurse to deal with - * nested variables and multi-word variable values.... - * The results are just placed at the end of the - * nodeLst we're returning. - */ - buf1 = Var_Subst(memName, ctxt, TRUE); - memName = Buf_Data(buf1); - - sz = strlen(memName) + strlen(libName) + 3; - buf = emalloc(sz); - - snprintf(buf, sz, "%s(%s)", libName, memName); - - sacrifice = buf; - - if (strchr(memName, '$') && - strcmp(memName, oldMemName) == 0) { - /* - * Must contain dynamic sources, so we can't - * deal with it now. - * Just create an ARCHV node for the thing and - * let SuffExpandChildren handle it... - */ - gn = Targ_FindNode(buf, TARG_CREATE); - - if (gn == NULL) { - free(buf); - Buf_Destroy(buf1, FALSE); - return (FALSE); - } - gn->type |= OP_ARCHV; - Lst_AtEnd(nodeLst, (void *)gn); - } else if (!Arch_ParseArchive(&sacrifice, nodeLst, - ctxt)) { - /* - * Error in nested call -- free buffer and - * return FALSE ourselves. - */ - free(buf); - Buf_Destroy(buf1, FALSE); - return (FALSE); - } - - /* Free buffer and continue with our work. */ - free(buf); - Buf_Destroy(buf1, FALSE); - - } else if (Dir_HasWildcards(memName)) { - Lst members = Lst_Initializer(members); - char *member; - size_t sz = MAXPATHLEN; - size_t nsz; - - nameBuf = emalloc(sz); - - Path_Expand(memName, &dirSearchPath, &members); - while (!Lst_IsEmpty(&members)) { - member = Lst_DeQueue(&members); - nsz = strlen(libName) + strlen(member) + 3; - if (nsz > sz) { - sz = nsz * 2; - nameBuf = erealloc(nameBuf, sz); - } - - snprintf(nameBuf, sz, "%s(%s)", - libName, member); - free(member); - gn = Targ_FindNode(nameBuf, TARG_CREATE); - if (gn == NULL) { - free(nameBuf); - /* XXXHB Lst_Destroy(&members) */ - return (FALSE); - } - /* - * We've found the node, but have to make sure - * the rest of the world knows it's an archive - * member, without having to constantly check - * for parentheses, so we type the thing with - * the OP_ARCHV bit before we place it on the - * end of the provided list. - */ - gn->type |= OP_ARCHV; - Lst_AtEnd(nodeLst, gn); - } - free(nameBuf); - } else { - size_t sz = strlen(libName) + strlen(memName) + 3; - - nameBuf = emalloc(sz); - snprintf(nameBuf, sz, "%s(%s)", libName, memName); - gn = Targ_FindNode(nameBuf, TARG_CREATE); - free(nameBuf); - if (gn == NULL) { - return (FALSE); - } - /* - * We've found the node, but have to make sure the - * rest of the world knows it's an archive member, - * without having to constantly check for parentheses, - * so we type the thing with the OP_ARCHV bit before - * we place it on the end of the provided list. - */ - gn->type |= OP_ARCHV; - Lst_AtEnd(nodeLst, gn); - } - if (doSubst) { - free(memName); - } - - *cp = saveChar; - } - - /* - * If substituted libName, free it now, since we need it no longer. - */ - if (subLibName) { - free(libName); - } - - /* - * We promised the pointer would be set up at the next non-space, so - * we must advance cp there before setting *linePtr... (note that on - * entrance to the loop, cp is guaranteed to point at a ')') - */ - do { - cp++; - } while (*cp != '\0' && isspace((unsigned char)*cp)); - - *linePtr = cp; - return (TRUE); -} - -/* - * Close an archive file an free all resources - */ -static void -ArchArchiveClose(struct arfile *ar) -{ - - if (ar->nametab != NULL) - free(ar->nametab); - free(ar->member); - if (ar->fp != NULL) { - if (fclose(ar->fp) == EOF) - ArchError(("%s: close error", ar->fname)); - } - free(ar->fname); - free(ar); -} - -/* - * Open an archive file. - */ -static struct arfile * -ArchArchiveOpen(const char *archive, const char *mode) -{ - struct arfile *ar; - char magic[SARMAG]; - - ar = emalloc(sizeof(*ar)); - ar->fname = estrdup(archive); - ar->mlen = 100; - ar->member = emalloc(ar->mlen); - ar->nametab = NULL; - ar->nametablen = 0; - - if ((ar->fp = fopen(ar->fname, mode)) == NULL) { - DEBUGM(ARCH, ("%s", ar->fname)); - ArchArchiveClose(ar); - return (NULL); - } - - /* read MAGIC */ - if (fread(magic, SARMAG, 1, ar->fp) != 1 || - strncmp(magic, ARMAG, SARMAG) != 0) { - ArchError(("%s: bad archive magic\n", ar->fname)); - ArchArchiveClose(ar); - return (NULL); - } - - ar->pos = 0; - return (ar); -} - -/* - * Read the next header from the archive. The return value will be +1 if - * the header is read successfully, 0 on EOF and -1 if an error happened. - * On a successful return sname contains the truncated member name and - * member the full name. hdr contains the member header. For the symbol table - * names of length 0 are returned. The entry for the file name table is never - * returned. - */ -static int -ArchArchiveNext(struct arfile *ar) -{ - char *end; - int have_long_name; - u_long offs; - char *ptr; - size_t ret; - char buf[MAX(sizeof(ar->hdr.ar_size), sizeof(ar->hdr.ar_date)) + 1]; - - next: - /* - * Seek to the next header. - */ - if (ar->pos == 0) { - ar->pos = SARMAG; - } else { - ar->pos += sizeof(ar->hdr) + ar->size; - if (ar->size % 2 == 1) - ar->pos++; - } - - if (fseeko(ar->fp, ar->pos, SEEK_SET) == -1) { - ArchError(("%s: cannot seek to %jd: %s", ar->fname, - (intmax_t)ar->pos, strerror(errno))); - return (-1); - } - - /* - * Read next member header - */ - ret = fread(&ar->hdr, sizeof(ar->hdr), 1, ar->fp); - if (ret != 1) { - if (feof(ar->fp)) - return (0); - ArchError(("%s: error reading member header: %s", ar->fname, - strerror(errno))); - return (-1); - } - if (strncmp(ar->hdr.ar_fmag, ARFMAG, sizeof(ar->hdr.ar_fmag)) != 0) { - ArchError(("%s: bad entry magic", ar->fname)); - return (-1); - } - - /* - * looks like a member - get name by stripping trailing spaces - * and NUL terminating. - */ - strlcpy(ar->sname, ar->hdr.ar_name, AR_NAMSIZ + 1); - for (ptr = ar->sname + AR_NAMSIZ; ptr > ar->sname; ptr--) - if (ptr[-1] != ' ') - break; - - *ptr = '\0'; - - /* - * Parse the size. All entries need to have a size. Be careful - * to not allow buffer overruns. - */ - strlcpy(buf, ar->hdr.ar_size, sizeof(ar->hdr.ar_size) + 1); - - errno = 0; - ar->size = strtoumax(buf, &end, 10); - if (errno != 0 || strspn(end, " ") != strlen(end)) { - ArchError(("%s: bad size format in archive '%s'", - ar->fname, buf)); - return (-1); - } - - /* - * Look for the extended name table. Do this before parsing - * the date because this table doesn't need a date. - */ - if (strcmp(ar->sname, BSD_NAMEMAG) == 0 || - strcmp(ar->sname, SVR4_NAMEMAG) == 0) { - /* filename table - read it in */ - ar->nametablen = ar->size; - ar->nametab = emalloc(ar->nametablen); - - ret = fread(ar->nametab, 1, ar->nametablen, ar->fp); - if (ret != ar->nametablen) { - if (ferror(ar->fp)) { - ArchError(("%s: cannot read nametab: %s", - ar->fname, strerror(errno))); - } else { - ArchError(("%s: cannot read nametab: " - "short read", ar->fname, strerror(errno))); - } - return (-1); - } - - /* - * NUL terminate the entries. Entries are \n terminated - * and may have a trailing / or \. - */ - ptr = ar->nametab; - while (ptr < ar->nametab + ar->nametablen) { - if (*ptr == '\n') { - if (ptr[-1] == '/' || ptr[-1] == '\\') - ptr[-1] = '\0'; - *ptr = '\0'; - } - ptr++; - } - - /* get next archive entry */ - goto next; - } - - /* - * Now parse the modification date. Be careful to not overrun - * buffers. - */ - strlcpy(buf, ar->hdr.ar_date, sizeof(ar->hdr.ar_date) + 1); - - errno = 0; - ar->time = (int64_t)strtoll(buf, &end, 10); - if (errno != 0 || strspn(end, " ") != strlen(end)) { - ArchError(("%s: bad date format in archive '%s'", - ar->fname, buf)); - return (-1); - } - - /* - * Now check for the symbol table. This should really be the first - * entry, but we don't check this. - */ - if (strcmp(ar->sname, BSD_RANLIBMAG) == 0 || - strcmp(ar->sname, SVR4_RANLIBMAG) == 0) { - /* symbol table - return a zero length name */ - ar->member[0] = '\0'; - ar->sname[0] = '\0'; - return (1); - } - - have_long_name = 0; - - /* - * Look whether this is a long name. There are several variants - * of long names: - * "#1/12 " - 12 length of following filename - * "/17 " - index into name table - * " 17 " - index into name table - * Note that in the last case we must also check that there is no - * slash in the name because of filenames with leading spaces: - * " 777.o/ " - filename 777.o - */ - if (ar->sname[0] == '/' || (ar->sname[0] == ' ' && - strchr(ar->sname, '/') == NULL)) { - /* SVR4 extended name */ - errno = 0; - offs = strtoul(ar->sname + 1, &end, 10); - if (errno != 0 || *end != '\0' || offs >= ar->nametablen || - end == ar->sname + 1) { - ArchError(("%s: bad extended name '%s'", ar->fname, - ar->sname)); - return (-1); - } - - /* fetch the name */ - if (ar->mlen <= strlen(ar->nametab + offs)) { - ar->mlen = strlen(ar->nametab + offs) + 1; - ar->member = erealloc(ar->member, ar->mlen); - } - strcpy(ar->member, ar->nametab + offs); - - have_long_name = 1; - - } else if (strncmp(ar->sname, BSD_EXT1, BSD_EXT1LEN) == 0 && - isdigit(ar->sname[BSD_EXT1LEN])) { - /* BSD4.4 extended name */ - errno = 0; - offs = strtoul(ar->sname + BSD_EXT1LEN, &end, 10); - if (errno != 0 || *end != '\0' || - end == ar->sname + BSD_EXT1LEN) { - ArchError(("%s: bad extended name '%s'", ar->fname, - ar->sname)); - return (-1); - } - - /* read it from the archive */ - if (ar->mlen <= offs) { - ar->mlen = offs + 1; - ar->member = erealloc(ar->member, ar->mlen); - } - ret = fread(ar->member, 1, offs, ar->fp); - if (ret != offs) { - if (ferror(ar->fp)) { - ArchError(("%s: reading extended name: %s", - ar->fname, strerror(errno))); - } else { - ArchError(("%s: reading extended name: " - "short read", ar->fname)); - } - return (-1); - } - ar->member[offs] = '\0'; - - have_long_name = 1; - } - - /* - * Now remove the trailing slash that Svr4 puts at - * the end of the member name to support trailing spaces in names. - */ - if (ptr > ar->sname && ptr[-1] == '/') - *--ptr = '\0'; - - if (!have_long_name) { - if (strlen(ar->sname) >= ar->mlen) { - ar->mlen = strlen(ar->sname) + 1; - ar->member = erealloc(ar->member, ar->mlen); - } - strcpy(ar->member, ar->sname); - } - - return (1); -} - -/* - * Touch the current archive member by writing a new header with an - * updated timestamp. The return value is 0 for success and -1 for errors. - */ -static int -ArchArchiveTouch(struct arfile *ar, int64_t ts) -{ - - /* seek to our header */ - if (fseeko(ar->fp, ar->pos, SEEK_SET) == -1) { - ArchError(("%s: cannot seek to %jd: %s", ar->fname, - (intmax_t)ar->pos, strerror(errno))); - return (-1); - } - - /* - * change timestamp, be sure to not NUL-terminated it, but - * to fill with spaces. - */ - snprintf(ar->hdr.ar_date, sizeof(ar->hdr.ar_date), "%jd", - (intmax_t)ts); - memset(ar->hdr.ar_date + strlen(ar->hdr.ar_date), - ' ', sizeof(ar->hdr.ar_date) - strlen(ar->hdr.ar_date)); - - if (fwrite(&ar->hdr, sizeof(ar->hdr), 1, ar->fp) != 1) { - ArchError(("%s: cannot touch: %s", ar->fname, strerror(errno))); - return (-1); - } - return (0); -} - -/*- - *----------------------------------------------------------------------- - * ArchFindMember -- - * Locate a member of an archive, given the path of the archive and - * the path of the desired member. If the archive is to be modified, - * the mode should be "r+", if not, it should be "r". The archive - * file is returned positioned at the correct header. - * - * Results: - * A struct arfile *, opened for reading and, possibly writing, - * positioned at the member's header, or NULL if the member was - * nonexistent. - * - *----------------------------------------------------------------------- - */ -static struct arfile * -ArchFindMember(const char *archive, const char *member, const char *mode) -{ - struct arfile *ar; - const char *cp; /* Useful character pointer */ - - if ((ar = ArchArchiveOpen(archive, mode)) == NULL) - return (NULL); - - /* - * Because of space constraints and similar things, files are archived - * using their final path components, not the entire thing, so we need - * to point 'member' to the final component, if there is one, to make - * the comparisons easier... - */ - if (member != NULL) { - cp = strrchr(member, '/'); - if (cp != NULL) { - member = cp + 1; - } - } - - while (ArchArchiveNext(ar) > 0) { - /* - * When comparing there are actually three cases: - * (1) the name fits into the limit og af_name, - * (2) the name is longer and the archive supports long names, - * (3) the name is longer and the archive doesn't support long - * names. - * Because we don't know whether the archive supports long - * names or not we need to be careful. - */ - if (member == NULL) { - /* special case - symbol table */ - if (ar->member[0] == '\0') - return (ar); - } else if (strlen(member) <= AR_NAMSIZ) { - /* case (1) */ - if (strcmp(ar->member, member) == 0) - return (ar); - } else if (strcmp(ar->member, member) == 0) { - /* case (3) */ - return (ar); - } else { - /* case (2) */ - if (strlen(ar->member) == AR_NAMSIZ && - strncmp(member, ar->member, AR_NAMSIZ) == 0) - return (ar); - } - } - - /* not found */ - ArchArchiveClose(ar); - return (NULL); -} - -/*- - *----------------------------------------------------------------------- - * ArchStatMember -- - * Locate a member of an archive, given the path of the archive and - * the path of the desired member, and a boolean representing whether - * or not the archive should be hashed (if not already hashed). - * - * Results: - * A pointer to the current struct ar_hdr structure for the member. Note - * That no position is returned, so this is not useful for touching - * archive members. This is mostly because we have no assurances that - * The archive will remain constant after we read all the headers, so - * there's not much point in remembering the position... - * - * Side Effects: - * - *----------------------------------------------------------------------- - */ -static int64_t -ArchStatMember(const char *archive, const char *member, Boolean hash) -{ - struct arfile *arf; - int64_t ret; - int t; - char *cp; /* Useful character pointer */ - Arch *ar; /* Archive descriptor */ - Hash_Entry *he; /* Entry containing member's description */ - char copy[AR_NAMSIZ + 1]; - - /* - * Because of space constraints and similar things, files are archived - * using their final path components, not the entire thing, so we need - * to point 'member' to the final component, if there is one, to make - * the comparisons easier... - */ - if (member != NULL) { - cp = strrchr(member, '/'); - if (cp != NULL) - member = cp + 1; - } - - TAILQ_FOREACH(ar, &archives, link) { - if (strcmp(archive, ar->name) == 0) - break; - } - if (ar == NULL) { - /* archive not found */ - if (!hash) { - /* - * Caller doesn't want the thing hashed, just use - * ArchFindMember to read the header for the member - * out and close down the stream again. - */ - arf = ArchFindMember(archive, member, "r"); - if (arf == NULL) { - return (INT64_MIN); - } - ret = arf->time; - ArchArchiveClose(arf); - return (ret); - } - - /* - * We don't have this archive on the list yet, so we want to - * find out everything that's in it and cache it so we can get - * at it quickly. - */ - arf = ArchArchiveOpen(archive, "r"); - if (arf == NULL) { - return (INT64_MIN); - } - - /* create archive data structure */ - ar = emalloc(sizeof(*ar)); - ar->name = estrdup(archive); - Hash_InitTable(&ar->members, -1); - - while ((t = ArchArchiveNext(arf)) > 0) { - he = Hash_CreateEntry(&ar->members, arf->member, NULL); - Hash_SetValue(he, emalloc(sizeof(int64_t))); - *(int64_t *)Hash_GetValue(he) = arf->time; - } - - ArchArchiveClose(arf); - - if (t < 0) { - /* error happened - throw away everything */ - Hash_DeleteTable(&ar->members); - free(ar->name); - free(ar); - return (INT64_MIN); - } - - TAILQ_INSERT_TAIL(&archives, ar, link); - } - - /* - * Now that the archive has been read and cached, we can look into - * the hash table to find the desired member's header. - */ - he = Hash_FindEntry(&ar->members, member); - if (he != NULL) - return (*(int64_t *)Hash_GetValue (he)); - - if (member != NULL && strlen(member) > AR_NAMSIZ) { - /* Try truncated name */ - strlcpy(copy, member, AR_NAMSIZ + 1); - - if ((he = Hash_FindEntry(&ar->members, copy)) != NULL) - return (*(int64_t *)Hash_GetValue(he)); - } - - return (INT64_MIN); -} - -/*- - *----------------------------------------------------------------------- - * Arch_Touch -- - * Touch a member of an archive. - * - * Results: - * The 'time' field of the member's header is updated. - * - * Side Effects: - * The modification time of the entire archive is also changed. - * For a library, this could necessitate the re-ranlib'ing of the - * whole thing. - * - *----------------------------------------------------------------------- - */ -void -Arch_Touch(GNode *gn) -{ - struct arfile *ar; - - ar = ArchFindMember(Var_Value(ARCHIVE, gn), - Var_Value(TARGET, gn), "r+"); - - if (ar != NULL) { - ArchArchiveTouch(ar, (int64_t)now); - ArchArchiveClose(ar); - } -} - -/*- - *----------------------------------------------------------------------- - * Arch_TouchLib -- - * Given a node which represents a library, touch the thing, making - * sure that the table of contents also is touched. - * - * Results: - * None. - * - * Side Effects: - * Both the modification time of the library and of the RANLIBMAG - * member are set to 'now'. - * - *----------------------------------------------------------------------- - */ -void -Arch_TouchLib(GNode *gn) -{ - struct arfile *ar; /* Open archive */ - struct utimbuf times; /* Times for utime() call */ - - ar = ArchFindMember(gn->path, NULL, "r+"); - if (ar != NULL) { - ArchArchiveTouch(ar, (int64_t)now); - ArchArchiveClose(ar); - - times.actime = times.modtime = now; - utime(gn->path, ×); - } -} - -/*- - *----------------------------------------------------------------------- - * Arch_MTime -- - * Return the modification time of a member of an archive, given its - * name. - * - * Results: - * The modification time(seconds). - * XXXHB this should be a long. - * - * Side Effects: - * The mtime field of the given node is filled in with the value - * returned by the function. - * - *----------------------------------------------------------------------- - */ -int -Arch_MTime(GNode *gn) -{ - int64_t mtime; - - mtime = ArchStatMember(Var_Value(ARCHIVE, gn), - Var_Value(TARGET, gn), TRUE); - - if (mtime == INT_MIN) { - mtime = 0; - } - gn->mtime = (int)mtime; /* XXX */ - return (gn->mtime); -} - -/*- - *----------------------------------------------------------------------- - * Arch_MemMTime -- - * Given a non-existent archive member's node, get its modification - * time from its archived form, if it exists. - * - * Results: - * The modification time. - * - * Side Effects: - * The mtime field is filled in. - * - *----------------------------------------------------------------------- - */ -int -Arch_MemMTime(GNode *gn) -{ - LstNode *ln; - GNode *pgn; - char *nameStart; - char *nameEnd; - - for (ln = Lst_First(&gn->parents); ln != NULL; ln = Lst_Succ(ln)) { - pgn = Lst_Datum(ln); - - if (pgn->type & OP_ARCHV) { - /* - * If the parent is an archive specification and is - * being made and its member's name matches the name of - * the node we were given, record the modification time - * of the parent in the child. We keep searching its - * parents in case some other parent requires this - * child to exist... - */ - nameStart = strchr(pgn->name, '(') + 1; - nameEnd = strchr(nameStart, ')'); - - if (pgn->make && strncmp(nameStart, gn->name, - nameEnd - nameStart) == 0) { - gn->mtime = Arch_MTime(pgn); - } - } else if (pgn->make) { - /* - * Something which isn't a library depends on the - * existence of this target, so it needs to exist. - */ - gn->mtime = 0; - break; - } - } - return (gn->mtime); -} - -/*- - *----------------------------------------------------------------------- - * Arch_FindLib -- - * Search for a named library along the given search path. - * - * Results: - * None. - * - * Side Effects: - * The node's 'path' field is set to the found path (including the - * actual file name, not -l...). If the system can handle the -L - * flag when linking (or we cannot find the library), we assume that - * the user has placed the .LIBRARIES variable in the final linking - * command (or the linker will know where to find it) and set the - * TARGET variable for this node to be the node's name. Otherwise, - * we set the TARGET variable to be the full path of the library, - * as returned by Path_FindFile. - * - *----------------------------------------------------------------------- - */ -void -Arch_FindLib(GNode *gn, struct Path *path) -{ - char *libName; /* file name for archive */ - size_t sz; - - sz = strlen(gn->name) + 4; - libName = emalloc(sz); - snprintf(libName, sz, "lib%s.a", &gn->name[2]); - - gn->path = Path_FindFile(libName, path); - - free(libName); - -#ifdef LIBRARIES - Var_Set(TARGET, gn->name, gn); -#else - Var_Set(TARGET, gn->path == NULL ? gn->name : gn->path, gn); -#endif /* LIBRARIES */ -} - -/*- - *----------------------------------------------------------------------- - * Arch_LibOODate -- - * Decide if a node with the OP_LIB attribute is out-of-date. Called - * from Make_OODate to make its life easier, with the library's - * graph node. - * - * There are several ways for a library to be out-of-date that are - * not available to ordinary files. In addition, there are ways - * that are open to regular files that are not available to - * libraries. A library that is only used as a source is never - * considered out-of-date by itself. This does not preclude the - * library's modification time from making its parent be out-of-date. - * A library will be considered out-of-date for any of these reasons, - * given that it is a target on a dependency line somewhere: - * Its modification time is less than that of one of its - * sources (gn->mtime < gn->cmtime). - * Its modification time is greater than the time at which the - * make began (i.e. it's been modified in the course - * of the make, probably by archiving). - * The modification time of one of its sources is greater than - * the one of its RANLIBMAG member (i.e. its table of contents - * is out-of-date). We don't compare of the archive time - * vs. TOC time because they can be too close. In my - * opinion we should not bother with the TOC at all since - * this is used by 'ar' rules that affect the data contents - * of the archive, not by ranlib rules, which affect the - * TOC. - * - * Results: - * TRUE if the library is out-of-date. FALSE otherwise. - * - * Side Effects: - * The library will be hashed if it hasn't been already. - * - *----------------------------------------------------------------------- - */ -Boolean -Arch_LibOODate(GNode *gn) -{ - int64_t mtime; /* The table-of-contents's mod time */ - - if (OP_NOP(gn->type) && Lst_IsEmpty(&gn->children)) { - return (FALSE); - } - if (gn->mtime > now || gn->mtime < gn->cmtime) { - return (TRUE); - } - - mtime = ArchStatMember(gn->path, NULL, FALSE); - if (mtime == INT64_MIN) { - /* - * Not found. A library w/o a table of contents is out-of-date - */ - if (DEBUG(ARCH) || DEBUG(MAKE)) { - Debug("No TOC..."); - } - return (TRUE); - } - - /* XXX choose one. */ - if (DEBUG(ARCH) || DEBUG(MAKE)) { - Debug("TOC modified %s...", Targ_FmtTime(mtime)); - } - return (gn->cmtime > mtime); -} Property changes on: head/usr.bin/make/arch.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/job.h =================================================================== --- head/usr.bin/make/job.h (revision 284463) +++ head/usr.bin/make/job.h (nonexistent) @@ -1,80 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1988, 1989 by Adam de Boor - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)job.h 8.1 (Berkeley) 6/6/93 - * $FreeBSD$ - */ - -#ifndef job_h_4678dfd1 -#define job_h_4678dfd1 - -/*- - * job.h -- - * Definitions pertaining to the running of jobs in parallel mode. - */ - -#include - -#include "util.h" - -struct Buffer; -struct GNode; -struct Lst; - -void Job_Touch(struct GNode *, Boolean); -Boolean Job_CheckCommands(struct GNode *, void (*abortProc)(const char *, ...)); -void Job_CatchChildren(Boolean); -void Job_CatchOutput(int flag); -void Job_Make(struct GNode *); -void Job_Init(int); -Boolean Job_Full(void); -Boolean Job_Empty(void); -void Job_Finish(void); -void Job_Wait(void); -void Job_AbortAll(void); -void Job_SetPrefix(void); - -void Proc_Init(void); - -struct Buffer *Cmd_Exec(const char *, const char **); - -int Compat_Make(struct GNode *gn, struct GNode *pgn); -void Compat_InstallSignalHandlers(void); -void Compat_Run(struct Lst *); - -#endif /* job_h_4678dfd1 */ Property changes on: head/usr.bin/make/job.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/dir.h =================================================================== --- head/usr.bin/make/dir.h (revision 284463) +++ head/usr.bin/make/dir.h (nonexistent) @@ -1,72 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1988, 1989 by Adam de Boor - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)dir.h 8.2 (Berkeley) 4/28/95 - * $FreeBSD$ - */ - -#ifndef dir_h_6002e3b8 -#define dir_h_6002e3b8 - -#include -#include "hash.h" - -struct GNode; -struct Lst; -struct Dir; - -struct PathElement; -TAILQ_HEAD(Path, PathElement); - -void Dir_Init(void); -void Dir_InitDot(void); -Boolean Dir_HasWildcards(const char *); -int Dir_FindHereOrAbove(char *, char *, char *, int); -int Dir_MTime(struct GNode *); -void Dir_PrintDirectories(void); - -struct Dir *Path_AddDir(struct Path *, const char *); -void Path_Clear(struct Path *); -void Path_Concat(struct Path *, const struct Path *); -void Path_Duplicate(struct Path *, const struct Path *); -void Path_Expand(char *, struct Path *, struct Lst *); -char *Path_FindFile(char *, struct Path *); -char *Path_MakeFlags(const char *, const struct Path *); -void Path_Print(const struct Path *); - -#endif /* dir_h_6002e3b8 */ Property changes on: head/usr.bin/make/dir.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/for.h =================================================================== --- head/usr.bin/make/for.h (revision 284463) +++ head/usr.bin/make/for.h (nonexistent) @@ -1,50 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef for_h_9d770f33 -#define for_h_9d770f33 - -#include "util.h" - -Boolean For_For(char *); -Boolean For_Eval(char *); -void For_Run(int); - -#endif /* for_h_9d770f33 */ Property changes on: head/usr.bin/make/for.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/arch.h =================================================================== --- head/usr.bin/make/arch.h (revision 284463) +++ head/usr.bin/make/arch.h (nonexistent) @@ -1,61 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef arch_h_488adf7a -#define arch_h_488adf7a - -#include "util.h" - -struct GNode; -struct Lst; -struct Path; - -/* archive errors are fatal */ -extern Boolean arch_fatal; - -Boolean Arch_ParseArchive(char **, struct Lst *, struct GNode *); -void Arch_Touch(struct GNode *); -void Arch_TouchLib(struct GNode *); -int Arch_MTime(struct GNode *); -int Arch_MemMTime(struct GNode *); -void Arch_FindLib(struct GNode *, struct Path *); -Boolean Arch_LibOODate(struct GNode *); - -#endif /* arch_h_488adf7a */ Property changes on: head/usr.bin/make/arch.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/cond.c =================================================================== --- head/usr.bin/make/cond.c (revision 284463) +++ head/usr.bin/make/cond.c (nonexistent) @@ -1,1221 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1988, 1989 by Adam de Boor - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)cond.c 8.2 (Berkeley) 1/2/94 - */ - -#include -__FBSDID("$FreeBSD$"); - -/* - * Functions to handle conditionals in a makefile. - * - * Interface: - * Cond_Eval Evaluate the conditional in the passed line. - */ - -#include -#include -#include - -#include "buf.h" -#include "cond.h" -#include "dir.h" -#include "globals.h" -#include "GNode.h" -#include "make.h" -#include "parse.h" -#include "str.h" -#include "targ.h" -#include "util.h" -#include "var.h" - -/* - * The parsing of conditional expressions is based on this grammar: - * E -> F || E - * E -> F - * F -> T && F - * F -> T - * T -> defined(variable) - * T -> make(target) - * T -> exists(file) - * T -> empty(varspec) - * T -> target(name) - * T -> symbol - * T -> $(varspec) op value - * T -> $(varspec) == "string" - * T -> $(varspec) != "string" - * T -> ( E ) - * T -> ! T - * op -> == | != | > | < | >= | <= - * - * 'symbol' is some other symbol to which the default function (condDefProc) - * is applied. - * - * Tokens are scanned from the 'condExpr' string. The scanner (CondToken) - * will return And for '&' and '&&', Or for '|' and '||', Not for '!', - * LParen for '(', RParen for ')' and will evaluate the other terminal - * symbols, using either the default function or the function given in the - * terminal, and return the result as either True or False. - * - * All Non-Terminal functions (CondE, CondF and CondT) return Err on error. - */ -typedef enum { - And, - Or, - Not, - True, - False, - LParen, - RParen, - EndOfFile, - None, - Err -} Token; - -typedef Boolean CondProc(int, char *); - -/*- - * Structures to handle elegantly the different forms of #if's. The - * last two fields are stored in condInvert and condDefProc, respectively. - */ -static void CondPushBack(Token); -static int CondGetArg(char **, char **, const char *, Boolean); -static CondProc CondDoDefined; -static CondProc CondDoMake; -static CondProc CondDoExists; -static CondProc CondDoTarget; -static char *CondCvtArg(char *, double *); -static Token CondToken(Boolean); -static Token CondT(Boolean); -static Token CondF(Boolean); -static Token CondE(Boolean); - -static const struct If { - Boolean doNot; /* TRUE if default function should be negated */ - CondProc *defProc; /* Default function to apply */ - Boolean isElse; /* actually el */ -} ifs[] = { - [COND_IF] = { FALSE, CondDoDefined, FALSE }, - [COND_IFDEF] = { FALSE, CondDoDefined, FALSE }, - [COND_IFNDEF] = { TRUE, CondDoDefined, FALSE }, - [COND_IFMAKE] = { FALSE, CondDoMake, FALSE }, - [COND_IFNMAKE] = { TRUE, CondDoMake, FALSE }, - [COND_ELIF] = { FALSE, CondDoDefined, TRUE }, - [COND_ELIFDEF] = { FALSE, CondDoDefined, TRUE }, - [COND_ELIFNDEF] = { TRUE, CondDoDefined, TRUE }, - [COND_ELIFMAKE] = { FALSE, CondDoMake, TRUE }, - [COND_ELIFNMAKE] = { TRUE, CondDoMake, TRUE }, -}; - -static Boolean condInvert; /* Invert the default function */ -static CondProc *condDefProc; /* default function to apply */ -static char *condExpr; /* The expression to parse */ -static Token condPushBack = None; /* Single push-back token in parsing */ - -#define MAXIF 30 /* greatest depth of #if'ing */ - -static Boolean condStack[MAXIF]; /* Stack of conditionals's values */ -static int condLineno[MAXIF]; /* Line numbers of the opening .if */ -static int condTop = MAXIF; /* Top-most conditional */ -static int skipIfLevel = 0; /* Depth of skipped conditionals */ -static int skipIfLineno[MAXIF]; /* Line numbers of skipped .ifs */ -Boolean skipLine = FALSE; /* Whether the parse module is skipping - * lines */ - -/** - * CondPushBack - * Push back the most recent token read. We only need one level of - * this, so the thing is just stored in 'condPushback'. - * - * Side Effects: - * condPushback is overwritten. - */ -static void -CondPushBack(Token t) -{ - - condPushBack = t; -} - -/** - * CondGetArg - * Find the argument of a built-in function. parens is set to TRUE - * if the arguments are bounded by parens. - * - * Results: - * The length of the argument and the address of the argument. - * - * Side Effects: - * The pointer is set to point to the closing parenthesis of the - * function call. - */ -static int -CondGetArg(char **linePtr, char **argPtr, const char *func, Boolean parens) -{ - char *cp; - size_t argLen; - Buffer *buf; - - cp = *linePtr; - if (parens) { - while (*cp != '(' && *cp != '\0') { - cp++; - } - if (*cp == '(') { - cp++; - } - } - - if (*cp == '\0') { - /* - * No arguments whatsoever. Because 'make' and 'defined' - * aren't really "reserved words", we don't print a message. - * I think this is better than hitting the user with a warning - * message every time s/he uses the word 'make' or 'defined' - * at the beginning of a symbol... - */ - *argPtr = cp; - return (0); - } - - while (*cp == ' ' || *cp == '\t') { - cp++; - } - - /* - * Create a buffer for the argument and start it out at 16 characters - * long. Why 16? Why not? - */ - buf = Buf_Init(16); - - while ((strchr(" \t)&|", *cp) == NULL) && (*cp != '\0')) { - if (*cp == '$') { - /* - * Parse the variable spec and install it as part of - * the argument if it's valid. We tell Var_Parse to - * complain on an undefined variable, so we don't do - * it too. Nor do we return an error, though perhaps - * we should... - */ - char *cp2; - size_t len = 0; - Boolean doFree; - - cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &doFree); - - Buf_Append(buf, cp2); - if (doFree) { - free(cp2); - } - cp += len; - } else { - Buf_AddByte(buf, (Byte)*cp); - cp++; - } - } - - Buf_AddByte(buf, (Byte)'\0'); - *argPtr = (char *)Buf_GetAll(buf, &argLen); - Buf_Destroy(buf, FALSE); - - while (*cp == ' ' || *cp == '\t') { - cp++; - } - if (parens && *cp != ')') { - Parse_Error(PARSE_WARNING, - "Missing closing parenthesis for %s()", func); - return (0); - } else if (parens) { - /* - * Advance pointer past close parenthesis. - */ - cp++; - } - - *linePtr = cp; - return (argLen); -} - -/** - * CondDoDefined - * Handle the 'defined' function for conditionals. - * - * Results: - * TRUE if the given variable is defined. - */ -static Boolean -CondDoDefined(int argLen, char *arg) -{ - char savec = arg[argLen]; - Boolean result; - - arg[argLen] = '\0'; - if (Var_Value(arg, VAR_CMD) != NULL) { - result = TRUE; - } else { - result = FALSE; - } - arg[argLen] = savec; - return (result); -} - -/** - * CondDoMake - * Handle the 'make' function for conditionals. - * - * Results: - * TRUE if the given target is being made. - */ -static Boolean -CondDoMake(int argLen, char *arg) -{ - char savec = arg[argLen]; - Boolean result; - const LstNode *ln; - - arg[argLen] = '\0'; - result = FALSE; - LST_FOREACH(ln, &create) { - if (Str_Match(Lst_Datum(ln), arg)) { - result = TRUE; - break; - } - } - arg[argLen] = savec; - return (result); -} - -/** - * CondDoExists - * See if the given file exists. - * - * Results: - * TRUE if the file exists and FALSE if it does not. - */ -static Boolean -CondDoExists(int argLen, char *arg) -{ - char savec = arg[argLen]; - Boolean result; - char *path; - - arg[argLen] = '\0'; - path = Path_FindFile(arg, &dirSearchPath); - if (path != NULL) { - result = TRUE; - free(path); - } else { - result = FALSE; - } - arg[argLen] = savec; - return (result); -} - -/** - * CondDoTarget - * See if the given node exists and is an actual target. - * - * Results: - * TRUE if the node exists as a target and FALSE if it does not. - */ -static Boolean -CondDoTarget(int argLen, char *arg) -{ - char savec = arg[argLen]; - Boolean result; - GNode *gn; - - arg[argLen] = '\0'; - gn = Targ_FindNode(arg, TARG_NOCREATE); - if ((gn != NULL) && !OP_NOP(gn->type)) { - result = TRUE; - } else { - result = FALSE; - } - arg[argLen] = savec; - return (result); -} - -/** - * CondCvtArg - * Convert the given number into a double. If the number begins - * with 0x, it is interpreted as a hexadecimal integer - * and converted to a double from there. All other strings just have - * strtod called on them. - * - * Results: - * Sets 'value' to double value of string. - * Returns address of the first character after the last valid - * character of the converted number. - * - * Side Effects: - * Can change 'value' even if string is not a valid number. - */ -static char * -CondCvtArg(char *str, double *value) -{ - - if ((*str == '0') && (str[1] == 'x')) { - long i; - - for (str += 2, i = 0; ; str++) { - int x; - - if (isdigit((unsigned char)*str)) - x = *str - '0'; - else if (isxdigit((unsigned char)*str)) - x = 10 + *str - - isupper((unsigned char)*str) ? 'A' : 'a'; - else { - *value = (double)i; - return (str); - } - i = (i << 4) + x; - } - - } else { - char *eptr; - - *value = strtod(str, &eptr); - return (eptr); - } -} - -/** - * CondToken - * Return the next token from the input. - * - * Results: - * A Token for the next lexical token in the stream. - * - * Side Effects: - * condPushback will be set back to None if it is used. - */ -static Token -CondToken(Boolean doEval) -{ - Token t; - - if (condPushBack != None) { - t = condPushBack; - condPushBack = None; - return (t); - } - - while (*condExpr == ' ' || *condExpr == '\t') { - condExpr++; - } - switch (*condExpr) { - case '(': - t = LParen; - condExpr++; - break; - case ')': - t = RParen; - condExpr++; - break; - case '|': - if (condExpr[1] == '|') { - condExpr++; - } - condExpr++; - t = Or; - break; - case '&': - if (condExpr[1] == '&') { - condExpr++; - } - condExpr++; - t = And; - break; - case '!': - t = Not; - condExpr++; - break; - case '\n': - case '\0': - t = EndOfFile; - break; - case '$': { - char *lhs; - const char *op; - char *rhs; - char zero[] = "0"; - size_t varSpecLen = 0; - Boolean doFree; - - /* - * Parse the variable spec and skip over it, saving its - * value in lhs. - */ - t = Err; - lhs = Var_Parse(condExpr, VAR_CMD, doEval, - &varSpecLen, &doFree); - if (lhs == var_Error) { - /* - * Even if !doEval, we still report syntax - * errors, which is what getting var_Error - * back with !doEval means. - */ - return (Err); - } - condExpr += varSpecLen; - - if (!isspace((unsigned char)*condExpr) && - strchr("!=><", *condExpr) == NULL) { - Buffer *buf; - - buf = Buf_Init(0); - - Buf_Append(buf, lhs); - - if (doFree) - free(lhs); - - for (;*condExpr && - !isspace((unsigned char)*condExpr); - condExpr++) - Buf_AddByte(buf, (Byte)*condExpr); - - Buf_AddByte(buf, (Byte)'\0'); - lhs = (char *)Buf_GetAll(buf, &varSpecLen); - Buf_Destroy(buf, FALSE); - - doFree = TRUE; - } - - /* - * Skip whitespace to get to the operator - */ - while (isspace((unsigned char)*condExpr)) - condExpr++; - - /* - * Make sure the operator is a valid one. If it isn't a - * known relational operator, pretend we got a - * != 0 comparison. - */ - op = condExpr; - switch (*condExpr) { - case '!': - case '=': - case '<': - case '>': - if (condExpr[1] == '=') { - condExpr += 2; - } else { - condExpr += 1; - } - while (isspace((unsigned char)*condExpr)) { - condExpr++; - } - if (*condExpr == '\0') { - Parse_Error(PARSE_WARNING, - "Missing right-hand-side of operator"); - goto error; - } - rhs = condExpr; - break; - - default: - op = "!="; - rhs = zero; - break; - } - if (*rhs == '"') { - /* - * Doing a string comparison. Only allow == and - * != for * operators. - */ - char *string; - char *cp, *cp2; - int qt; - Buffer *buf; - - do_string_compare: - if (((*op != '!') && (*op != '=')) || - (op[1] != '=')) { - Parse_Error(PARSE_WARNING, - "String comparison operator should " - "be either == or !="); - goto error; - } - - buf = Buf_Init(0); - qt = *rhs == '"' ? 1 : 0; - - for (cp = &rhs[qt]; - ((qt && (*cp != '"')) || - (!qt && strchr(" \t)", *cp) == NULL)) && - (*cp != '\0'); cp++) { - if ((*cp == '\\') && (cp[1] != '\0')) { - /* - * Backslash escapes things -- - * skip over next character, * if it exists. - */ - cp++; - Buf_AddByte(buf, (Byte)*cp); - - } else if (*cp == '$') { - size_t len = 0; - Boolean freeIt; - - cp2 = Var_Parse(cp, VAR_CMD, - doEval, &len, &freeIt); - if (cp2 != var_Error) { - Buf_Append(buf, cp2); - if (freeIt) { - free(cp2); - } - cp += len - 1; - } else { - Buf_AddByte(buf, - (Byte)*cp); - } - } else { - Buf_AddByte(buf, (Byte)*cp); - } - } - - string = Buf_Peel(buf); - - DEBUGF(COND, ("lhs = \"%s\", rhs = \"%s\", " - "op = %.2s\n", lhs, string, op)); - /* - * Null-terminate rhs and perform the - * comparison. t is set to the result. - */ - if (*op == '=') { - t = strcmp(lhs, string) ? False : True; - } else { - t = strcmp(lhs, string) ? True : False; - } - free(string); - if (rhs == condExpr) { - if (*cp == '\0' || (!qt && *cp == ')')) - condExpr = cp; - else - condExpr = cp + 1; - } - } else { - /* - * rhs is either a float or an integer. - * Convert both the lhs and the rhs to a - * double and compare the two. - */ - double left, right; - char *string; - - if (*CondCvtArg(lhs, &left) != '\0') - goto do_string_compare; - if (*rhs == '$') { - size_t len = 0; - Boolean freeIt; - - string = Var_Parse(rhs, VAR_CMD, doEval, - &len, &freeIt); - if (string == var_Error) { - right = 0.0; - } else { - if (*CondCvtArg(string, - &right) != '\0') { - if (freeIt) - free(string); - goto do_string_compare; - } - if (freeIt) - free(string); - if (rhs == condExpr) - condExpr += len; - } - } else { - char *c = CondCvtArg(rhs, &right); - - if (c == rhs) - goto do_string_compare; - if (rhs == condExpr) { - /* - * Skip over the right-hand side - */ - condExpr = c; - } - } - - DEBUGF(COND, ("left = %f, right = %f, " - "op = %.2s\n", left, right, op)); - switch (op[0]) { - case '!': - if (op[1] != '=') { - Parse_Error(PARSE_WARNING, - "Unknown operator"); - goto error; - } - t = (left != right ? True : False); - break; - case '=': - if (op[1] != '=') { - Parse_Error(PARSE_WARNING, - "Unknown operator"); - goto error; - } - t = (left == right ? True : False); - break; - case '<': - if (op[1] == '=') { - t = (left <= right?True:False); - } else { - t = (left < right?True:False); - } - break; - case '>': - if (op[1] == '=') { - t = (left >= right?True:False); - } else { - t = (left > right?True:False); - } - break; - default: - break; - } - } - error: - if (doFree) - free(lhs); - break; - } - - default: { - CondProc *evalProc; - Boolean invert = FALSE; - char *arg; - int arglen; - - if (strncmp(condExpr, "defined", 7) == 0) { - /* - * Use CondDoDefined to evaluate the argument - * and CondGetArg to extract the argument from - * the 'function call'. - */ - evalProc = CondDoDefined; - condExpr += 7; - arglen = CondGetArg(&condExpr, &arg, - "defined", TRUE); - if (arglen == 0) { - condExpr -= 7; - goto use_default; - } - - } else if (strncmp(condExpr, "make", 4) == 0) { - /* - * Use CondDoMake to evaluate the argument and - * CondGetArg to extract the argument from the - * 'function call'. - */ - evalProc = CondDoMake; - condExpr += 4; - arglen = CondGetArg(&condExpr, &arg, - "make", TRUE); - if (arglen == 0) { - condExpr -= 4; - goto use_default; - } - - } else if (strncmp(condExpr, "exists", 6) == 0) { - /* - * Use CondDoExists to evaluate the argument and - * CondGetArg to extract the argument from the - * 'function call'. - */ - evalProc = CondDoExists; - condExpr += 6; - arglen = CondGetArg(&condExpr, &arg, - "exists", TRUE); - if (arglen == 0) { - condExpr -= 6; - goto use_default; - } - - } else if (strncmp(condExpr, "empty", 5) == 0) { - /* - * Use Var_Parse to parse the spec in parens and - * return True if the resulting string is empty. - */ - size_t length; - Boolean doFree; - char *val; - - condExpr += 5; - - for (arglen = 0; - condExpr[arglen] != '(' && - condExpr[arglen] != '\0'; arglen += 1) - continue; - - if (condExpr[arglen] != '\0') { - length = 0; - val = Var_Parse(&condExpr[arglen - 1], - VAR_CMD, FALSE, &length, &doFree); - if (val == var_Error) { - t = Err; - } else { - /* - * A variable is empty when it - * just contains spaces... - * 4/15/92, christos - */ - char *p; - - for (p = val; - *p && - isspace((unsigned char)*p); - p++) - continue; - t = (*p == '\0') ? True : False; - } - if (doFree) { - free(val); - } - /* - * Advance condExpr to beyond the - * closing ). Note that we subtract - * one from arglen + length b/c length - * is calculated from - * condExpr[arglen - 1]. - */ - condExpr += arglen + length - 1; - } else { - condExpr -= 5; - goto use_default; - } - break; - - } else if (strncmp(condExpr, "target", 6) == 0) { - /* - * Use CondDoTarget to evaluate the argument and - * CondGetArg to extract the argument from the - * 'function call'. - */ - evalProc = CondDoTarget; - condExpr += 6; - arglen = CondGetArg(&condExpr, &arg, - "target", TRUE); - if (arglen == 0) { - condExpr -= 6; - goto use_default; - } - - } else { - /* - * The symbol is itself the argument to the - * default function. We advance condExpr to - * the end of the symbol by hand (the next - * whitespace, closing paren or binary operator) - * and set to invert the evaluation - * function if condInvert is TRUE. - */ - use_default: - invert = condInvert; - evalProc = condDefProc; - arglen = CondGetArg(&condExpr, &arg, "", FALSE); - } - - /* - * Evaluate the argument using the set function. If - * invert is TRUE, we invert the sense of the function. - */ - t = (!doEval || (* evalProc) (arglen, arg) ? - (invert ? False : True) : - (invert ? True : False)); - free(arg); - break; - } - } - return (t); -} - -/** - * CondT - * Parse a single term in the expression. This consists of a terminal - * symbol or Not and a terminal symbol (not including the binary - * operators): - * T -> defined(variable) | make(target) | exists(file) | symbol - * T -> ! T | ( E ) - * - * Results: - * True, False or Err. - * - * Side Effects: - * Tokens are consumed. - */ -static Token -CondT(Boolean doEval) -{ - Token t; - - t = CondToken(doEval); - if (t == EndOfFile) { - /* - * If we reached the end of the expression, the expression - * is malformed... - */ - t = Err; - } else if (t == LParen) { - /* - * T -> ( E ) - */ - t = CondE(doEval); - if (t != Err) { - if (CondToken(doEval) != RParen) { - t = Err; - } - } - } else if (t == Not) { - t = CondT(doEval); - if (t == True) { - t = False; - } else if (t == False) { - t = True; - } - } - return (t); -} - -/** - * CondF -- - * Parse a conjunctive factor (nice name, wot?) - * F -> T && F | T - * - * Results: - * True, False or Err - * - * Side Effects: - * Tokens are consumed. - */ -static Token -CondF(Boolean doEval) -{ - Token l, o; - - l = CondT(doEval); - if (l != Err) { - o = CondToken(doEval); - - if (o == And) { - /* - * F -> T && F - * - * If T is False, the whole thing will be False, but - * we have to parse the r.h.s. anyway (to throw it - * away). If T is True, the result is the r.h.s., - * be it an Err or no. - */ - if (l == True) { - l = CondF(doEval); - } else { - CondF(FALSE); - } - } else { - /* - * F -> T - */ - CondPushBack(o); - } - } - return (l); -} - -/** - * CondE -- - * Main expression production. - * E -> F || E | F - * - * Results: - * True, False or Err. - * - * Side Effects: - * Tokens are, of course, consumed. - */ -static Token -CondE(Boolean doEval) -{ - Token l, o; - - l = CondF(doEval); - if (l != Err) { - o = CondToken(doEval); - - if (o == Or) { - /* - * E -> F || E - * - * A similar thing occurs for ||, except that here we - * make sure the l.h.s. is False before we bother to - * evaluate the r.h.s. Once again, if l is False, the - * result is the r.h.s. and once again if l is True, - * we parse the r.h.s. to throw it away. - */ - if (l == False) { - l = CondE(doEval); - } else { - CondE(FALSE); - } - } else { - /* - * E -> F - */ - CondPushBack(o); - } - } - return (l); -} - -/** - * Cond_If - * Handle .if and .elif directives. - * This function is called even when we're skipping. - */ -void -Cond_If(char *line, int code, int lineno) -{ - const struct If *ifp; - Boolean value; - - ifp = &ifs[code]; - - if (ifp->isElse) { - if (condTop == MAXIF) { - Parse_Error(PARSE_FATAL, "if-less elif"); - return; - } - if (skipIfLevel != 0) { - /* - * If skipping this conditional, just ignore - * the whole thing. If we don't, the user - * might be employing a variable that's - * undefined, for which there's an enclosing - * ifdef that we're skipping... - */ - skipIfLineno[skipIfLevel - 1] = lineno; - return; - } - - } else if (skipLine) { - /* - * Don't even try to evaluate a conditional that's - * not an else if we're skipping things... - */ - skipIfLineno[skipIfLevel] = lineno; - skipIfLevel += 1; - return; - } - - /* - * Initialize file-global variables for parsing - */ - condDefProc = ifp->defProc; - condInvert = ifp->doNot; - - while (*line == ' ' || *line == '\t') { - line++; - } - - condExpr = line; - condPushBack = None; - - switch (CondE(TRUE)) { - case True: - if (CondToken(TRUE) != EndOfFile) - goto err; - value = TRUE; - break; - - case False: - if (CondToken(TRUE) != EndOfFile) - goto err; - value = FALSE; - break; - - case Err: - err: Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", line); - return; - - default: - abort(); - } - - if (!ifp->isElse) { - /* push this value */ - condTop -= 1; - - } else if (skipIfLevel != 0 || condStack[condTop]) { - /* - * If this is an else-type conditional, it should only take - * effect if its corresponding if was evaluated and FALSE. - * If its if was TRUE or skipped, we return COND_SKIP (and - * start skipping in case we weren't already), leaving the - * stack unmolested so later elif's don't screw up... - */ - skipLine = TRUE; - return; - } - - if (condTop < 0) { - /* - * This is the one case where we can definitely proclaim a fatal - * error. If we don't, we're hosed. - */ - Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.",MAXIF); - return; - } - - /* push */ - condStack[condTop] = value; - condLineno[condTop] = lineno; - skipLine = !value; -} - -/** - * Cond_Else - * Handle .else statement. - */ -void -Cond_Else(char *line __unused, int code __unused, int lineno __unused) -{ - - while (isspace((u_char)*line)) - line++; - - if (*line != '\0' && (warn_flags & WARN_DIRSYNTAX)) { - Parse_Error(PARSE_WARNING, "junk after .else ignored '%s'", - line); - } - - if (condTop == MAXIF) { - Parse_Error(PARSE_FATAL, "if-less else"); - return; - } - if (skipIfLevel != 0) - return; - - if (skipIfLevel != 0 || condStack[condTop]) { - /* - * An else should only take effect if its corresponding if was - * evaluated and FALSE. - * If its if was TRUE or skipped, we return COND_SKIP (and - * start skipping in case we weren't already), leaving the - * stack unmolested so later elif's don't screw up... - * XXX How does this work with two .else's? - */ - skipLine = TRUE; - return; - } - - /* inverse value */ - condStack[condTop] = !condStack[condTop]; - skipLine = !condStack[condTop]; -} - -/** - * Cond_Endif - * Handle .endif statement. - */ -void -Cond_Endif(char *line __unused, int code __unused, int lineno __unused) -{ - - while (isspace((u_char)*line)) - line++; - - if (*line != '\0' && (warn_flags & WARN_DIRSYNTAX)) { - Parse_Error(PARSE_WARNING, "junk after .endif ignored '%s'", - line); - } - - /* - * End of a conditional section. If skipIfLevel is non-zero, - * that conditional was skipped, so lines following it should - * also be skipped. Hence, we return COND_SKIP. Otherwise, - * the conditional was read so succeeding lines should be - * parsed (think about it...) so we return COND_PARSE, unless - * this endif isn't paired with a decent if. - */ - if (skipIfLevel != 0) { - skipIfLevel -= 1; - return; - } - - if (condTop == MAXIF) { - Parse_Error(PARSE_FATAL, "if-less endif"); - return; - } - - /* pop */ - skipLine = FALSE; - condTop += 1; -} - -/** - * Cond_End - * Make sure everything's clean at the end of a makefile. - * - * Side Effects: - * Parse_Error will be called if open conditionals are around. - */ -void -Cond_End(void) -{ - int level; - - if (condTop != MAXIF) { - Parse_Error(PARSE_FATAL, "%d open conditional%s:", - MAXIF - condTop + skipIfLevel, - MAXIF - condTop + skipIfLevel== 1 ? "" : "s"); - - for (level = skipIfLevel; level > 0; level--) - Parse_Error(PARSE_FATAL, "\t%*sat line %d (skipped)", - MAXIF - condTop + level + 1, "", - skipIfLineno[level - 1]); - for (level = condTop; level < MAXIF; level++) - Parse_Error(PARSE_FATAL, "\t%*sat line %d " - "(evaluated to %s)", MAXIF - level + skipIfLevel, - "", condLineno[level], - condStack[level] ? "true" : "false"); - } - condTop = MAXIF; -} Property changes on: head/usr.bin/make/cond.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/cond.h =================================================================== --- head/usr.bin/make/cond.h (revision 284463) +++ head/usr.bin/make/cond.h (nonexistent) @@ -1,73 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef cond_h_6e96ad7c -#define cond_h_6e96ad7c - -/* - * Values returned by Cond_Eval. - */ -#define COND_PARSE 0 /* Parse the next lines */ -#define COND_SKIP 1 /* Skip the next lines */ -#define COND_INVALID 2 /* Not a conditional statement */ - -enum { - COND_IF, - COND_IFDEF, - COND_IFNDEF, - COND_IFMAKE, - COND_IFNMAKE, - COND_ELSE, - COND_ELIF, - COND_ELIFDEF, - COND_ELIFNDEF, - COND_ELIFMAKE, - COND_ELIFNMAKE, - COND_ENDIF, -}; - -void Cond_If(char *, int, int); -void Cond_Else(char *, int, int); -void Cond_Endif(char *, int, int); -void Cond_End(void); - -extern Boolean skipLine; - -#endif /* cond_h_6e96ad7c */ Property changes on: head/usr.bin/make/cond.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/var.c =================================================================== --- head/usr.bin/make/var.c (revision 284463) +++ head/usr.bin/make/var.c (nonexistent) @@ -1,2623 +0,0 @@ -/*- - * Copyright (c) 2002 Juli Mallett. - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)var.c 8.3 (Berkeley) 3/19/94 - */ - -#include -__FBSDID("$FreeBSD$"); - -/** - * var.c -- - * Variable-handling functions - * - * Interface: - * Var_Set Set the value of a variable in the given - * context. The variable is created if it doesn't - * yet exist. The value and variable name need not - * be preserved. - * - * Var_Append Append more characters to an existing variable - * in the given context. The variable needn't - * exist already -- it will be created if it doesn't. - * A space is placed between the old value and the - * new one. - * - * Var_Exists See if a variable exists. - * - * Var_Value Return the value of a variable in a context or - * NULL if the variable is undefined. - * - * Var_Subst Substitute named variable, or all variables if - * NULL in a string using - * the given context as the top-most one. If the - * third argument is non-zero, Parse_Error is - * called if any variables are undefined. - * - * Var_Parse Parse a variable expansion from a string and - * return the result and the number of characters - * consumed. - * - * Var_Delete Delete a variable in a context. - * - * Var_Init Initialize this module. - * - * Debugging: - * Var_Dump Print out all variables defined in the given - * context. - * - * XXX: There's a lot of duplication in these functions. - */ - -#include -#include -#include -#include -#include - -#include "buf.h" -#include "config.h" -#include "globals.h" -#include "GNode.h" -#include "job.h" -#include "lst.h" -#include "parse.h" -#include "str.h" -#include "targ.h" -#include "util.h" -#include "var.h" - -/** - * - */ -typedef struct VarParser { - const char *const input; /* pointer to input string */ - const char *ptr; /* current parser pos in input str */ - GNode *ctxt; - Boolean err; - Boolean execute; -} VarParser; - -typedef struct Var { - char *name; /* the variable's name */ - struct Buffer *val; /* its value */ - int flags; /* miscellaneous status flags */ - -#define VAR_IN_USE 1 /* Variable's value currently being used. - * Used to avoid recursion */ - -#define VAR_JUNK 4 /* Variable is a junk variable that - * should be destroyed when done with - * it. Used by Var_Parse for undefined, - * modified variables */ - -#define VAR_TO_ENV 8 /* Place variable in environment */ -} Var; - -typedef struct { - struct Buffer *lhs; /* String to match */ - struct Buffer *rhs; /* Replacement string (w/ &'s removed) */ - - regex_t re; - int nsub; - regmatch_t *matches; - - int flags; -#define VAR_SUB_GLOBAL 0x01 /* Apply substitution globally */ -#define VAR_SUB_ONE 0x02 /* Apply substitution to one word */ -#define VAR_SUB_MATCHED 0x04 /* There was a match */ -#define VAR_MATCH_START 0x08 /* Match at start of word */ -#define VAR_MATCH_END 0x10 /* Match at end of word */ -} VarPattern; - -typedef Boolean VarModifyProc(const char *, Boolean, struct Buffer *, void *); - -static char *VarParse(VarParser *, Boolean *); - -/* - * This is a harmless return value for Var_Parse that can be used by Var_Subst - * to determine if there was an error in parsing -- easier than returning - * a flag, as things outside this module don't give a hoot. - */ -char var_Error[] = ""; - -/* - * Similar to var_Error, but returned when the 'err' flag for Var_Parse is - * set false. Why not just use a constant? Well, gcc likes to condense - * identical string instances... - */ -static char varNoError[] = ""; - -/* - * Internally, variables are contained in four different contexts. - * 1) the environment. They may not be changed. If an environment - * variable is appended-to, the result is placed in the global - * context. - * 2) the global context. Variables set in the Makefile are located in - * the global context. It is the penultimate context searched when - * substituting. - * 3) the command-line context. All variables set on the command line - * are placed in this context. They are UNALTERABLE once placed here. - * 4) the local context. Each target has associated with it a context - * list. On this list are located the structures describing such - * local variables as $(@) and $(*) - * The four contexts are searched in the reverse order from which they are - * listed. - */ -static GNode *VAR_ENV; /* variables from the environment */ -GNode *VAR_GLOBAL; /* variables from the makefile */ -GNode *VAR_CMD; /* variables defined on the command-line */ - -Boolean oldVars; /* variable substitution style */ -Boolean checkEnvFirst; /* -e flag */ - -#define OPEN_PAREN '(' -#define CLOSE_PAREN ')' -#define OPEN_BRACE '{' -#define CLOSE_BRACE '}' - -/** - * Create a Var object. - * - * Params: - * name Name of variable (copied). - * value Value of variable (copied) or NULL. - * flags Flags set on variable. - * - * Returns: - * New variable. - */ -static Var * -VarCreate(const char name[], const char value[], int flags) -{ - Var *v; - - v = emalloc(sizeof(Var)); - v->name = estrdup(name); - v->val = Buf_Init(0); - v->flags = flags; - - if (value != NULL) { - Buf_Append(v->val, value); - } - return (v); -} - -/** - * Destroy a Var object. - * - * Params: - * v Object to destroy. - * f True if internal buffer in Buffer object is to be removed. - */ -static void -VarDestroy(Var *v, Boolean f) -{ - - Buf_Destroy(v->val, f); - free(v->name); - free(v); -} - -/** - * Remove the tail of the given word and place the result in the given - * buffer. - * - * Results: - * TRUE if characters were added to the buffer (a space needs to be - * added to the buffer before the next word). - * - * Side Effects: - * The trimmed word is added to the buffer. - */ -static Boolean -VarHead(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused) -{ - char *slash; - - slash = strrchr(word, '/'); - if (slash != NULL) { - if (addSpace) { - Buf_AddByte(buf, (Byte)' '); - } - Buf_AppendRange(buf, word, slash); - } else { - /* - * If no directory part, give . (q.v. the POSIX standard) - */ - if (addSpace) { - Buf_Append(buf, " ."); - } else { - Buf_AddByte(buf, (Byte)'.'); - } - } - return (TRUE); -} - -/** - * Remove the head of the given word and place the result in the given - * buffer. - * - * Results: - * TRUE if characters were added to the buffer (a space needs to be - * added to the buffer before the next word). - * - * Side Effects: - * The trimmed word is added to the buffer. - */ -static Boolean -VarTail(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused) -{ - const char *slash; - - if (addSpace) { - Buf_AddByte (buf, (Byte)' '); - } - - slash = strrchr(word, '/'); - if (slash != NULL) { - slash++; - Buf_Append(buf, slash); - } else { - Buf_Append(buf, word); - } - return (TRUE); -} - -/** - * Place the suffix of the given word in the given buffer. - * - * Results: - * TRUE if characters were added to the buffer (a space needs to be - * added to the buffer before the next word). - * - * Side Effects: - * The suffix from the word is placed in the buffer. - */ -static Boolean -VarSuffix(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused) -{ - const char *dot; - - dot = strrchr(word, '.'); - if (dot != NULL) { - if (addSpace) { - Buf_AddByte(buf, (Byte)' '); - } - dot++; - Buf_Append(buf, dot); - addSpace = TRUE; - } - return (addSpace); -} - -/** - * Remove the suffix of the given word and place the result in the - * buffer. - * - * Results: - * TRUE if characters were added to the buffer (a space needs to be - * added to the buffer before the next word). - * - * Side Effects: - * The trimmed word is added to the buffer. - */ -static Boolean -VarRoot(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused) -{ - char *dot; - - if (addSpace) { - Buf_AddByte(buf, (Byte)' '); - } - - dot = strrchr(word, '.'); - if (dot != NULL) { - Buf_AppendRange(buf, word, dot); - } else { - Buf_Append(buf, word); - } - return (TRUE); -} - -/** - * Place the word in the buffer if it matches the given pattern. - * Callback function for VarModify to implement the :M modifier. - * A space will be added if requested. A pattern is supplied - * which the word must match. - * - * Results: - * TRUE if a space should be placed in the buffer before the next - * word. - * - * Side Effects: - * The word may be copied to the buffer. - */ -static Boolean -VarMatch(const char *word, Boolean addSpace, Buffer *buf, void *pattern) -{ - - if (Str_Match(word, pattern)) { - if (addSpace) { - Buf_AddByte(buf, (Byte)' '); - } - addSpace = TRUE; - Buf_Append(buf, word); - } - return (addSpace); -} - -#ifdef SYSVVARSUB -/** - * Place the word in the buffer if it matches the given pattern. - * Callback function for VarModify to implement the System V % - * modifiers. A space is added if requested. - * - * Results: - * TRUE if a space should be placed in the buffer before the next - * word. - * - * Side Effects: - * The word may be copied to the buffer. - */ -static Boolean -VarSYSVMatch(const char *word, Boolean addSpace, Buffer *buf, void *patp) -{ - int len; - const char *ptr; - VarPattern *pat = (VarPattern *)patp; - - if (addSpace) - Buf_AddByte(buf, (Byte)' '); - - addSpace = TRUE; - - if ((ptr = Str_SYSVMatch(word, Buf_Data(pat->lhs), &len)) != NULL) - Str_SYSVSubst(buf, Buf_Data(pat->rhs), ptr, len); - else - Buf_Append(buf, word); - - return (addSpace); -} -#endif - -/** - * Place the word in the buffer if it doesn't match the given pattern. - * Callback function for VarModify to implement the :N modifier. A - * space is added if requested. - * - * Results: - * TRUE if a space should be placed in the buffer before the next - * word. - * - * Side Effects: - * The word may be copied to the buffer. - */ -static Boolean -VarNoMatch(const char *word, Boolean addSpace, Buffer *buf, void *pattern) -{ - - if (!Str_Match(word, pattern)) { - if (addSpace) { - Buf_AddByte(buf, (Byte)' '); - } - addSpace = TRUE; - Buf_Append(buf, word); - } - return (addSpace); -} - -/** - * Perform a string-substitution on the given word, placing the - * result in the passed buffer. A space is added if requested. - * - * Results: - * TRUE if a space is needed before more characters are added. - */ -static Boolean -VarSubstitute(const char *word, Boolean addSpace, Buffer *buf, void *patternp) -{ - size_t wordLen; /* Length of word */ - const char *cp; /* General pointer */ - VarPattern *pattern = patternp; - - wordLen = strlen(word); - if (1) { /* substitute in each word of the variable */ - /* - * Break substitution down into simple anchored cases - * and if none of them fits, perform the general substitution - * case. - */ - if ((pattern->flags & VAR_MATCH_START) && - (strncmp(word, Buf_Data(pattern->lhs), - Buf_Size(pattern->lhs)) == 0)) { - /* - * Anchored at start and beginning of word matches - * pattern. - */ - if ((pattern->flags & VAR_MATCH_END) && - (wordLen == Buf_Size(pattern->lhs))) { - /* - * Also anchored at end and matches to the end - * (word is same length as pattern) add space - * and rhs only if rhs is non-null. - */ - if (Buf_Size(pattern->rhs) != 0) { - if (addSpace) { - Buf_AddByte(buf, (Byte)' '); - } - addSpace = TRUE; - Buf_AppendBuf(buf, pattern->rhs); - } - - } else if (pattern->flags & VAR_MATCH_END) { - /* - * Doesn't match to end -- copy word wholesale - */ - goto nosub; - - } else { - /* - * Matches at start but need to copy in - * trailing characters. - */ - if ((Buf_Size(pattern->rhs) + wordLen - - Buf_Size(pattern->lhs)) != 0) { - if (addSpace) { - Buf_AddByte(buf, (Byte)' '); - } - addSpace = TRUE; - } - Buf_AppendBuf(buf, pattern->rhs); - Buf_AddBytes(buf, wordLen - - Buf_Size(pattern->lhs), - (word + Buf_Size(pattern->lhs))); - } - - } else if (pattern->flags & VAR_MATCH_START) { - /* - * Had to match at start of word and didn't -- copy - * whole word. - */ - goto nosub; - - } else if (pattern->flags & VAR_MATCH_END) { - /* - * Anchored at end, Find only place match could occur - * (leftLen characters from the end of the word) and - * see if it does. Note that because the $ will be - * left at the end of the lhs, we have to use strncmp. - */ - cp = word + (wordLen - Buf_Size(pattern->lhs)); - if ((cp >= word) && (strncmp(cp, Buf_Data(pattern->lhs), - Buf_Size(pattern->lhs)) == 0)) { - /* - * Match found. If we will place characters in - * the buffer, add a space before hand as - * indicated by addSpace, then stuff in the - * initial, unmatched part of the word followed - * by the right-hand-side. - */ - if ((cp - word) + Buf_Size(pattern->rhs) != 0) { - if (addSpace) { - Buf_AddByte(buf, (Byte)' '); - } - addSpace = TRUE; - } - Buf_AppendRange(buf, word, cp); - Buf_AppendBuf(buf, pattern->rhs); - - } else { - /* - * Had to match at end and didn't. Copy entire - * word. - */ - goto nosub; - } - } else { - /* - * Pattern is unanchored: search for the pattern in the - * word using strstr(3), copying unmatched portions and - * the right-hand-side for each match found, handling - * non-global substitutions correctly, etc. When the - * loop is done, any remaining part of the word (word - * and wordLen are adjusted accordingly through the - * loop) is copied straight into the buffer. - * addSpace is set FALSE as soon as a space is added - * to the buffer. - */ - Boolean done; - size_t origSize; - - done = FALSE; - origSize = Buf_Size(buf); - while (!done) { - cp = strstr(word, Buf_Data(pattern->lhs)); - if (cp != NULL) { - if (addSpace && (((cp - word) + - Buf_Size(pattern->rhs)) != 0)) { - Buf_AddByte(buf, (Byte)' '); - addSpace = FALSE; - } - Buf_AppendRange(buf, word, cp); - Buf_AppendBuf(buf, pattern->rhs); - wordLen -= (cp - word) + - Buf_Size(pattern->lhs); - word = cp + Buf_Size(pattern->lhs); - if (wordLen == 0 || (pattern->flags & - VAR_SUB_GLOBAL) == 0) { - done = TRUE; - } - } else { - done = TRUE; - } - } - if (wordLen != 0) { - if (addSpace) { - Buf_AddByte(buf, (Byte)' '); - } - Buf_AddBytes(buf, wordLen, (const Byte *)word); - } - - /* - * If added characters to the buffer, need to add a - * space before we add any more. If we didn't add any, - * just return the previous value of addSpace. - */ - return ((Buf_Size(buf) != origSize) || addSpace); - } - /* - * Common code for anchored substitutions: - * addSpace was set TRUE if characters were added to the buffer. - */ - return (addSpace); - } - nosub: - if (addSpace) { - Buf_AddByte(buf, (Byte)' '); - } - Buf_AddBytes(buf, wordLen, (const Byte *)word); - return (TRUE); -} - -/** - * Print the error caused by a regcomp or regexec call. - * - * Side Effects: - * An error gets printed. - */ -static void -VarREError(int err, regex_t *pat, const char *str) -{ - char *errbuf; - int errlen; - - errlen = regerror(err, pat, 0, 0); - errbuf = emalloc(errlen); - regerror(err, pat, errbuf, errlen); - Error("%s: %s", str, errbuf); - free(errbuf); -} - - -/** - * Perform a regex substitution on the given word, placing the - * result in the passed buffer. A space is added if requested. - * - * Results: - * TRUE if a space is needed before more characters are added. - */ -static Boolean -VarRESubstitute(const char *word, Boolean addSpace, Buffer *buf, void *patternp) -{ - VarPattern *pat; - int xrv; - const char *wp; - char *rp; - int added; - int flags = 0; - -#define MAYBE_ADD_SPACE() \ - if (addSpace && !added) \ - Buf_AddByte(buf, (Byte)' '); \ - added = 1 - - added = 0; - wp = word; - pat = patternp; - - if ((pat->flags & (VAR_SUB_ONE | VAR_SUB_MATCHED)) == - (VAR_SUB_ONE | VAR_SUB_MATCHED)) { - xrv = REG_NOMATCH; - } else { - tryagain: - xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags); - } - - switch (xrv) { - case 0: - pat->flags |= VAR_SUB_MATCHED; - if (pat->matches[0].rm_so > 0) { - MAYBE_ADD_SPACE(); - Buf_AddBytes(buf, pat->matches[0].rm_so, - (const Byte *)wp); - } - - for (rp = Buf_Data(pat->rhs); *rp; rp++) { - if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) { - MAYBE_ADD_SPACE(); - Buf_AddByte(buf, (Byte)rp[1]); - rp++; - - } else if ((*rp == '&') || - ((*rp == '\\') && isdigit((unsigned char)rp[1]))) { - int n; - const char *subbuf; - int sublen; - char errstr[3]; - - if (*rp == '&') { - n = 0; - errstr[0] = '&'; - errstr[1] = '\0'; - } else { - n = rp[1] - '0'; - errstr[0] = '\\'; - errstr[1] = rp[1]; - errstr[2] = '\0'; - rp++; - } - - if (n > pat->nsub) { - Error("No subexpression %s", - &errstr[0]); - subbuf = ""; - sublen = 0; - - } else if ((pat->matches[n].rm_so == -1) && - (pat->matches[n].rm_eo == -1)) { - Error("No match for subexpression %s", - &errstr[0]); - subbuf = ""; - sublen = 0; - - } else { - subbuf = wp + pat->matches[n].rm_so; - sublen = pat->matches[n].rm_eo - - pat->matches[n].rm_so; - } - - if (sublen > 0) { - MAYBE_ADD_SPACE(); - Buf_AddBytes(buf, sublen, - (const Byte *)subbuf); - } - } else { - MAYBE_ADD_SPACE(); - Buf_AddByte(buf, (Byte)*rp); - } - } - wp += pat->matches[0].rm_eo; - if (pat->flags & VAR_SUB_GLOBAL) { - flags |= REG_NOTBOL; - if (pat->matches[0].rm_so == 0 && - pat->matches[0].rm_eo == 0) { - MAYBE_ADD_SPACE(); - Buf_AddByte(buf, (Byte)*wp); - wp++; - } - if (*wp) - goto tryagain; - } - if (*wp) { - MAYBE_ADD_SPACE(); - Buf_Append(buf, wp); - } - break; - - default: - VarREError(xrv, &pat->re, "Unexpected regex error"); - /* fall through */ - - case REG_NOMATCH: - if (*wp) { - MAYBE_ADD_SPACE(); - Buf_Append(buf, wp); - } - break; - } - return (addSpace || added); -} - -/** - * Find a variable in a variable list. - */ -static Var * -VarLookup(Lst *vlist, const char *name) -{ - LstNode *ln; - - LST_FOREACH(ln, vlist) - if (strcmp(((const Var *)Lst_Datum(ln))->name, name) == 0) - return (Lst_Datum(ln)); - return (NULL); -} - -/** - * Expand a variable name's embedded variables in the given context. - * - * Results: - * The contents of name, possibly expanded. - */ -static char * -VarPossiblyExpand(const char *name, GNode *ctxt) -{ - Buffer *buf; - - if (strchr(name, '$') != NULL) { - buf = Var_Subst(name, ctxt, 0); - return (Buf_Peel(buf)); - } else { - return estrdup(name); - } -} - -/** - * If the variable name begins with a '.', it could very well be - * one of the local ones. We check the name against all the local - * variables and substitute the short version in for 'name' if it - * matches one of them. - */ -static const char * -VarLocal(const char name[]) -{ - if (name[0] == '.') { - switch (name[1]) { - case 'A': - if (!strcmp(name, ".ALLSRC")) - return (ALLSRC); - if (!strcmp(name, ".ARCHIVE")) - return (ARCHIVE); - break; - case 'I': - if (!strcmp(name, ".IMPSRC")) - return (IMPSRC); - break; - case 'M': - if (!strcmp(name, ".MEMBER")) - return (MEMBER); - break; - case 'O': - if (!strcmp(name, ".OODATE")) - return (OODATE); - break; - case 'P': - if (!strcmp(name, ".PREFIX")) - return (PREFIX); - break; - case 'T': - if (!strcmp(name, ".TARGET")) - return (TARGET); - break; - default: - break; - } - } - return (name); -} - -/** - * Find the given variable in the given context and the environment. - * - * Results: - * A pointer to the structure describing the desired variable or - * NULL if the variable does not exist. - */ -static Var * -VarFindEnv(const char name[], GNode *ctxt) -{ - Var *var; - - name = VarLocal(name); - - if ((var = VarLookup(&ctxt->context, name)) != NULL) - return (var); - - if ((var = VarLookup(&VAR_ENV->context, name)) != NULL) - return (var); - - return (NULL); -} - -/** - * Look for the variable in the given context. - */ -static Var * -VarFindOnly(const char name[], GNode *ctxt) -{ - Var *var; - - name = VarLocal(name); - - if ((var = VarLookup(&ctxt->context, name)) != NULL) - return (var); - - return (NULL); -} - -/** - * Look for the variable in all contexts. - */ -static Var * -VarFindAny(const char name[], GNode *ctxt) -{ - Boolean localCheckEnvFirst; - LstNode *ln; - Var *var; - - name = VarLocal(name); - - /* - * Note whether this is one of the specific variables we were told - * through the -E flag to use environment-variable-override for. - */ - localCheckEnvFirst = FALSE; - LST_FOREACH(ln, &envFirstVars) { - if (strcmp(Lst_Datum(ln), name) == 0) { - localCheckEnvFirst = TRUE; - break; - } - } - - /* - * First look for the variable in the given context. If it's not there, - * look for it in VAR_CMD, VAR_GLOBAL and the environment, - * in that order, depending on the FIND_* flags in 'flags' - */ - if ((var = VarLookup(&ctxt->context, name)) != NULL) - return (var); - - /* not there - try command line context */ - if (ctxt != VAR_CMD) { - if ((var = VarLookup(&VAR_CMD->context, name)) != NULL) - return (var); - } - - /* not there - try global context, but only if not -e/-E */ - if (ctxt != VAR_GLOBAL && (!checkEnvFirst && !localCheckEnvFirst)) { - if ((var = VarLookup(&VAR_GLOBAL->context, name)) != NULL) - return (var); - } - - if ((var = VarLookup(&VAR_ENV->context, name)) != NULL) - return (var); - - /* deferred check for the environment (in case of -e/-E) */ - if ((ctxt != VAR_GLOBAL) && (checkEnvFirst || localCheckEnvFirst)) { - if ((var = VarLookup(&VAR_GLOBAL->context, name)) != NULL) - return (var); - } - - return (NULL); -} - -/** - * Add a new variable of name name and value val to the given context. - * - * Side Effects: - * The new variable is placed at the front of the given context - * The name and val arguments are duplicated so they may - * safely be freed. - */ -static Var * -VarAdd(const char *name, const char *val, GNode *ctxt) -{ - Var *v; - - Lst_AtFront(&ctxt->context, v = VarCreate(name, val, 0)); - DEBUGF(VAR, ("%s:%s = %s\n", ctxt->name, name, val)); - return (v); -} - -/** - * Remove a variable from a context. - * - * Side Effects: - * The Var structure is removed and freed. - */ -void -Var_Delete(const char *name, GNode *ctxt) -{ - LstNode *ln; - - DEBUGF(VAR, ("%s:delete %s\n", ctxt->name, name)); - LST_FOREACH(ln, &ctxt->context) { - if (strcmp(((const Var *)Lst_Datum(ln))->name, name) == 0) { - VarDestroy(Lst_Datum(ln), TRUE); - Lst_Remove(&ctxt->context, ln); - break; - } - } -} - -/** - * Set the variable name to the value val in the given context. - * - * Side Effects: - * If the variable doesn't yet exist, a new record is created for it. - * Else the old value is freed and the new one stuck in its place - * - * Notes: - * The variable is searched for only in its context before being - * created in that context. I.e. if the context is VAR_GLOBAL, - * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only - * VAR_CMD->context is searched. This is done to avoid the literally - * thousands of unnecessary strcmp's that used to be done to - * set, say, $(@) or $(<). - */ -void -Var_Set(const char *name, const char *val, GNode *ctxt) -{ - Var *v; - char *n; - - /* - * We only look for a variable in the given context since anything - * set here will override anything in a lower context, so there's not - * much point in searching them all just to save a bit of memory... - */ - n = VarPossiblyExpand(name, ctxt); - v = VarFindOnly(n, ctxt); - if (v == NULL) { - v = VarAdd(n, val, ctxt); - } else { - Buf_Clear(v->val); - Buf_Append(v->val, val); - DEBUGF(VAR, ("%s:%s = %s\n", ctxt->name, n, val)); - } - - if (ctxt == VAR_CMD || (v->flags & VAR_TO_ENV)) { - /* - * Any variables given on the command line - * are automatically exported to the - * environment (as per POSIX standard) - */ - setenv(n, val, 1); - } - - free(n); -} - -/** - * Set the a global name variable to the value. - */ -void -Var_SetGlobal(const char name[], const char value[]) -{ - - Var_Set(name, value, VAR_GLOBAL); -} - - -/** - * Set the VAR_TO_ENV flag on a variable - */ -void -Var_SetEnv(const char *name, GNode *ctxt) -{ - Var *v; - - v = VarFindOnly(name, VAR_CMD); - if (v != NULL) { - /* - * Do not allow .EXPORT: to be set on variables - * from the comand line or MAKEFLAGS. - */ - Error( - "Warning: Did not set .EXPORTVAR: on %s because it " - "is from the comand line or MAKEFLAGS", name); - return; - } - - v = VarFindAny(name, ctxt); - if (v == NULL) { - Lst_AtFront(&VAR_ENV->context, - VarCreate(name, NULL, VAR_TO_ENV)); - setenv(name, "", 1); - Error("Warning: .EXPORTVAR: set on undefined variable %s", name); - } else { - if ((v->flags & VAR_TO_ENV) == 0) { - v->flags |= VAR_TO_ENV; - setenv(v->name, Buf_Data(v->val), 1); - } - } -} - -/** - * The variable of the given name has the given value appended to it in - * the given context. - * - * Side Effects: - * If the variable doesn't exist, it is created. Else the strings - * are concatenated (with a space in between). - * - * Notes: - * Only if the variable is being sought in the global context is the - * environment searched. - * XXX: Knows its calling circumstances in that if called with ctxt - * an actual target, it will only search that context since only - * a local variable could be being appended to. This is actually - * a big win and must be tolerated. - */ -void -Var_Append(const char *name, const char *val, GNode *ctxt) -{ - Var *v; - char *n; - - n = VarPossiblyExpand(name, ctxt); - if (ctxt == VAR_GLOBAL) { - v = VarFindEnv(n, ctxt); - } else { - v = VarFindOnly(n, ctxt); - } - if (v == NULL) { - VarAdd(n, val, ctxt); - } else { - Buf_AddByte(v->val, (Byte)' '); - Buf_Append(v->val, val); - DEBUGF(VAR, ("%s:%s = %s\n", ctxt->name, n, Buf_Data(v->val))); - } - free(n); -} - -/** - * See if the given variable exists. - * - * Results: - * TRUE if it does, FALSE if it doesn't - */ -Boolean -Var_Exists(const char *name, GNode *ctxt) -{ - Var *v; - char *n; - - n = VarPossiblyExpand(name, ctxt); - v = VarFindAny(n, ctxt); - if (v == NULL) { - free(n); - return (FALSE); - } else { - free(n); - return (TRUE); - } -} - -/** - * Return the value of the named variable in the given context - * - * Results: - * The value if the variable exists, NULL if it doesn't. - */ -const char * -Var_Value(const char name[], GNode *ctxt) -{ - Var *v; - char *n; - - n = VarPossiblyExpand(name, ctxt); - v = VarFindAny(n, ctxt); - free(n); - if (v == NULL) { - return (NULL); - } else { - return (Buf_Data(v->val)); - } -} - -/** - * Modify each of the words of the passed string using the given - * function. Used to implement all modifiers. - * - * Results: - * A string of all the words modified appropriately. - * - * Side Effects: - * Uses brk_string() so it invalidates any previous call to - * brk_string(). - */ -static char * -VarModify(const char *str, VarModifyProc *modProc, void *datum) -{ - ArgArray aa; - Buffer *buf; /* Buffer for the new string */ - int i; - Boolean addSpace; /* - * TRUE if need to add a space to - * the buffer before adding the - * trimmed word - */ - - brk_string(&aa, str, FALSE); - - addSpace = FALSE; - buf = Buf_Init(0); - for (i = 1; i < aa.argc; i++) - addSpace = (*modProc)(aa.argv[i], addSpace, buf, datum); - - ArgArray_Done(&aa); - return (Buf_Peel(buf)); -} - -/** - * Sort the words in the string. - * - * Input: - * str String whose words should be sorted - * cmp A comparison function to control the ordering - * - * Results: - * A string containing the words sorted - */ -static char * -VarSortWords(const char *str, int (*cmp)(const void *, const void *)) -{ - ArgArray aa; - Buffer *buf; - int i; - - brk_string(&aa, str, FALSE); - qsort(aa.argv + 1, aa.argc - 1, sizeof(char *), cmp); - - buf = Buf_Init(0); - for (i = 1; i < aa.argc; i++) { - Buf_Append(buf, aa.argv[i]); - Buf_AddByte(buf, (Byte)((i < aa.argc - 1) ? ' ' : '\0')); - } - - ArgArray_Done(&aa); - return (Buf_Peel(buf)); -} - -static int -SortIncreasing(const void *l, const void *r) -{ - - return (strcmp(*(const char* const*)l, *(const char* const*)r)); -} - -/** - * Remove adjacent duplicate words. - * - * Results: - * A string containing the resulting words. - */ -static char * -VarUniq(const char *str) -{ - ArgArray aa; - Buffer *buf; /* Buffer for new string */ - int i, j; - - buf = Buf_Init(0); - brk_string(&aa, str, FALSE); - - if (aa.argc > 2) { - for (j = 1, i = 2; i < aa.argc; i++) { - if (strcmp(aa.argv[i], aa.argv[j]) != 0 && (++j != i)) - aa.argv[j] = aa.argv[i]; - } - aa.argc = j + 1; - } - - for (i = 1; i < aa.argc; i++) { - Buf_AddBytes(buf, strlen(aa.argv[i]), (Byte *)aa.argv[i]); - if (i != aa.argc - 1) - Buf_AddByte(buf, ' '); - } - Buf_AddByte(buf, '\0'); - - ArgArray_Done(&aa); - return (Buf_Peel(buf)); -} - -/** - * Pass through the tstr looking for 1) escaped delimiters, - * '$'s and backslashes (place the escaped character in - * uninterpreted) and 2) unescaped $'s that aren't before - * the delimiter (expand the variable substitution). - * Return the expanded string or NULL if the delimiter was missing - * If pattern is specified, handle escaped ampersands, and replace - * unescaped ampersands with the lhs of the pattern. - * - * Results: - * A string of all the words modified appropriately. - * If length is specified, return the string length of the buffer - * If flags is specified and the last character of the pattern is a - * $ set the VAR_MATCH_END bit of flags. - */ -static Buffer * -VarGetPattern(VarParser *vp, int delim, int *flags, VarPattern *patt) -{ - Buffer *buf; - - buf = Buf_Init(0); - - /* - * Skim through until the matching delimiter is found; pick up - * variable substitutions on the way. Also allow backslashes to quote - * the delimiter, $, and \, but don't touch other backslashes. - */ - while (*vp->ptr != '\0') { - if (*vp->ptr == delim) { - return (buf); - - } else if ((vp->ptr[0] == '\\') && - ((vp->ptr[1] == delim) || - (vp->ptr[1] == '\\') || - (vp->ptr[1] == '$') || - (vp->ptr[1] == '&' && patt != NULL))) { - vp->ptr++; /* consume backslash */ - Buf_AddByte(buf, (Byte)vp->ptr[0]); - vp->ptr++; - - } else if (vp->ptr[0] == '$') { - if (vp->ptr[1] == delim) { - if (flags == NULL) { - Buf_AddByte(buf, (Byte)vp->ptr[0]); - vp->ptr++; - } else { - /* - * Unescaped $ at end of patt => - * anchor patt at end. - */ - *flags |= VAR_MATCH_END; - vp->ptr++; - } - } else { - VarParser subvp = { - vp->ptr, - vp->ptr, - vp->ctxt, - vp->err, - vp->execute - }; - char *rval; - Boolean rfree; - - /* - * If unescaped dollar sign not - * before the delimiter, assume it's - * a variable substitution and - * recurse. - */ - rval = VarParse(&subvp, &rfree); - Buf_Append(buf, rval); - if (rfree) - free(rval); - vp->ptr = subvp.ptr; - } - } else if (vp->ptr[0] == '&' && patt != NULL) { - Buf_AppendBuf(buf, patt->lhs); - vp->ptr++; - } else { - Buf_AddByte(buf, (Byte)vp->ptr[0]); - vp->ptr++; - } - } - - Buf_Destroy(buf, TRUE); - return (NULL); -} - -/** - * Make sure this variable is fully expanded. - */ -static char * -VarExpand(Var *v, VarParser *vp) -{ - char *value; - char *result; - - if (v->flags & VAR_IN_USE) { - Fatal("Variable %s is recursive.", v->name); - /* NOTREACHED */ - } - - v->flags |= VAR_IN_USE; - - /* - * Before doing any modification, we have to make sure the - * value has been fully expanded. If it looks like recursion - * might be necessary (there's a dollar sign somewhere in the - * variable's value) we just call Var_Subst to do any other - * substitutions that are necessary. Note that the value - * returned by Var_Subst will have been - * dynamically-allocated, so it will need freeing when we - * return. - */ - value = Buf_Data(v->val); - if (strchr(value, '$') == NULL) { - result = strdup(value); - } else { - Buffer *buf; - - buf = Var_Subst(value, vp->ctxt, vp->err); - result = Buf_Peel(buf); - } - - v->flags &= ~VAR_IN_USE; - - return (result); -} - -/** - * Select only those words in value that match the modifier. - */ -static char * -modifier_M(VarParser *vp, const char value[], char endc) -{ - char *patt; - char *ptr; - char *newValue; - char modifier; - - modifier = vp->ptr[0]; - vp->ptr++; /* consume 'M' or 'N' */ - - /* - * Compress the \:'s out of the pattern, so allocate enough - * room to hold the uncompressed pattern and compress the - * pattern into that space. - */ - patt = estrdup(vp->ptr); - ptr = patt; - while (vp->ptr[0] != '\0') { - if (vp->ptr[0] == endc || vp->ptr[0] == ':') { - break; - } - if (vp->ptr[0] == '\\' && - (vp->ptr[1] == endc || vp->ptr[1] == ':')) { - vp->ptr++; /* consume backslash */ - } - *ptr = vp->ptr[0]; - ptr++; - vp->ptr++; - } - *ptr = '\0'; - DEBUGF(VAR, ("Pattern :%s\n", patt)); - - if (modifier == 'M') { - newValue = VarModify(value, VarMatch, patt); - } else { - newValue = VarModify(value, VarNoMatch, patt); - } - free(patt); - - return (newValue); -} - -/** - * Substitute the replacement string for the pattern. The substitution - * is applied to each word in value. - */ -static char * -modifier_S(VarParser *vp, const char value[], Var *v) -{ - VarPattern patt; - char delim; - char *newValue; - - patt.flags = 0; - - vp->ptr++; /* consume 'S' */ - - delim = *vp->ptr; /* used to find end of pattern */ - vp->ptr++; /* consume 1st delim */ - - /* - * If pattern begins with '^', it is anchored to the start of the - * word -- skip over it and flag pattern. - */ - if (*vp->ptr == '^') { - patt.flags |= VAR_MATCH_START; - vp->ptr++; - } - - patt.lhs = VarGetPattern(vp, delim, &patt.flags, NULL); - if (patt.lhs == NULL) { - /* - * LHS didn't end with the delim, complain and exit. - */ - Fatal("Unclosed substitution for %s (%c missing)", - v->name, delim); - } - - vp->ptr++; /* consume 2nd delim */ - - patt.rhs = VarGetPattern(vp, delim, NULL, &patt); - if (patt.rhs == NULL) { - /* - * RHS didn't end with the delim, complain and exit. - */ - Fatal("Unclosed substitution for %s (%c missing)", - v->name, delim); - } - - vp->ptr++; /* consume last delim */ - - /* - * Check for global substitution. If 'g' after the final delimiter, - * substitution is global and is marked that way. - */ - if (vp->ptr[0] == 'g') { - patt.flags |= VAR_SUB_GLOBAL; - vp->ptr++; - } - - /* - * Global substitution of the empty string causes an infinite number - * of matches, unless anchored by '^' (start of string) or '$' (end - * of string). Catch the infinite substitution here. Note that flags - * can only contain the 3 bits we're interested in so we don't have - * to mask unrelated bits. We can test for equality. - */ - if (Buf_Size(patt.lhs) == 0 && patt.flags == VAR_SUB_GLOBAL) - Fatal("Global substitution of the empty string"); - - newValue = VarModify(value, VarSubstitute, &patt); - - /* - * Free the two strings. - */ - free(patt.lhs); - free(patt.rhs); - - return (newValue); -} - -static char * -modifier_C(VarParser *vp, char value[], Var *v) -{ - VarPattern patt; - char delim; - int error; - char *newValue; - - patt.flags = 0; - - vp->ptr++; /* consume 'C' */ - - delim = *vp->ptr; /* delimiter between sections */ - - vp->ptr++; /* consume 1st delim */ - - patt.lhs = VarGetPattern(vp, delim, NULL, NULL); - if (patt.lhs == NULL) { - Fatal("Unclosed substitution for %s (%c missing)", - v->name, delim); - } - - vp->ptr++; /* consume 2st delim */ - - patt.rhs = VarGetPattern(vp, delim, NULL, NULL); - if (patt.rhs == NULL) { - Fatal("Unclosed substitution for %s (%c missing)", - v->name, delim); - } - - vp->ptr++; /* consume last delim */ - - switch (*vp->ptr) { - case 'g': - patt.flags |= VAR_SUB_GLOBAL; - vp->ptr++; /* consume 'g' */ - break; - case '1': - patt.flags |= VAR_SUB_ONE; - vp->ptr++; /* consume '1' */ - break; - default: - break; - } - - error = regcomp(&patt.re, Buf_Data(patt.lhs), REG_EXTENDED); - if (error) { - VarREError(error, &patt.re, "RE substitution error"); - free(patt.rhs); - free(patt.lhs); - return (var_Error); - } - - patt.nsub = patt.re.re_nsub + 1; - if (patt.nsub < 1) - patt.nsub = 1; - if (patt.nsub > 10) - patt.nsub = 10; - patt.matches = emalloc(patt.nsub * sizeof(regmatch_t)); - - newValue = VarModify(value, VarRESubstitute, &patt); - - regfree(&patt.re); - free(patt.matches); - free(patt.rhs); - free(patt.lhs); - - return (newValue); -} - -static char * -sysVvarsub(VarParser *vp, char startc, Var *v, const char value[]) -{ -#ifdef SYSVVARSUB - /* - * This can either be a bogus modifier or a System-V substitution - * command. - */ - char endc; - VarPattern patt; - Boolean eqFound; - int cnt; - char *newStr; - const char *cp; - - endc = (startc == OPEN_PAREN) ? CLOSE_PAREN : CLOSE_BRACE; - - patt.flags = 0; - - /* - * First we make a pass through the string trying to verify it is a - * SYSV-make-style translation: it must be: =) - */ - eqFound = FALSE; - cp = vp->ptr; - cnt = 1; - while (*cp != '\0' && cnt) { - if (*cp == '=') { - eqFound = TRUE; - /* continue looking for endc */ - } else if (*cp == endc) - cnt--; - else if (*cp == startc) - cnt++; - if (cnt) - cp++; - } - - if (*cp == endc && eqFound) { - /* - * Now we break this sucker into the lhs and rhs. - */ - patt.lhs = VarGetPattern(vp, '=', &patt.flags, NULL); - if (patt.lhs == NULL) { - Fatal("Unclosed substitution for %s (%c missing)", - v->name, '='); - } - vp->ptr++; /* consume '=' */ - - patt.rhs = VarGetPattern(vp, endc, NULL, &patt); - if (patt.rhs == NULL) { - Fatal("Unclosed substitution for %s (%c missing)", - v->name, endc); - } - - /* - * SYSV modifications happen through the whole string. Note - * the pattern is anchored at the end. - */ - newStr = VarModify(value, VarSYSVMatch, &patt); - - free(patt.lhs); - free(patt.rhs); - } else -#endif - { - Error("Unknown modifier '%c'\n", *vp->ptr); - vp->ptr++; - while (*vp->ptr != '\0') { - if (*vp->ptr == endc && *vp->ptr == ':') { - break; - } - vp->ptr++; - } - newStr = var_Error; - } - - return (newStr); -} - -/** - * Quote shell meta-characters in the string - * - * Results: - * The quoted string - */ -static char * -Var_Quote(const char *str) -{ - Buffer *buf; - /* This should cover most shells :-( */ - static char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~"; - - buf = Buf_Init(MAKE_BSIZE); - for (; *str; str++) { - if (strchr(meta, *str) != NULL) - Buf_AddByte(buf, (Byte)'\\'); - Buf_AddByte(buf, (Byte)*str); - } - - return (Buf_Peel(buf)); -} - - -/* - * Now we need to apply any modifiers the user wants applied. - * These are: - * :M - * words which match the given . - * is of the standard file - * wildcarding form. - * :N - * words which do not match the given - * is of the standard file - * wildcarding form. - * :S[g] - * Substitute for in the value - * :C[g] - * Substitute for regex in the value - * :H Substitute the head of each word - * :T Substitute the tail of each word - * :E Substitute the extension (minus '.') of - * each word - * :R Substitute the root of each word - * (pathname minus the suffix). - * :lhs=rhs - * Like :S, but the rhs goes to the end of - * the invocation. - * :U Converts variable to upper-case. - * :L Converts variable to lower-case. - * :O ("Order") Alphabeticaly sort words in variable. - * :u ("uniq") Remove adjacent duplicate words. - */ -static char * -ParseModifier(VarParser *vp, char startc, Var *v, Boolean *freeResult) -{ - char *value; - char endc; - - value = VarExpand(v, vp); - *freeResult = TRUE; - - endc = (startc == OPEN_PAREN) ? CLOSE_PAREN : CLOSE_BRACE; - - vp->ptr++; /* consume first colon */ - - while (*vp->ptr != '\0') { - char *newStr; /* New value to return */ - - if (*vp->ptr == endc) { - return (value); - } - - DEBUGF(VAR, ("Applying :%c to \"%s\"\n", *vp->ptr, value)); - switch (*vp->ptr) { - case 'N': - case 'M': - newStr = modifier_M(vp, value, endc); - break; - case 'S': - newStr = modifier_S(vp, value, v); - break; - case 'C': - newStr = modifier_C(vp, value, v); - break; - case 't': - /* :tl :tu for OSF ODE & NetBSD make compatibility */ - switch (vp->ptr[1]) { - case 'l': - vp->ptr++; - goto mod_lower; - break; - case 'u': - vp->ptr++; - goto mod_upper; - break; - } - /* FALLTHROUGH */ - default: - if (vp->ptr[1] != endc && vp->ptr[1] != ':') { -#ifdef SUNSHCMD - if ((vp->ptr[0] == 's') && - (vp->ptr[1] == 'h') && - (vp->ptr[2] == endc || vp->ptr[2] == ':')) { - const char *error = NULL; - - if (vp->execute) { - newStr = Buf_Peel( - Cmd_Exec(value, &error)); - } else { - newStr = estrdup(""); - } - - if (error) - Error(error, value); - vp->ptr += 2; - } else -#endif - { - newStr = sysVvarsub(vp, startc, v, value); - } - break; - } - - switch (vp->ptr[0]) { - case 'L': - mod_lower: - { - const char *cp; - Buffer *buf; - buf = Buf_Init(MAKE_BSIZE); - for (cp = value; *cp; cp++) - Buf_AddByte(buf, (Byte)tolower(*cp)); - - newStr = Buf_Peel(buf); - - vp->ptr++; - break; - } - case 'O': - newStr = VarSortWords(value, SortIncreasing); - vp->ptr++; - break; - case 'Q': - newStr = Var_Quote(value); - vp->ptr++; - break; - case 'T': - newStr = VarModify(value, VarTail, NULL); - vp->ptr++; - break; - case 'U': - mod_upper: - { - const char *cp; - Buffer *buf; - buf = Buf_Init(MAKE_BSIZE); - for (cp = value; *cp; cp++) - Buf_AddByte(buf, (Byte)toupper(*cp)); - - newStr = Buf_Peel(buf); - - vp->ptr++; - break; - } - case 'H': - newStr = VarModify(value, VarHead, NULL); - vp->ptr++; - break; - case 'E': - newStr = VarModify(value, VarSuffix, NULL); - vp->ptr++; - break; - case 'R': - newStr = VarModify(value, VarRoot, NULL); - vp->ptr++; - break; - case 'u': - newStr = VarUniq(value); - vp->ptr++; - break; - default: - newStr = sysVvarsub(vp, startc, v, value); - break; - } - break; - } - - DEBUGF(VAR, ("Result is \"%s\"\n", newStr)); - if (*freeResult) { - free(value); - } - - value = newStr; - *freeResult = (value == var_Error) ? FALSE : TRUE; - - if (vp->ptr[0] == ':') { - vp->ptr++; /* consume colon */ - } - } - - return (value); -} - -static char * -ParseRestModifier(VarParser *vp, char startc, Buffer *buf, Boolean *freeResult) -{ - const char *vname; - size_t vlen; - Var *v; - char *value; - - vname = Buf_GetAll(buf, &vlen); - - v = VarFindAny(vname, vp->ctxt); - if (v != NULL) { - value = ParseModifier(vp, startc, v, freeResult); - return (value); - } - - if ((vp->ctxt == VAR_CMD) || (vp->ctxt == VAR_GLOBAL)) { - size_t consumed; - /* - * Still need to get to the end of the variable - * specification, so kludge up a Var structure for the - * modifications - */ - v = VarCreate(vname, NULL, VAR_JUNK); - value = ParseModifier(vp, startc, v, freeResult); - if (*freeResult) { - free(value); - } - VarDestroy(v, TRUE); - - consumed = vp->ptr - vp->input + 1; - /* - * If substituting a local variable in a non-local context, - * assume it's for dynamic source stuff. We have to handle - * this specially and return the longhand for the variable - * with the dollar sign escaped so it makes it back to the - * caller. Only four of the local variables are treated - * specially as they are the only four that will be set when - * dynamic sources are expanded. - */ - if (vlen == 1 || - (vlen == 2 && (vname[1] == 'F' || vname[1] == 'D'))) { - if (strchr("!%*@", vname[0]) != NULL) { - value = emalloc(consumed + 1); - strncpy(value, vp->input, consumed); - value[consumed] = '\0'; - - *freeResult = TRUE; - return (value); - } - } - if (vlen > 2 && - vname[0] == '.' && - isupper((unsigned char)vname[1])) { - if ((strncmp(vname, ".TARGET", vlen - 1) == 0) || - (strncmp(vname, ".ARCHIVE", vlen - 1) == 0) || - (strncmp(vname, ".PREFIX", vlen - 1) == 0) || - (strncmp(vname, ".MEMBER", vlen - 1) == 0)) { - value = emalloc(consumed + 1); - strncpy(value, vp->input, consumed); - value[consumed] = '\0'; - - *freeResult = TRUE; - return (value); - } - } - - *freeResult = FALSE; - return (vp->err ? var_Error : varNoError); - } else { - /* - * Check for D and F forms of local variables since we're in - * a local context and the name is the right length. - */ - if (vlen == 2 && - (vname[1] == 'F' || vname[1] == 'D') && - (strchr("!%*<>@", vname[0]) != NULL)) { - char name[2]; - - name[0] = vname[0]; - name[1] = '\0'; - - v = VarFindOnly(name, vp->ctxt); - if (v != NULL) { - value = ParseModifier(vp, startc, v, freeResult); - return (value); - } - } - - /* - * Still need to get to the end of the variable - * specification, so kludge up a Var structure for the - * modifications - */ - v = VarCreate(vname, NULL, VAR_JUNK); - value = ParseModifier(vp, startc, v, freeResult); - if (*freeResult) { - free(value); - } - VarDestroy(v, TRUE); - - *freeResult = FALSE; - return (vp->err ? var_Error : varNoError); - } -} - -static char * -ParseRestEnd(VarParser *vp, Buffer *buf, Boolean *freeResult) -{ - const char *vname; - size_t vlen; - Var *v; - char *value; - - vname = Buf_GetAll(buf, &vlen); - - v = VarFindAny(vname, vp->ctxt); - if (v != NULL) { - value = VarExpand(v, vp); - *freeResult = TRUE; - return (value); - } - - if ((vp->ctxt == VAR_CMD) || (vp->ctxt == VAR_GLOBAL)) { - size_t consumed = vp->ptr - vp->input + 1; - - /* - * If substituting a local variable in a non-local context, - * assume it's for dynamic source stuff. We have to handle - * this specially and return the longhand for the variable - * with the dollar sign escaped so it makes it back to the - * caller. Only four of the local variables are treated - * specially as they are the only four that will be set when - * dynamic sources are expanded. - */ - if (vlen == 1 || - (vlen == 2 && (vname[1] == 'F' || vname[1] == 'D'))) { - if (strchr("!%*@", vname[0]) != NULL) { - value = emalloc(consumed + 1); - strncpy(value, vp->input, consumed); - value[consumed] = '\0'; - - *freeResult = TRUE; - return (value); - } - } - if (vlen > 2 && - vname[0] == '.' && - isupper((unsigned char)vname[1])) { - if ((strncmp(vname, ".TARGET", vlen - 1) == 0) || - (strncmp(vname, ".ARCHIVE", vlen - 1) == 0) || - (strncmp(vname, ".PREFIX", vlen - 1) == 0) || - (strncmp(vname, ".MEMBER", vlen - 1) == 0)) { - value = emalloc(consumed + 1); - strncpy(value, vp->input, consumed); - value[consumed] = '\0'; - - *freeResult = TRUE; - return (value); - } - } - } else { - /* - * Check for D and F forms of local variables since we're in - * a local context and the name is the right length. - */ - if (vlen == 2 && - (vname[1] == 'F' || vname[1] == 'D') && - (strchr("!%*<>@", vname[0]) != NULL)) { - char name[2]; - - name[0] = vname[0]; - name[1] = '\0'; - - v = VarFindOnly(name, vp->ctxt); - if (v != NULL) { - char *val; - /* - * No need for nested expansion or anything, - * as we're the only one who sets these - * things and we sure don't put nested - * invocations in them... - */ - val = Buf_Data(v->val); - - if (vname[1] == 'D') { - val = VarModify(val, VarHead, NULL); - } else { - val = VarModify(val, VarTail, NULL); - } - - *freeResult = TRUE; - return (val); - } - } - } - - *freeResult = FALSE; - return (vp->err ? var_Error : varNoError); -} - -/** - * Parse a multi letter variable name, and return it's value. - */ -static char * -VarParseLong(VarParser *vp, Boolean *freeResult) -{ - Buffer *buf; - char startc; - char endc; - char *value; - - buf = Buf_Init(MAKE_BSIZE); - - startc = vp->ptr[0]; - vp->ptr++; /* consume opening paren or brace */ - - endc = (startc == OPEN_PAREN) ? CLOSE_PAREN : CLOSE_BRACE; - - /* - * Process characters until we reach an end character or a colon, - * replacing embedded variables as we go. - */ - while (*vp->ptr != '\0') { - if (*vp->ptr == endc) { - value = ParseRestEnd(vp, buf, freeResult); - vp->ptr++; /* consume closing paren or brace */ - Buf_Destroy(buf, TRUE); - return (value); - - } else if (*vp->ptr == ':') { - value = ParseRestModifier(vp, startc, buf, freeResult); - vp->ptr++; /* consume closing paren or brace */ - Buf_Destroy(buf, TRUE); - return (value); - - } else if (*vp->ptr == '$') { - VarParser subvp = { - vp->ptr, - vp->ptr, - vp->ctxt, - vp->err, - vp->execute - }; - char *rval; - Boolean rfree; - - rval = VarParse(&subvp, &rfree); - if (rval == var_Error) { - Fatal("Error expanding embedded variable."); - } - Buf_Append(buf, rval); - if (rfree) - free(rval); - vp->ptr = subvp.ptr; - } else { - Buf_AddByte(buf, (Byte)*vp->ptr); - vp->ptr++; - } - } - - /* If we did not find the end character, return var_Error */ - Buf_Destroy(buf, TRUE); - *freeResult = FALSE; - return (var_Error); -} - -/** - * Parse a single letter variable name, and return it's value. - */ -static char * -VarParseShort(VarParser *vp, Boolean *freeResult) -{ - char vname[2]; - Var *v; - char *value; - - vname[0] = vp->ptr[0]; - vname[1] = '\0'; - - vp->ptr++; /* consume single letter */ - - v = VarFindAny(vname, vp->ctxt); - if (v != NULL) { - value = VarExpand(v, vp); - *freeResult = TRUE; - return (value); - } - - /* - * If substituting a local variable in a non-local context, assume - * it's for dynamic source stuff. We have to handle this specially - * and return the longhand for the variable with the dollar sign - * escaped so it makes it back to the caller. Only four of the local - * variables are treated specially as they are the only four that - * will be set when dynamic sources are expanded. - */ - if ((vp->ctxt == VAR_CMD) || (vp->ctxt == VAR_GLOBAL)) { - - /* XXX: It looks like $% and $! are reversed here */ - switch (vname[0]) { - case '@': - *freeResult = TRUE; - return (estrdup("$(.TARGET)")); - case '%': - *freeResult = TRUE; - return (estrdup("$(.ARCHIVE)")); - case '*': - *freeResult = TRUE; - return (estrdup("$(.PREFIX)")); - case '!': - *freeResult = TRUE; - return (estrdup("$(.MEMBER)")); - default: - *freeResult = FALSE; - return (vp->err ? var_Error : varNoError); - } - } - - /* Variable name was not found. */ - *freeResult = FALSE; - return (vp->err ? var_Error : varNoError); -} - -static char * -VarParse(VarParser *vp, Boolean *freeResult) -{ - - vp->ptr++; /* consume '$' or last letter of conditional */ - - if (vp->ptr[0] == '\0') { - /* Error, there is only a dollar sign in the input string. */ - *freeResult = FALSE; - return (vp->err ? var_Error : varNoError); - - } else if (vp->ptr[0] == OPEN_PAREN || vp->ptr[0] == OPEN_BRACE) { - /* multi letter variable name */ - return (VarParseLong(vp, freeResult)); - - } else { - /* single letter variable name */ - return (VarParseShort(vp, freeResult)); - } -} - -/** - * Given the start of a variable invocation, extract the variable - * name and find its value, then modify it according to the - * specification. - * - * Results: - * The value of the variable or var_Error if the specification - * is invalid. The number of characters in the specification - * is placed in the variable pointed to by consumed. (for - * invalid specifications, this is just 2 to skip the '$' and - * the following letter, or 1 if '$' was the last character - * in the string). A Boolean in *freeResult telling whether the - * returned string should be freed by the caller. - */ -char * -Var_Parse(const char input[], GNode *ctxt, Boolean err, - size_t *consumed, Boolean *freeResult) -{ - VarParser vp = { - input, - input, - ctxt, - err, - TRUE - }; - char *value; - - value = VarParse(&vp, freeResult); - *consumed += vp.ptr - vp.input; - return (value); -} - -/* - * Given the start of a variable invocation, determine the length - * of the specification. - * - * Results: - * The number of characters in the specification. For invalid - * specifications, this is just 2 to skip the '$' and the - * following letter, or 1 if '$' was the last character in the - * string. - */ -size_t -Var_Match(const char input[], GNode *ctxt) -{ - VarParser vp = { - input, - input, - ctxt, - FALSE, - FALSE - }; - char *value; - Boolean freeResult; - - value = VarParse(&vp, &freeResult); - if (freeResult) { - free(value); - } - return (vp.ptr - vp.input); -} - -static int -match_var(const char str[], const char var[]) -{ - const char *start = str; - size_t len; - - str++; /* consume '$' */ - - if (str[0] == OPEN_PAREN || str[0] == OPEN_BRACE) { - str++; /* consume opening paren or brace */ - - while (str[0] != '\0') { - if (str[0] == '$') { - /* - * A variable inside the variable. We cannot - * expand the external variable yet. - */ - return (str - start); - } else if (str[0] == ':' || - str[0] == CLOSE_PAREN || - str[0] == CLOSE_BRACE) { - len = str - (start + 2); - - if (strncmp(var, start + 2, len) == 0 && var[len] == '\0') { - return (0); /* match */ - } else { - /* - * Not the variable we want to - * expand. - */ - return (str - start); - } - } else { - ++str; - } - } - return (str - start); - } else { - /* Single letter variable name */ - if (var[1] == '\0' && var[0] == str[0]) { - return (0); /* match */ - } else { - str++; /* consume variable name */ - return (str - start); - } - } -} - -/** - * Substitute for all variables in the given string in the given - * context If err is TRUE, Parse_Error will be called when an - * undefined variable is encountered. - * - * Results: - * The resulting string. - * - * Side Effects: - * None. The old string must be freed by the caller - */ -Buffer * -Var_Subst(const char *str, GNode *ctxt, Boolean err) -{ - Boolean errorReported; - Buffer *buf; /* Buffer for forming things */ - - /* - * Set TRUE if an error has already been reported to prevent a - * plethora of messages when recursing. XXXHB this comment sounds - * wrong. - */ - errorReported = FALSE; - - buf = Buf_Init(0); - while (str[0] != '\0') { - if ((str[0] == '$') && (str[1] == '$')) { - /* - * A dollar sign may be escaped with another dollar - * sign. In such a case, we skip over the escape - * character and store the dollar sign into the - * buffer directly. - */ - str++; - Buf_AddByte(buf, (Byte)str[0]); - str++; - - } else if (str[0] == '$') { - /* Variable invocation. */ - VarParser subvp = { - str, - str, - ctxt, - err, - TRUE - }; - char *rval; - Boolean rfree; - - rval = VarParse(&subvp, &rfree); - - /* - * When we come down here, val should either point to - * the value of this variable, suitably modified, or - * be NULL. Length should be the total length of the - * potential variable invocation (from $ to end - * character...) - */ - if (rval == var_Error || rval == varNoError) { - /* - * If performing old-time variable - * substitution, skip over the variable and - * continue with the substitution. Otherwise, - * store the dollar sign and advance str so - * we continue with the string... - */ - if (oldVars) { - str = subvp.ptr; - } else if (err) { - /* - * If variable is undefined, complain - * and skip the variable. The - * complaint will stop us from doing - * anything when the file is parsed. - */ - if (!errorReported) { - Parse_Error(PARSE_FATAL, - "Undefined variable \"%.*s\"", subvp.ptr - subvp.input, str); - } - errorReported = TRUE; - str = subvp.ptr; - } else { - Buf_AddByte(buf, (Byte)str[0]); - str++; - } - } else { - /* - * Copy all the characters from the variable - * value straight into the new string. - */ - Buf_Append(buf, rval); - if (rfree) { - free(rval); - } - str = subvp.ptr; - } - } else { - Buf_AddByte(buf, (Byte)str[0]); - str++; - } - } - - return (buf); -} - -/** - * Substitute for all variables except if it is the same as 'var', - * in the given string in the given context. If err is TRUE, - * Parse_Error will be called when an undefined variable is - * encountered. - * - * Results: - * The resulting string. - * - * Side Effects: - * None. The old string must be freed by the caller - */ -Buffer * -Var_SubstOnly(const char *var, const char *str, Boolean err) -{ - GNode *ctxt = VAR_GLOBAL; - Boolean errorReported; - Buffer *buf; /* Buffer for forming things */ - - /* - * Set TRUE if an error has already been reported to prevent a - * plethora of messages when recursing. XXXHB this comment sounds - * wrong. - */ - errorReported = FALSE; - - buf = Buf_Init(0); - while (str[0] != '\0') { - if (str[0] == '$') { - int skip; - - skip = match_var(str, var); - if (skip > 0) { - Buf_AddBytes(buf, skip, str); - str += skip; - } else { - /* Variable invocation. */ - VarParser subvp = { - str, - str, - ctxt, - err, - TRUE - }; - char *rval; - Boolean rfree; - - rval = VarParse(&subvp, &rfree); - - /* - * When we get down here, rval should either - * point to the value of this variable, or be - * NULL. - */ - if (rval == var_Error || rval == varNoError) { - /* - * If performing old-time variable - * substitution, skip over the - * variable and continue with the - * substitution. Otherwise, store the - * dollar sign and advance str so we - * continue with the string... - */ - if (oldVars) { - str = subvp.ptr; - } else if (err) { - /* - * If variable is undefined, - * complain and skip the - * variable. The complaint - * will stop us from doing - * anything when the file is - * parsed. - */ - if (!errorReported) { - Parse_Error(PARSE_FATAL, - "Undefined variable \"%.*s\"", subvp.ptr - subvp.input, str); - } - errorReported = TRUE; - str = subvp.ptr; - } else { - Buf_AddByte(buf, (Byte)str[0]); - str++; - } - } else { - /* - * Copy all the characters from the - * variable value straight into the - * new string. - */ - Buf_Append(buf, rval); - if (rfree) { - free(rval); - } - str = subvp.ptr; - } - } - } else { - Buf_AddByte(buf, (Byte)str[0]); - str++; - } - } - - return (buf); -} - -/** - * Initialize the module - * - * Side Effects: - * The VAR_CMD and VAR_GLOBAL contexts are created - */ -void -Var_Init(char **env) -{ - char **ptr; - - VAR_CMD = Targ_NewGN("Command"); - VAR_ENV = Targ_NewGN("Environment"); - VAR_GLOBAL = Targ_NewGN("Global"); - - /* - * Copy user environment variables into ENV context. - */ - for (ptr = env; *ptr != NULL; ++ptr) { - char *tmp = estrdup(*ptr); - const char *name = tmp; - char *sep = strchr(name, '='); - const char *value = sep + 1; - - if (sep != NULL) { - *sep = '\0'; - VarAdd(name, value, VAR_ENV); - } - free(tmp); - } -} - -/** - * Print all variables in global and command line contexts. - */ -void -Var_Dump(void) -{ - const LstNode *ln; - const Var *v; - - printf("#*** Global Variables:\n"); - LST_FOREACH(ln, &VAR_GLOBAL->context) { - v = Lst_Datum(ln); - printf("%-16s = %s\n", v->name, Buf_Data(v->val)); - } - - printf("#*** Command-line Variables:\n"); - LST_FOREACH(ln, &VAR_CMD->context) { - v = Lst_Datum(ln); - printf("%-16s = %s\n", v->name, Buf_Data(v->val)); - } -} - -/** - * Print the values of any variables requested by - * the user. - */ -void -Var_Print(Lst *vlist, Boolean expandVars) -{ - LstNode *n; - char *name; - - LST_FOREACH(n, vlist) { - name = Lst_Datum(n); - if (expandVars) { - char *value; - char *v; - - if (*name == '$') { - v = name; - } else { - v = emalloc(strlen(name) + 1 + 3); - sprintf(v, "${%s}", name); - } - value = Buf_Peel(Var_Subst(v, VAR_GLOBAL, FALSE)); - printf("%s\n", value); - - if (v != name) - free(v); - free(value); - } else { - const char *value = Var_Value(name, VAR_GLOBAL); - printf("%s\n", value != NULL ? value : ""); - } - } -} - Property changes on: head/usr.bin/make/var.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/hash.c =================================================================== --- head/usr.bin/make/hash.c (revision 284463) +++ head/usr.bin/make/hash.c (nonexistent) @@ -1,398 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1988, 1989 by Adam de Boor - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)hash.c 8.1 (Berkeley) 6/6/93 - */ - -#include -__FBSDID("$FreeBSD$"); - -/* hash.c -- - * - * This module contains routines to manipulate a hash table. - * See hash.h for a definition of the structure of the hash - * table. Hash tables grow automatically as the amount of - * information increases. - */ - -#include -#include -#include - -#include "hash.h" -#include "util.h" - -/* - * Forward references to local procedures that are used before they're - * defined: - */ -static void RebuildTable(Hash_Table *); - -/* - * The following defines the ratio of # entries to # buckets - * at which we rebuild the table to make it larger. - */ - -#define rebuildLimit 8 - -/* - *--------------------------------------------------------- - * - * Hash_InitTable -- - * - * Set up the hash table t with a given number of buckets, or a - * reasonable default if the number requested is less than or - * equal to zero. Hash tables will grow in size as needed. - * - * - * Results: - * None. - * - * Side Effects: - * Memory is allocated for the initial bucket area. - * - *--------------------------------------------------------- - */ -void -Hash_InitTable(Hash_Table *t, int numBuckets) -{ - int i; - struct Hash_Entry **hp; - - /* - * Round up the size to a power of two. - */ - if (numBuckets <= 0) - i = 16; - else { - for (i = 2; i < numBuckets; i <<= 1) - continue; - } - t->numEntries = 0; - t->size = i; - t->mask = i - 1; - t->bucketPtr = hp = emalloc(sizeof(*hp) * i); - while (--i >= 0) - *hp++ = NULL; -} - -/* - *--------------------------------------------------------- - * - * Hash_DeleteTable -- - * - * This routine removes everything from a hash table - * and frees up the memory space it occupied (except for - * the space in the Hash_Table structure). - * - * Results: - * None. - * - * Side Effects: - * Lots of memory is freed up. - * - *--------------------------------------------------------- - */ -void -Hash_DeleteTable(Hash_Table *t) -{ - struct Hash_Entry **hp, *h, *nexth = NULL; - int i; - - for (hp = t->bucketPtr, i = t->size; --i >= 0;) { - for (h = *hp++; h != NULL; h = nexth) { - nexth = h->next; - free(h); - } - } - free(t->bucketPtr); - - /* - * Set up the hash table to cause memory faults on any future access - * attempts until re-initialization. - */ - t->bucketPtr = NULL; -} - -/* - *--------------------------------------------------------- - * - * Hash_FindEntry -- - * - * Searches a hash table for an entry corresponding to key. - * - * Results: - * The return value is a pointer to the entry for key, - * if key was present in the table. If key was not - * present, NULL is returned. - * - * Side Effects: - * None. - * - *--------------------------------------------------------- - */ -Hash_Entry * -Hash_FindEntry(const Hash_Table *t, const char *key) -{ - Hash_Entry *e; - unsigned h; - const char *p; - - for (h = 0, p = key; *p;) - h = (h << 5) - h + *p++; - p = key; - for (e = t->bucketPtr[h & t->mask]; e != NULL; e = e->next) - if (e->namehash == h && strcmp(e->name, p) == 0) - return (e); - return (NULL); -} - -/* - *--------------------------------------------------------- - * - * Hash_CreateEntry -- - * - * Searches a hash table for an entry corresponding to - * key. If no entry is found, then one is created. - * - * Results: - * The return value is a pointer to the entry. If *newPtr - * isn't NULL, then *newPtr is filled in with TRUE if a - * new entry was created, and FALSE if an entry already existed - * with the given key. - * - * Side Effects: - * Memory may be allocated, and the hash buckets may be modified. - *--------------------------------------------------------- - */ -Hash_Entry * -Hash_CreateEntry(Hash_Table *t, const char *key, Boolean *newPtr) -{ - Hash_Entry *e; - unsigned int h; - const char *p; - int keylen; - struct Hash_Entry **hp; - - /* - * Hash the key. As a side effect, save the length (strlen) of the - * key in case we need to create the entry. - */ - for (h = 0, p = key; *p;) - h = (h << 5) - h + *p++; - keylen = p - key; - p = key; - for (e = t->bucketPtr[h & t->mask]; e != NULL; e = e->next) { - if (e->namehash == h && strcmp(e->name, p) == 0) { - if (newPtr != NULL) - *newPtr = FALSE; - return (e); - } - } - - /* - * The desired entry isn't there. Before allocating a new entry, - * expand the table if necessary (and this changes the resulting - * bucket chain). - */ - if (t->numEntries >= rebuildLimit * t->size) - RebuildTable(t); - e = emalloc(sizeof(*e) + keylen); - hp = &t->bucketPtr[h & t->mask]; - e->next = *hp; - *hp = e; - e->clientData = NULL; - e->namehash = h; - strcpy(e->name, p); - t->numEntries++; - - if (newPtr != NULL) - *newPtr = TRUE; - return (e); -} - -/* - *--------------------------------------------------------- - * - * Hash_DeleteEntry -- - * - * Delete the given hash table entry and free memory associated with - * it. - * - * Results: - * None. - * - * Side Effects: - * Hash chain that entry lives in is modified and memory is freed. - * - *--------------------------------------------------------- - */ -void -Hash_DeleteEntry(Hash_Table *t, Hash_Entry *e) -{ - Hash_Entry **hp, *p; - - if (e == NULL) - return; - for (hp = &t->bucketPtr[e->namehash & t->mask]; - (p = *hp) != NULL; hp = &p->next) { - if (p == e) { - *hp = p->next; - free(p); - t->numEntries--; - return; - } - } - write(STDERR_FILENO, "bad call to Hash_DeleteEntry\n", 29); - abort(); -} - -/* - *--------------------------------------------------------- - * - * Hash_EnumFirst -- - * This procedure sets things up for a complete search - * of all entries recorded in the hash table. - * - * Results: - * The return value is the address of the first entry in - * the hash table, or NULL if the table is empty. - * - * Side Effects: - * The information in searchPtr is initialized so that successive - * calls to Hash_Next will return successive HashEntry's - * from the table. - * - *--------------------------------------------------------- - */ -Hash_Entry * -Hash_EnumFirst(const Hash_Table *t, Hash_Search *searchPtr) -{ - - searchPtr->tablePtr = t; - searchPtr->nextIndex = 0; - searchPtr->hashEntryPtr = NULL; - return (Hash_EnumNext(searchPtr)); -} - -/* - *--------------------------------------------------------- - * - * Hash_EnumNext -- - * This procedure returns successive entries in the hash table. - * - * Results: - * The return value is a pointer to the next HashEntry - * in the table, or NULL when the end of the table is - * reached. - * - * Side Effects: - * The information in searchPtr is modified to advance to the - * next entry. - * - *--------------------------------------------------------- - */ -Hash_Entry * -Hash_EnumNext(Hash_Search *searchPtr) -{ - Hash_Entry *e; - const Hash_Table *t = searchPtr->tablePtr; - - /* - * The hashEntryPtr field points to the most recently returned - * entry, or is NULL if we are starting up. If not NULL, we have - * to start at the next one in the chain. - */ - e = searchPtr->hashEntryPtr; - if (e != NULL) - e = e->next; - /* - * If the chain ran out, or if we are starting up, we need to - * find the next nonempty chain. - */ - while (e == NULL) { - if (searchPtr->nextIndex >= t->size) - return (NULL); - e = t->bucketPtr[searchPtr->nextIndex++]; - } - searchPtr->hashEntryPtr = e; - return (e); -} - -/* - *--------------------------------------------------------- - * - * RebuildTable -- - * This local routine makes a new hash table that - * is larger than the old one. - * - * Results: - * None. - * - * Side Effects: - * The entire hash table is moved, so any bucket numbers - * from the old table are invalid. - * - *--------------------------------------------------------- - */ -static void -RebuildTable(Hash_Table *t) -{ - Hash_Entry *e, *next = NULL, **hp, **xp; - int i, mask; - Hash_Entry **oldhp; - int oldsize; - - oldhp = t->bucketPtr; - oldsize = i = t->size; - i <<= 1; - t->size = i; - t->mask = mask = i - 1; - t->bucketPtr = hp = emalloc(sizeof(*hp) * i); - while (--i >= 0) - *hp++ = NULL; - for (hp = oldhp, i = oldsize; --i >= 0;) { - for (e = *hp++; e != NULL; e = next) { - next = e->next; - xp = &t->bucketPtr[e->namehash & mask]; - e->next = *xp; - *xp = e; - } - } - free(oldhp); -} Property changes on: head/usr.bin/make/hash.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/main.c =================================================================== --- head/usr.bin/make/main.c (revision 284463) +++ head/usr.bin/make/main.c (nonexistent) @@ -1,1339 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)main.c 8.3 (Berkeley) 3/19/94 - */ - -#ifndef lint -#if 0 -static char copyright[] = -"@(#) Copyright (c) 1988, 1989, 1990, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif -#endif /* not lint */ -#include -__FBSDID("$FreeBSD$"); - -/* - * main.c - * The main file for this entire program. Exit routines etc - * reside here. - * - * Utility functions defined in this file: - * Main_ParseArgLine - * Takes a line of arguments, breaks them and - * treats them as if they were given when first - * invoked. Used by the parse module to implement - * the .MFLAGS target. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "arch.h" -#include "buf.h" -#include "config.h" -#include "dir.h" -#include "globals.h" -#include "GNode.h" -#include "job.h" -#include "make.h" -#include "parse.h" -#include "pathnames.h" -#include "shell.h" -#include "str.h" -#include "suff.h" -#include "targ.h" -#include "util.h" -#include "var.h" - -extern char **environ; /* XXX what header declares this variable? */ - -#define WANT_ENV_MKLVL 1 -#define MKLVL_MAXVAL 500 -#define MKLVL_ENVVAR "__MKLVL__" - -/* ordered list of makefiles to read */ -static Lst makefiles = Lst_Initializer(makefiles); - -/* ordered list of source makefiles */ -static Lst source_makefiles = Lst_Initializer(source_makefiles); - -/* list of variables to print */ -static Lst variables = Lst_Initializer(variables); - -static Boolean expandVars; /* fully expand printed variables */ -static Boolean noBuiltins; /* -r flag */ -static Boolean forceJobs; /* -j argument given */ -static char *curdir; /* startup directory */ -static char *objdir; /* where we chdir'ed to */ -static char **save_argv; /* saved argv */ -static char *save_makeflags;/* saved MAKEFLAGS */ - -/* (-E) vars to override from env */ -Lst envFirstVars = Lst_Initializer(envFirstVars); - -/* Targets to be made */ -Lst create = Lst_Initializer(create); - -Boolean allPrecious; /* .PRECIOUS given on line by itself */ -Boolean is_posix; /* .POSIX target seen */ -Boolean mfAutoDeps; /* .MAKEFILEDEPS target seen */ -Boolean remakingMakefiles; /* True if remaking makefiles is in progress */ -Boolean beSilent; /* -s flag */ -Boolean beVerbose; /* -v flag */ -Boolean beQuiet; /* -Q flag */ -Boolean compatMake; /* -B argument */ -int debug; /* -d flag */ -Boolean ignoreErrors; /* -i flag */ -int jobLimit; /* -j argument */ -int makeErrors; /* Number of targets not remade due to errors */ -Boolean jobsRunning; /* TRUE if the jobs might be running */ -Boolean keepgoing; /* -k flag */ -Boolean noExecute; /* -n flag */ -Boolean printGraphOnly; /* -p flag */ -Boolean queryFlag; /* -q flag */ -Boolean touchFlag; /* -t flag */ -Boolean usePipes; /* !-P flag */ -uint32_t warn_cmd; /* command line warning flags */ -uint32_t warn_flags; /* actual warning flags */ -uint32_t warn_nocmd; /* command line no-warning flags */ - -time_t now; /* Time at start of make */ -struct GNode *DEFAULT; /* .DEFAULT node */ - -static struct { - const char *foreign_name; - const char *freebsd_name; -} arch_aliases[] = { - { "x86_64", "amd64" }, - { "mipsel", "mips" }, -}; - -/** - * Exit with usage message. - */ -static void -usage(void) -{ - fprintf(stderr, - "usage: make [-BPSXeiknpqrstv] [-C directory] [-D variable]\n" - "\t[-d flags] [-E variable] [-f makefile] [-I directory]\n" - "\t[-j max_jobs] [-m directory] [-V variable]\n" - "\t[variable=value] [target ...]\n"); - exit(2); -} - -/** - * MFLAGS_append - * Append a flag with an optional argument to MAKEFLAGS and MFLAGS - */ -static void -MFLAGS_append(const char *flag, char *arg) -{ - char *str; - - Var_Append(".MAKEFLAGS", flag, VAR_GLOBAL); - if (arg != NULL) { - str = MAKEFLAGS_quote(arg); - Var_Append(".MAKEFLAGS", str, VAR_GLOBAL); - free(str); - } - - Var_Append("MFLAGS", flag, VAR_GLOBAL); - if (arg != NULL) { - str = MAKEFLAGS_quote(arg); - Var_Append("MFLAGS", str, VAR_GLOBAL); - free(str); - } -} - -/** - * Main_ParseWarn - * - * Handle argument to warning option. - */ -int -Main_ParseWarn(const char *arg, int iscmd) -{ - int i, neg; - - static const struct { - const char *option; - uint32_t flag; - } options[] = { - { "dirsyntax", WARN_DIRSYNTAX }, - { NULL, 0 } - }; - - neg = 0; - if (arg[0] == 'n' && arg[1] == 'o') { - neg = 1; - arg += 2; - } - - for (i = 0; options[i].option != NULL; i++) - if (strcmp(arg, options[i].option) == 0) - break; - - if (options[i].option == NULL) - /* unknown option */ - return (-1); - - if (iscmd) { - if (!neg) { - warn_cmd |= options[i].flag; - warn_nocmd &= ~options[i].flag; - warn_flags |= options[i].flag; - } else { - warn_nocmd |= options[i].flag; - warn_cmd &= ~options[i].flag; - warn_flags &= ~options[i].flag; - } - } else { - if (!neg) { - warn_flags |= (options[i].flag & ~warn_nocmd); - } else { - warn_flags &= ~(options[i].flag | warn_cmd); - } - } - return (0); -} - -/** - * Open and parse the given makefile. - * - * Results: - * TRUE if ok. FALSE if couldn't open file. - */ -static Boolean -ReadMakefile(const char p[]) -{ - char *fname, *fnamesave; /* makefile to read */ - FILE *stream; - char *name, path[MAXPATHLEN]; - char *MAKEFILE; - int setMAKEFILE; - - /* XXX - remove this once constification is done */ - fnamesave = fname = estrdup(p); - - if (!strcmp(fname, "-")) { - Parse_File("(stdin)", stdin); - Var_SetGlobal("MAKEFILE", ""); - } else { - setMAKEFILE = strcmp(fname, ".depend"); - - /* if we've chdir'd, rebuild the path name */ - if (curdir != objdir && *fname != '/') { - snprintf(path, MAXPATHLEN, "%s/%s", curdir, fname); - /* - * XXX The realpath stuff breaks relative includes - * XXX in some cases. The problem likely is in - * XXX parse.c where it does special things in - * XXX ParseDoInclude if the file is relative - * XXX or absolute and not a system file. There - * XXX it assumes that if the current file that's - * XXX being included is absolute, that any files - * XXX that it includes shouldn't do the -I path - * XXX stuff, which is inconsistent with historical - * XXX behavior. However, I can't penetrate the mists - * XXX further, so I'm putting this workaround in - * XXX here until such time as the underlying bug - * XXX can be fixed. - */ -#if THIS_BREAKS_THINGS - if (realpath(path, path) != NULL && - (stream = fopen(path, "r")) != NULL) { - MAKEFILE = fname; - fname = path; - goto found; - } - } else if (realpath(fname, path) != NULL) { - MAKEFILE = fname; - fname = path; - if ((stream = fopen(fname, "r")) != NULL) - goto found; - } -#else - if ((stream = fopen(path, "r")) != NULL) { - MAKEFILE = fname; - fname = path; - goto found; - } - } else { - MAKEFILE = fname; - if ((stream = fopen(fname, "r")) != NULL) - goto found; - } -#endif - /* look in -I and system include directories. */ - name = Path_FindFile(fname, &parseIncPath); - if (!name) - name = Path_FindFile(fname, &sysIncPath); - if (!name || !(stream = fopen(name, "r"))) { - free(fnamesave); - return (FALSE); - } - MAKEFILE = fname = name; - /* - * set the MAKEFILE variable desired by System V fans -- the - * placement of the setting here means it gets set to the last - * makefile specified, as it is set by SysV make. - */ -found: - if (setMAKEFILE) - Var_SetGlobal("MAKEFILE", MAKEFILE); - Parse_File(fname, stream); - } - free(fnamesave); - return (TRUE); -} - -/** - * Open and parse the given makefile. - * If open is successful add it to the list of makefiles. - * - * Results: - * TRUE if ok. FALSE if couldn't open file. - */ -static Boolean -TryReadMakefile(const char p[]) -{ - char *data; - LstNode *last = Lst_Last(&source_makefiles); - - if (!ReadMakefile(p)) - return (FALSE); - - data = estrdup(p); - if (last == NULL) { - LstNode *first = Lst_First(&source_makefiles); - Lst_Insert(&source_makefiles, first, data); - } else - Lst_Append(&source_makefiles, last, estrdup(p)); - return (TRUE); -} - -/** - * MainParseArgs - * Parse a given argument vector. Called from main() and from - * Main_ParseArgLine() when the .MAKEFLAGS target is used. - * - * XXX: Deal with command line overriding .MAKEFLAGS in makefile - * - * Side Effects: - * Various global and local flags will be set depending on the flags - * given - */ -static void -MainParseArgs(int argc, char **argv) -{ - int c; - Boolean found_dd = FALSE; - char found_dir[MAXPATHLEN + 1]; /* for searching for sys.mk */ - -rearg: - optind = 1; /* since we're called more than once */ - optreset = 1; -#define OPTFLAGS "ABC:D:d:E:ef:I:ij:km:nPpQqrSstV:vXx:" - for (;;) { - if ((optind < argc) && strcmp(argv[optind], "--") == 0) { - found_dd = TRUE; - } - if ((c = getopt(argc, argv, OPTFLAGS)) == -1) { - break; - } - switch(c) { - - case 'A': - arch_fatal = FALSE; - MFLAGS_append("-A", NULL); - break; - case 'B': - compatMake = TRUE; - MFLAGS_append("-B", NULL); - unsetenv("MAKE_JOBS_FIFO"); - break; - case 'C': - if (chdir(optarg) == -1) - err(1, "chdir %s", optarg); - if (getcwd(curdir, MAXPATHLEN) == NULL) - err(2, NULL); - break; - case 'D': - Var_SetGlobal(optarg, "1"); - MFLAGS_append("-D", optarg); - break; - case 'd': { - char *modules = optarg; - - for (; *modules; ++modules) - switch (*modules) { - case 'A': - debug = ~0; - break; - case 'a': - debug |= DEBUG_ARCH; - break; - case 'c': - debug |= DEBUG_COND; - break; - case 'd': - debug |= DEBUG_DIR; - break; - case 'f': - debug |= DEBUG_FOR; - break; - case 'g': - if (modules[1] == '1') { - debug |= DEBUG_GRAPH1; - ++modules; - } - else if (modules[1] == '2') { - debug |= DEBUG_GRAPH2; - ++modules; - } - break; - case 'j': - debug |= DEBUG_JOB; - break; - case 'l': - debug |= DEBUG_LOUD; - break; - case 'm': - debug |= DEBUG_MAKE; - break; - case 's': - debug |= DEBUG_SUFF; - break; - case 't': - debug |= DEBUG_TARG; - break; - case 'v': - debug |= DEBUG_VAR; - break; - default: - warnx("illegal argument to d option " - "-- %c", *modules); - usage(); - } - MFLAGS_append("-d", optarg); - break; - } - case 'E': - Lst_AtEnd(&envFirstVars, estrdup(optarg)); - MFLAGS_append("-E", optarg); - break; - case 'e': - checkEnvFirst = TRUE; - MFLAGS_append("-e", NULL); - break; - case 'f': - Lst_AtEnd(&makefiles, estrdup(optarg)); - break; - case 'I': - Parse_AddIncludeDir(optarg); - MFLAGS_append("-I", optarg); - break; - case 'i': - ignoreErrors = TRUE; - MFLAGS_append("-i", NULL); - break; - case 'j': { - char *endptr; - - forceJobs = TRUE; - jobLimit = strtol(optarg, &endptr, 10); - if (jobLimit <= 0 || *endptr != '\0') { - warnx("illegal number, -j argument -- %s", - optarg); - usage(); - } - MFLAGS_append("-j", optarg); - break; - } - case 'k': - keepgoing = TRUE; - MFLAGS_append("-k", NULL); - break; - case 'm': - /* look for magic parent directory search string */ - if (strncmp(".../", optarg, 4) == 0) { - if (!Dir_FindHereOrAbove(curdir, optarg + 4, - found_dir, sizeof(found_dir))) - break; /* nothing doing */ - Path_AddDir(&sysIncPath, found_dir); - } else { - Path_AddDir(&sysIncPath, optarg); - } - MFLAGS_append("-m", optarg); - break; - case 'n': - noExecute = TRUE; - MFLAGS_append("-n", NULL); - break; - case 'P': - usePipes = FALSE; - MFLAGS_append("-P", NULL); - break; - case 'p': - printGraphOnly = TRUE; - debug |= DEBUG_GRAPH1; - break; - case 'Q': - beQuiet = TRUE; - beVerbose = FALSE; - MFLAGS_append("-Q", NULL); - break; - case 'q': - queryFlag = TRUE; - /* Kind of nonsensical, wot? */ - MFLAGS_append("-q", NULL); - break; - case 'r': - noBuiltins = TRUE; - MFLAGS_append("-r", NULL); - break; - case 'S': - keepgoing = FALSE; - MFLAGS_append("-S", NULL); - break; - case 's': - beSilent = TRUE; - MFLAGS_append("-s", NULL); - break; - case 't': - touchFlag = TRUE; - MFLAGS_append("-t", NULL); - break; - case 'V': - Lst_AtEnd(&variables, estrdup(optarg)); - MFLAGS_append("-V", optarg); - break; - case 'v': - beVerbose = TRUE; - beQuiet = FALSE; - MFLAGS_append("-v", NULL); - break; - case 'X': - expandVars = FALSE; - break; - case 'x': - if (Main_ParseWarn(optarg, 1) != -1) - MFLAGS_append("-x", optarg); - break; - - default: - case '?': - usage(); - } - } - argv += optind; - argc -= optind; - - oldVars = TRUE; - - /* - * Parse the rest of the arguments. - * o Check for variable assignments and perform them if so. - * o Check for more flags and restart getopt if so. - * o Anything else is taken to be a target and added - * to the end of the "create" list. - */ - for (; *argv != NULL; ++argv, --argc) { - if (Parse_IsVar(*argv)) { - char *ptr = MAKEFLAGS_quote(*argv); - char *v = estrdup(*argv); - - Var_Append(".MAKEFLAGS", ptr, VAR_GLOBAL); - Parse_DoVar(v, VAR_CMD); - free(ptr); - free(v); - - } else if ((*argv)[0] == '-') { - if ((*argv)[1] == '\0') { - /* - * (*argv) is a single dash, so we - * just ignore it. - */ - } else if (found_dd) { - /* - * Double dash has been found, ignore - * any more options. But what do we do - * with it? For now treat it like a target. - */ - Lst_AtEnd(&create, estrdup(*argv)); - } else { - /* - * (*argv) is a -flag, so backup argv and - * argc. getopt() expects options to start - * in the 2nd position. - */ - argc++; - argv--; - goto rearg; - } - - } else if ((*argv)[0] == '\0') { - Punt("illegal (null) argument."); - - } else { - Lst_AtEnd(&create, estrdup(*argv)); - } - } -} - -/** - * Main_ParseArgLine - * Used by the parse module when a .MFLAGS or .MAKEFLAGS target - * is encountered and by main() when reading the .MAKEFLAGS envariable. - * Takes a line of arguments and breaks it into its - * component words and passes those words and the number of them to the - * MainParseArgs function. - * The line should have all its leading whitespace removed. - * - * Side Effects: - * Only those that come from the various arguments. - */ -void -Main_ParseArgLine(char *line, int mflags) -{ - ArgArray aa; - - if (line == NULL) - return; - for (; *line == ' '; ++line) - continue; - if (!*line) - return; - - if (mflags) - MAKEFLAGS_break(&aa, line); - else - brk_string(&aa, line, TRUE); - - MainParseArgs(aa.argc, aa.argv); - ArgArray_Done(&aa); -} - -static char * -chdir_verify_path(const char *path, char *obpath) -{ - struct stat sb; - - if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { - if (chdir(path) == -1 || getcwd(obpath, MAXPATHLEN) == NULL) { - warn("warning: %s", path); - return (NULL); - } - return (obpath); - } - - return (NULL); -} - -/** - * In lieu of a good way to prevent every possible looping in make(1), stop - * there from being more than MKLVL_MAXVAL processes forked by make(1), to - * prevent a forkbomb from happening, in a dumb and mechanical way. - * - * Side Effects: - * Creates or modifies environment variable MKLVL_ENVVAR via setenv(). - */ -static void -check_make_level(void) -{ -#ifdef WANT_ENV_MKLVL - char *value = getenv(MKLVL_ENVVAR); - int level = (value == NULL) ? 0 : atoi(value); - - if (level < 0) { - errx(2, "Invalid value for recursion level (%d).", level); - } else if (level > MKLVL_MAXVAL) { - errx(2, "Max recursion level (%d) exceeded.", MKLVL_MAXVAL); - } else { - char new_value[32]; - sprintf(new_value, "%d", level + 1); - setenv(MKLVL_ENVVAR, new_value, 1); - } -#endif /* WANT_ENV_MKLVL */ -} - -/** - * Main_AddSourceMakefile - * Add a file to the list of source makefiles - */ -void -Main_AddSourceMakefile(const char *name) -{ - - Lst_AtEnd(&source_makefiles, estrdup(name)); -} - -/** - * Remake_Makefiles - * Remake all the makefiles - */ -static void -Remake_Makefiles(void) -{ - Lst cleanup; - LstNode *ln; - int error_cnt = 0; - int remade_cnt = 0; - - Compat_InstallSignalHandlers(); - if (curdir != objdir) { - if (chdir(curdir) < 0) - Fatal("Failed to change directory to %s.", curdir); - } - - Lst_Init(&cleanup); - LST_FOREACH(ln, &source_makefiles) { - LstNode *ln2; - struct GNode *gn; - const char *name = Lst_Datum(ln); - Boolean saveTouchFlag = touchFlag; - Boolean saveQueryFlag = queryFlag; - Boolean saveNoExecute = noExecute; - int mtime; - - /* - * Create node - */ - gn = Targ_FindNode(name, TARG_CREATE); - DEBUGF(MAKE, ("Checking %s...", gn->name)); - Suff_FindDeps(gn); - - /* - * -t, -q and -n has no effect unless the makefile is - * specified as one of the targets explicitly in the - * command line - */ - LST_FOREACH(ln2, &create) { - if (!strcmp(gn->name, Lst_Datum(ln2))) { - /* found as a target */ - break; - } - } - if (ln2 == NULL) { - touchFlag = FALSE; - queryFlag = FALSE; - noExecute = FALSE; - } - - /* - * Check and remake the makefile - */ - mtime = Dir_MTime(gn); - remakingMakefiles = TRUE; - Compat_Make(gn, gn); - remakingMakefiles = FALSE; - - /* - * Restore -t, -q and -n behaviour - */ - touchFlag = saveTouchFlag; - queryFlag = saveQueryFlag; - noExecute = saveNoExecute; - - /* - * Compat_Make will leave the 'made' field of gn - * in one of the following states: - * UPTODATE gn was already up-to-date - * MADE gn was recreated successfully - * ERROR An error occurred while gn was being created - * ABORTED gn was not remade because one of its inferiors - * could not be made due to errors. - */ - if (gn->made == MADE) { - if (mtime != Dir_MTime(gn)) { - DEBUGF(MAKE, - ("%s updated (%d -> %d).\n", - gn->name, mtime, gn->mtime)); - remade_cnt++; - } else { - DEBUGF(MAKE, - ("%s not updated: skipping restart.\n", - gn->name)); - } - } else if (gn->made == ERROR) - error_cnt++; - else if (gn->made == ABORTED) { - printf("`%s' not remade because of errors.\n", - gn->name); - error_cnt++; - } else if (gn->made == UPTODATE) { - Lst_EnQueue(&cleanup, gn); - } - } - - if (error_cnt > 0) - Fatal("Failed to remake Makefiles."); - if (remade_cnt > 0) { - DEBUGF(MAKE, ("Restarting `%s'.\n", save_argv[0])); - - /* - * Some of makefiles were remade -- restart from clean state - */ - if (save_makeflags != NULL) - setenv("MAKEFLAGS", save_makeflags, 1); - else - unsetenv("MAKEFLAGS"); - if (execvp(save_argv[0], save_argv) < 0) { - Fatal("Can't restart `%s': %s.", - save_argv[0], strerror(errno)); - } - } - - while (!Lst_IsEmpty(&cleanup)) { - GNode *gn = Lst_DeQueue(&cleanup); - - gn->unmade = 0; - gn->make = FALSE; - gn->made = UNMADE; - gn->childMade = FALSE; - gn->mtime = gn->cmtime = 0; - gn->cmtime_gn = NULL; - - LST_FOREACH(ln, &gn->children) { - GNode *cgn = Lst_Datum(ln); - - gn->unmade++; - Lst_EnQueue(&cleanup, cgn); - } - } - - if (curdir != objdir) { - if (chdir(objdir) < 0) - Fatal("Failed to change directory to %s.", objdir); - } -} - -/** - * main - * The main function, for obvious reasons. Initializes variables - * and a few modules, then parses the arguments give it in the - * environment and on the command line. Reads the system makefile - * followed by either Makefile, makefile or the file given by the - * -f argument. Sets the .MAKEFLAGS PMake variable based on all the - * flags it has received by then uses either the Make or the Compat - * module to create the initial list of targets. - * - * Results: - * If -q was given, exits -1 if anything was out-of-date. Else it exits - * 0. - * - * Side Effects: - * The program exits when done. Targets are created. etc. etc. etc. - */ -int -main(int argc, char **argv) -{ - const char *machine; - const char *machine_arch; - const char *machine_cpu; - Boolean outOfDate = TRUE; /* FALSE if all targets up to date */ - const char *p; - const char *pathp; - const char *path; - char mdpath[MAXPATHLEN]; - char obpath[MAXPATHLEN]; - char cdpath[MAXPATHLEN]; - char found_dir[MAXPATHLEN + 1]; /* for searching for sys.mk */ - char *cp = NULL, *start; - - save_argv = argv; - save_makeflags = getenv("MAKEFLAGS"); - if (save_makeflags != NULL) - save_makeflags = estrdup(save_makeflags); - - /* - * Initialize file global variables. - */ - expandVars = TRUE; - noBuiltins = FALSE; /* Read the built-in rules */ - forceJobs = FALSE; /* No -j flag */ - curdir = cdpath; - - /* - * Initialize program global variables. - */ - beSilent = FALSE; /* Print commands as executed */ - ignoreErrors = FALSE; /* Pay attention to non-zero returns */ - noExecute = FALSE; /* Execute all commands */ - printGraphOnly = FALSE; /* Don't stop after printing graph */ - keepgoing = FALSE; /* Stop on error */ - allPrecious = FALSE; /* Remove targets when interrupted */ - queryFlag = FALSE; /* This is not just a check-run */ - touchFlag = FALSE; /* Actually update targets */ - usePipes = TRUE; /* Catch child output in pipes */ - debug = 0; /* No debug verbosity, please. */ - jobsRunning = FALSE; - - jobLimit = DEFMAXJOBS; - compatMake = FALSE; /* No compat mode */ - - check_make_level(); - -#ifdef RLIMIT_NOFILE - /* - * get rid of resource limit on file descriptors - */ - { - struct rlimit rl; - if (getrlimit(RLIMIT_NOFILE, &rl) == -1) { - err(2, "getrlimit"); - } - rl.rlim_cur = rl.rlim_max; - if (setrlimit(RLIMIT_NOFILE, &rl) == -1) { - err(2, "setrlimit"); - } - } -#endif - - /* - * Get the name of this type of MACHINE from utsname - * so we can share an executable for similar machines. - * (i.e. m68k: amiga hp300, mac68k, sun3, ...) - * - * Note that both MACHINE and MACHINE_ARCH are decided at - * run-time. - */ - if ((machine = getenv("MACHINE")) == NULL) { - static struct utsname utsname; - unsigned int i; - - if (uname(&utsname) == -1) - err(2, "uname"); - machine = utsname.machine; - - /* Canonicalize non-FreeBSD naming conventions */ - for (i = 0; i < sizeof(arch_aliases) - / sizeof(arch_aliases[0]); i++) - if (!strcmp(machine, arch_aliases[i].foreign_name)) { - machine = arch_aliases[i].freebsd_name; - break; - } - } - - if ((machine_arch = getenv("MACHINE_ARCH")) == NULL) { -#ifdef MACHINE_ARCH - machine_arch = MACHINE_ARCH; -#else - machine_arch = "unknown"; -#endif - } - - /* - * Set machine_cpu to the minimum supported CPU revision based - * on the target architecture, if not already set. - */ - if ((machine_cpu = getenv("MACHINE_CPU")) == NULL) { - if (!strcmp(machine_arch, "i386")) - machine_cpu = "i486"; - else - machine_cpu = "unknown"; - } - - /* - * Initialize the parsing, directory and variable modules to prepare - * for the reading of inclusion paths and variable settings on the - * command line - */ - Proc_Init(); - - Dir_Init(); /* Initialize directory structures so -I flags - * can be processed correctly */ - Var_Init(environ); /* As well as the lists of variables for - * parsing arguments */ - - /* - * Initialize the Shell so that we have a shell for != assignments - * on the command line. - */ - Shell_Init(); - - /* - * Initialize various variables. - * MAKE also gets this name, for compatibility - * .MAKEFLAGS gets set to the empty string just in case. - * MFLAGS also gets initialized empty, for compatibility. - */ - Var_SetGlobal("MAKE", argv[0]); - Var_SetGlobal(".MAKEFLAGS", ""); - Var_SetGlobal("MFLAGS", ""); - Var_SetGlobal("MACHINE", machine); - Var_SetGlobal("MACHINE_ARCH", machine_arch); - Var_SetGlobal("MACHINE_CPU", machine_cpu); -#ifdef MAKE_VERSION - Var_SetGlobal("MAKE_VERSION", MAKE_VERSION); -#endif - Var_SetGlobal(".newline", "\n"); /* handy for :@ loops */ - { - char tmp[64]; - - snprintf(tmp, sizeof(tmp), "%u", getpid()); - Var_SetGlobal(".MAKE.PID", tmp); - snprintf(tmp, sizeof(tmp), "%u", getppid()); - Var_SetGlobal(".MAKE.PPID", tmp); - } - Job_SetPrefix(); - - /* - * Find where we are... - */ - if (getcwd(curdir, MAXPATHLEN) == NULL) - err(2, NULL); - - /* - * First snag things out of the MAKEFLAGS environment - * variable. Then parse the command line arguments. - */ - Main_ParseArgLine(getenv("MAKEFLAGS"), 1); - - MainParseArgs(argc, argv); - - /* - * Verify that cwd is sane (after -C may have changed it). - */ - { - struct stat sa; - - if (stat(curdir, &sa) == -1) - err(2, "%s", curdir); - } - - /* - * The object directory location is determined using the - * following order of preference: - * - * 1. MAKEOBJDIRPREFIX`cwd` - * 2. MAKEOBJDIR - * 3. PATH_OBJDIR.${MACHINE} - * 4. PATH_OBJDIR - * 5. PATH_OBJDIRPREFIX`cwd` - * - * If one of the first two fails, use the current directory. - * If the remaining three all fail, use the current directory. - * - * Once things are initted, - * have to add the original directory to the search path, - * and modify the paths for the Makefiles appropriately. The - * current directory is also placed as a variable for make scripts. - */ - if (!(pathp = getenv("MAKEOBJDIRPREFIX"))) { - if (!(path = getenv("MAKEOBJDIR"))) { - path = PATH_OBJDIR; - pathp = PATH_OBJDIRPREFIX; - snprintf(mdpath, MAXPATHLEN, "%s.%s", path, machine); - if (!(objdir = chdir_verify_path(mdpath, obpath))) - if (!(objdir=chdir_verify_path(path, obpath))) { - snprintf(mdpath, MAXPATHLEN, - "%s%s", pathp, curdir); - if (!(objdir=chdir_verify_path(mdpath, - obpath))) - objdir = curdir; - } - } - else if (!(objdir = chdir_verify_path(path, obpath))) - objdir = curdir; - } - else { - snprintf(mdpath, MAXPATHLEN, "%s%s", pathp, curdir); - if (!(objdir = chdir_verify_path(mdpath, obpath))) - objdir = curdir; - } - Dir_InitDot(); /* Initialize the "." directory */ - if (objdir != curdir) - Path_AddDir(&dirSearchPath, curdir); - Var_SetGlobal(".ST_EXPORTVAR", "YES"); - Var_SetGlobal(".CURDIR", curdir); - Var_SetGlobal(".OBJDIR", objdir); - - if (getenv("MAKE_JOBS_FIFO") != NULL) - forceJobs = TRUE; - /* - * Be compatible if user did not specify -j and did not explicitly - * turned compatibility on - */ - if (!compatMake && !forceJobs) - compatMake = TRUE; - - /* - * Initialize target and suffix modules in preparation for - * parsing the makefile(s) - */ - Targ_Init(); - Suff_Init(); - - DEFAULT = NULL; - time(&now); - - /* - * Set up the .TARGETS variable to contain the list of targets to be - * created. If none specified, make the variable empty -- the parser - * will fill the thing in with the default or .MAIN target. - */ - if (Lst_IsEmpty(&create)) { - Var_SetGlobal(".TARGETS", ""); - } else { - LstNode *ln; - - for (ln = Lst_First(&create); ln != NULL; ln = Lst_Succ(ln)) { - char *name = Lst_Datum(ln); - - Var_Append(".TARGETS", name, VAR_GLOBAL); - } - } - - - /* - * If no user-supplied system path was given (through the -m option) - * add the directories from the DEFSYSPATH (more than one may be given - * as dir1:...:dirn) to the system include path. - */ - if (TAILQ_EMPTY(&sysIncPath)) { - char defsyspath[] = PATH_DEFSYSPATH; - char *syspath = getenv("MAKESYSPATH"); - - /* - * If no user-supplied system path was given (thru -m option) - * add the directories from the DEFSYSPATH (more than one may - * be given as dir1:...:dirn) to the system include path. - */ - if (syspath == NULL || *syspath == '\0') - syspath = defsyspath; - else - syspath = estrdup(syspath); - - for (start = syspath; *start != '\0'; start = cp) { - for (cp = start; *cp != '\0' && *cp != ':'; cp++) - continue; - if (*cp == ':') { - *cp++ = '\0'; - } - /* look for magic parent directory search string */ - if (strncmp(".../", start, 4) == 0) { - if (Dir_FindHereOrAbove(curdir, start + 4, - found_dir, sizeof(found_dir))) { - Path_AddDir(&sysIncPath, found_dir); - } - } else { - Path_AddDir(&sysIncPath, start); - } - } - if (syspath != defsyspath) - free(syspath); - } - - /* - * Read in the built-in rules first, followed by the specified - * makefile, if it was (makefile != (char *) NULL), or the default - * Makefile and makefile, in that order, if it wasn't. - */ - if (!noBuiltins) { - /* Path of sys.mk */ - Lst sysMkPath = Lst_Initializer(sysMkPath); - LstNode *ln; - char defsysmk[] = PATH_DEFSYSMK; - - Path_Expand(defsysmk, &sysIncPath, &sysMkPath); - if (Lst_IsEmpty(&sysMkPath)) - Fatal("make: no system rules (%s).", PATH_DEFSYSMK); - LST_FOREACH(ln, &sysMkPath) { - if (!ReadMakefile(Lst_Datum(ln))) - break; - } - if (ln != NULL) - Fatal("make: cannot open %s.", (char *)Lst_Datum(ln)); - Lst_Destroy(&sysMkPath, free); - } - - if (!Lst_IsEmpty(&makefiles)) { - LstNode *ln; - - LST_FOREACH(ln, &makefiles) { - if (!TryReadMakefile(Lst_Datum(ln))) - break; - } - if (ln != NULL) - Fatal("make: cannot open %s.", (char *)Lst_Datum(ln)); - } else if (!TryReadMakefile("BSDmakefile")) - if (!TryReadMakefile("makefile")) - TryReadMakefile("Makefile"); - - ReadMakefile(".depend"); - - /* Install all the flags into the MAKEFLAGS envariable. */ - if (((p = Var_Value(".MAKEFLAGS", VAR_GLOBAL)) != NULL) && *p) - setenv("MAKEFLAGS", p, 1); - else - setenv("MAKEFLAGS", "", 1); - - /* - * For compatibility, look at the directories in the VPATH variable - * and add them to the search path, if the variable is defined. The - * variable's value is in the same format as the PATH envariable, i.e. - * ::... - */ - if (Var_Exists("VPATH", VAR_CMD)) { - /* - * GCC stores string constants in read-only memory, but - * Var_Subst will want to write this thing, so store it - * in an array - */ - static char VPATH[] = "${VPATH}"; - Buffer *buf; - char *vpath; - char *ptr; - char savec; - - buf = Var_Subst(VPATH, VAR_CMD, FALSE); - - vpath = Buf_Data(buf); - do { - /* skip to end of directory */ - for (ptr = vpath; *ptr != ':' && *ptr != '\0'; ptr++) - ; - - /* Save terminator character so know when to stop */ - savec = *ptr; - *ptr = '\0'; - - /* Add directory to search path */ - Path_AddDir(&dirSearchPath, vpath); - - vpath = ptr + 1; - } while (savec != '\0'); - - Buf_Destroy(buf, TRUE); - } - - /* - * Now that all search paths have been read for suffixes et al, it's - * time to add the default search path to their lists... - */ - Suff_DoPaths(); - - /* print the initial graph, if the user requested it */ - if (DEBUG(GRAPH1)) - Targ_PrintGraph(1); - - /* print the values of any variables requested by the user */ - if (Lst_IsEmpty(&variables) && !printGraphOnly) { - /* - * Since the user has not requested that any variables - * be printed, we can build targets. - * - * Have read the entire graph and need to make a list of targets - * to create. If none was given on the command line, we consult - * the parsing module to find the main target(s) to create. - */ - Lst targs = Lst_Initializer(targs); - - if (!is_posix && mfAutoDeps) { - /* - * Check if any of the makefiles are out-of-date. - */ - Remake_Makefiles(); - } - - if (Lst_IsEmpty(&create)) - Parse_MainName(&targs); - else - Targ_FindList(&targs, &create, TARG_CREATE); - - if (compatMake) { - /* - * Compat_Init will take care of creating - * all the targets as well as initializing - * the module. - */ - Compat_Run(&targs); - outOfDate = 0; - } else { - /* - * Initialize job module before traversing - * the graph, now that any .BEGIN and .END - * targets have been read. This is done - * only if the -q flag wasn't given (to - * prevent the .BEGIN from being executed - * should it exist). - */ - if (!queryFlag) { - Job_Init(jobLimit); - jobsRunning = TRUE; - } - - /* Traverse the graph, checking on all the targets */ - outOfDate = Make_Run(&targs); - } - Lst_Destroy(&targs, NOFREE); - - } else { - Var_Print(&variables, expandVars); - } - - Lst_Destroy(&variables, free); - Lst_Destroy(&makefiles, free); - Lst_Destroy(&source_makefiles, free); - Lst_Destroy(&create, free); - - /* print the graph now it's been processed if the user requested it */ - if (DEBUG(GRAPH2)) - Targ_PrintGraph(2); - - if (queryFlag) - return (outOfDate); - - if (makeErrors != 0) - Finish(makeErrors); - - return (0); -} Property changes on: head/usr.bin/make/main.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/make.c =================================================================== --- head/usr.bin/make/make.c (revision 284463) +++ head/usr.bin/make/make.c (nonexistent) @@ -1,819 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)make.c 8.1 (Berkeley) 6/6/93 - */ - -#include -__FBSDID("$FreeBSD$"); - -/* - * make.c - * The functions which perform the examination of targets and - * their suitability for creation - * - * Interface: - * Make_Run Initialize things for the module and recreate - * whatever needs recreating. Returns TRUE if - * work was (or would have been) done and FALSE - * otherwise. - * - * Make_Update Update all parents of a given child. Performs - * various bookkeeping chores like the updating - * of the cmtime field of the parent, filling - * of the IMPSRC context variable, etc. It will - * place the parent on the toBeMade queue if it should be. - * - * Make_TimeStamp Function to set the parent's cmtime field - * based on a child's modification time. - * - * Make_DoAllVar Set up the various local variables for a - * target, including the .ALLSRC variable, making - * sure that any variable that needs to exist - * at the very least has the empty value. - * - * Make_OODate Determine if a target is out-of-date. - * - * Make_HandleUse See if a child is a .USE node for a parent - * and perform the .USE actions if so. - */ - -#include "arch.h" -#include "config.h" -#include "dir.h" -#include "globals.h" -#include "GNode.h" -#include "job.h" -#include "make.h" -#include "parse.h" -#include "suff.h" -#include "targ.h" -#include "util.h" -#include "var.h" - -/* The current fringe of the graph. These are nodes which await examination - * by MakeOODate. It is added to by Make_Update and subtracted from by - * MakeStartJobs */ -static Lst toBeMade = Lst_Initializer(toBeMade); - -/* - * Number of nodes to be processed. If this is non-zero when Job_Empty() - * returns TRUE, there's a cycle in the graph. - */ -static int numNodes; - -static Boolean MakeStartJobs(void); - -/** - * Make_TimeStamp - * Set the cmtime field of a parent node based on the mtime stamp in its - * child. Called from MakeOODate via LST_FOREACH. - * - * Results: - * Always returns 0. - * - * Side Effects: - * The cmtime of the parent node will be changed if the mtime - * field of the child is greater than it. - */ -int -Make_TimeStamp(GNode *pgn, GNode *cgn) -{ - - if (cgn->mtime > pgn->cmtime) { - pgn->cmtime = cgn->mtime; - pgn->cmtime_gn = cgn; - } - return (0); -} - -/** - * Make_OODate - * See if a given node is out of date with respect to its sources. - * Used by Make_Run when deciding which nodes to place on the - * toBeMade queue initially and by Make_Update to screen out USE and - * EXEC nodes. In the latter case, however, any other sort of node - * must be considered out-of-date since at least one of its children - * will have been recreated. - * - * Results: - * TRUE if the node is out of date. FALSE otherwise. - * - * Side Effects: - * The mtime field of the node and the cmtime field of its parents - * will/may be changed. - */ -Boolean -Make_OODate(GNode *gn) -{ - Boolean oodate; - LstNode *ln; - - /* - * Certain types of targets needn't even be sought as their datedness - * doesn't depend on their modification time... - */ - if ((gn->type & (OP_JOIN | OP_USE | OP_EXEC)) == 0) { - Dir_MTime(gn); - if (gn->mtime != 0) { - DEBUGF(MAKE, ("modified %s...", - Targ_FmtTime(gn->mtime))); - } else { - DEBUGF(MAKE, ("non-existent...")); - } - } - - /* - * A target is remade in one of the following circumstances: - * its modification time is smaller than that of its youngest child - * and it would actually be run (has commands or type OP_NOP) - * it's the object of a force operator - * it has no children, was on the lhs of an operator and doesn't - * exist already. - * - * Libraries are only considered out-of-date if the archive module says - * they are. - * - * These weird rules are brought to you by Backward-Compatibility and - * the strange people who wrote 'Make'. - */ - if (gn->type & OP_USE) { - /* - * If the node is a USE node it is *never* out of date - * no matter *what*. - */ - DEBUGF(MAKE, (".USE node...")); - oodate = FALSE; - - } else if (gn->type & OP_LIB) { - DEBUGF(MAKE, ("library...")); - - /* - * always out of date if no children and :: target - */ - oodate = Arch_LibOODate(gn) || - ((gn->cmtime == 0) && (gn->type & OP_DOUBLEDEP)); - - } else if (gn->type & OP_JOIN) { - /* - * A target with the .JOIN attribute is only considered - * out-of-date if any of its children was out-of-date. - */ - DEBUGF(MAKE, (".JOIN node...")); - oodate = gn->childMade; - - } else if (gn->type & (OP_FORCE|OP_EXEC|OP_PHONY)) { - /* - * A node which is the object of the force (!) operator or - * which has the .EXEC attribute is always considered - * out-of-date. - */ - if (gn->type & OP_FORCE) { - DEBUGF(MAKE, ("! operator...")); - } else if (gn->type & OP_PHONY) { - DEBUGF(MAKE, (".PHONY node...")); - } else { - DEBUGF(MAKE, (".EXEC node...")); - } - - if (remakingMakefiles) { - DEBUGF(MAKE, ("skipping (remaking makefiles)...")); - oodate = FALSE; - } else { - oodate = TRUE; - } - } else if (gn->mtime < gn->cmtime || - (gn->cmtime == 0 && (gn->mtime == 0 || (gn->type & OP_DOUBLEDEP)))) { - /* - * A node whose modification time is less than that of its - * youngest child or that has no children (cmtime == 0) and - * either doesn't exist (mtime == 0) or was the object of a - * :: operator is out-of-date. Why? Because that's the way - * Make does it. - */ - if (gn->mtime < gn->cmtime) { - DEBUGF(MAKE, ("modified before source (%s)...", - gn->cmtime_gn ? gn->cmtime_gn->path : "???")); - oodate = TRUE; - } else if (gn->mtime == 0) { - DEBUGF(MAKE, ("non-existent and no sources...")); - if (remakingMakefiles && Lst_IsEmpty(&gn->commands)) { - DEBUGF(MAKE, ("skipping (no commands and remaking makefiles)...")); - oodate = FALSE; - } else { - oodate = TRUE; - } - } else { - DEBUGF(MAKE, (":: operator and no sources...")); - if (remakingMakefiles) { - DEBUGF(MAKE, ("skipping (remaking makefiles)...")); - oodate = FALSE; - } else { - oodate = TRUE; - } - } - } else - oodate = FALSE; - - /* - * If the target isn't out-of-date, the parents need to know its - * modification time. Note that targets that appear to be out-of-date - * but aren't, because they have no commands and aren't of type OP_NOP, - * have their mtime stay below their children's mtime to keep parents - * from thinking they're out-of-date. - */ - if (!oodate) { - LST_FOREACH(ln, &gn->parents) - if (Make_TimeStamp(Lst_Datum(ln), gn)) - break; - } - - return (oodate); -} - -/** - * Make_HandleUse - * Function called by Make_Run and SuffApplyTransform on the downward - * pass to handle .USE and transformation nodes. A callback function - * for LST_FOREACH, it implements the .USE and transformation - * functionality by copying the node's commands, type flags - * and children to the parent node. Should be called before the - * children are enqueued to be looked at. - * - * A .USE node is much like an explicit transformation rule, except - * its commands are always added to the target node, even if the - * target already has commands. - * - * Results: - * returns 0. - * - * Side Effects: - * Children and commands may be added to the parent and the parent's - * type may be changed. - * - *----------------------------------------------------------------------- - */ -int -Make_HandleUse(GNode *cgn, GNode *pgn) -{ - GNode *gn; /* A child of the .USE node */ - LstNode *ln; /* An element in the children list */ - - if (cgn->type & (OP_USE | OP_TRANSFORM)) { - if ((cgn->type & OP_USE) || Lst_IsEmpty(&pgn->commands)) { - /* - * .USE or transformation and target has no commands -- - * append the child's commands to the parent. - */ - Lst_Concat(&pgn->commands, &cgn->commands, LST_CONCNEW); - } - - for (ln = Lst_First(&cgn->children); ln != NULL; - ln = Lst_Succ(ln)) { - gn = Lst_Datum(ln); - - if (Lst_Member(&pgn->children, gn) == NULL) { - Lst_AtEnd(&pgn->children, gn); - Lst_AtEnd(&gn->parents, pgn); - pgn->unmade += 1; - } - } - - pgn->type |= cgn->type & ~(OP_OPMASK | OP_USE | OP_TRANSFORM); - - /* - * This child node is now "made", so we decrement the count of - * unmade children in the parent... We also remove the child - * from the parent's list to accurately reflect the number of - * decent children the parent has. This is used by Make_Run to - * decide whether to queue the parent or examine its children... - */ - if (cgn->type & OP_USE) { - pgn->unmade--; - } - } - return (0); -} - -/** - * Make_Update - * Perform update on the parents of a node. Used by JobFinish once - * a node has been dealt with and by MakeStartJobs if it finds an - * up-to-date node. - * - * Results: - * Always returns 0 - * - * Side Effects: - * The unmade field of pgn is decremented and pgn may be placed on - * the toBeMade queue if this field becomes 0. - * - * If the child was made, the parent's childMade field will be set true - * and its cmtime set to now. - * - * If the child wasn't made, the cmtime field of the parent will be - * altered if the child's mtime is big enough. - * - * Finally, if the child is the implied source for the parent, the - * parent's IMPSRC variable is set appropriately. - */ -void -Make_Update(GNode *cgn) -{ - GNode *pgn; /* the parent node */ - const char *cname; /* the child's name */ - LstNode *ln; /* Element in parents and iParents lists */ - const char *cpref; - - cname = Var_Value(TARGET, cgn); - - /* - * If the child was actually made, see what its modification time is - * now -- some rules won't actually update the file. If the file still - * doesn't exist, make its mtime now. - */ - if (cgn->made != UPTODATE) { -#ifndef RECHECK - /* - * We can't re-stat the thing, but we can at least take care - * of rules where a target depends on a source that actually - * creates the target, but only if it has changed, e.g. - * - * parse.h : parse.o - * - * parse.o : parse.y - * yacc -d parse.y - * cc -c y.tab.c - * mv y.tab.o parse.o - * cmp -s y.tab.h parse.h || mv y.tab.h parse.h - * - * In this case, if the definitions produced by yacc haven't - * changed from before, parse.h won't have been updated and - * cgn->mtime will reflect the current modification time for - * parse.h. This is something of a kludge, I admit, but it's a - * useful one.. - * XXX: People like to use a rule like - * - * FRC: - * - * To force things that depend on FRC to be made, so we have to - * check for gn->children being empty as well... - */ - if (!Lst_IsEmpty(&cgn->commands) || - Lst_IsEmpty(&cgn->children)) { - cgn->mtime = now; - } - #else - /* - * This is what Make does and it's actually a good thing, as it - * allows rules like - * - * cmp -s y.tab.h parse.h || cp y.tab.h parse.h - * - * to function as intended. Unfortunately, thanks to the - * stateless nature of NFS (by which I mean the loose coupling - * of two clients using the same file from a common server), - * there are times when the modification time of a file created - * on a remote machine will not be modified before the local - * stat() implied by the Dir_MTime occurs, thus leading us to - * believe that the file is unchanged, wreaking havoc with - * files that depend on this one. - * - * I have decided it is better to make too much than to make too - * little, so this stuff is commented out unless you're sure - * it's ok. - * -- ardeb 1/12/88 - */ - /* - * Christos, 4/9/92: If we are saving commands pretend that - * the target is made now. Otherwise archives with ... rules - * don't work! - */ - if (noExecute || (cgn->type & OP_SAVE_CMDS) || - Dir_MTime(cgn) == 0) { - cgn->mtime = now; - } - DEBUGF(MAKE, ("update time: %s\n", Targ_FmtTime(cgn->mtime))); -#endif - } - - for (ln = Lst_First(&cgn->parents); ln != NULL; ln = Lst_Succ(ln)) { - pgn = Lst_Datum(ln); - if (pgn->make) { - pgn->unmade -= 1; - - if (!(cgn->type & (OP_EXEC | OP_USE))) { - if (cgn->made == MADE) - pgn->childMade = TRUE; - Make_TimeStamp(pgn, cgn); - } - if (pgn->unmade == 0) { - /* - * Queue the node up -- any unmade predecessors - * will be dealt with in MakeStartJobs. - */ - Lst_EnQueue(&toBeMade, pgn); - } else if (pgn->unmade < 0) { - Error("Graph cycles through %s", pgn->name); - } - } - } - - /* - * Deal with successor nodes. If any is marked for making and has an - * unmade count of 0, has not been made and isn't in the examination - * queue, it means we need to place it in the queue as it restrained - * itself before. - */ - for (ln = Lst_First(&cgn->successors); ln != NULL; ln = Lst_Succ(ln)) { - GNode *succ = Lst_Datum(ln); - - if (succ->make && succ->unmade == 0 && succ->made == UNMADE && - Lst_Member(&toBeMade, succ) == NULL) { - Lst_EnQueue(&toBeMade, succ); - } - } - - /* - * Set the .PREFIX and .IMPSRC variables for all the implied parents - * of this node. - */ - cpref = Var_Value(PREFIX, cgn); - for (ln = Lst_First(&cgn->iParents); ln != NULL; ln = Lst_Succ(ln)) { - pgn = Lst_Datum(ln); - if (pgn->make) { - Var_Set(IMPSRC, cname, pgn); - Var_Set(PREFIX, cpref, pgn); - } - } -} - -/** - * Make_DoAllVar - * Set up the ALLSRC and OODATE variables. Sad to say, it must be - * done separately, rather than while traversing the graph. This is - * because Make defined OODATE to contain all sources whose modification - * times were later than that of the target, *not* those sources that - * were out-of-date. Since in both compatibility and native modes, - * the modification time of the parent isn't found until the child - * has been dealt with, we have to wait until now to fill in the - * variable. As for ALLSRC, the ordering is important and not - * guaranteed when in native mode, so it must be set here, too. - * - * Side Effects: - * The ALLSRC and OODATE variables of the given node is filled in. - * If the node is a .JOIN node, its TARGET variable will be set to - * match its ALLSRC variable. - */ -void -Make_DoAllVar(GNode *gn) -{ - LstNode *ln; - GNode *cgn; - const char *child; - - LST_FOREACH(ln, &gn->children) { - /* - * Add the child's name to the ALLSRC and OODATE variables of - * the given node. The child is added only if it has not been - * given the .EXEC, .USE or .INVISIBLE attributes. .EXEC and - * .USE children are very rarely going to be files, so... - * - * A child is added to the OODATE variable if its modification - * time is later than that of its parent, as defined by Make, - * except if the parent is a .JOIN node. In that case, it is - * only added to the OODATE variable if it was actually made - * (since .JOIN nodes don't have modification times, the - * comparison is rather unfair...). - */ - cgn = Lst_Datum(ln); - - if ((cgn->type & (OP_EXEC | OP_USE | OP_INVISIBLE)) == 0) { - if (OP_NOP(cgn->type)) { - /* - * this node is only source; use the specific - * pathname for it - */ - child = cgn->path ? cgn->path : cgn->name; - } else - child = Var_Value(TARGET, cgn); - Var_Append(ALLSRC, child, gn); - if (gn->type & OP_JOIN) { - if (cgn->made == MADE) { - Var_Append(OODATE, child, gn); - } - } else if (gn->mtime < cgn->mtime || - (cgn->mtime >= now && cgn->made == MADE)) { - /* - * It goes in the OODATE variable if the parent - * is younger than the child or if the child has - * been modified more recently than the start of - * the make. This is to keep pmake from getting - * confused if something else updates the parent - * after the make starts (shouldn't happen, I - * know, but sometimes it does). In such a case, - * if we've updated the kid, the parent is - * likely to have a modification time later than - * that of the kid and anything that relies on - * the OODATE variable will be hosed. - * - * XXX: This will cause all made children to - * go in the OODATE variable, even if they're - * not touched, if RECHECK isn't defined, since - * cgn->mtime is set to now in Make_Update. - * According to some people, this is good... - */ - Var_Append(OODATE, child, gn); - } - } - } - - if (!Var_Exists (OODATE, gn)) { - Var_Set(OODATE, "", gn); - } - if (!Var_Exists (ALLSRC, gn)) { - Var_Set(ALLSRC, "", gn); - } - - if (gn->type & OP_JOIN) { - Var_Set(TARGET, Var_Value(ALLSRC, gn), gn); - } -} - -/** - * MakeStartJobs - * Start as many jobs as possible. - * - * Results: - * If the query flag was given to pmake, no job will be started, - * but as soon as an out-of-date target is found, this function - * returns TRUE. At all other times, this function returns FALSE. - * - * Side Effects: - * Nodes are removed from the toBeMade queue and job table slots - * are filled. - */ -static Boolean -MakeStartJobs(void) -{ - GNode *gn; - - while (!Lst_IsEmpty(&toBeMade) && !Job_Full()) { - gn = Lst_DeQueue(&toBeMade); - DEBUGF(MAKE, ("Examining %s...", gn->name)); - - /* - * Make sure any and all predecessors that are going to be made, - * have been. - */ - if (!Lst_IsEmpty(&gn->preds)) { - LstNode *ln; - - for (ln = Lst_First(&gn->preds); ln != NULL; - ln = Lst_Succ(ln)){ - GNode *pgn = Lst_Datum(ln); - - if (pgn->make && pgn->made == UNMADE) { - DEBUGF(MAKE, ("predecessor %s not made " - "yet.\n", pgn->name)); - break; - } - } - /* - * If ln isn't NULL, there's a predecessor as yet - * unmade, so we just drop this node on the floor. - * When the node in question has been made, it will - * notice this node as being ready to make but as yet - * unmade and will place the node on the queue. - */ - if (ln != NULL) { - continue; - } - } - - numNodes--; - if (Make_OODate(gn)) { - DEBUGF(MAKE, ("out-of-date\n")); - if (queryFlag) { - return (TRUE); - } - Make_DoAllVar(gn); - Job_Make(gn); - } else { - DEBUGF(MAKE, ("up-to-date\n")); - gn->made = UPTODATE; - if (gn->type & OP_JOIN) { - /* - * Even for an up-to-date .JOIN node, we need - * it to have its context variables so - * references to it get the correct value for - * .TARGET when building up the context - * variables of its parent(s)... - */ - Make_DoAllVar(gn); - } - - Make_Update(gn); - } - } - return (FALSE); -} - -/** - * MakePrintStatus - * Print the status of a top-level node, viz. it being up-to-date - * already or not created due to an error in a lower level. - * Callback function for Make_Run via LST_FOREACH. If gn->unmade is - * nonzero and that is meant to imply a cycle in the graph, then - * cycle is TRUE. - * - * Side Effects: - * A message may be printed. - */ -static void -MakePrintStatus(GNode *gn, Boolean cycle) -{ - LstNode *ln; - - if (gn->made == UPTODATE) { - printf("`%s' is up to date.\n", gn->name); - - } else if (gn->unmade != 0) { - if (cycle) { - /* - * If printing cycles and came to one that has unmade - * children, print out the cycle by recursing on its - * children. Note a cycle like: - * a : b - * b : c - * c : b - * will cause this to erroneously complain about a - * being in the cycle, but this is a good approximation. - */ - if (gn->made == CYCLE) { - Error("Graph cycles through `%s'", gn->name); - gn->made = ENDCYCLE; - LST_FOREACH(ln, &gn->children) - MakePrintStatus(Lst_Datum(ln), TRUE); - gn->made = UNMADE; - } else if (gn->made != ENDCYCLE) { - gn->made = CYCLE; - LST_FOREACH(ln, &gn->children) - MakePrintStatus(Lst_Datum(ln), TRUE); - } - } else { - printf("`%s' not remade because of errors.\n", - gn->name); - } - } -} - -/** - * Make_Run - * Initialize the nodes to remake and the list of nodes which are - * ready to be made by doing a breadth-first traversal of the graph - * starting from the nodes in the given list. Once this traversal - * is finished, all the 'leaves' of the graph are in the toBeMade - * queue. - * Using this queue and the Job module, work back up the graph, - * calling on MakeStartJobs to keep the job table as full as - * possible. - * - * Results: - * TRUE if work was done. FALSE otherwise. - * - * Side Effects: - * The make field of all nodes involved in the creation of the given - * targets is set to 1. The toBeMade list is set to contain all the - * 'leaves' of these subgraphs. - */ -Boolean -Make_Run(Lst *targs) -{ - GNode *gn; /* a temporary pointer */ - GNode *cgn; - Lst examine; /* List of targets to examine */ - LstNode *ln; - - Lst_Init(&examine); - Lst_Duplicate(&examine, targs, NOCOPY); - numNodes = 0; - - /* - * Make an initial downward pass over the graph, marking nodes to be - * made as we go down. We call Suff_FindDeps to find where a node is and - * to get some children for it if it has none and also has no commands. - * If the node is a leaf, we stick it on the toBeMade queue to - * be looked at in a minute, otherwise we add its children to our queue - * and go on about our business. - */ - while (!Lst_IsEmpty(&examine)) { - gn = Lst_DeQueue(&examine); - - if (!gn->make) { - gn->make = TRUE; - numNodes++; - - /* - * Apply any .USE rules before looking for implicit - * dependencies to make sure everything has commands - * that should... - */ - LST_FOREACH(ln, &gn->children) - if (Make_HandleUse(Lst_Datum(ln), gn)) - break; - - Suff_FindDeps(gn); - - if (gn->unmade != 0) { - LST_FOREACH(ln, &gn->children) { - cgn = Lst_Datum(ln); - if (!cgn->make && !(cgn->type & OP_USE)) - Lst_EnQueue(&examine, cgn); - } - } else { - Lst_EnQueue(&toBeMade, gn); - } - } - } - - if (queryFlag) { - /* - * We wouldn't do any work unless we could start some jobs in - * the next loop... (we won't actually start any, of course, - * this is just to see if any of the targets was out of date) - */ - return (MakeStartJobs()); - - } else { - /* - * Initialization. At the moment, no jobs are running and - * until some get started, nothing will happen since the - * remaining upward traversal of the graph is performed by the - * routines in job.c upon the finishing of a job. So we fill - * the Job table as much as we can before going into our loop. - */ - MakeStartJobs(); - } - - /* - * Main Loop: The idea here is that the ending of jobs will take - * care of the maintenance of data structures and the waiting for output - * will cause us to be idle most of the time while our children run as - * much as possible. Because the job table is kept as full as possible, - * the only time when it will be empty is when all the jobs which need - * running have been run, so that is the end condition of this loop. - * Note that the Job module will exit if there were any errors unless - * the keepgoing flag was given. - */ - while (!Job_Empty()) { - Job_CatchOutput(!Lst_IsEmpty(&toBeMade)); - Job_CatchChildren(!usePipes); - MakeStartJobs(); - } - - Job_Finish(); - - /* - * Print the final status of each target. E.g. if it wasn't made - * because some inferior reported an error. - */ - LST_FOREACH(ln, targs) - MakePrintStatus(Lst_Datum(ln), (makeErrors == 0) && (numNodes != 0)); - - return (TRUE); -} Property changes on: head/usr.bin/make/make.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/Makefile.dist =================================================================== --- head/usr.bin/make/Makefile.dist (revision 284463) +++ head/usr.bin/make/Makefile.dist (nonexistent) @@ -1,10 +0,0 @@ -# $FreeBSD$ -# a simple makefile to help builds on !FreeBSD systems -pmake: - @echo 'make started.' - cc -D__dead2="" -D__unused="" -Darc4random=random -D__FBSDID="static const char *id=" -DDEFSHELLNAME=\"sh\" -I. -c *.c - cc *.o -o pmake - @echo 'make completed.' - -clean: - @rm -f *.o pmake Property changes on: head/usr.bin/make/Makefile.dist ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/Makefile.depend =================================================================== --- head/usr.bin/make/Makefile.depend (revision 284463) +++ head/usr.bin/make/Makefile.depend (nonexistent) @@ -1,19 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - -DEP_MACHINE := ${.PARSEFILE:E} - -DIRDEPS = \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Property changes on: head/usr.bin/make/Makefile.depend ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/usr.bin/make/hash.h =================================================================== --- head/usr.bin/make/hash.h (revision 284463) +++ head/usr.bin/make/hash.h (nonexistent) @@ -1,103 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1988, 1989 by Adam de Boor - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)hash.h 8.1 (Berkeley) 6/6/93 - * $FreeBSD$ - */ - -#ifndef hash_h_f6312f46 -#define hash_h_f6312f46 - -/* hash.h -- - * - * This file contains definitions used by the hash module, - * which maintains hash tables. - */ - -#include "util.h" - -/* - * The following defines one entry in the hash table. - */ -typedef struct Hash_Entry { - struct Hash_Entry *next; /* Link entries within same bucket. */ - void *clientData; /* Data associated with key. */ - unsigned namehash; /* hash value of key */ - char name[1]; /* key string */ -} Hash_Entry; - -typedef struct Hash_Table { - struct Hash_Entry **bucketPtr; /* Buckets in the table */ - int size; /* Actual size of array. */ - int numEntries; /* Number of entries in the table. */ - int mask; /* Used to select bits for hashing. */ -} Hash_Table; - -/* - * The following structure is used by the searching routines - * to record where we are in the search. - */ -typedef struct Hash_Search { - const Hash_Table *tablePtr; /* Table being searched. */ - int nextIndex; /* Next bucket to check */ - Hash_Entry *hashEntryPtr; /* Next entry in current bucket */ -} Hash_Search; - -/* - * Macros. - */ - -/* - * void *Hash_GetValue(const Hash_Entry *h) - */ -#define Hash_GetValue(h) ((h)->clientData) - -/* - * Hash_SetValue(Hash_Entry *h, void *val); - */ -#define Hash_SetValue(h, val) ((h)->clientData = (val)) - -void Hash_InitTable(Hash_Table *, int); -void Hash_DeleteTable(Hash_Table *); -Hash_Entry *Hash_FindEntry(const Hash_Table *, const char *); -Hash_Entry *Hash_CreateEntry(Hash_Table *, const char *, Boolean *); -void Hash_DeleteEntry(Hash_Table *, Hash_Entry *); -Hash_Entry *Hash_EnumFirst(const Hash_Table *, Hash_Search *); -Hash_Entry *Hash_EnumNext(Hash_Search *); - -#endif /* hash_h_f6312f46 */ Property changes on: head/usr.bin/make/hash.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/suff.c =================================================================== --- head/usr.bin/make/suff.c (revision 284463) +++ head/usr.bin/make/suff.c (nonexistent) @@ -1,2205 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)suff.c 8.4 (Berkeley) 3/21/94 - */ - -#include -__FBSDID("$FreeBSD$"); - -/*- - * suff.c -- - * Functions to maintain suffix lists and find implicit dependents - * using suffix transformation rules - * - * Interface: - * Suff_Init Initialize all things to do with suffixes. - * - * Suff_DoPaths This function is used to make life easier - * when searching for a file according to its - * suffix. It takes the global search path, - * as defined using the .PATH: target, and appends - * its directories to the path of each of the - * defined suffixes, as specified using - * .PATH: targets. In addition, all - * directories given for suffixes labeled as - * include files or libraries, using the .INCLUDES - * or .LIBS targets, are played with using - * Dir_MakeFlags to create the .INCLUDES and - * .LIBS global variables. - * - * Suff_ClearSuffixes Clear out all the suffixes and defined - * transformations. - * - * Suff_IsTransform Return TRUE if the passed string is the lhs - * of a transformation rule. - * - * Suff_AddSuffix Add the passed string as another known suffix. - * - * Suff_GetPath Return the search path for the given suffix. - * - * Suff_AddInclude Mark the given suffix as denoting an include - * file. - * - * Suff_AddLib Mark the given suffix as denoting a library. - * - * Suff_AddTransform Add another transformation to the suffix - * graph. Returns GNode suitable for framing, I - * mean, tacking commands, attributes, etc. on. - * - * Suff_SetNull Define the suffix to consider the suffix of - * any file that doesn't have a known one. - * - * Suff_FindDeps Find implicit sources for and the location of - * a target based on its suffix. Returns the - * bottom-most node added to the graph or NULL - * if the target had no implicit sources. - */ - -#include -#include -#include -#include - -#include "arch.h" -#include "buf.h" -#include "config.h" -#include "dir.h" -#include "globals.h" -#include "GNode.h" -#include "lst.h" -#include "make.h" -#include "parse.h" -#include "str.h" -#include "suff.h" -#include "targ.h" -#include "util.h" -#include "var.h" - -/* Lst of suffixes */ -static Lst sufflist = Lst_Initializer(sufflist); - -/* Lst of suffixes to be cleaned */ -static Lst suffClean = Lst_Initializer(suffClean); - -/* Lst of sources */ -static Lst srclist = Lst_Initializer(srclist); - -/* Lst of transformation rules */ -static Lst transforms = Lst_Initializer(transforms); - -/* Counter for assigning suffix numbers */ -static int sNum = 0; - -/* - * Structure describing an individual suffix. - */ -typedef struct Suff { - char *name; /* The suffix itself */ - int nameLen; /* Length of the suffix */ - short flags; /* Type of suffix */ -#define SUFF_INCLUDE 0x01 /* One which is #include'd */ -#define SUFF_LIBRARY 0x02 /* One which contains a library */ -#define SUFF_NULL 0x04 /* The empty suffix */ - struct Path searchPath; /* Path for files with this suffix */ - int sNum; /* The suffix number */ - int refCount; /* Reference count of list membership */ - Lst parents; /* Suffixes we have a transformation to */ - Lst children; /* Suffixes we have a transformation from */ - Lst ref; /* List of lists this suffix is referenced */ -} Suff; - -/* - * Structure used in the search for implied sources. - */ -typedef struct Src { - char *file; /* The file to look for */ - char *pref; /* Prefix from which file was formed */ - Suff *suff; /* The suffix on the file */ - struct Src *parent; /* The Src for which this is a source */ - GNode *node; /* The node describing the file */ - int children; /* Count of existing children (so we don't free - * this thing too early or never nuke it) */ -#ifdef DEBUG_SRC - Lst cp; /* Debug; children list */ -#endif -} Src; - -/* The NULL suffix for this run */ -static Suff *suffNull; - -/* The empty suffix required for POSIX single-suffix transformation rules */ -static Suff *emptySuff; - -static void SuffFindDeps(GNode *, Lst *); - - -/*- - *----------------------------------------------------------------------- - * SuffSuffIsSuffix -- - * See if suff is a suffix of str. - * - * Results: - * NULL if it ain't, pointer to character in str before suffix if - * it is. - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -static char * -SuffSuffIsSuffix(const Suff *s, char *str) -{ - const char *p1; /* Pointer into suffix name */ - char *p2; /* Pointer into string being examined */ - size_t len; - - len = strlen(str); - p1 = s->name + s->nameLen; - p2 = str + len; - - while (p1 >= s->name && len > 0 && *p1 == *p2) { - p1--; - p2--; - len--; - } - - return (p1 == s->name - 1 ? p2 : NULL); -} - -/*- - *----------------------------------------------------------------------- - * SuffSuffFind -- - * Find a suffix given its name. - * - * Results: - * The suffix or NULL. - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -static Suff * -SuffSuffFind(const char *s) -{ - LstNode *ln; - - LST_FOREACH(ln, &sufflist) { - if (strcmp(s, ((const Suff *)Lst_Datum(ln))->name) == 0) - return (Lst_Datum(ln)); - } - return (NULL); -} - -/*- - *----------------------------------------------------------------------- - * SuffTransFind - * Find a transform. - * - * Results: - * transform or NULL. - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -static GNode * -SuffTransFind(const char *name) -{ - LstNode *ln; - - LST_FOREACH(ln, &transforms) { - if (strcmp(name, ((const GNode *)Lst_Datum(ln))->name) == 0) - return (Lst_Datum(ln)); - } - return (NULL); -} - - /*********** Maintenance Functions ************/ - -#if 0 -/* - * Keep this function for now until it is clear why a .SUFFIXES: doesn't - * actually delete the suffixes but just puts them on the suffClean list. - */ -/*- - *----------------------------------------------------------------------- - * SuffFree -- - * Free up all memory associated with the given suffix structure. - * - * Results: - * none - * - * Side Effects: - * the suffix entry is detroyed - *----------------------------------------------------------------------- - */ -static void -SuffFree(void *sp) -{ - Suff *s = sp; - - if (s == suffNull) - suffNull = NULL; - - if (s == emptySuff) - emptySuff = NULL; - - Lst_Destroy(&s->ref, NOFREE); - Lst_Destroy(&s->children, NOFREE); - Lst_Destroy(&s->parents, NOFREE); - Lst_Destroy(&s->searchPath, Dir_Destroy); - - free(s->name); - free(s); -} -#endif - -/*- - *----------------------------------------------------------------------- - * SuffRemove -- - * Remove the suffix into the list - * - * Results: - * None - * - * Side Effects: - * The reference count for the suffix is decremented - *----------------------------------------------------------------------- - */ -static void -SuffRemove(Lst *l, Suff *s) -{ - LstNode *ln = Lst_Member(l, s); - - if (ln != NULL) { - Lst_Remove(l, ln); - s->refCount--; - } -} - -/*- - *----------------------------------------------------------------------- - * SuffInsert -- - * Insert the suffix into the list keeping the list ordered by suffix - * numbers. - * - * Results: - * None - * - * Side Effects: - * The reference count of the suffix is incremented - *----------------------------------------------------------------------- - */ -static void -SuffInsert(Lst *l, Suff *s) -{ - LstNode *ln; /* current element in l we're examining */ - Suff *s2; /* the suffix descriptor in this element */ - - s2 = NULL; - for (ln = Lst_First(l); ln != NULL; ln = Lst_Succ(ln)) { - s2 = Lst_Datum(ln); - if (s2->sNum >= s->sNum) - break; - } - if (s2 == NULL) { - DEBUGF(SUFF, ("inserting an empty list?...")); - } - - DEBUGF(SUFF, ("inserting %s(%d)...", s->name, s->sNum)); - if (ln == NULL) { - DEBUGF(SUFF, ("at end of list\n")); - Lst_AtEnd(l, s); - s->refCount++; - Lst_AtEnd(&s->ref, l); - } else if (s2->sNum != s->sNum) { - DEBUGF(SUFF, ("before %s(%d)\n", s2->name, s2->sNum)); - Lst_Insert(l, ln, s); - s->refCount++; - Lst_AtEnd(&s->ref, l); - } else { - DEBUGF(SUFF, ("already there\n")); - } -} - -/*- - *----------------------------------------------------------------------- - * Suff_ClearSuffixes -- - * This is gross. Nuke the list of suffixes but keep all transformation - * rules around. The transformation graph is destroyed in this process, - * but we leave the list of rules so when a new graph is formed the rules - * will remain. - * This function is called from the parse module when a - * .SUFFIXES:\n line is encountered. - * - * Results: - * none - * - * Side Effects: - * the sufflist and its graph nodes are destroyed - *----------------------------------------------------------------------- - */ -void -Suff_ClearSuffixes(void) -{ - - Lst_Concat(&suffClean, &sufflist, LST_CONCLINK); - - sNum = 1; - suffNull = emptySuff; - /* - * Clear suffNull's children list (the other suffixes are built new, but - * suffNull is used as is). - * NOFREE is used because all suffixes are are on the suffClean list. - * suffNull should not have parents. - */ - Lst_Destroy(&suffNull->children, NOFREE); -} - -/*- - *----------------------------------------------------------------------- - * SuffParseTransform -- - * Parse a transformation string to find its two component suffixes. - * - * Results: - * TRUE if the string is a valid transformation and FALSE otherwise. - * - * Side Effects: - * The passed pointers are overwritten. - * - *----------------------------------------------------------------------- - */ -static Boolean -SuffParseTransform(char *str, Suff **srcPtr, Suff **targPtr) -{ - LstNode *srcLn; /* element in suffix list of trans source*/ - Suff *src; /* Source of transformation */ - char *str2; /* Extra pointer (maybe target suffix) */ - LstNode *singleLn; /* element in suffix list of any suffix - * that exactly matches str */ - Suff *single = NULL; /* Source of possible transformation to - * null suffix */ - - singleLn = NULL; - - /* - * Loop looking first for a suffix that matches the start of the - * string and then for one that exactly matches the rest of it. If - * we can find two that meet these criteria, we've successfully - * parsed the string. - */ - srcLn = Lst_First(&sufflist); - for (;;) { - /* advance to next possible suffix */ - while (srcLn != NULL) { - src = Lst_Datum(srcLn); - if (strncmp(str, src->name, strlen(src->name)) == 0) - break; - srcLn = LST_NEXT(srcLn); - } - - if (srcLn == NULL) { - /* - * Ran out of source suffixes -- no such rule - */ - if (singleLn != NULL) { - /* - * Not so fast Mr. Smith! There was a suffix - * that encompassed the entire string, so we - * assume it was a transformation to the null - * suffix (thank you POSIX). We still prefer to - * find a double rule over a singleton, hence we - * leave this check until the end. - * - * XXX: Use emptySuff over suffNull? - */ - *srcPtr = single; - *targPtr = suffNull; - return (TRUE); - } - return (FALSE); - } - str2 = str + src->nameLen; - if (*str2 == '\0') { - single = src; - singleLn = srcLn; - } else { - - *targPtr = SuffSuffFind(str2); - if (*targPtr != NULL) { - *srcPtr = src; - return (TRUE); - } - } - /* next one */ - srcLn = LST_NEXT(srcLn); - } -} - -/*- - *----------------------------------------------------------------------- - * Suff_IsTransform -- - * Return TRUE if the given string is a transformation rule - * - * - * Results: - * TRUE if the string is a concatenation of two known suffixes. - * FALSE otherwise - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -Boolean -Suff_IsTransform(char *str) -{ - Suff *src, *targ; - - return (SuffParseTransform(str, &src, &targ)); -} - -/*- - *----------------------------------------------------------------------- - * Suff_AddTransform -- - * Add the transformation rule described by the line to the - * list of rules and place the transformation itself in the graph - * - * Results: - * The node created for the transformation in the transforms list - * - * Side Effects: - * The node is placed on the end of the transforms Lst and links are - * made between the two suffixes mentioned in the target name - *----------------------------------------------------------------------- - */ -GNode * -Suff_AddTransform(char *line) -{ - GNode *gn; /* GNode of transformation rule */ - Suff *s; /* source suffix */ - Suff *t; /* target suffix */ - - s = t = NULL; /* silence gcc */ - gn = SuffTransFind(line); - if (gn == NULL) { - /* - * Make a new graph node for the transformation. - * It will be filled in by the Parse module. - */ - gn = Targ_NewGN(line); - Lst_AtEnd(&transforms, gn); - } else { - /* - * New specification for transformation rule. Just nuke the - * old list of commands so they can be filled in again... - * We don't actually free the commands themselves, because a - * given command can be attached to several different - * transformations. - */ - Lst_Destroy(&gn->commands, NOFREE); - Lst_Destroy(&gn->children, NOFREE); - } - - gn->type = OP_TRANSFORM; - - SuffParseTransform(line, &s, &t); - - /* - * link the two together in the proper relationship and order - */ - DEBUGF(SUFF, ("defining transformation from `%s' to `%s'\n", - s->name, t->name)); - SuffInsert(&t->children, s); - SuffInsert(&s->parents, t); - - return (gn); -} - -/*- - *----------------------------------------------------------------------- - * Suff_EndTransform -- - * Handle the finish of a transformation definition, removing the - * transformation from the graph if it has neither commands nor - * sources. This is called from the Parse module at the end of - * a dependency block. - * - * Side Effects: - * If the node has no commands or children, the children and parents - * lists of the affected suffices are altered. - * - *----------------------------------------------------------------------- - */ -void -Suff_EndTransform(const GNode *gn) -{ - Suff *s, *t; - - if (!Lst_IsEmpty(&gn->commands) || !Lst_IsEmpty(&gn->children)) { - DEBUGF(SUFF, ("transformation %s complete\n", gn->name)); - return; - } - - /* - * SuffParseTransform() may fail for special rules which are not - * actual transformation rules (e.g., .DEFAULT). - */ - if (!SuffParseTransform(gn->name, &s, &t)) - return; - - DEBUGF(SUFF, ("deleting transformation from `%s' to `%s'\n", - s->name, t->name)); - - /* - * Remove the source from the target's children list. We check - * for a NULL return to handle a beanhead saying something like - * .c.o .c.o: - * - * We'll be called twice when the next target is seen, but .c - * and .o are only linked once... - */ - SuffRemove(&t->children, s); - - /* - * Remove the target from the source's parents list - */ - SuffRemove(&s->parents, t); -} - -/*- - *----------------------------------------------------------------------- - * SuffRebuildGraph -- - * Called from Suff_AddSuffix via LST_FOREACH to search through the - * list of existing transformation rules and rebuild the transformation - * graph when it has been destroyed by Suff_ClearSuffixes. If the - * given rule is a transformation involving this suffix and another, - * existing suffix, the proper relationship is established between - * the two. - * - * Side Effects: - * The appropriate links will be made between this suffix and - * others if transformation rules exist for it. - * - *----------------------------------------------------------------------- - */ -static void -SuffRebuildGraph(const GNode *transform, Suff *s) -{ - char *cp; - Suff *s2 = NULL; - - /* - * First see if it is a transformation from this suffix. - */ - if (strncmp(transform->name, s->name, strlen(s->name)) == 0) { - cp = transform->name + strlen(s->name); - - if (cp[0] == '\0') /* null rule */ - s2 = suffNull; - else - s2 = SuffSuffFind(cp); - if (s2 != NULL) { - /* - * Found target. Link in and return, since it can't be - * anything else. - */ - SuffInsert(&s2->children, s); - SuffInsert(&s->parents, s2); - return; - } - } - - /* - * Not from, maybe to? - */ - cp = SuffSuffIsSuffix(s, transform->name); - if (cp != NULL) { - /* - * Null-terminate the source suffix in order to find it. - */ - cp[1] = '\0'; - s2 = SuffSuffFind(transform->name); - - /* - * Replace the start of the target suffix - */ - cp[1] = s->name[0]; - if (s2 != NULL) { - /* - * Found it -- establish the proper relationship - */ - SuffInsert(&s->children, s2); - SuffInsert(&s2->parents, s); - } - } -} - -/*- - *----------------------------------------------------------------------- - * Suff_AddSuffix -- - * Add the suffix in string to the end of the list of known suffixes. - * Should we restructure the suffix graph? Make doesn't... - * - * Results: - * None - * - * Side Effects: - * A GNode is created for the suffix and a Suff structure is created and - * added to the suffixes list unless the suffix was already known. - *----------------------------------------------------------------------- - */ -void -Suff_AddSuffix(char *str) -{ - Suff *s; /* new suffix descriptor */ - LstNode *ln; - - if (SuffSuffFind(str) != NULL) - /* - * Already known - */ - return; - - s = emalloc(sizeof(Suff)); - - s->name = estrdup(str); - s->nameLen = strlen(s->name); - TAILQ_INIT(&s->searchPath); - Lst_Init(&s->children); - Lst_Init(&s->parents); - Lst_Init(&s->ref); - s->sNum = sNum++; - s->flags = 0; - s->refCount = 0; - - Lst_AtEnd(&sufflist, s); - - /* - * Look for any existing transformations from or to this suffix. - * XXX: Only do this after a Suff_ClearSuffixes? - */ - LST_FOREACH(ln, &transforms) - SuffRebuildGraph(Lst_Datum(ln), s); -} - -/*- - *----------------------------------------------------------------------- - * Suff_GetPath -- - * Return the search path for the given suffix, if it's defined. - * - * Results: - * The searchPath for the desired suffix or NULL if the suffix isn't - * defined. - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -struct Path * -Suff_GetPath(char *sname) -{ - Suff *s; - - s = SuffSuffFind(sname); - if (s == NULL) - return (NULL); - return (&s->searchPath); -} - -/*- - *----------------------------------------------------------------------- - * Suff_DoPaths -- - * Extend the search paths for all suffixes to include the default - * search path. - * - * Results: - * None. - * - * Side Effects: - * The searchPath field of all the suffixes is extended by the - * directories in dirSearchPath. If paths were specified for the - * ".h" suffix, the directories are stuffed into a global variable - * called ".INCLUDES" with each directory preceded by a -I. The same - * is done for the ".a" suffix, except the variable is called - * ".LIBS" and the flag is -L. - *----------------------------------------------------------------------- - */ -void -Suff_DoPaths(void) -{ - Suff *s; - LstNode *ln; - char *ptr; - struct Path inIncludes; /* Cumulative .INCLUDES path */ - struct Path inLibs; /* Cumulative .LIBS path */ - - TAILQ_INIT(&inIncludes); - TAILQ_INIT(&inLibs); - - for (ln = Lst_First(&sufflist); ln != NULL; ln = Lst_Succ(ln)) { - s = Lst_Datum(ln); -#ifdef INCLUDES - if (s->flags & SUFF_INCLUDE) { - Path_Concat(&inIncludes, &s->searchPath); - } -#endif /* INCLUDES */ -#ifdef LIBRARIES - if (s->flags & SUFF_LIBRARY) { - Path_Concat(&inLibs, &s->searchPath); - } -#endif /* LIBRARIES */ - Path_Concat(&s->searchPath, &dirSearchPath); - } - - ptr = Path_MakeFlags("-I", &inIncludes); - Var_SetGlobal(".INCLUDES", ptr); - free(ptr); - - ptr = Path_MakeFlags("-L", &inLibs); - Var_SetGlobal(".LIBS", ptr); - free(ptr); - - Path_Clear(&inIncludes); - Path_Clear(&inLibs); -} - -/*- - *----------------------------------------------------------------------- - * Suff_AddInclude -- - * Add the given suffix as a type of file which gets included. - * Called from the parse module when a .INCLUDES line is parsed. - * The suffix must have already been defined. - * - * Results: - * None. - * - * Side Effects: - * The SUFF_INCLUDE bit is set in the suffix's flags field - * - *----------------------------------------------------------------------- - */ -void -Suff_AddInclude(char *sname) -{ - Suff *s; - - if ((s = SuffSuffFind(sname)) != NULL) - s->flags |= SUFF_INCLUDE; -} - -/*- - *----------------------------------------------------------------------- - * Suff_AddLib -- - * Add the given suffix as a type of file which is a library. - * Called from the parse module when parsing a .LIBS line. The - * suffix must have been defined via .SUFFIXES before this is - * called. - * - * Results: - * None. - * - * Side Effects: - * The SUFF_LIBRARY bit is set in the suffix's flags field - * - *----------------------------------------------------------------------- - */ -void -Suff_AddLib(char *sname) -{ - Suff *s; - - if ((s = SuffSuffFind(sname)) != NULL) - s->flags |= SUFF_LIBRARY; -} - -/* - * Create a new Src structure - */ -static Src * -SuffSrcCreate(char *file, char *prefix, Suff *suff, Src *parent, GNode *node) -{ - Src *s; - - s = emalloc(sizeof(*s)); - s->file = file; - s->pref = prefix; - s->suff = suff; - s->parent = parent; - s->node = node; - s->children = 0; - -#ifdef DEBUG_SRC - Lst_Init(&s->cp); -#endif - - return (s); -} - - /********** Implicit Source Search Functions *********/ - -/*- - *----------------------------------------------------------------------- - * SuffAddLevel -- - * Add all the children of targ as Src structures to the given list: - * Add a suffix as a Src structure to the given list with its parent - * being the given Src structure. If the suffix is the null suffix, - * the prefix is used unaltered as the file name in the Src structure. - * - * Results: - * None - * - * Side Effects: - * Lots of structures are created and added to the list - *----------------------------------------------------------------------- - */ -static void -SuffAddLevel(Lst *l, Src *targ) -{ - LstNode *ln; - Suff *suff; - Src *s2; -#ifdef DEBUG_SRC - const LstNode *ln1; -#endif - - LST_FOREACH(ln, &targ->suff->children) { - suff = Lst_Datum(ln); - - if ((suff->flags & SUFF_NULL) && *suff->name != '\0') { - /* - * If the suffix has been marked as the NULL suffix, - * also create a Src structure for a file with no suffix - * attached. Two birds, and all that... - */ - s2 = SuffSrcCreate(estrdup(targ->pref), targ->pref, - suff, targ, NULL); - suff->refCount++; - targ->children += 1; - Lst_AtEnd(l, s2); -#ifdef DEBUG_SRC - Lst_AtEnd(&targ->cp, s2); - printf("1 add %p %p to %p:", targ, s2, l); - LST_FOREACH(ln1, l) - printf("%p ", (const void *)Lst_Datum(ln1)); - printf("\n"); -#endif - } - s2 = SuffSrcCreate(str_concat(targ->pref, suff->name, 0), - targ->pref, suff, targ, NULL); - suff->refCount++; - targ->children += 1; - Lst_AtEnd(l, s2); -#ifdef DEBUG_SRC - Lst_AtEnd(&targ->cp, s2); - printf("2 add %p %p to %p:", targ, s2, l); - LST_FOREACH(ln1, l) - printf("%p ", (const void *)Lst_Datum(ln1)); - printf("\n"); -#endif - } -} - -/*- - *---------------------------------------------------------------------- - * SuffRemoveSrc -- - * Free all src structures in list that don't have a reference count - * XXX this actually frees only the first of these. - * - * Results: - * True if a src was removed - * - * Side Effects: - * The memory is free'd. - *---------------------------------------------------------------------- - */ -static int -SuffRemoveSrc(Lst *l) -{ - LstNode *ln, *ln1; - Src *s; - int t = 0; - -#ifdef DEBUG_SRC - printf("cleaning %lx: ", (unsigned long) l); - LST_FOREACH(ln, l) - printf("%p ", (const void *)Lst_Datum(ln)); - printf("\n"); -#endif - - for (ln = Lst_First(l); ln != NULL; ln = ln1) { - ln1 = Lst_Succ(ln); - - s = (Src *)Lst_Datum(ln); - if (s->children == 0) { - free(s->file); - if (!s->parent) - free(s->pref); - else { -#ifdef DEBUG_SRC - LstNode *ln = Lst_Member(&s->parent->cp, s); - if (ln != NULL) - Lst_Remove(&s->parent->cp, ln); -#endif - --s->parent->children; - } -#ifdef DEBUG_SRC - printf("free: [l=%p] p=%p %d\n", l, s, s->children); - Lst_Destroy(&s->cp, NOFREE); -#endif - Lst_Remove(l, ln); - free(s); - t |= 1; - return (TRUE); - } -#ifdef DEBUG_SRC - else { - const LstNode *tln; - - printf("keep: [l=%p] p=%p %d: ", l, s, s->children); - LST_FOREACH(tln, &s->cp) - printf("%p ", (const void *)Lst_Datum(tln)); - printf("\n"); - } -#endif - } - - return (t); -} - -/*- - *----------------------------------------------------------------------- - * SuffFindThem -- - * Find the first existing file/target in the list srcs - * - * Results: - * The lowest structure in the chain of transformations - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -static Src * -SuffFindThem(Lst *srcs, Lst *slst) -{ - Src *s; /* current Src */ - Src *rs; /* returned Src */ - char *ptr; - - rs = NULL; - - while (!Lst_IsEmpty (srcs)) { - s = Lst_DeQueue(srcs); - - DEBUGF(SUFF, ("\ttrying %s...", s->file)); - - /* - * A file is considered to exist if either a node exists in the - * graph for it or the file actually exists. - */ - if (Targ_FindNode(s->file, TARG_NOCREATE) != NULL) { -#ifdef DEBUG_SRC - printf("remove %p from %p\n", s, srcs); -#endif - rs = s; - break; - } - - if ((ptr = Path_FindFile(s->file, - &s->suff->searchPath)) != NULL) { - rs = s; -#ifdef DEBUG_SRC - printf("remove %p from %p\n", s, srcs); -#endif - free(ptr); - break; - } - - DEBUGF(SUFF, ("not there\n")); - - SuffAddLevel(srcs, s); - Lst_AtEnd(slst, s); - } - - if (rs) { - DEBUGF(SUFF, ("got it\n")); - } - return (rs); -} - -/*- - *----------------------------------------------------------------------- - * SuffFindCmds -- - * See if any of the children of the target in the Src structure is - * one from which the target can be transformed. If there is one, - * a Src structure is put together for it and returned. - * - * Results: - * The Src structure of the "winning" child, or NULL if no such beast. - * - * Side Effects: - * A Src structure may be allocated. - * - *----------------------------------------------------------------------- - */ -static Src * -SuffFindCmds(Src *targ, Lst *slst) -{ - LstNode *ln; /* General-purpose list node */ - GNode *t; /* Target GNode */ - GNode *s; /* Source GNode */ - int prefLen;/* The length of the defined prefix */ - Suff *suff; /* Suffix on matching beastie */ - Src *ret; /* Return value */ - char *cp; - - t = targ->node; - prefLen = strlen(targ->pref); - - for (ln = Lst_First(&t->children); ln != NULL; ln = Lst_Succ(ln)) { - s = Lst_Datum(ln); - - cp = strrchr(s->name, '/'); - if (cp == NULL) { - cp = s->name; - } else { - cp++; - } - if (strncmp(cp, targ->pref, prefLen) == 0) { - /* - * The node matches the prefix ok, see if it has - * a known suffix. - */ - suff = SuffSuffFind(&cp[prefLen]); - if (suff != NULL) { - /* - * It even has a known suffix, see if there's - * a transformation defined between the node's - * suffix and the target's suffix. - * - * XXX: Handle multi-stage transformations - * here, too. - */ - if (Lst_Member(&suff->parents, - targ->suff) != NULL) { - /* - * Hot Damn! Create a new Src structure - * to describe this transformation - * (making sure to duplicate the - * source node's name so Suff_FindDeps - * can free it again (ick)), and return - * the new structure. - */ - ret = SuffSrcCreate(estrdup(s->name), - targ->pref, suff, targ, s); - suff->refCount++; - targ->children += 1; -#ifdef DEBUG_SRC - printf("3 add %p %p\n", &targ, ret); - Lst_AtEnd(&targ->cp, ret); -#endif - Lst_AtEnd(slst, ret); - DEBUGF(SUFF, ("\tusing existing source " - "%s\n", s->name)); - return (ret); - } - } - } - } - return (NULL); -} - -/*- - * The child node contains variable references. Expand them and return - * a list of expansions. - */ -static void -SuffExpandVariables(GNode *parent, GNode *child, Lst *members) -{ - Buffer *buf; - char *cp; - char *start; - - Lst_Init(members); - - DEBUGF(SUFF, ("Expanding \"%s\"...", child->name)); - buf = Var_Subst(child->name, parent, TRUE); - cp = Buf_Data(buf); - - if (child->type & OP_ARCHV) { - /* - * Node was an archive(member) target, so we - * want to call on the Arch module to find the - * nodes for us, expanding variables in the - * parent's context. - */ - Arch_ParseArchive(&cp, members, parent); - Buf_Destroy(buf, TRUE); - return; - } - /* - * Break the result into a vector of strings whose nodes we can find, - * then add those nodes to the members list. Unfortunately, we can't use - * brk_string b/c it doesn't understand about variable specifications - * with spaces in them... XXX - */ - for (start = cp; *start == ' ' || *start == '\t'; start++) - ; - - for (cp = start; *cp != '\0'; cp++) { - if (*cp == ' ' || *cp == '\t') { - /* - * White-space -- terminate element, find the node, - * add it, skip any further spaces. - */ - *cp++ = '\0'; - Lst_AtEnd(members, Targ_FindNode(start, TARG_CREATE)); - - while (*cp == ' ' || *cp == '\t') { - cp++; - } - /* - * Adjust cp for increment at - * start of loop, but set start - * to first non-space. - */ - start = cp--; - - } else if (*cp == '$') { - /* - * Start of a variable spec -- contact variable module - * to find the end so we can skip over it. - */ - char *junk; - size_t len = 0; - Boolean doFree; - - junk = Var_Parse(cp, parent, TRUE, &len, &doFree); - if (junk != var_Error) { - cp += len - 1; - } - if (doFree) { - free(junk); - } - - } else if (*cp == '\\' && *cp != '\0') { - /* - * Escaped something -- skip over it - */ - cp++; - } - } - - if (cp != start) { - /* - * Stuff left over -- add it to the - * list too - */ - Lst_AtEnd(members, Targ_FindNode(start, TARG_CREATE)); - } - - Buf_Destroy(buf, TRUE); -} - -/*- - * The child node contains wildcards. Expand them and return a list of - * expansions. - */ -static void -SuffExpandWildcards(GNode *child, Lst *members) -{ - char *cp; - Lst exp; /* List of expansions */ - LstNode *ln; - struct Path *path; /* Search path along which to expand */ - - Lst_Init(members); - - /* - * Find a path along which to expand the word. - * - * If the word has a known suffix, use that path. - * If it has no known suffix and we're allowed to use the null - * suffix, use its path. - * Else use the default system search path. - */ - LST_FOREACH(ln, &sufflist) { - if (SuffSuffIsSuffix(Lst_Datum(ln), child->name) != NULL) - break; - } - - DEBUGF(SUFF, ("Wildcard expanding \"%s\"...", child->name)); - - if (ln != NULL) { - Suff *s = Lst_Datum(ln); - - DEBUGF(SUFF, ("suffix is \"%s\"...", s->name)); - path = &s->searchPath; - } else { - /* - * Use default search path - */ - path = &dirSearchPath; - } - - /* - * Expand the word along the chosen path - */ - Lst_Init(&exp); - Path_Expand(child->name, path, &exp); - - while (!Lst_IsEmpty(&exp)) { - /* - * Fetch next expansion off the list and find its GNode - */ - cp = Lst_DeQueue(&exp); - - DEBUGF(SUFF, ("%s...", cp)); - Lst_AtEnd(members, Targ_FindNode(cp, TARG_CREATE)); - } -} - -/*- - *----------------------------------------------------------------------- - * SuffExpandChildren -- - * Expand the names of any children of a given node that contain - * variable invocations or file wildcards into actual targets. - * - * Results: - * == 0 (continue) - * - * Side Effects: - * The expanded node is removed from the parent's list of children, - * and the parent's unmade counter is decremented, but other nodes - * may be added. - * - *----------------------------------------------------------------------- - */ -static void -SuffExpandChildren(GNode *parent, LstNode *current) -{ - GNode *cchild; /* current child */ - GNode *gn; - LstNode *prev; /* node after which to append new source */ - Lst members; /* expanded nodes */ - - if (current == NULL) { - /* start from begin of parent's children list */ - current = Lst_First(&parent->children); - } - - while (current != NULL) { - cchild = Lst_Datum(current); - - /* - * First do variable expansion -- this takes precedence over - * wildcard expansion. If the result contains wildcards, they'll - * be gotten to later since the resulting words are tacked - * instead of the current child onto the children list. - * - * XXXHB what if cchild contains lib.a(t1.o t2.o t3.o) but - * no $? - */ - if (strchr(cchild->name, '$') != NULL) { - SuffExpandVariables(parent, cchild, &members); - - } else if (Dir_HasWildcards(cchild->name)) { - SuffExpandWildcards(cchild, &members); - - } else { - /* nothing special just advance to next child */ - current = LST_NEXT(current); - continue; - } - - /* - * New nodes effectively take the place of the child, - * so place them after the child - */ - prev = current; - - /* - * Add all new elements to the parent node if they aren't - * already children of it. - */ - while(!Lst_IsEmpty(&members)) { - gn = Lst_DeQueue(&members); - - DEBUGF(SUFF, ("%s...", gn->name)); - if (Lst_Member(&parent->children, gn) == NULL) { - Lst_Append(&parent->children, prev, gn); - prev = Lst_Succ(prev); - Lst_AtEnd(&gn->parents, parent); - parent->unmade++; - } - } - - /* - * Now the source is expanded, remove it from the list - * of children to keep it from being processed. - * Advance to the next child. - */ - prev = current; - current = LST_NEXT(current); - - parent->unmade--; - Lst_Remove(&parent->children, prev); - DEBUGF(SUFF, ("\n")); - } -} - -/*- - *----------------------------------------------------------------------- - * SuffApplyTransform -- - * Apply a transformation rule, given the source and target nodes - * and suffixes. - * - * Results: - * TRUE if successful, FALSE if not. - * - * Side Effects: - * The source and target are linked and the commands from the - * transformation are added to the target node's commands list. - * All attributes but OP_DEPMASK and OP_TRANSFORM are applied - * to the target. The target also inherits all the sources for - * the transformation rule. - * - *----------------------------------------------------------------------- - */ -static Boolean -SuffApplyTransform(GNode *tGn, GNode *sGn, Suff *t, Suff *s) -{ - LstNode *ln; /* General node */ - char *tname; /* Name of transformation rule */ - GNode *gn; /* Node for same */ - - if (Lst_Member(&tGn->children, sGn) == NULL) { - /* - * Not already linked, so form the proper links between the - * target and source. - */ - Lst_AtEnd(&tGn->children, sGn); - Lst_AtEnd(&sGn->parents, tGn); - tGn->unmade += 1; - } - - if ((sGn->type & OP_OPMASK) == OP_DOUBLEDEP) { - /* - * When a :: node is used as the implied source of a node, - * we have to link all its cohorts in as sources as well. Only - * the initial sGn gets the target in its iParents list, however - * as that will be sufficient to get the .IMPSRC variable set - * for tGn - */ - for (ln = Lst_First(&sGn->cohorts); ln != NULL; - ln = Lst_Succ(ln)) { - gn = Lst_Datum(ln); - - if (Lst_Member(&tGn->children, gn) == NULL) { - /* - * Not already linked, so form the proper - * links between the target and source. - */ - Lst_AtEnd(&tGn->children, gn); - Lst_AtEnd(&gn->parents, tGn); - tGn->unmade += 1; - } - } - } - /* - * Locate the transformation rule itself - */ - tname = str_concat(s->name, t->name, 0); - gn = SuffTransFind(tname); - free(tname); - - if (gn == NULL) { - /* - * Not really such a transformation rule (can happen when we're - * called to link an OP_MEMBER and OP_ARCHV node), so return - * FALSE. - */ - return (FALSE); - } - - DEBUGF(SUFF, ("\tapplying %s -> %s to \"%s\"\n", - s->name, t->name, tGn->name)); - - /* - * Record last child for expansion purposes - */ - ln = Lst_Last(&tGn->children); - - /* - * Pass the buck to Make_HandleUse to apply the rule - */ - Make_HandleUse(gn, tGn); - - /* - * Deal with wildcards and variables in any acquired sources - */ - ln = Lst_Succ(ln); - if (ln != NULL) { - SuffExpandChildren(tGn, ln); - } - - /* - * Keep track of another parent to which this beast is transformed so - * the .IMPSRC variable can be set correctly for the parent. - */ - Lst_AtEnd(&sGn->iParents, tGn); - - return (TRUE); -} - - -/*- - *----------------------------------------------------------------------- - * SuffFindArchiveDeps -- - * Locate dependencies for an OP_ARCHV node. - * - * Results: - * None - * - * Side Effects: - * Same as Suff_FindDeps - * - *----------------------------------------------------------------------- - */ -static void -SuffFindArchiveDeps(GNode *gn, Lst *slst) -{ - char *eoarch; /* End of archive portion */ - char *eoname; /* End of member portion */ - char *name; /* Start of member's name */ - GNode *mem; /* Node for member */ - Suff *ms; /* Suffix descriptor for member */ - - static const char *copy[] = { - TARGET, /* Must be first */ - PREFIX, /* Must be second */ - }; - - /* - * The node is an archive(member) pair. so we must find a - * suffix for both of them. - */ - eoarch = strchr(gn->name, '('); - eoname = strchr(eoarch, ')'); - - *eoname = '\0'; /* Nuke parentheses during suffix search */ - *eoarch = '\0'; /* So a suffix can be found */ - - name = eoarch + 1; - - /* - * To simplify things, call Suff_FindDeps recursively on the member now, - * so we can simply compare the member's .PREFIX and .TARGET variables - * to locate its suffix. This allows us to figure out the suffix to - * use for the archive without having to do a quadratic search over the - * suffix list, backtracking for each one... - */ - mem = Targ_FindNode(name, TARG_CREATE); - SuffFindDeps(mem, slst); - - /* - * Create the link between the two nodes right off - */ - if (Lst_Member(&gn->children, mem) == NULL) { - Lst_AtEnd(&gn->children, mem); - Lst_AtEnd(&mem->parents, gn); - gn->unmade += 1; - } - - /* - * Copy in the variables from the member node to this one. - */ - Var_Set(copy[1], Var_Value(copy[1], mem), gn); - Var_Set(copy[0], Var_Value(copy[0], mem), gn); - - ms = mem->suffix; - if (ms == NULL) { - /* - * Didn't know what it was -- use .NULL suffix if not in - * make mode - */ - DEBUGF(SUFF, ("using null suffix\n")); - ms = suffNull; - } - - /* - * Set the other two local variables required for this target. - */ - Var_Set(MEMBER, name, gn); - Var_Set(ARCHIVE, gn->name, gn); - - if (ms != NULL) { - /* - * Member has a known suffix, so look for a transformation rule - * from it to a possible suffix of the archive. Rather than - * searching through the entire list, we just look at suffixes - * to which the member's suffix may be transformed... - */ - LstNode *ln; - - /* - * Use first matching suffix... - */ - LST_FOREACH(ln, &ms->parents) { - if (SuffSuffIsSuffix(Lst_Datum(ln), gn->name) != NULL) - break; - } - - if (ln != NULL) { - /* - * Got one -- apply it - */ - if (!SuffApplyTransform(gn, mem, Lst_Datum(ln), ms)) { - DEBUGF(SUFF, ("\tNo transformation from " - "%s -> %s\n", ms->name, - ((Suff *)Lst_Datum(ln))->name)); - } - } - } - - /* - * Replace the opening and closing parens now we've no need - * of the separate pieces. - */ - *eoarch = '('; - *eoname = ')'; - - /* - * Pretend gn appeared to the left of a dependency operator so - * the user needn't provide a transformation from the member to the - * archive. - */ - if (OP_NOP(gn->type)) { - gn->type |= OP_DEPENDS; - } - - /* - * Flag the member as such so we remember to look in the archive for - * its modification time. - */ - mem->type |= OP_MEMBER; -} - -/*- - *----------------------------------------------------------------------- - * SuffFindNormalDeps -- - * Locate implicit dependencies for regular targets. - * - * Results: - * None. - * - * Side Effects: - * Same as Suff_FindDeps... - * - *----------------------------------------------------------------------- - */ -static void -SuffFindNormalDeps(GNode *gn, Lst *slst) -{ - char *eoname; /* End of name */ - char *sopref; /* Start of prefix */ - LstNode *ln; /* Next suffix node to check */ - Lst srcs; /* List of sources at which to look */ - Lst targs; /* List of targets to which things can be - * transformed. They all have the same file, - * but different suff and pref fields */ - Src *bottom; /* Start of found transformation path */ - Src *src; /* General Src pointer */ - char *pref; /* Prefix to use */ - Src *targ; /* General Src target pointer */ - - eoname = gn->name + strlen(gn->name); - sopref = gn->name; - - /* - * Begin at the beginning... - */ - ln = Lst_First(&sufflist); - Lst_Init(&srcs); - Lst_Init(&targs); - - /* - * We're caught in a catch-22 here. On the one hand, we want to use any - * transformation implied by the target's sources, but we can't examine - * the sources until we've expanded any variables/wildcards they may - * hold, and we can't do that until we've set up the target's local - * variables and we can't do that until we know what the proper suffix - * for the target is (in case there are two suffixes one of which is a - * suffix of the other) and we can't know that until we've found its - * implied source, which we may not want to use if there's an existing - * source that implies a different transformation. - * - * In an attempt to get around this, which may not work all the time, - * but should work most of the time, we look for implied sources first, - * checking transformations to all possible suffixes of the target, - * use what we find to set the target's local variables, expand the - * children, then look for any overriding transformations they imply. - * Should we find one, we discard the one we found before. - */ - - while (ln != NULL) { - /* - * Look for next possible suffix... - */ - while (ln != NULL) { - if (SuffSuffIsSuffix(Lst_Datum(ln), gn->name) != NULL) - break; - ln = LST_NEXT(ln); - } - - if (ln != NULL) { - int prefLen; /* Length of the prefix */ - Src *target; - - /* - * Allocate a Src structure to which things can be - * transformed - */ - target = SuffSrcCreate(estrdup(gn->name), NULL, - Lst_Datum(ln), NULL, gn); - target->suff->refCount++; - - /* - * Allocate room for the prefix, whose end is found - * by subtracting the length of the suffix from - * the end of the name. - */ - prefLen = (eoname - target->suff->nameLen) - sopref; - assert(prefLen >= 0); - target->pref = emalloc(prefLen + 1); - memcpy(target->pref, sopref, prefLen); - target->pref[prefLen] = '\0'; - - /* - * Add nodes from which the target can be made - */ - SuffAddLevel(&srcs, target); - - /* - * Record the target so we can nuke it - */ - Lst_AtEnd(&targs, target); - - /* - * Search from this suffix's successor... - */ - ln = Lst_Succ(ln); - } - } - - /* - * Handle target of unknown suffix... - */ - if (Lst_IsEmpty(&targs) && suffNull != NULL) { - DEBUGF(SUFF, ("\tNo known suffix on %s. Using .NULL suffix\n", - gn->name)); - - targ = SuffSrcCreate(estrdup(gn->name), estrdup(sopref), - suffNull, NULL, gn); - targ->suff->refCount++; - - /* - * Only use the default suffix rules if we don't have commands - * or dependencies defined for this gnode - */ - if (Lst_IsEmpty(&gn->commands) && Lst_IsEmpty(&gn->children)) - SuffAddLevel(&srcs, targ); - else { - DEBUGF(SUFF, ("not ")); - } - - DEBUGF(SUFF, ("adding suffix rules\n")); - - Lst_AtEnd(&targs, targ); - } - - /* - * Using the list of possible sources built up from the target - * suffix(es), try and find an existing file/target that matches. - */ - bottom = SuffFindThem(&srcs, slst); - - if (bottom == NULL) { - /* - * No known transformations -- use the first suffix found for - * setting the local variables. - */ - if (!Lst_IsEmpty(&targs)) { - targ = Lst_Datum(Lst_First(&targs)); - } else { - targ = NULL; - } - } else { - /* - * Work up the transformation path to find the suffix of the - * target to which the transformation was made. - */ - for (targ = bottom; targ->parent != NULL; targ = targ->parent) - continue; - } - - /* - * The .TARGET variable we always set to be the name at this point, - * since it's only set to the path if the thing is only a source and - * if it's only a source, it doesn't matter what we put here as far - * as expanding sources is concerned, since it has none... - */ - Var_Set(TARGET, gn->name, gn); - - pref = (targ != NULL) ? targ->pref : gn->name; - Var_Set(PREFIX, pref, gn); - - /* - * Now we've got the important local variables set, expand any sources - * that still contain variables or wildcards in their names. - */ - SuffExpandChildren(gn, NULL); - - if (targ == NULL) { - DEBUGF(SUFF, ("\tNo valid suffix on %s\n", gn->name)); - - sfnd_abort: - /* - * Deal with finding the thing on the default search path if the - * node is only a source (not on the lhs of a dependency - * operator or [XXX] it has neither children or commands). - */ - if (OP_NOP(gn->type) || (Lst_IsEmpty(&gn->children) && - Lst_IsEmpty(&gn->commands))) { - gn->path = Path_FindFile(gn->name, - (targ == NULL ? &dirSearchPath : - &targ->suff->searchPath)); - if (gn->path != NULL) { - char *ptr; - Var_Set(TARGET, gn->path, gn); - - if (targ != NULL) { - /* - * Suffix known for the thing -- trim - * the suffix off the path to form the - * proper .PREFIX variable. - */ - int savep = strlen(gn->path) - - targ->suff->nameLen; - char savec; - - if (gn->suffix) - gn->suffix->refCount--; - gn->suffix = targ->suff; - gn->suffix->refCount++; - - savec = gn->path[savep]; - gn->path[savep] = '\0'; - - if ((ptr = strrchr(gn->path, '/')) != NULL) - ptr++; - else - ptr = gn->path; - - Var_Set(PREFIX, ptr, gn); - - gn->path[savep] = savec; - } else { - /* - * The .PREFIX gets the full path if - * the target has no known suffix. - */ - if (gn->suffix) - gn->suffix->refCount--; - gn->suffix = NULL; - - if ((ptr = strrchr(gn->path, '/')) != NULL) - ptr++; - else - ptr = gn->path; - - Var_Set(PREFIX, ptr, gn); - } - } - } else { - /* - * Not appropriate to search for the thing -- set the - * path to be the name so Dir_MTime won't go - * grovelling for it. - */ - if (gn->suffix) - gn->suffix->refCount--; - gn->suffix = (targ == NULL) ? NULL : targ->suff; - if (gn->suffix) - gn->suffix->refCount++; - free(gn->path); - gn->path = estrdup(gn->name); - } - - goto sfnd_return; - } - - /* - * If the suffix indicates that the target is a library, mark that in - * the node's type field. - */ - if (targ->suff->flags & SUFF_LIBRARY) { - gn->type |= OP_LIB; - } - - /* - * Check for overriding transformation rule implied by sources - */ - if (!Lst_IsEmpty(&gn->children)) { - src = SuffFindCmds(targ, slst); - - if (src != NULL) { - /* - * Free up all the Src structures in the - * transformation path up to, but not including, - * the parent node. - */ - while (bottom && bottom->parent != NULL) { - if (Lst_Member(slst, bottom) == NULL) { - Lst_AtEnd(slst, bottom); - } - bottom = bottom->parent; - } - bottom = src; - } - } - - if (bottom == NULL) { - /* - * No idea from where it can come -- return now. - */ - goto sfnd_abort; - } - - /* - * We now have a list of Src structures headed by 'bottom' and linked - * via their 'parent' pointers. What we do next is create links between - * source and target nodes (which may or may not have been created) - * and set the necessary local variables in each target. The - * commands for each target are set from the commands of the - * transformation rule used to get from the src suffix to the targ - * suffix. Note that this causes the commands list of the original - * node, gn, to be replaced by the commands of the final - * transformation rule. Also, the unmade field of gn is incremented. - * Etc. - */ - if (bottom->node == NULL) { - bottom->node = Targ_FindNode(bottom->file, TARG_CREATE); - } - - for (src = bottom; src->parent != NULL; src = src->parent) { - targ = src->parent; - - if (src->node->suffix) - src->node->suffix->refCount--; - src->node->suffix = src->suff; - src->node->suffix->refCount++; - - if (targ->node == NULL) { - targ->node = Targ_FindNode(targ->file, TARG_CREATE); - } - - SuffApplyTransform(targ->node, src->node, - targ->suff, src->suff); - - if (targ->node != gn) { - /* - * Finish off the dependency-search process for any - * nodes between bottom and gn (no point in questing - * around the filesystem for their implicit source - * when it's already known). Note that the node can't - * have any sources that need expanding, since - * SuffFindThem will stop on an existing - * node, so all we need to do is set the standard and - * System V variables. - */ - targ->node->type |= OP_DEPS_FOUND; - - Var_Set(PREFIX, targ->pref, targ->node); - Var_Set(TARGET, targ->node->name, targ->node); - } - } - - if (gn->suffix) - gn->suffix->refCount--; - gn->suffix = src->suff; - gn->suffix->refCount++; - - /* - * So Dir_MTime doesn't go questing for it... - */ - free(gn->path); - gn->path = estrdup(gn->name); - - /* - * Nuke the transformation path and the Src structures left over in the - * two lists. - */ - sfnd_return: - if (bottom) - if (Lst_Member(slst, bottom) == NULL) - Lst_AtEnd(slst, bottom); - - while (SuffRemoveSrc(&srcs) || SuffRemoveSrc(&targs)) - continue; - - Lst_Concat(slst, &srcs, LST_CONCLINK); - Lst_Concat(slst, &targs, LST_CONCLINK); -} - -/*- - *----------------------------------------------------------------------- - * Suff_FindDeps -- - * Find implicit sources for the target described by the graph node - * gn - * - * Results: - * Nothing. - * - * Side Effects: - * Nodes are added to the graph below the passed-in node. The nodes - * are marked to have their IMPSRC variable filled in. The - * PREFIX variable is set for the given node and all its - * implied children. - * - * Notes: - * The path found by this target is the shortest path in the - * transformation graph, which may pass through non-existent targets, - * to an existing target. The search continues on all paths from the - * root suffix until a file is found. I.e. if there's a path - * .o -> .c -> .l -> .l,v from the root and the .l,v file exists but - * the .c and .l files don't, the search will branch out in - * all directions from .o and again from all the nodes on the - * next level until the .l,v node is encountered. - * - *----------------------------------------------------------------------- - */ -void -Suff_FindDeps(GNode *gn) -{ - - SuffFindDeps(gn, &srclist); - while (SuffRemoveSrc(&srclist)) - continue; -} - - -static void -SuffFindDeps(GNode *gn, Lst *slst) -{ - - if (gn->type & OP_DEPS_FOUND) { - /* - * If dependencies already found, no need to do it again... - */ - return; - } else { - gn->type |= OP_DEPS_FOUND; - } - - DEBUGF(SUFF, ("SuffFindDeps (%s)\n", gn->name)); - - if (gn->type & OP_ARCHV) { - SuffFindArchiveDeps(gn, slst); - - } else if (gn->type & OP_LIB) { - /* - * If the node is a library, it is the arch module's job to find - * it and set the TARGET variable accordingly. We merely provide - * the search path, assuming all libraries end in ".a" (if the - * suffix hasn't been defined, there's nothing we can do for it, - * so we just set the TARGET variable to the node's name in order - * to give it a value). - */ - Suff *s; - - s = SuffSuffFind(LIBSUFF); - if (gn->suffix) - gn->suffix->refCount--; - if (s != NULL) { - gn->suffix = s; - gn->suffix->refCount++; - Arch_FindLib(gn, &s->searchPath); - } else { - gn->suffix = NULL; - Var_Set(TARGET, gn->name, gn); - } - - /* - * Because a library (-lfoo) target doesn't follow the standard - * filesystem conventions, we don't set the regular variables for - * the thing. .PREFIX is simply made empty... - */ - Var_Set(PREFIX, "", gn); - - } else { - SuffFindNormalDeps(gn, slst); - } -} - -/*- - *----------------------------------------------------------------------- - * Suff_SetNull -- - * Define which suffix is the null suffix. - * - * Results: - * None. - * - * Side Effects: - * 'suffNull' is altered. - * - * Notes: - * Need to handle the changing of the null suffix gracefully so the - * old transformation rules don't just go away. - * - *----------------------------------------------------------------------- - */ -void -Suff_SetNull(char *name) -{ - Suff *s; - - if ((s = SuffSuffFind(name)) == NULL) { - Parse_Error(PARSE_WARNING, "Desired null suffix %s " - "not defined.", name); - return; - } - - if (suffNull != NULL) { - suffNull->flags &= ~SUFF_NULL; - } - s->flags |= SUFF_NULL; - - /* - * XXX: Here's where the transformation mangling - * would take place - */ - suffNull = s; -} - -/*- - *----------------------------------------------------------------------- - * Suff_Init -- - * Initialize suffixes module - * - * Results: - * None - * - * Side Effects: - * Many - *----------------------------------------------------------------------- - */ -void -Suff_Init(void) -{ - - sNum = 0; - /* - * Create null suffix for single-suffix rules (POSIX). The thing doesn't - * actually go on the suffix list or everyone will think that's its - * suffix. - */ - emptySuff = suffNull = emalloc(sizeof(Suff)); - - suffNull->name = estrdup(""); - suffNull->nameLen = 0; - TAILQ_INIT(&suffNull->searchPath); - Path_Concat(&suffNull->searchPath, &dirSearchPath); - Lst_Init(&suffNull->children); - Lst_Init(&suffNull->parents); - Lst_Init(&suffNull->ref); - suffNull->sNum = sNum++; - suffNull->flags = SUFF_NULL; - suffNull->refCount = 1; -} - -/********************* DEBUGGING FUNCTIONS **********************/ - -void -Suff_PrintAll(void) -{ - const LstNode *ln; - const LstNode *tln; - const GNode *gn; - const Suff *s; - - static const struct flag2str suff_flags[] = { - { SUFF_INCLUDE, "INCLUDE" }, - { SUFF_LIBRARY, "LIBRARY" }, - { SUFF_NULL, "NULL" }, - { 0, NULL } - }; - - printf("#*** Suffixes:\n"); - LST_FOREACH(ln, &sufflist) { - s = Lst_Datum(ln); - printf("# `%s' [%d] ", s->name, s->refCount); - - if (s->flags != 0) { - printf(" "); - print_flags(stdout, suff_flags, s->flags, 1); - } - - printf("\n#\tTo: "); - LST_FOREACH(tln, &s->parents) - printf("`%s' ", ((const Suff *)Lst_Datum(tln))->name); - - printf("\n#\tFrom: "); - LST_FOREACH(tln, &s->children) - printf("`%s' ", ((const Suff *)Lst_Datum(tln))->name); - - printf("\n#\tSearch Path: "); - Path_Print(&s->searchPath); - - printf("\n"); - } - - printf("#*** Transformations:\n"); - LST_FOREACH(ln, &transforms) { - gn = Lst_Datum(ln); - printf("%-16s: ", gn->name); - Targ_PrintType(gn->type); - printf("\n"); - LST_FOREACH(tln, &gn->commands) - printf("\t%s\n", (const char *)Lst_Datum(tln)); - printf("\n"); - } -} Property changes on: head/usr.bin/make/suff.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/var.h =================================================================== --- head/usr.bin/make/var.h (revision 284463) +++ head/usr.bin/make/var.h (nonexistent) @@ -1,85 +0,0 @@ -/*- - * Copyright (c) 2002 Juli Mallett. - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef var_h_9cccafce -#define var_h_9cccafce - -struct Buffer; -struct GNode; -struct List; - -/* Variables defined in a global context, e.g in the Makefile itself */ -extern struct GNode *VAR_GLOBAL; - -/* Variables defined on the command line */ -extern struct GNode *VAR_CMD; - -/* - * Value returned by Var_Parse when an error is encountered. It actually - * points to an empty string, so naive callers needn't worry about it. - */ -extern char var_Error[]; - -/* - * TRUE if environment should be searched for all variables before - * the global context - */ -extern Boolean checkEnvFirst; - -/* Do old-style variable substitution */ -extern Boolean oldVars; - -void Var_Append(const char *, const char *, struct GNode *); -void Var_Delete(const char *, struct GNode *); -void Var_Dump(void); -Boolean Var_Exists(const char *, struct GNode *); -void Var_Init(char **); -size_t Var_Match(const char [], struct GNode *); -char *Var_Parse(const char *, struct GNode *, Boolean, size_t *, Boolean *); -void Var_Print(struct Lst *, Boolean); -void Var_Set(const char *, const char *, struct GNode *); -void Var_SetGlobal(const char *, const char *); -void Var_SetEnv(const char *, struct GNode *); -struct Buffer *Var_Subst(const char *, struct GNode *, Boolean); -struct Buffer *Var_SubstOnly(const char *, const char *, Boolean); -const char *Var_Value(const char [], struct GNode *); - -#endif /* var_h_9cccafce */ Property changes on: head/usr.bin/make/var.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/proc.c =================================================================== --- head/usr.bin/make/proc.c (revision 284463) +++ head/usr.bin/make/proc.c (nonexistent) @@ -1,134 +0,0 @@ -/*- - * Copyright (C) 2005 Max Okumoto. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include - -#include "proc.h" -#include "shell.h" -#include "util.h" - -/** - * Replace the current process. - */ -void -Proc_Exec(const ProcStuff *ps) -{ - - if (ps->in != STDIN_FILENO) { - /* - * Redirect the child's stdin to the input fd - * and reset it to the beginning (again). - */ - if (dup2(ps->in, STDIN_FILENO) == -1) - Punt("Cannot dup2: %s", strerror(errno)); - lseek(STDIN_FILENO, (off_t)0, SEEK_SET); - } - - if (ps->out != STDOUT_FILENO) { - /* - * Redirect the child's stdout to the output fd. - */ - if (dup2(ps->out, STDOUT_FILENO) == -1) - Punt("Cannot dup2: %s", strerror(errno)); - close(ps->out); - } - - if (ps->err != STDERR_FILENO) { - /* - * Redirect the child's stderr to the err fd. - */ - if (dup2(ps->err, STDERR_FILENO) == -1) - Punt("Cannot dup2: %s", strerror(errno)); - close(ps->err); - } - - if (ps->merge_errors) { - /* - * Send stderr to parent process too. - */ - if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1) - Punt("Cannot dup2: %s", strerror(errno)); - } - - if (commandShell->unsetenv) { - /* for the benfit of ksh */ - unsetenv("ENV"); - } - - /* - * The file descriptors for stdin, stdout, or stderr might - * have been marked close-on-exec. Clear the flag on all - * of them. - */ - fcntl(STDIN_FILENO, F_SETFD, - fcntl(STDIN_FILENO, F_GETFD) & (~FD_CLOEXEC)); - fcntl(STDOUT_FILENO, F_SETFD, - fcntl(STDOUT_FILENO, F_GETFD) & (~FD_CLOEXEC)); - fcntl(STDERR_FILENO, F_SETFD, - fcntl(STDERR_FILENO, F_GETFD) & (~FD_CLOEXEC)); - - if (ps->pgroup) { -#ifdef USE_PGRP - /* - * Become a process group leader, so we can kill it and all - * its descendants in one fell swoop, by killing its process - * family, but not commit suicide. - */ -#if defined(SYSV) - setsid(); -#else - setpgid(0, getpid()); -#endif -#endif /* USE_PGRP */ - } - - if (ps->searchpath) { - execvp(ps->argv[0], ps->argv); - - write(STDERR_FILENO, ps->argv[0], strlen(ps->argv[0])); - write(STDERR_FILENO, ": ", 2); - write(STDERR_FILENO, strerror(errno), strlen(strerror(errno))); - write(STDERR_FILENO, "\n", 1); - } else { - execv(commandShell->path, ps->argv); - - write(STDERR_FILENO, - "Could not execute shell\n", - sizeof("Could not execute shell")); - } - - /* - * Since we are the child process, exit without flushing buffers. - */ - _exit(1); -} Property changes on: head/usr.bin/make/proc.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/make.h =================================================================== --- head/usr.bin/make/make.h (revision 284463) +++ head/usr.bin/make/make.h (nonexistent) @@ -1,75 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)make.h 8.3 (Berkeley) 6/13/95 - * $FreeBSD$ - */ - -#ifndef make_h_a91074b9 -#define make_h_a91074b9 - -/** - * make.h - * The global definitions for make - */ - -#include "util.h" - -#define MAKE_JOB_PREFIX ".MAKE.JOB.PREFIX" - -struct GNode; -struct Lst; -struct Buffer; - -/* - * Warning flags - */ -enum { - WARN_DIRSYNTAX = 0x0001, /* syntax errors in directives */ -}; - -int Make_TimeStamp(struct GNode *, struct GNode *); -Boolean Make_OODate(struct GNode *); -int Make_HandleUse(struct GNode *, struct GNode *); -void Make_Update(struct GNode *); -void Make_DoAllVar(struct GNode *); -Boolean Make_Run(struct Lst *); -void Main_ParseArgLine(char *, int); -int Main_ParseWarn(const char *, int); -void Main_AddSourceMakefile(const char *); - -#endif /* make_h_a91074b9 */ Property changes on: head/usr.bin/make/make.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/GNode.h =================================================================== --- head/usr.bin/make/GNode.h (revision 284463) +++ head/usr.bin/make/GNode.h (nonexistent) @@ -1,224 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef GNode_h_39503bf2 -#define GNode_h_39503bf2 - -#include "lst.h" -#include "util.h" - -struct Suff; - -/* - * The structure for an individual graph node. Each node has several - * pieces of data associated with it. - */ -typedef struct GNode { - char *name; /* The target's name */ - char *path; /* The full pathname of the target file */ - - /* - * The type of operator used to define the sources (qv. parse.c) - * - * The OP_ constants are used when parsing a dependency line as a way of - * communicating to other parts of the program the way in which a target - * should be made. These constants are bitwise-OR'ed together and - * placed in the 'type' field of each node. Any node that has - * a 'type' field which satisfies the OP_NOP function was never never on - * the lefthand side of an operator, though it may have been on the - * righthand side... - */ - int type; -#define OP_DEPENDS 0x00000001 /* Execution of commands depends on - * kids (:) */ -#define OP_FORCE 0x00000002 /* Always execute commands (!) */ -#define OP_DOUBLEDEP 0x00000004 /* Execution of commands depends on - * kids per line (::) */ -#define OP_OPMASK (OP_DEPENDS|OP_FORCE|OP_DOUBLEDEP) - -#define OP_OPTIONAL 0x00000008 /* Don't care if the target doesn't - * exist and can't be created */ -#define OP_USE 0x00000010 /* - * Use associated commands for - * parents - */ -#define OP_EXEC 0x00000020 /* Target is never out of date, but - * always execute commands anyway. - * Its time doesn't matter, so it has - * none...sort of - */ -#define OP_IGNORE 0x00000040 /* - * Ignore errors when creating the node - */ -#define OP_PRECIOUS 0x00000080 /* Don't remove the target when - * interrupted */ -#define OP_SILENT 0x00000100 /* Don't echo commands when executed */ -#define OP_MAKE 0x00000200 /* - * Target is a recurrsive make so its - * commands should always be executed - * when it is out of date, regardless - * of the state of the -n or -t flags - */ -#define OP_JOIN 0x00000400 /* Target is out-of-date only if any of - * its children was out-of-date */ -#define OP_INVISIBLE 0x00004000 /* The node is invisible to its parents. - * I.e. it doesn't show up in the - * parents's local variables. */ -#define OP_NOTMAIN 0x00008000 /* The node is exempt from normal 'main - * target' processing in parse.c */ -#define OP_PHONY 0x00010000 /* Not a file target; run always */ -/* Attributes applied by PMake */ -#define OP_TRANSFORM 0x80000000 /* The node is a transformation rule */ -#define OP_MEMBER 0x40000000 /* Target is a member of an archive */ -#define OP_LIB 0x20000000 /* Target is a library */ -#define OP_ARCHV 0x10000000 /* Target is an archive construct */ -#define OP_HAS_COMMANDS 0x08000000 /* Target has all the commands it - * should. Used when parsing to catch - * multiple commands for a target */ -#define OP_SAVE_CMDS 0x04000000 /* Saving commands on .END (Compat) */ -#define OP_DEPS_FOUND 0x02000000 /* Already processed by Suff_FindDeps */ - -/* - * OP_NOP will return TRUE if the node with the given type was not the - * object of a dependency operator - */ -#define OP_NOP(t) (((t) & OP_OPMASK) == 0x00000000) - - int order; /* Its wait weight */ - - Boolean make; /* TRUE if this target needs to be remade */ - - /* Set to reflect the state of processing on this node */ - enum { - UNMADE, /* Not examined yet */ - - /* - * Target is already being made. Indicates a cycle in the graph. - * (compat mode only) - */ - BEINGMADE, - - MADE, /* Was out-of-date and has been made */ - UPTODATE, /* Was already up-to-date */ - - /* - * An error occurred while it was being - * made (used only in compat mode) - */ - ERROR, - - /* - * The target was aborted due to an - * error making an inferior (compat). - */ - ABORTED, - - /* - * Marked as potentially being part of a graph cycle. If we - * come back to a node marked this way, it is printed and - * 'made' is changed to ENDCYCLE. - */ - CYCLE, - - /* - * The cycle has been completely printed. Go back and - * unmark all its members. - */ - ENDCYCLE - } made; - - /* TRUE if one of this target's children was made */ - Boolean childMade; - - int unmade; /* The number of unmade children */ - int mtime; /* Its modification time */ - int cmtime; /* Modification time of its youngest child */ - struct GNode *cmtime_gn;/* Youngest child */ - - /* - * Links to parents for which this is an implied source, if any. (nodes - * that depend on this, as gleaned from the transformation rules. - */ - Lst iParents; - - /* List of nodes of the same name created by the :: operator */ - Lst cohorts; - - /* Lst of nodes for which this is a source (that depend on this one) */ - Lst parents; - - /* List of nodes on which this depends */ - Lst children; - - /* - * List of nodes that must be made (if they're made) after this node is, - * but that do not depend on this node, in the normal sense. - */ - Lst successors; - - /* - * List of nodes that must be made (if they're made) before this node - * can be, but that do no enter into the datedness of this node. - */ - Lst preds; - - /* - * List of ``local'' variables that are specific to this target - * and this target only (qv. var.c [$@ $< $?, etc.]) - */ - Lst context; - - /* - * List of strings that are commands to be given to a shell - * to create this target. - */ - Lst commands; - - /* current command executing in compat mode */ - LstNode *compat_command; - - /* - * Suffix for the node (determined by Suff_FindDeps and opaque to - * everyone but the Suff module) - */ - struct Suff *suffix; -} GNode; - -#endif /* GNode_h_39503bf2 */ Property changes on: head/usr.bin/make/GNode.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/util.c =================================================================== --- head/usr.bin/make/util.c (revision 284463) +++ head/usr.bin/make/util.c (nonexistent) @@ -1,316 +0,0 @@ -/*- - * Copyright (c) 2002 Juli Mallett. All rights reserved. - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)main.c 8.3 (Berkeley) 3/19/94 - */ - -#include -__FBSDID("$FreeBSD$"); - -/*- - * util.c -- - * General utilitarian routines for make(1). - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "globals.h" -#include "job.h" -#include "targ.h" -#include "util.h" - -static void enomem(void) __dead2; - -/*- - * Debug -- - * Print a debugging message given its format. - * - * Results: - * None. - * - * Side Effects: - * The message is printed. - */ -/* VARARGS */ -void -Debug(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fflush(stderr); -} - -/*- - * Print a debugging message given its format and append the current - * errno description. Terminate with a newline. - */ -/* VARARGS */ -void -DebugM(const char *fmt, ...) -{ - va_list ap; - int e = errno; - - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - fprintf(stderr, ": %s\n", strerror(e)); - va_end(ap); - fflush(stderr); -} - -/*- - * Error -- - * Print an error message given its format. - * - * Results: - * None. - * - * Side Effects: - * The message is printed. - */ -/* VARARGS */ -void -Error(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fprintf(stderr, "\n"); - fflush(stderr); -} - -/*- - * Fatal -- - * Produce a Fatal error message. If jobs are running, waits for them - * to finish. - * - * Results: - * None - * - * Side Effects: - * The program exits - */ -/* VARARGS */ -void -Fatal(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - if (jobsRunning) - Job_Wait(); - - vfprintf(stderr, fmt, ap); - va_end(ap); - fprintf(stderr, "\n"); - fflush(stderr); - - if (DEBUG(GRAPH2)) - Targ_PrintGraph(2); - exit(2); /* Not 1 so -q can distinguish error */ -} - -/* - * Punt -- - * Major exception once jobs are being created. Kills all jobs, prints - * a message and exits. - * - * Results: - * None - * - * Side Effects: - * All children are killed indiscriminately and the program Lib_Exits - */ -/* VARARGS */ -void -Punt(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - fprintf(stderr, "make: "); - vfprintf(stderr, fmt, ap); - va_end(ap); - fprintf(stderr, "\n"); - fflush(stderr); - - DieHorribly(); -} - -/*- - * DieHorribly -- - * Exit without giving a message. - * - * Results: - * None - * - * Side Effects: - * A big one... - */ -void -DieHorribly(void) -{ - if (jobsRunning) - Job_AbortAll(); - if (DEBUG(GRAPH2)) - Targ_PrintGraph(2); - exit(2); /* Not 1, so -q can distinguish error */ -} - -/* - * Finish -- - * Called when aborting due to errors in child shell to signal - * abnormal exit, with the number of errors encountered in Make_Make. - * - * Results: - * None - * - * Side Effects: - * The program exits - */ -void -Finish(int errors) -{ - - Fatal("%d error%s", errors, errors == 1 ? "" : "s"); -} - -/* - * emalloc -- - * malloc, but die on error. - */ -void * -emalloc(size_t len) -{ - void *p; - - if ((p = malloc(len)) == NULL) - enomem(); - return (p); -} - -/* - * estrdup -- - * strdup, but die on error. - */ -char * -estrdup(const char *str) -{ - char *p; - - if ((p = strdup(str)) == NULL) - enomem(); - return (p); -} - -/* - * erealloc -- - * realloc, but die on error. - */ -void * -erealloc(void *ptr, size_t size) -{ - - if ((ptr = realloc(ptr, size)) == NULL) - enomem(); - return (ptr); -} - -/* - * enomem -- - * die when out of memory. - */ -static void -enomem(void) -{ - err(2, NULL); -} - -/* - * enunlink -- - * Remove a file carefully, avoiding directories. - */ -int -eunlink(const char *file) -{ - struct stat st; - - if (lstat(file, &st) == -1) - return (-1); - - if (S_ISDIR(st.st_mode)) { - errno = EISDIR; - return (-1); - } - return (unlink(file)); -} - -/* - * Convert a flag word to a printable thing and print it - */ -void -print_flags(FILE *fp, const struct flag2str *tab, u_int flags, int par) -{ - int first = 1; - - if (par) - fprintf(fp, "("); - while (tab->str != NULL) { - if (flags & tab->flag) { - if (!first) - fprintf(fp, par ? "|" : " "); - first = 0; - fprintf(fp, "%s", tab->str); - } - tab++; - } - if (par) - fprintf(fp, ")"); -} Property changes on: head/usr.bin/make/util.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/suff.h =================================================================== --- head/usr.bin/make/suff.h (revision 284463) +++ head/usr.bin/make/suff.h (nonexistent) @@ -1,61 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef suff_h_2d5a821c -#define suff_h_2d5a821c - -struct GNode; -struct Path; - -void Suff_ClearSuffixes(void); -Boolean Suff_IsTransform(char *); -struct GNode *Suff_AddTransform(char *); -void Suff_EndTransform(const struct GNode *); -void Suff_AddSuffix(char *); -struct Path *Suff_GetPath(char *); -void Suff_DoPaths(void); -void Suff_AddInclude(char *); -void Suff_AddLib(char *); -void Suff_FindDeps(struct GNode *); -void Suff_SetNull(char *); -void Suff_Init(void); -void Suff_PrintAll(void); - -#endif /* suff_h_2d5a821c */ Property changes on: head/usr.bin/make/suff.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/proc.h =================================================================== --- head/usr.bin/make/proc.h (revision 284463) +++ head/usr.bin/make/proc.h (nonexistent) @@ -1,53 +0,0 @@ -/*- - * Copyright (C) 2005 Max Okumoto. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef proc_h_458845848 -#define proc_h_458845848 - -/** - * Information used to create a new process. - */ -typedef struct ProcStuff { - int in; /* stdin for new process */ - int out; /* stdout for new process */ - int err; /* stderr for new process */ - - int merge_errors; /* true if stderr is redirected to stdin */ - int pgroup; /* true if new process a process leader */ - int searchpath; /* true if binary should be found via $PATH */ - - char **argv; - int argv_free; /* release argv after use */ - int errCheck; - - pid_t child_pid; -} ProcStuff; - -void Proc_Exec(const ProcStuff *) __dead2; - -#endif /* proc_h_458845848 */ Property changes on: head/usr.bin/make/proc.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/targ.c =================================================================== --- head/usr.bin/make/targ.c (revision 284463) +++ head/usr.bin/make/targ.c (nonexistent) @@ -1,472 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)targ.c 8.2 (Berkeley) 3/19/94 - */ - -#include -__FBSDID("$FreeBSD$"); - -/* - * Functions for maintaining the Lst allTargets. Target nodes are - * kept in two structures: a Lst, maintained by the list library, and a - * hash table, maintained by the hash library. - * - * Interface: - * Targ_Init Initialization procedure. - * - * Targ_NewGN Create a new GNode for the passed target (string). - * The node is *not* placed in the hash table, though all - * its fields are initialized. - * - * Targ_FindNode Find the node for a given target, creating and storing - * it if it doesn't exist and the flags are right - * (TARG_CREATE) - * - * Targ_FindList Given a list of names, find nodes for all of them. If a - * name doesn't exist and the TARG_NOCREATE flag was given, - * an error message is printed. Else, if a name doesn't - * exist, its node is created. - * - * Targ_Ignore Return TRUE if errors should be ignored when creating - * the given target. - * - * Targ_Silent Return TRUE if we should be silent when creating the - * given target. - * - * Targ_Precious Return TRUE if the target is precious and should not - * be removed if we are interrupted. - * - * Debugging: - * Targ_PrintGraph Print out the entire graphm all variables and statistics - * for the directory cache. Should print something for - * suffixes, too, but... - */ - -#include - -#include "dir.h" -#include "globals.h" -#include "GNode.h" -#include "hash.h" -#include "suff.h" -#include "targ.h" -#include "util.h" -#include "var.h" - -/* the list of all targets found so far */ -static Lst allTargets = Lst_Initializer(allTargets); - -static Hash_Table targets; /* a hash table of same */ - -#define HTSIZE 191 /* initial size of hash table */ - -/** - * Targ_Init - * Initialize this module - * - * Side Effects: - * The allTargets list and the targets hash table are initialized - */ -void -Targ_Init(void) -{ - - Hash_InitTable(&targets, HTSIZE); -} - -/** - * Targ_NewGN - * Create and initialize a new graph node - * - * Results: - * An initialized graph node with the name field filled with a copy - * of the passed name - * - * Side Effects: - * The gnode is added to the list of all gnodes. - */ -GNode * -Targ_NewGN(const char *name) -{ - GNode *gn; - - gn = emalloc(sizeof(GNode)); - gn->name = estrdup(name); - gn->path = NULL; - if (name[0] == '-' && name[1] == 'l') { - gn->type = OP_LIB; - } else { - gn->type = 0; - } - gn->unmade = 0; - gn->make = FALSE; - gn->made = UNMADE; - gn->childMade = FALSE; - gn->order = 0; - gn->mtime = gn->cmtime = 0; - gn->cmtime_gn = NULL; - Lst_Init(&gn->iParents); - Lst_Init(&gn->cohorts); - Lst_Init(&gn->parents); - Lst_Init(&gn->children); - Lst_Init(&gn->successors); - Lst_Init(&gn->preds); - Lst_Init(&gn->context); - Lst_Init(&gn->commands); - gn->suffix = NULL; - - return (gn); -} - -/** - * Targ_FindNode - * Find a node in the list using the given name for matching - * - * Results: - * The node in the list if it was. If it wasn't, return NULL of - * flags was TARG_NOCREATE or the newly created and initialized node - * if it was TARG_CREATE - * - * Side Effects: - * Sometimes a node is created and added to the list - */ -GNode * -Targ_FindNode(const char *name, int flags) -{ - GNode *gn; /* node in that element */ - Hash_Entry *he; /* New or used hash entry for node */ - Boolean isNew; /* Set TRUE if Hash_CreateEntry had to create */ - /* an entry for the node */ - - if (flags & TARG_CREATE) { - he = Hash_CreateEntry(&targets, name, &isNew); - if (isNew) { - gn = Targ_NewGN(name); - Hash_SetValue(he, gn); - Lst_AtEnd(&allTargets, gn); - } - } else { - he = Hash_FindEntry(&targets, name); - } - - if (he == NULL) { - return (NULL); - } else { - return (Hash_GetValue(he)); - } -} - -/** - * Targ_FindList - * Make a complete list of GNodes from the given list of names - * - * Results: - * A complete list of graph nodes corresponding to all instances of all - * the names in names. - * - * Side Effects: - * If flags is TARG_CREATE, nodes will be created for all names in - * names which do not yet have graph nodes. If flags is TARG_NOCREATE, - * an error message will be printed for each name which can't be found. - */ -void -Targ_FindList(Lst *nodes, Lst *names, int flags) -{ - LstNode *ln; /* name list element */ - GNode *gn; /* node in tLn */ - char *name; - - for (ln = Lst_First(names); ln != NULL; ln = Lst_Succ(ln)) { - name = Lst_Datum(ln); - gn = Targ_FindNode(name, flags); - if (gn != NULL) { - /* - * Note: Lst_AtEnd must come before the Lst_Concat so - * the nodes are added to the list in the order in which - * they were encountered in the makefile. - */ - Lst_AtEnd(nodes, gn); - if (gn->type & OP_DOUBLEDEP) { - Lst_Concat(nodes, &gn->cohorts, LST_CONCNEW); - } - - } else if (flags == TARG_NOCREATE) { - Error("\"%s\" -- target unknown.", name); - } - } -} - -/** - * Targ_Ignore - * Return true if should ignore errors when creating gn - * - * Results: - * TRUE if should ignore errors - */ -Boolean -Targ_Ignore(GNode *gn) -{ - - if (ignoreErrors || (gn->type & OP_IGNORE)) { - return (TRUE); - } else { - return (FALSE); - } -} - -/** - * Targ_Silent - * Return true if be silent when creating gn - * - * Results: - * TRUE if should be silent - */ -Boolean -Targ_Silent(GNode *gn) -{ - - if (beSilent || (gn->type & OP_SILENT)) { - return (TRUE); - } else { - return (FALSE); - } -} - -/** - * Targ_Precious - * See if the given target is precious - * - * Results: - * TRUE if it is precious. FALSE otherwise - */ -Boolean -Targ_Precious(GNode *gn) -{ - - if (allPrecious || (gn->type & (OP_PRECIOUS | OP_DOUBLEDEP))) { - return (TRUE); - } else { - return (FALSE); - } -} - -static GNode *mainTarg; /* the main target, as set by Targ_SetMain */ - -/** - * Targ_SetMain - * Set our idea of the main target we'll be creating. Used for - * debugging output. - * - * Side Effects: - * "mainTarg" is set to the main target's node. - */ -void -Targ_SetMain(GNode *gn) -{ - - mainTarg = gn; -} - -/** - * Targ_FmtTime - * Format a modification time in some reasonable way and return it. - * - * Results: - * The time reformatted. - * - * Side Effects: - * The time is placed in a static area, so it is overwritten - * with each call. - */ -char * -Targ_FmtTime(time_t modtime) -{ - struct tm *parts; - static char buf[128]; - - parts = localtime(&modtime); - - strftime(buf, sizeof(buf), "%H:%M:%S %b %d, %Y", parts); - buf[sizeof(buf) - 1] = '\0'; - return (buf); -} - -/** - * Targ_PrintType - * Print out a type field giving only those attributes the user can - * set. - */ -void -Targ_PrintType(int type) -{ - static const struct flag2str type2str[] = { - { OP_OPTIONAL, ".OPTIONAL" }, - { OP_USE, ".USE" }, - { OP_EXEC, ".EXEC" }, - { OP_IGNORE, ".IGNORE" }, - { OP_PRECIOUS, ".PRECIOUS" }, - { OP_SILENT, ".SILENT" }, - { OP_MAKE, ".MAKE" }, - { OP_JOIN, ".JOIN" }, - { OP_INVISIBLE, ".INVISIBLE" }, - { OP_NOTMAIN, ".NOTMAIN" }, - { OP_PHONY, ".PHONY" }, - { OP_LIB, ".LIB" }, - { OP_MEMBER, ".MEMBER" }, - { OP_ARCHV, ".ARCHV" }, - { 0, NULL } - }; - - type &= ~OP_OPMASK; - if (!DEBUG(TARG)) - type &= ~(OP_ARCHV | OP_LIB | OP_MEMBER); - print_flags(stdout, type2str, type, 0); -} - -/** - * TargPrintNode - * print the contents of a node - */ -static int -TargPrintNode(const GNode *gn, int pass) -{ - const LstNode *tln; - - if (!OP_NOP(gn->type)) { - printf("#\n"); - if (gn == mainTarg) { - printf("# *** MAIN TARGET ***\n"); - } - if (pass == 2) { - if (gn->unmade) { - printf("# %d unmade children\n", gn->unmade); - } else { - printf("# No unmade children\n"); - } - if (!(gn->type & (OP_JOIN | OP_USE | OP_EXEC))) { - if (gn->mtime != 0) { - printf("# last modified %s: %s\n", - Targ_FmtTime(gn->mtime), - gn->made == UNMADE ? "unmade" : - gn->made == MADE ? "made" : - gn->made == UPTODATE ? "up-to-date": - "error when made"); - } else if (gn->made != UNMADE) { - printf("# non-existent (maybe): %s\n", - gn->made == MADE ? "made" : - gn->made == UPTODATE ? "up-to-date": - gn->made == ERROR?"error when made": - "aborted"); - } else { - printf("# unmade\n"); - } - } - if (!Lst_IsEmpty(&gn->iParents)) { - printf("# implicit parents: "); - LST_FOREACH(tln, &gn->iParents) - printf("%s ", ((const GNode *) - Lst_Datum(tln))->name); - printf("\n"); - } - } - if (!Lst_IsEmpty(&gn->parents)) { - printf("# parents: "); - LST_FOREACH(tln, &gn->parents) - printf("%s ", ((const GNode *) - Lst_Datum(tln))->name); - printf("\n"); - } - - printf("%-16s", gn->name); - switch (gn->type & OP_OPMASK) { - case OP_DEPENDS: - printf(": "); - break; - case OP_FORCE: - printf("! "); - break; - case OP_DOUBLEDEP: - printf(":: "); - break; - default: - break; - } - Targ_PrintType(gn->type); - LST_FOREACH(tln, &gn->children) - printf("%s ", ((const GNode *)Lst_Datum(tln))->name); - printf("\n"); - LST_FOREACH(tln, &gn->commands) - printf("\t%s\n", (const char *)Lst_Datum(tln)); - printf("\n\n"); - if (gn->type & OP_DOUBLEDEP) { - LST_FOREACH(tln, &gn->cohorts) - TargPrintNode((const GNode *)Lst_Datum(tln), - pass); - } - } - return (0); -} - -/** - * Targ_PrintGraph - * Print the entire graph. - */ -void -Targ_PrintGraph(int pass) -{ - const GNode *gn; - const LstNode *tln; - - printf("#*** Input graph:\n"); - LST_FOREACH(tln, &allTargets) - TargPrintNode((const GNode *)Lst_Datum(tln), pass); - printf("\n\n"); - - printf("#\n# Files that are only sources:\n"); - LST_FOREACH(tln, &allTargets) { - gn = Lst_Datum(tln); - if (OP_NOP(gn->type)) - printf("#\t%s [%s]\n", gn->name, - gn->path ? gn->path : gn->name); - } - Var_Dump(); - printf("\n"); - Dir_PrintDirectories(); - printf("\n"); - Suff_PrintAll(); -} Property changes on: head/usr.bin/make/targ.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/parse.c =================================================================== --- head/usr.bin/make/parse.c (revision 284463) +++ head/usr.bin/make/parse.c (nonexistent) @@ -1,2545 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)parse.c 8.3 (Berkeley) 3/19/94 - */ - -#include -__FBSDID("$FreeBSD$"); - -/*- - * parse.c -- - * Functions to parse a makefile. - * - * Most important structures are kept in Lsts. Directories for - * the #include "..." function are kept in the 'parseIncPath' Lst, while - * those for the #include <...> are kept in the 'sysIncPath' Lst. The - * targets currently being defined are kept in the 'targets' Lst. - * - * Interface: - * - * Parse_File Function used to parse a makefile. It must - * be given the name of the file, which should - * already have been opened, and a function - * to call to read a character from the file. - * - * Parse_IsVar Returns TRUE if the given line is a - * variable assignment. Used by MainParseArgs - * to determine if an argument is a target - * or a variable assignment. Used internally - * for pretty much the same thing... - * - * Parse_Error Function called when an error occurs in - * parsing. Used by the variable and - * conditional modules. - * - * Parse_MainName Returns a Lst of the main target to create. - */ - -#include -#include -#include -#include -#include -#include - -#include "arch.h" -#include "buf.h" -#include "cond.h" -#include "config.h" -#include "dir.h" -#include "for.h" -#include "globals.h" -#include "GNode.h" -#include "hash_tables.h" -#include "job.h" -#include "make.h" -#include "parse.h" -#include "pathnames.h" -#include "shell.h" -#include "str.h" -#include "suff.h" -#include "targ.h" -#include "util.h" -#include "var.h" - -/* - * These values are returned by ParsePopInput to tell Parse_File whether to - * CONTINUE parsing, i.e. it had only reached the end of an include file, - * or if it's DONE. - */ -#define CONTINUE 1 -#define DONE 0 - -/* targets we're working on */ -static Lst targets = Lst_Initializer(targets); - -/* true if currently in a dependency line or its commands */ -static Boolean inLine; - -static int fatals = 0; - -/* - * The main target to create. This is the first target on the - * first dependency line in the first makefile. - */ -static GNode *mainNode; - -/* - * Definitions for handling #include specifications - */ -struct IFile { - char *fname; /* name of previous file */ - int lineno; /* saved line number */ - FILE *F; /* the open stream */ - char *str; /* the string when parsing a string */ - char *ptr; /* the current pointer when parsing a string */ - TAILQ_ENTRY(IFile) link;/* stack the files */ -}; - -/* stack of IFiles generated by * #includes */ -static TAILQ_HEAD(, IFile) includes = TAILQ_HEAD_INITIALIZER(includes); - -/* access current file */ -#define CURFILE (TAILQ_FIRST(&includes)) - -/* list of directories for "..." includes */ -struct Path parseIncPath = TAILQ_HEAD_INITIALIZER(parseIncPath); - -/* list of directories for <...> includes */ -struct Path sysIncPath = TAILQ_HEAD_INITIALIZER(sysIncPath); - -/* - * specType contains the SPECial TYPE of the current target. It is - * Not if the target is unspecial. If it *is* special, however, the children - * are linked as children of the parent but not vice versa. This variable is - * set in ParseDoDependency - */ -typedef enum { - Begin, /* .BEGIN */ - Default, /* .DEFAULT */ - End, /* .END */ - ExportVar, /* .EXPORTVAR */ - Ignore, /* .IGNORE */ - Includes, /* .INCLUDES */ - Interrupt, /* .INTERRUPT */ - Libs, /* .LIBS */ - MFlags, /* .MFLAGS or .MAKEFLAGS */ - Main, /* .MAIN and we don't have anyth. user-spec. to make */ - Not, /* Not special */ - NotParallel, /* .NOTPARALELL */ - Null, /* .NULL */ - Order, /* .ORDER */ - Parallel, /* .PARALLEL */ - ExPath, /* .PATH */ - Phony, /* .PHONY */ - Posix, /* .POSIX */ - MakefileDeps, /* .MAKEFILEDEPS */ - Precious, /* .PRECIOUS */ - ExShell, /* .SHELL */ - Silent, /* .SILENT */ - SingleShell, /* .SINGLESHELL */ - Suffixes, /* .SUFFIXES */ - Wait, /* .WAIT */ - Warn, /* .WARN */ - Attribute /* Generic attribute */ -} ParseSpecial; - -static ParseSpecial specType; -static int waiting; - -/* - * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER - * seen, then set to each successive source on the line. - */ -static GNode *predecessor; - -/* - * The parseKeywords table is searched using binary search when deciding - * if a target or source is special. The 'spec' field is the ParseSpecial - * type of the keyword ("Not" if the keyword isn't special as a target) while - * the 'op' field is the operator to apply to the list of targets if the - * keyword is used as a source ("0" if the keyword isn't special as a source) - */ -static const struct keyword { - const char *name; /* Name of keyword */ - ParseSpecial spec; /* Type when used as a target */ - int op; /* Operator when used as a source */ -} parseKeywords[] = { - /* KEYWORD-START-TAG */ - { ".BEGIN", Begin, 0 }, - { ".DEFAULT", Default, 0 }, - { ".END", End, 0 }, - { ".EXEC", Attribute, OP_EXEC }, - { ".EXPORTVAR", ExportVar, 0 }, - { ".IGNORE", Ignore, OP_IGNORE }, - { ".INCLUDES", Includes, 0 }, - { ".INTERRUPT", Interrupt, 0 }, - { ".INVISIBLE", Attribute, OP_INVISIBLE }, - { ".JOIN", Attribute, OP_JOIN }, - { ".LIBS", Libs, 0 }, - { ".MAIN", Main, 0 }, - { ".MAKE", Attribute, OP_MAKE }, - { ".MAKEFILEDEPS", MakefileDeps, 0 }, - { ".MAKEFLAGS", MFlags, 0 }, - { ".MFLAGS", MFlags, 0 }, - { ".NOTMAIN", Attribute, OP_NOTMAIN }, - { ".NOTPARALLEL", NotParallel, 0 }, - { ".NO_PARALLEL", NotParallel, 0 }, - { ".NULL", Null, 0 }, - { ".OPTIONAL", Attribute, OP_OPTIONAL }, - { ".ORDER", Order, 0 }, - { ".PARALLEL", Parallel, 0 }, - { ".PATH", ExPath, 0 }, - { ".PHONY", Phony, OP_PHONY }, - { ".POSIX", Posix, 0 }, - { ".PRECIOUS", Precious, OP_PRECIOUS }, - { ".RECURSIVE", Attribute, OP_MAKE }, - { ".SHELL", ExShell, 0 }, - { ".SILENT", Silent, OP_SILENT }, - { ".SINGLESHELL", SingleShell, 0 }, - { ".SUFFIXES", Suffixes, 0 }, - { ".USE", Attribute, OP_USE }, - { ".WAIT", Wait, 0 }, - { ".WARN", Warn, 0 }, - /* KEYWORD-END-TAG */ -}; -#define NKEYWORDS (sizeof(parseKeywords) / sizeof(parseKeywords[0])) - -static void parse_include(char *, int, int); -static void parse_sinclude(char *, int, int); -static void parse_message(char *, int, int); -static void parse_undef(char *, int, int); -static void parse_for(char *, int, int); -static void parse_endfor(char *, int, int); - -static const struct directive { - const char *name; - int code; - Boolean skip_flag; /* execute even when skipped */ - void (*func)(char *, int, int); -} directives[] = { - /* DIRECTIVES-START-TAG */ - { "elif", COND_ELIF, TRUE, Cond_If }, - { "elifdef", COND_ELIFDEF, TRUE, Cond_If }, - { "elifmake", COND_ELIFMAKE, TRUE, Cond_If }, - { "elifndef", COND_ELIFNDEF, TRUE, Cond_If }, - { "elifnmake", COND_ELIFNMAKE, TRUE, Cond_If }, - { "else", COND_ELSE, TRUE, Cond_Else }, - { "endfor", 0, FALSE, parse_endfor }, - { "endif", COND_ENDIF, TRUE, Cond_Endif }, - { "error", 1, FALSE, parse_message }, - { "for", 0, FALSE, parse_for }, - { "if", COND_IF, TRUE, Cond_If }, - { "ifdef", COND_IFDEF, TRUE, Cond_If }, - { "ifmake", COND_IFMAKE, TRUE, Cond_If }, - { "ifndef", COND_IFNDEF, TRUE, Cond_If }, - { "ifnmake", COND_IFNMAKE, TRUE, Cond_If }, - { "include", 0, FALSE, parse_include }, - { "sinclude", 0, FALSE, parse_sinclude }, - { "undef", 0, FALSE, parse_undef }, - { "warning", 0, FALSE, parse_message }, - /* DIRECTIVES-END-TAG */ -}; -#define NDIRECTS (sizeof(directives) / sizeof(directives[0])) - -/*- - * ParseFindKeyword - * Look in the table of keywords for one matching the given string. - * - * Results: - * The pointer to keyword table entry or NULL. - */ -static const struct keyword * -ParseFindKeyword(const char *str) -{ - int kw; - - kw = keyword_hash(str, strlen(str)); - if (kw < 0 || kw >= (int)NKEYWORDS || - strcmp(str, parseKeywords[kw].name) != 0) - return (NULL); - return (&parseKeywords[kw]); -} - -/*- - * Parse_Error -- - * Error message abort function for parsing. Prints out the context - * of the error (line number and file) as well as the message with - * two optional arguments. - * - * Results: - * None - * - * Side Effects: - * "fatals" is incremented if the level is PARSE_FATAL. - */ -/* VARARGS */ -void -Parse_Error(int type, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - if (CURFILE != NULL) - fprintf(stderr, "\"%s\", line %d: ", - CURFILE->fname, CURFILE->lineno); - if (type == PARSE_WARNING) - fprintf(stderr, "warning: "); - vfprintf(stderr, fmt, ap); - va_end(ap); - fprintf(stderr, "\n"); - fflush(stderr); - if (type == PARSE_FATAL) - fatals += 1; -} - -/** - * ParsePushInput - * - * Push a new input source onto the input stack. If ptr is NULL - * the fullname is used to fopen the file. If it is not NULL, - * ptr is assumed to point to the string to be parsed. If opening the - * file fails, the fullname is freed. - */ -static void -ParsePushInput(char *fullname, FILE *fp, char *ptr, int lineno) -{ - struct IFile *nf; - - nf = emalloc(sizeof(*nf)); - nf->fname = fullname; - nf->lineno = lineno; - - if (ptr == NULL) { - /* the input source is a file */ - if ((nf->F = fp) == NULL) { - nf->F = fopen(fullname, "r"); - if (nf->F == NULL) { - Parse_Error(PARSE_FATAL, "Cannot open %s", - fullname); - free(fullname); - free(nf); - return; - } - } - nf->str = nf->ptr = NULL; - Var_Append(".MAKEFILE_LIST", fullname, VAR_GLOBAL); - } else { - nf->str = nf->ptr = ptr; - nf->F = NULL; - } - TAILQ_INSERT_HEAD(&includes, nf, link); -} - -/** - * ParsePopInput - * Called when EOF is reached in the current file. If we were reading - * an include file, the includes stack is popped and things set up - * to go back to reading the previous file at the previous location. - * - * Results: - * CONTINUE if there's more to do. DONE if not. - * - * Side Effects: - * The old curFile.F is closed. The includes list is shortened. - * curFile.lineno, curFile.F, and curFile.fname are changed if - * CONTINUE is returned. - */ -static int -ParsePopInput(void) -{ - struct IFile *ifile; /* the state on the top of the includes stack */ - - assert(!TAILQ_EMPTY(&includes)); - - ifile = TAILQ_FIRST(&includes); - TAILQ_REMOVE(&includes, ifile, link); - - free(ifile->fname); - if (ifile->F != NULL) { - fclose(ifile->F); - Var_Append(".MAKEFILE_LIST", "..", VAR_GLOBAL); - } - if (ifile->str != NULL) { - free(ifile->str); - } - free(ifile); - - return (TAILQ_EMPTY(&includes) ? DONE : CONTINUE); -} - -/** - * parse_warn - * Parse the .WARN pseudo-target. - */ -static void -parse_warn(char *line) -{ - ArgArray aa; - int i; - - brk_string(&aa, line, TRUE); - - for (i = 1; i < aa.argc; i++) - Main_ParseWarn(aa.argv[i], 0); -} - -/*- - *--------------------------------------------------------------------- - * ParseLinkSrc -- - * Link the parent nodes to their new child. Used by - * ParseDoDependency. If the specType isn't 'Not', the parent - * isn't linked as a parent of the child. - * - * Side Effects: - * New elements are added to the parents lists of cgn and the - * children list of cgn. the unmade field of pgn is updated - * to reflect the additional child. - *--------------------------------------------------------------------- - */ -static void -ParseLinkSrc(Lst *parents, GNode *cgn) -{ - LstNode *ln; - GNode *pgn; - - LST_FOREACH(ln, parents) { - pgn = Lst_Datum(ln); - if (Lst_Member(&pgn->children, cgn) == NULL) { - Lst_AtEnd(&pgn->children, cgn); - if (specType == Not) { - Lst_AtEnd(&cgn->parents, pgn); - } - pgn->unmade += 1; - } - } -} - -/*- - *--------------------------------------------------------------------- - * ParseDoOp -- - * Apply the parsed operator to all target nodes. Used in - * ParseDoDependency once all targets have been found and their - * operator parsed. If the previous and new operators are incompatible, - * a major error is taken. - * - * Side Effects: - * The type field of the node is altered to reflect any new bits in - * the op. - *--------------------------------------------------------------------- - */ -static void -ParseDoOp(int op) -{ - GNode *cohort; - LstNode *ln; - GNode *gn; - - LST_FOREACH(ln, &targets) { - gn = Lst_Datum(ln); - - /* - * If the dependency mask of the operator and the node don't - * match and the node has actually had an operator applied to - * it before, and the operator actually has some dependency - * information in it, complain. - */ - if ((op & OP_OPMASK) != (gn->type & OP_OPMASK) && - !OP_NOP(gn->type) && !OP_NOP(op)) { - Parse_Error(PARSE_FATAL, "Inconsistent operator for %s", - gn->name); - return; - } - - if (op == OP_DOUBLEDEP && - (gn->type & OP_OPMASK) == OP_DOUBLEDEP) { - /* - * If the node was the object of a :: operator, we need - * to create a new instance of it for the children and - * commands on this dependency line. The new instance - * is placed on the 'cohorts' list of the initial one - * (note the initial one is not on its own cohorts list) - * and the new instance is linked to all parents of the - * initial instance. - */ - cohort = Targ_NewGN(gn->name); - - /* - * Duplicate links to parents so graph traversal is - * simple. Perhaps some type bits should be duplicated? - * - * Make the cohort invisible as well to avoid - * duplicating it into other variables. True, parents - * of this target won't tend to do anything with their - * local variables, but better safe than sorry. - */ - ParseLinkSrc(&gn->parents, cohort); - cohort->type = OP_DOUBLEDEP|OP_INVISIBLE; - Lst_AtEnd(&gn->cohorts, cohort); - - /* - * Replace the node in the targets list with the - * new copy - */ - Lst_Replace(ln, cohort); - gn = cohort; - } - /* - * We don't want to nuke any previous flags (whatever they were) - * so we just OR the new operator into the old - */ - gn->type |= op; - } -} - -/*- - *--------------------------------------------------------------------- - * ParseDoSrc -- - * Given the name of a source, figure out if it is an attribute - * and apply it to the targets if it is. Else decide if there is - * some attribute which should be applied *to* the source because - * of some special target and apply it if so. Otherwise, make the - * source be a child of the targets in the list 'targets' - * - * Results: - * None - * - * Side Effects: - * Operator bits may be added to the list of targets or to the source. - * The targets may have a new source added to their lists of children. - *--------------------------------------------------------------------- - */ -static void -ParseDoSrc(int tOp, char *src, Lst *allsrc) -{ - GNode *gn = NULL; - const struct keyword *kw; - - if (src[0] == '.' && isupper ((unsigned char)src[1])) { - if ((kw = ParseFindKeyword(src)) != NULL) { - if (kw->op != 0) { - ParseDoOp(kw->op); - return; - } - if (kw->spec == Wait) { - waiting++; - return; - } - } - } - - switch (specType) { - case Main: - /* - * If we have noted the existence of a .MAIN, it means we need - * to add the sources of said target to the list of things - * to create. The string 'src' is likely to be free, so we - * must make a new copy of it. Note that this will only be - * invoked if the user didn't specify a target on the command - * line. This is to allow #ifmake's to succeed, or something... - */ - Lst_AtEnd(&create, estrdup(src)); - /* - * Add the name to the .TARGETS variable as well, so the user - * can employ that, if desired. - */ - Var_Append(".TARGETS", src, VAR_GLOBAL); - return; - - case Order: - /* - * Create proper predecessor/successor links between the - * previous source and the current one. - */ - gn = Targ_FindNode(src, TARG_CREATE); - if (predecessor != NULL) { - Lst_AtEnd(&predecessor->successors, gn); - Lst_AtEnd(&gn->preds, predecessor); - } - /* - * The current source now becomes the predecessor for the next - * one. - */ - predecessor = gn; - break; - - default: - /* - * If the source is not an attribute, we need to find/create - * a node for it. After that we can apply any operator to it - * from a special target or link it to its parents, as - * appropriate. - * - * In the case of a source that was the object of a :: operator, - * the attribute is applied to all of its instances (as kept in - * the 'cohorts' list of the node) or all the cohorts are linked - * to all the targets. - */ - gn = Targ_FindNode(src, TARG_CREATE); - if (tOp) { - gn->type |= tOp; - } else { - ParseLinkSrc(&targets, gn); - } - if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) { - GNode *cohort; - LstNode *ln; - - for (ln = Lst_First(&gn->cohorts); ln != NULL; - ln = Lst_Succ(ln)) { - cohort = Lst_Datum(ln); - if (tOp) { - cohort->type |= tOp; - } else { - ParseLinkSrc(&targets, cohort); - } - } - } - break; - } - - gn->order = waiting; - Lst_AtEnd(allsrc, gn); - if (waiting) { - LstNode *ln; - GNode *p; - - /* - * Check if GNodes needs to be synchronized. - * This has to be when two nodes are on different sides of a - * .WAIT directive. - */ - LST_FOREACH(ln, allsrc) { - p = Lst_Datum(ln); - - if (p->order >= gn->order) - break; - /* - * XXX: This can cause loops, and loops can cause - * unmade targets, but checking is tedious, and the - * debugging output can show the problem - */ - Lst_AtEnd(&p->successors, gn); - Lst_AtEnd(&gn->preds, p); - } - } -} - - -/*- - *--------------------------------------------------------------------- - * ParseDoDependency -- - * Parse the dependency line in line. - * - * Results: - * None - * - * Side Effects: - * The nodes of the sources are linked as children to the nodes of the - * targets. Some nodes may be created. - * - * We parse a dependency line by first extracting words from the line and - * finding nodes in the list of all targets with that name. This is done - * until a character is encountered which is an operator character. Currently - * these are only ! and :. At this point the operator is parsed and the - * pointer into the line advanced until the first source is encountered. - * The parsed operator is applied to each node in the 'targets' list, - * which is where the nodes found for the targets are kept, by means of - * the ParseDoOp function. - * The sources are read in much the same way as the targets were except - * that now they are expanded using the wildcarding scheme of the C-Shell - * and all instances of the resulting words in the list of all targets - * are found. Each of the resulting nodes is then linked to each of the - * targets as one of its children. - * Certain targets are handled specially. These are the ones detailed - * by the specType variable. - * The storing of transformation rules is also taken care of here. - * A target is recognized as a transformation rule by calling - * Suff_IsTransform. If it is a transformation rule, its node is gotten - * from the suffix module via Suff_AddTransform rather than the standard - * Targ_FindNode in the target module. - *--------------------------------------------------------------------- - */ -static void -ParseDoDependency(char *line) -{ - char *cp; /* our current position */ - char *lstart = line; /* original input line */ - GNode *gn; /* a general purpose temporary node */ - int op; /* the operator on the line */ - char savec; /* a place to save a character */ - Lst paths; /* Search paths to alter when parsing .PATH targets */ - int tOp; /* operator from special target */ - LstNode *ln; - const struct keyword *kw; - - tOp = 0; - - specType = Not; - waiting = 0; - Lst_Init(&paths); - - do { - for (cp = line; - *cp && !isspace((unsigned char)*cp) && *cp != '('; - cp++) { - if (*cp == '$') { - /* - * Must be a dynamic source (would have been - * expanded otherwise), so call the Var module - * to parse the puppy so we can safely advance - * beyond it...There should be no errors in this - * as they would have been discovered in the - * initial Var_Subst and we wouldn't be here. - */ - size_t length = 0; - Boolean freeIt; - char *result; - - result = Var_Parse(cp, VAR_CMD, TRUE, - &length, &freeIt); - - if (freeIt) { - free(result); - } - cp += length - 1; - - } else if (*cp == '!' || *cp == ':') { - /* - * We don't want to end a word on ':' or '!' if - * there is a better match later on in the - * string (greedy matching). - * This allows the user to have targets like: - * fie::fi:fo: fum - * foo::bar: - * where "fie::fi:fo" and "foo::bar" are the - * targets. In real life this is used for perl5 - * library man pages where "::" separates an - * object from its class. Ie: - * "File::Spec::Unix". This behaviour is also - * consistent with other versions of make. - */ - char *p = cp + 1; - - if (*cp == ':' && *p == ':') - p++; - - /* Found the best match already. */ - if (*p == '\0' || isspace(*p)) - break; - - p += strcspn(p, "!:"); - - /* No better match later on... */ - if (*p == '\0') - break; - } - continue; - } - if (*cp == '(') { - /* - * Archives must be handled specially to make sure the - * OP_ARCHV flag is set in their 'type' field, for one - * thing, and because things like "archive(file1.o - * file2.o file3.o)" are permissible. Arch_ParseArchive - * will set 'line' to be the first non-blank after the - * archive-spec. It creates/finds nodes for the members - * and places them on the given list, returning TRUE - * if all went well and FALSE if there was an error in - * the specification. On error, line should remain - * untouched. - */ - if (!Arch_ParseArchive(&line, &targets, VAR_CMD)) { - Parse_Error(PARSE_FATAL, - "Error in archive specification: \"%s\"", - line); - return; - } else { - cp = line; - continue; - } - } - savec = *cp; - - if (!*cp) { - /* - * Ending a dependency line without an operator is a * Bozo no-no. As a heuristic, this is also often - * triggered by undetected conflicts from cvs/rcs - * merges. - */ - if (strncmp(line, "<<<<<<", 6) == 0 || - strncmp(line, "||||||", 6) == 0 || - strncmp(line, "======", 6) == 0 || - strncmp(line, ">>>>>>", 6) == 0) { - Parse_Error(PARSE_FATAL, "Makefile appears to " - "contain unresolved cvs/rcs/??? merge " - "conflicts"); - } else - Parse_Error(PARSE_FATAL, lstart[0] == '.' ? - "Unknown directive" : "Need an operator"); - return; - } - *cp = '\0'; - /* - * Have a word in line. See if it's a special target and set - * specType to match it. - */ - if (*line == '.' && isupper((unsigned char)line[1])) { - /* - * See if the target is a special target that must have - * it or its sources handled specially. - */ - if ((kw = ParseFindKeyword(line)) != NULL) { - if (specType == ExPath && kw->spec != ExPath) { - Parse_Error(PARSE_FATAL, - "Mismatched special targets"); - return; - } - - specType = kw->spec; - tOp = kw->op; - - /* - * Certain special targets have special - * semantics: - * .PATH Have to set the dirSearchPath - * variable too - * .MAIN Its sources are only used if - * nothing has been specified to - * create. - * .DEFAULT Need to create a node to hang - * commands on, but we don't want - * it in the graph, nor do we want - * it to be the Main Target, so we - * create it, set OP_NOTMAIN and - * add it to the list, setting - * DEFAULT to the new node for - * later use. We claim the node is - * A transformation rule to make - * life easier later, when we'll - * use Make_HandleUse to actually - * apply the .DEFAULT commands. - * .PHONY The list of targets - * .BEGIN - * .END - * .INTERRUPT Are not to be considered the - * main target. - * .NOTPARALLEL Make only one target at a time. - * .SINGLESHELL Create a shell for each - * command. - * .ORDER Must set initial predecessor - * to NULL - */ - switch (specType) { - case ExPath: - Lst_AtEnd(&paths, &dirSearchPath); - break; - case Main: - if (!Lst_IsEmpty(&create)) { - specType = Not; - } - break; - case Begin: - case End: - case Interrupt: - gn = Targ_FindNode(line, TARG_CREATE); - gn->type |= OP_NOTMAIN; - Lst_AtEnd(&targets, gn); - break; - case Default: - gn = Targ_NewGN(".DEFAULT"); - gn->type |= (OP_NOTMAIN|OP_TRANSFORM); - Lst_AtEnd(&targets, gn); - DEFAULT = gn; - break; - case NotParallel: - jobLimit = 1; - break; - case SingleShell: - compatMake = 1; - break; - case Order: - predecessor = NULL; - break; - default: - break; - } - - } else if (strncmp(line, ".PATH", 5) == 0) { - /* - * .PATH has to be handled specially. - * Call on the suffix module to give us a path - * to modify. - */ - struct Path *path; - - specType = ExPath; - path = Suff_GetPath(&line[5]); - if (path == NULL) { - Parse_Error(PARSE_FATAL, "Suffix '%s' " - "not defined (yet)", &line[5]); - return; - } else - Lst_AtEnd(&paths, path); - } - } - - /* - * Have word in line. Get or create its node and stick it at - * the end of the targets list - */ - if (specType == Not && *line != '\0') { - - /* target names to be found and added to targets list */ - Lst curTargs = Lst_Initializer(curTargs); - - if (Dir_HasWildcards(line)) { - /* - * Targets are to be sought only in the current - * directory, so create an empty path for the - * thing. Note we need to use Path_Clear in the - * destruction of the path as the Dir module - * could have added a directory to the path... - */ - struct Path emptyPath = - TAILQ_HEAD_INITIALIZER(emptyPath); - - Path_Expand(line, &emptyPath, &curTargs); - Path_Clear(&emptyPath); - - } else { - /* - * No wildcards, but we want to avoid code - * duplication, so create a list with the word - * on it. - */ - Lst_AtEnd(&curTargs, line); - } - - while (!Lst_IsEmpty(&curTargs)) { - char *targName = Lst_DeQueue(&curTargs); - - if (!Suff_IsTransform (targName)) { - gn = Targ_FindNode(targName, - TARG_CREATE); - } else { - gn = Suff_AddTransform(targName); - } - - Lst_AtEnd(&targets, gn); - } - } else if (specType == ExPath && *line != '.' && *line != '\0'){ - Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", - line); - } - - *cp = savec; - /* - * If it is a special type and not .PATH, it's the only - * target we allow on this line... - */ - if (specType != Not && specType != ExPath) { - Boolean warnFlag = FALSE; - - while (*cp != '!' && *cp != ':' && *cp) { - if (*cp != ' ' && *cp != '\t') { - warnFlag = TRUE; - } - cp++; - } - if (warnFlag) { - Parse_Error(PARSE_WARNING, - "Extra target ignored"); - } - } else { - while (*cp && isspace((unsigned char)*cp)) { - cp++; - } - } - line = cp; - } while (*line != '!' && *line != ':' && *line); - - if (!Lst_IsEmpty(&targets)) { - switch (specType) { - default: - Parse_Error(PARSE_WARNING, "Special and mundane " - "targets don't mix. Mundane ones ignored"); - break; - case Default: - case Begin: - case End: - case Interrupt: - /* - * These four create nodes on which to hang commands, so - * targets shouldn't be empty... - */ - case Not: - /* - * Nothing special here -- targets can be empty if it - * wants. - */ - break; - } - } - - /* - * Have now parsed all the target names. Must parse the operator next. - * The result is left in op. - */ - if (*cp == '!') { - op = OP_FORCE; - } else if (*cp == ':') { - if (cp[1] == ':') { - op = OP_DOUBLEDEP; - cp++; - } else { - op = OP_DEPENDS; - } - } else { - Parse_Error(PARSE_FATAL, lstart[0] == '.' ? - "Unknown directive" : "Missing dependency operator"); - return; - } - - cp++; /* Advance beyond operator */ - - ParseDoOp(op); - - /* - * Get to the first source - */ - while (*cp && isspace((unsigned char)*cp)) { - cp++; - } - line = cp; - - /* - * Several special targets take different actions if present with no - * sources: - * a .SUFFIXES line with no sources clears out all old suffixes - * a .PRECIOUS line makes all targets precious - * a .IGNORE line ignores errors for all targets - * a .SILENT line creates silence when making all targets - * a .PATH removes all directories from the search path(s). - */ - if (!*line) { - switch (specType) { - case Suffixes: - Suff_ClearSuffixes(); - break; - case Precious: - allPrecious = TRUE; - break; - case Ignore: - ignoreErrors = TRUE; - break; - case Silent: - beSilent = TRUE; - break; - case ExPath: - LST_FOREACH(ln, &paths) - Path_Clear(Lst_Datum(ln)); - break; - case MakefileDeps: - mfAutoDeps = TRUE; - break; - case Posix: - is_posix = TRUE; - Var_SetGlobal("%POSIX", "1003.2"); - break; - default: - break; - } - - } else if (specType == MFlags) { - /* - * Call on functions in main.c to deal with these arguments and - * set the initial character to a null-character so the loop to - * get sources won't get anything - */ - Main_ParseArgLine(line, 0); - *line = '\0'; - - } else if (specType == Warn) { - parse_warn(line); - *line = '\0'; - - } else if (specType == ExShell) { - if (!Shell_Parse(line)) { - Parse_Error(PARSE_FATAL, - "improper shell specification"); - return; - } - *line = '\0'; - - } else if (specType == NotParallel || specType == SingleShell) { - *line = '\0'; - } - - /* - * NOW GO FOR THE SOURCES - */ - if (specType == Suffixes || specType == ExPath || - specType == Includes || specType == Libs || - specType == Null) { - while (*line) { - /* - * If the target was one that doesn't take files as its - * sources but takes something like suffixes, we take - * each space-separated word on the line as a something - * and deal with it accordingly. - * - * If the target was .SUFFIXES, we take each source as - * a suffix and add it to the list of suffixes - * maintained by the Suff module. - * - * If the target was a .PATH, we add the source as a - * directory to search on the search path. - * - * If it was .INCLUDES, the source is taken to be the - * suffix of files which will be #included and whose - * search path should be present in the .INCLUDES - * variable. - * - * If it was .LIBS, the source is taken to be the - * suffix of files which are considered libraries and - * whose search path should be present in the .LIBS - * variable. - * - * If it was .NULL, the source is the suffix to use - * when a file has no valid suffix. - */ - char savech; - while (*cp && !isspace((unsigned char)*cp)) { - cp++; - } - savech = *cp; - *cp = '\0'; - switch (specType) { - case Suffixes: - Suff_AddSuffix(line); - break; - case ExPath: - LST_FOREACH(ln, &paths) - Path_AddDir(Lst_Datum(ln), line); - break; - case Includes: - Suff_AddInclude(line); - break; - case Libs: - Suff_AddLib(line); - break; - case Null: - Suff_SetNull(line); - break; - default: - break; - } - *cp = savech; - if (savech != '\0') { - cp++; - } - while (*cp && isspace((unsigned char)*cp)) { - cp++; - } - line = cp; - } - Lst_Destroy(&paths, NOFREE); - - } else if (specType == ExportVar) { - Var_SetEnv(line, VAR_GLOBAL); - - } else { - /* list of sources in order */ - Lst curSrcs = Lst_Initializer(curSrc); - - while (*line) { - /* - * The targets take real sources, so we must beware of - * archive specifications (i.e. things with left - * parentheses in them) and handle them accordingly. - */ - while (*cp && !isspace((unsigned char)*cp)) { - if (*cp == '(' && cp > line && cp[-1] != '$') { - /* - * Only stop for a left parenthesis if - * it isn't at the start of a word - * (that'll be for variable changes - * later) and isn't preceded by a dollar - * sign (a dynamic source). - */ - break; - } else { - cp++; - } - } - - if (*cp == '(') { - GNode *gnp; - - /* list of archive source names after exp. */ - Lst sources = Lst_Initializer(sources); - - if (!Arch_ParseArchive(&line, &sources, - VAR_CMD)) { - Parse_Error(PARSE_FATAL, "Error in " - "source archive spec \"%s\"", line); - return; - } - - while (!Lst_IsEmpty(&sources)) { - gnp = Lst_DeQueue(&sources); - ParseDoSrc(tOp, gnp->name, &curSrcs); - } - cp = line; - } else { - if (*cp) { - *cp = '\0'; - cp += 1; - } - - ParseDoSrc(tOp, line, &curSrcs); - } - while (*cp && isspace((unsigned char)*cp)) { - cp++; - } - line = cp; - } - Lst_Destroy(&curSrcs, NOFREE); - } - - if (mainNode == NULL) { - /* - * If we have yet to decide on a main target to make, in the - * absence of any user input, we want the first target on - * the first dependency line that is actually a real target - * (i.e. isn't a .USE or .EXEC rule) to be made. - */ - LST_FOREACH(ln, &targets) { - gn = Lst_Datum(ln); - if ((gn->type & (OP_NOTMAIN | OP_USE | - OP_EXEC | OP_TRANSFORM)) == 0) { - mainNode = gn; - Targ_SetMain(gn); - break; - } - } - } -} - -/*- - *--------------------------------------------------------------------- - * Parse_IsVar -- - * Return TRUE if the passed line is a variable assignment. A variable - * assignment consists of a single word followed by optional whitespace - * followed by either a += or an = operator. - * This function is used both by the Parse_File function and main when - * parsing the command-line arguments. - * - * Results: - * TRUE if it is. FALSE if it ain't - * - * Side Effects: - * none - *--------------------------------------------------------------------- - */ -Boolean -Parse_IsVar(char *line) -{ - Boolean wasSpace = FALSE; /* set TRUE if found a space */ - Boolean haveName = FALSE; /* Set TRUE if have a variable name */ - - int level = 0; -#define ISEQOPERATOR(c) \ - ((c) == '+' || (c) == ':' || (c) == '?' || (c) == '!') - - /* - * Skip to variable name - */ - for (; *line == ' ' || *line == '\t'; line++) - continue; - - for (; *line != '=' || level != 0; line++) { - switch (*line) { - case '\0': - /* - * end-of-line -- can't be a variable assignment. - */ - return (FALSE); - - case ' ': - case '\t': - /* - * there can be as much white space as desired so long - * as there is only one word before the operator - */ - wasSpace = TRUE; - break; - - case '(': - case '{': - level++; - break; - - case '}': - case ')': - level--; - break; - - default: - if (wasSpace && haveName) { - if (ISEQOPERATOR(*line)) { - /* - * We must have a finished word - */ - if (level != 0) - return (FALSE); - - /* - * When an = operator [+?!:] is found, - * the next character must be an = or - * it ain't a valid assignment. - */ - if (line[1] == '=') - return (haveName); -#ifdef SUNSHCMD - /* - * This is a shell command - */ - if (strncmp(line, ":sh", 3) == 0) - return (haveName); -#endif - } - /* - * This is the start of another word, so not - * assignment. - */ - return (FALSE); - - } else { - haveName = TRUE; - wasSpace = FALSE; - } - break; - } - } - - return (haveName); -} - -/*- - *--------------------------------------------------------------------- - * Parse_DoVar -- - * Take the variable assignment in the passed line and do it in the - * global context. - * - * Note: There is a lexical ambiguity with assignment modifier characters - * in variable names. This routine interprets the character before the = - * as a modifier. Therefore, an assignment like - * C++=/usr/bin/CC - * is interpreted as "C+ +=" instead of "C++ =". - * - * Results: - * none - * - * Side Effects: - * the variable structure of the given variable name is altered in the - * global context. - *--------------------------------------------------------------------- - */ -void -Parse_DoVar(char *line, GNode *ctxt) -{ - char *cp; /* pointer into line */ - enum { - VAR_SUBST, - VAR_APPEND, - VAR_SHELL, - VAR_NORMAL - } type; /* Type of assignment */ - char *opc; /* ptr to operator character to - * null-terminate the variable name */ - - /* - * Skip to variable name - */ - while (*line == ' ' || *line == '\t') { - line++; - } - - /* - * Skip to operator character, nulling out whitespace as we go - */ - for (cp = line + 1; *cp != '='; cp++) { - if (isspace((unsigned char)*cp)) { - *cp = '\0'; - } - } - opc = cp - 1; /* operator is the previous character */ - *cp++ = '\0'; /* nuke the = */ - - /* - * Check operator type - */ - switch (*opc) { - case '+': - type = VAR_APPEND; - *opc = '\0'; - break; - - case '?': - /* - * If the variable already has a value, we don't do anything. - */ - *opc = '\0'; - if (Var_Exists(line, ctxt)) { - return; - } else { - type = VAR_NORMAL; - } - break; - - case ':': - type = VAR_SUBST; - *opc = '\0'; - break; - - case '!': - type = VAR_SHELL; - *opc = '\0'; - break; - - default: -#ifdef SUNSHCMD - while (*opc != ':') { - if (opc == line) - break; - else - --opc; - } - - if (strncmp(opc, ":sh", 3) == 0) { - type = VAR_SHELL; - *opc = '\0'; - break; - } -#endif - type = VAR_NORMAL; - break; - } - - while (isspace((unsigned char)*cp)) { - cp++; - } - - if (type == VAR_APPEND) { - Var_Append(line, cp, ctxt); - - } else if (type == VAR_SUBST) { - /* - * Allow variables in the old value to be undefined, but leave - * their invocation alone -- this is done by forcing oldVars - * to be false. - * XXX: This can cause recursive variables, but that's not - * hard to do, and this allows someone to do something like - * - * CFLAGS = $(.INCLUDES) - * CFLAGS := -I.. $(CFLAGS) - * - * And not get an error. - */ - Boolean oldOldVars = oldVars; - - oldVars = FALSE; - - /* - * make sure that we set the variable the first time to nothing - * so that it gets substituted! - */ - if (!Var_Exists(line, ctxt)) - Var_Set(line, "", ctxt); - - cp = Buf_Peel(Var_Subst(cp, ctxt, FALSE)); - - oldVars = oldOldVars; - - Var_Set(line, cp, ctxt); - free(cp); - - } else if (type == VAR_SHELL) { - /* - * TRUE if the command needs to be freed, i.e. - * if any variable expansion was performed - */ - Boolean freeCmd = FALSE; - Buffer *buf; - const char *error; - - if (strchr(cp, '$') != NULL) { - /* - * There's a dollar sign in the command, so perform - * variable expansion on the whole thing. The - * resulting string will need freeing when we're done, - * so set freeCmd to TRUE. - */ - cp = Buf_Peel(Var_Subst(cp, VAR_CMD, TRUE)); - freeCmd = TRUE; - } - - buf = Cmd_Exec(cp, &error); - Var_Set(line, Buf_Data(buf), ctxt); - Buf_Destroy(buf, TRUE); - - if (error) - Parse_Error(PARSE_WARNING, error, cp); - - if (freeCmd) - free(cp); - - } else { - /* - * Normal assignment -- just do it. - */ - Var_Set(line, cp, ctxt); - } - if (strcmp(line, MAKE_JOB_PREFIX) == 0) - Job_SetPrefix(); -} - -/*- - *----------------------------------------------------------------------- - * ParseHasCommands -- - * Callback procedure for Parse_File when destroying the list of - * targets on the last dependency line. Marks a target as already - * having commands if it does, to keep from having shell commands - * on multiple dependency lines. - * - * Results: - * None - * - * Side Effects: - * OP_HAS_COMMANDS may be set for the target. - * - *----------------------------------------------------------------------- - */ -static void -ParseHasCommands(void *gnp) -{ - GNode *gn = gnp; - - if (!Lst_IsEmpty(&gn->commands)) { - gn->type |= OP_HAS_COMMANDS; - } -} - -/*- - *----------------------------------------------------------------------- - * Parse_AddIncludeDir -- - * Add a directory to the path searched for included makefiles - * bracketed by double-quotes. Used by functions in main.c - * - * Results: - * None. - * - * Side Effects: - * The directory is appended to the list. - * - *----------------------------------------------------------------------- - */ -void -Parse_AddIncludeDir(char *dir) -{ - - Path_AddDir(&parseIncPath, dir); -} - -/*- - *--------------------------------------------------------------------- - * Parse_FromString -- - * Start Parsing from the given string - * - * Results: - * None - * - * Side Effects: - * A structure is added to the includes Lst and readProc, curFile.lineno, - * curFile.fname and curFile.F are altered for the new file - *--------------------------------------------------------------------- - */ -void -Parse_FromString(char *str, int lineno) -{ - - DEBUGF(FOR, ("%s\n---- at line %d\n", str, lineno)); - - ParsePushInput(estrdup(CURFILE->fname), NULL, str, lineno); -} - -#ifdef SYSVINCLUDE -/*- - *--------------------------------------------------------------------- - * ParseTraditionalInclude -- - * Push to another file. - * - * The input is the line minus the "include". The file name is - * the string following the "include". - * - * Results: - * None - * - * Side Effects: - * A structure is added to the includes Lst and readProc, curFile.lineno, - * curFile.fname and curFile.F are altered for the new file - *--------------------------------------------------------------------- - */ -static void -ParseTraditionalInclude(char *file) -{ - char *fullname; /* full pathname of file */ - char *cp; /* current position in file spec */ - - /* - * Skip over whitespace - */ - while (*file == ' ' || *file == '\t') { - file++; - } - - if (*file == '\0') { - Parse_Error(PARSE_FATAL, "Filename missing from \"include\""); - return; - } - - /* - * Skip to end of line or next whitespace - */ - for (cp = file; *cp && *cp != '\n' && *cp != '\t' && *cp != ' '; cp++) { - continue; - } - - *cp = '\0'; - - /* - * Substitute for any variables in the file name before trying to - * find the thing. - */ - file = Buf_Peel(Var_Subst(file, VAR_CMD, FALSE)); - - /* - * Now we know the file's name, we attempt to find the durn thing. - * Search for it first on the -I search path, then on the .PATH - * search path, if not found in a -I directory. - */ - fullname = Path_FindFile(file, &parseIncPath); - if (fullname == NULL) { - fullname = Path_FindFile(file, &dirSearchPath); - } - - if (fullname == NULL) { - /* - * Still haven't found the makefile. Look for it on the system - * path as a last resort. - */ - fullname = Path_FindFile(file, &sysIncPath); - } - - if (fullname == NULL) { - Parse_Error(PARSE_FATAL, "Could not find %s", file); - /* XXXHB free(file) */ - return; - } - - /* XXXHB free(file) */ - - /* - * We set up the name of the file to be the absolute - * name of the include file so error messages refer to the right - * place. - */ - ParsePushInput(fullname, NULL, NULL, 0); -} -#endif - -/*- - *--------------------------------------------------------------------- - * ParseReadc -- - * Read a character from the current file - * - * Results: - * The character that was read - * - * Side Effects: - *--------------------------------------------------------------------- - */ -static int -ParseReadc(void) -{ - - if (CURFILE->F != NULL) - return (fgetc(CURFILE->F)); - - if (CURFILE->str != NULL && *CURFILE->ptr != '\0') - return (*CURFILE->ptr++); - - return (EOF); -} - - -/*- - *--------------------------------------------------------------------- - * ParseUnreadc -- - * Put back a character to the current file - * - * Results: - * None. - * - * Side Effects: - *--------------------------------------------------------------------- - */ -static void -ParseUnreadc(int c) -{ - - if (CURFILE->F != NULL) { - ungetc(c, CURFILE->F); - return; - } - if (CURFILE->str != NULL) { - *--(CURFILE->ptr) = c; - return; - } -} - -/* ParseSkipLine(): - * Grab the next line unless it begins with a dot (`.') and we're told to - * ignore such lines. - */ -static char * -ParseSkipLine(int skip, int keep_newline) -{ - char *line; - int c, lastc; - Buffer *buf; - - buf = Buf_Init(MAKE_BSIZE); - - do { - Buf_Clear(buf); - lastc = '\0'; - - while (((c = ParseReadc()) != '\n' || lastc == '\\') - && c != EOF) { - if (skip && c == '#' && lastc != '\\') { - /* - * let a comment be terminated even by an - * escaped \n. This is consistent to comment - * handling in ParseReadLine - */ - while ((c = ParseReadc()) != '\n' && c != EOF) - ; - break; - } - if (c == '\n') { - if (keep_newline) - Buf_AddByte(buf, (Byte)c); - else - Buf_ReplaceLastByte(buf, (Byte)' '); - CURFILE->lineno++; - - while ((c = ParseReadc()) == ' ' || c == '\t') - continue; - - if (c == EOF) - break; - } - - Buf_AddByte(buf, (Byte)c); - lastc = c; - } - - if (c == EOF) { - Parse_Error(PARSE_FATAL, - "Unclosed conditional/for loop"); - Buf_Destroy(buf, TRUE); - return (NULL); - } - - CURFILE->lineno++; - Buf_AddByte(buf, (Byte)'\0'); - line = Buf_Data(buf); - } while (skip == 1 && line[0] != '.'); - - Buf_Destroy(buf, FALSE); - return (line); -} - -/*- - *--------------------------------------------------------------------- - * ParseReadLine -- - * Read an entire line from the input file. Called only by Parse_File. - * To facilitate escaped newlines and what have you, a character is - * buffered in 'lastc', which is '\0' when no characters have been - * read. When we break out of the loop, c holds the terminating - * character and lastc holds a character that should be added to - * the line (unless we don't read anything but a terminator). - * - * Results: - * A line w/o its newline - * - * Side Effects: - * Only those associated with reading a character - *--------------------------------------------------------------------- - */ -static char * -ParseReadLine(void) -{ - Buffer *buf; /* Buffer for current line */ - int c; /* the current character */ - int lastc; /* The most-recent character */ - Boolean semiNL; /* treat semi-colons as newlines */ - Boolean ignDepOp; /* TRUE if should ignore dependency operators - * for the purposes of setting semiNL */ - Boolean ignComment; /* TRUE if should ignore comments (in a - * shell command */ - char *line; /* Result */ - char *ep; /* to strip trailing blanks */ - - again: - semiNL = FALSE; - ignDepOp = FALSE; - ignComment = FALSE; - - lastc = '\0'; - - /* - * Handle tab at the beginning of the line. A leading tab (shell - * command) forces us to ignore comments and dependency operators and - * treat semi-colons as semi-colons (by leaving semiNL FALSE). - * This also discards completely blank lines. - */ - for (;;) { - c = ParseReadc(); - if (c == EOF) { - if (ParsePopInput() == DONE) { - /* End of all inputs - return NULL */ - return (NULL); - } - continue; - } - - if (c == '\t') { - ignComment = ignDepOp = TRUE; - lastc = c; - break; - } - if (c != '\n') { - ParseUnreadc(c); - break; - } - CURFILE->lineno++; - } - - buf = Buf_Init(MAKE_BSIZE); - - while (((c = ParseReadc()) != '\n' || lastc == '\\') && c != EOF) { - test_char: - switch (c) { - case '\n': - /* - * Escaped newline: read characters until a - * non-space or an unescaped newline and - * replace them all by a single space. This is - * done by storing the space over the backslash - * and dropping through with the next nonspace. - * If it is a semi-colon and semiNL is TRUE, - * it will be recognized as a newline in the - * code below this... - */ - CURFILE->lineno++; - lastc = ' '; - while ((c = ParseReadc()) == ' ' || c == '\t') { - continue; - } - if (c == EOF || c == '\n') { - goto line_read; - } else { - /* - * Check for comments, semiNL's, etc. -- - * easier than ParseUnreadc(c); - * continue; - */ - goto test_char; - } - /*NOTREACHED*/ - break; - - case ';': - /* - * Semi-colon: Need to see if it should be - * interpreted as a newline - */ - if (semiNL) { - /* - * To make sure the command that may - * be following this semi-colon begins - * with a tab, we push one back into the - * input stream. This will overwrite the - * semi-colon in the buffer. If there is - * no command following, this does no - * harm, since the newline remains in - * the buffer and the - * whole line is ignored. - */ - ParseUnreadc('\t'); - goto line_read; - } - break; - case '=': - if (!semiNL) { - /* - * Haven't seen a dependency operator - * before this, so this must be a - * variable assignment -- don't pay - * attention to dependency operators - * after this. - */ - ignDepOp = TRUE; - } else if (lastc == ':' || lastc == '!') { - /* - * Well, we've seen a dependency - * operator already, but it was the - * previous character, so this is really - * just an expanded variable assignment. - * Revert semi-colons to being just - * semi-colons again and ignore any more - * dependency operators. - * - * XXX: Note that a line like - * "foo : a:=b" will blow up, but who'd - * write a line like that anyway? - */ - ignDepOp = TRUE; - semiNL = FALSE; - } - break; - case '#': - if (!ignComment) { - if (lastc != '\\') { - /* - * If the character is a hash - * mark and it isn't escaped - * (or we're being compatible), - * the thing is a comment. - * Skip to the end of the line. - */ - do { - c = ParseReadc(); - } while (c != '\n' && c != EOF); - goto line_read; - } else { - /* - * Don't add the backslash. - * Just let the # get copied - * over. - */ - lastc = c; - continue; - } - } - break; - - case ':': - case '!': - if (!ignDepOp) { - /* - * A semi-colon is recognized as a - * newline only on dependency lines. - * Dependency lines are lines with a - * colon or an exclamation point. - * Ergo... - */ - semiNL = TRUE; - } - break; - - default: - break; - } - /* - * Copy in the previous character (there may be none if this - * was the first character) and save this one in - * lastc. - */ - if (lastc != '\0') - Buf_AddByte(buf, (Byte)lastc); - lastc = c; - } - line_read: - CURFILE->lineno++; - - if (lastc != '\0') { - Buf_AddByte(buf, (Byte)lastc); - } - Buf_AddByte(buf, (Byte)'\0'); - line = Buf_Peel(buf); - - /* - * Strip trailing blanks and tabs from the line. - * Do not strip a blank or tab that is preceded by - * a '\' - */ - ep = line; - while (*ep) - ++ep; - while (ep > line + 1 && (ep[-1] == ' ' || ep[-1] == '\t')) { - if (ep > line + 1 && ep[-2] == '\\') - break; - --ep; - } - *ep = 0; - - if (line[0] == '\0') { - /* empty line - just ignore */ - free(line); - goto again; - } - - return (line); -} - -/*- - *----------------------------------------------------------------------- - * ParseFinishLine -- - * Handle the end of a dependency group. - * - * Results: - * Nothing. - * - * Side Effects: - * inLine set FALSE. 'targets' list destroyed. - * - *----------------------------------------------------------------------- - */ -static void -ParseFinishLine(void) -{ - const LstNode *ln; - - if (inLine) { - LST_FOREACH(ln, &targets) { - if (((const GNode *)Lst_Datum(ln))->type & OP_TRANSFORM) - Suff_EndTransform(Lst_Datum(ln)); - } - Lst_Destroy(&targets, ParseHasCommands); - inLine = FALSE; - } -} - -/** - * xparse_include - * Parse an .include directive and push the file onto the input stack. - * The input is the line minus the .include. A file spec is a string - * enclosed in <> or "". The former is looked for only in sysIncPath. - * The latter in . and the directories specified by -I command line - * options - */ -static void -xparse_include(char *file, int sinclude) -{ - char *fullname; /* full pathname of file */ - char endc; /* the character which ends the file spec */ - char *cp; /* current position in file spec */ - Boolean isSystem; /* TRUE if makefile is a system makefile */ - char *prefEnd, *Fname; - char *newName; - - /* - * Skip to delimiter character so we know where to look - */ - while (*file == ' ' || *file == '\t') { - file++; - } - - if (*file != '"' && *file != '<') { - Parse_Error(PARSE_FATAL, - ".include filename must be delimited by '\"' or '<'"); - return; - } - - /* - * Set the search path on which to find the include file based on the - * characters which bracket its name. Angle-brackets imply it's - * a system Makefile while double-quotes imply it's a user makefile - */ - if (*file == '<') { - isSystem = TRUE; - endc = '>'; - } else { - isSystem = FALSE; - endc = '"'; - } - - /* - * Skip to matching delimiter - */ - for (cp = ++file; *cp != endc; cp++) { - if (*cp == '\0') { - Parse_Error(PARSE_FATAL, - "Unclosed .include filename. '%c' expected", endc); - return; - } - } - *cp = '\0'; - - /* - * Substitute for any variables in the file name before trying to - * find the thing. - */ - file = Buf_Peel(Var_Subst(file, VAR_CMD, FALSE)); - - /* - * Now we know the file's name and its search path, we attempt to - * find the durn thing. A return of NULL indicates the file don't - * exist. - */ - if (!isSystem) { - /* - * Include files contained in double-quotes are first searched - * for relative to the including file's location. We don't want - * to cd there, of course, so we just tack on the old file's - * leading path components and call Path_FindFile to see if - * we can locate the beast. - */ - - /* Make a temporary copy of this, to be safe. */ - Fname = estrdup(CURFILE->fname); - - prefEnd = strrchr(Fname, '/'); - if (prefEnd != NULL) { - *prefEnd = '\0'; - if (file[0] == '/') - newName = estrdup(file); - else - newName = str_concat(Fname, file, STR_ADDSLASH); - fullname = Path_FindFile(newName, &parseIncPath); - if (fullname == NULL) { - fullname = Path_FindFile(newName, - &dirSearchPath); - } - free(newName); - *prefEnd = '/'; - } else { - fullname = NULL; - } - free(Fname); - if (fullname == NULL) { - /* - * Makefile wasn't found in same directory as included - * makefile. Search for it first on the -I search path, - * then on the .PATH search path, if not found in a -I - * directory. - * XXX: Suffix specific? - */ - fullname = Path_FindFile(file, &parseIncPath); - if (fullname == NULL) { - fullname = Path_FindFile(file, &dirSearchPath); - } - } - } else { - fullname = NULL; - } - - if (fullname == NULL) { - /* - * System makefile or still haven't found the makefile. - * Look for it on the system path. - */ - fullname = Path_FindFile(file, &sysIncPath); - } - - if (fullname == NULL) { - *cp = endc; - if (!sinclude) - Parse_Error(PARSE_FATAL, "Could not find %s", file); - else - Main_AddSourceMakefile(file); - free(file); - return; - } - Main_AddSourceMakefile(fullname); - free(file); - - /* - * We set up the name of the file to be the absolute - * name of the include file so error messages refer to the right - * place. - */ - ParsePushInput(fullname, NULL, NULL, 0); - DEBUGF(DIR, (".include %s\n", fullname)); -} - -static void -parse_include(char *file, int code __unused, int lineno __unused) -{ - xparse_include(file, 0); -} - -static void -parse_sinclude(char *file, int code __unused, int lineno __unused) -{ - xparse_include(file, 1); -} - -/** - * parse_message - * Parse a .warning or .error directive - * - * The input is the line minus the ".error"/".warning". We substitute - * variables, print the message and exit(1) (for .error) or just print - * a warning if the directive is malformed. - */ -static void -parse_message(char *line, int iserror, int lineno __unused) -{ - - if (!isspace((u_char)*line)) { - Parse_Error(PARSE_WARNING, "invalid syntax: .%s%s", - iserror ? "error" : "warning", line); - return; - } - - while (isspace((u_char)*line)) - line++; - - line = Buf_Peel(Var_Subst(line, VAR_CMD, FALSE)); - Parse_Error(iserror ? PARSE_FATAL : PARSE_WARNING, "%s", line); - free(line); - - if (iserror) { - /* Terminate immediately. */ - exit(1); - } -} - -/** - * parse_undef - * Parse an .undef directive. - */ -static void -parse_undef(char *line, int code __unused, int lineno __unused) -{ - char *cp; - - while (isspace((u_char)*line)) - line++; - - for (cp = line; !isspace((u_char)*cp) && *cp != '\0'; cp++) { - ; - } - *cp = '\0'; - - cp = Buf_Peel(Var_Subst(line, VAR_CMD, FALSE)); - Var_Delete(cp, VAR_GLOBAL); - free(cp); -} - -/** - * parse_for - * Parse a .for directive. - */ -static void -parse_for(char *line, int code __unused, int lineno) -{ - - if (!For_For(line)) { - /* syntax error */ - return; - } - line = NULL; - - /* - * Skip after the matching endfor. - */ - do { - free(line); - line = ParseSkipLine(0, 1); - if (line == NULL) { - Parse_Error(PARSE_FATAL, - "Unexpected end of file in for loop.\n"); - return; - } - } while (For_Eval(line)); - free(line); - - /* execute */ - For_Run(lineno); -} - -/** - * parse_endfor - * Parse endfor. This may only happen if there was no matching .for. - */ -static void -parse_endfor(char *line __unused, int code __unused, int lineno __unused) -{ - - Parse_Error(PARSE_FATAL, "for-less endfor"); -} - -/** - * parse_directive - * Got a line starting with a '.'. Check if this is a directive - * and parse it. - * - * return: - * TRUE if line was a directive, FALSE otherwise. - */ -static Boolean -parse_directive(char *line) -{ - char *start; - char *cp; - int dir; - - /* - * Get the keyword: - * .[[:space:]]*\([[:alpha:]][[:alnum:]_]*\).* - * \1 is the keyword. - */ - for (start = line; isspace((u_char)*start); start++) { - ; - } - - if (!isalpha((u_char)*start)) { - return (FALSE); - } - - cp = start + 1; - while (isalnum((u_char)*cp) || *cp == '_') { - cp++; - } - - dir = directive_hash(start, cp - start); - if (dir < 0 || dir >= (int)NDIRECTS || - (size_t)(cp - start) != strlen(directives[dir].name) || - strncmp(start, directives[dir].name, cp - start) != 0) { - /* not actually matched */ - return (FALSE); - } - - if (!skipLine || directives[dir].skip_flag) - (*directives[dir].func)(cp, directives[dir].code, - CURFILE->lineno); - return (TRUE); -} - -/*- - *--------------------------------------------------------------------- - * Parse_File -- - * Parse a file into its component parts, incorporating it into the - * current dependency graph. This is the main function and controls - * almost every other function in this module - * - * Results: - * None - * - * Side Effects: - * Loads. Nodes are added to the list of all targets, nodes and links - * are added to the dependency graph. etc. etc. etc. - *--------------------------------------------------------------------- - */ -void -Parse_File(const char *name, FILE *stream) -{ - char *cp; /* pointer into the line */ - char *line; /* the line we're working on */ - - inLine = FALSE; - fatals = 0; - - ParsePushInput(estrdup(name), stream, NULL, 0); - - while ((line = ParseReadLine()) != NULL) { - if (*line == '.' && parse_directive(line + 1)) { - /* directive consumed */ - goto nextLine; - } - if (skipLine || *line == '#') { - /* Skipping .if block or comment. */ - goto nextLine; - } - - if (*line == '\t') { - /* - * If a line starts with a tab, it can only - * hope to be a creation command. - */ - for (cp = line + 1; isspace((unsigned char)*cp); cp++) { - continue; - } - if (*cp) { - if (inLine) { - LstNode *ln; - GNode *gn; - - /* - * So long as it's not a blank - * line and we're actually in a - * dependency spec, add the - * command to the list of - * commands of all targets in - * the dependency spec. - */ - LST_FOREACH(ln, &targets) { - gn = Lst_Datum(ln); - - /* - * if target already - * supplied, ignore - * commands - */ - if (!(gn->type & OP_HAS_COMMANDS)) - Lst_AtEnd(&gn->commands, cp); - else - Parse_Error(PARSE_WARNING, "duplicate script " - "for target \"%s\" ignored", gn->name); - } - continue; - } else { - Parse_Error(PARSE_FATAL, - "Unassociated shell command \"%s\"", - cp); - } - } -#ifdef SYSVINCLUDE - } else if (strncmp(line, "include", 7) == 0 && - isspace((unsigned char)line[7]) && - strchr(line, ':') == NULL) { - /* - * It's an S3/S5-style "include". - */ - ParseTraditionalInclude(line + 7); - goto nextLine; -#endif - } else if (Parse_IsVar(line)) { - ParseFinishLine(); - Parse_DoVar(line, VAR_GLOBAL); - - } else { - /* - * We now know it's a dependency line so it - * needs to have all variables expanded before - * being parsed. Tell the variable module to - * complain if some variable is undefined... - * To make life easier on novices, if the line - * is indented we first make sure the line has - * a dependency operator in it. If it doesn't - * have an operator and we're in a dependency - * line's script, we assume it's actually a - * shell command and add it to the current - * list of targets. XXX this comment seems wrong. - */ - cp = line; - if (isspace((unsigned char)line[0])) { - while (*cp != '\0' && - isspace((unsigned char)*cp)) { - cp++; - } - if (*cp == '\0') { - goto nextLine; - } - } - - ParseFinishLine(); - - cp = Buf_Peel(Var_Subst(line, VAR_CMD, TRUE)); - - free(line); - line = cp; - - /* - * Need a non-circular list for the target nodes - */ - Lst_Destroy(&targets, NOFREE); - inLine = TRUE; - - ParseDoDependency(line); - } - - nextLine: - free(line); - } - - ParseFinishLine(); - - /* - * Make sure conditionals are clean - */ - Cond_End(); - - if (fatals) - errx(1, "fatal errors encountered -- cannot continue"); -} - -/*- - *----------------------------------------------------------------------- - * Parse_MainName -- - * Return a Lst of the main target to create for main()'s sake. If - * no such target exists, we Punt with an obnoxious error message. - * - * Results: - * A Lst of the single node to create. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -void -Parse_MainName(Lst *listmain) -{ - - if (mainNode == NULL) { - Punt("no target to make."); - /*NOTREACHED*/ - } else if (mainNode->type & OP_DOUBLEDEP) { - Lst_AtEnd(listmain, mainNode); - Lst_Concat(listmain, &mainNode->cohorts, LST_CONCNEW); - } else - Lst_AtEnd(listmain, mainNode); -} Property changes on: head/usr.bin/make/parse.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/make/util.h =================================================================== --- head/usr.bin/make/util.h (revision 284463) +++ head/usr.bin/make/util.h (nonexistent) @@ -1,116 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef util_h_b7020fdb -#define util_h_b7020fdb - -#include -#include - -/* - * A boolean type is defined as an integer, not an enum. This allows a - * boolean argument to be an expression that isn't strictly 0 or 1 valued. - */ - -typedef int Boolean; -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif /* TRUE */ - -#define CONCAT(a,b) a##b - -struct flag2str { - u_int flag; - const char *str; -}; - -/* - * debug control: - * There is one bit per module. It is up to the module what debug - * information to print. - */ -#define DEBUG_ARCH 0x0001 -#define DEBUG_COND 0x0002 -#define DEBUG_DIR 0x0004 -#define DEBUG_GRAPH1 0x0008 -#define DEBUG_GRAPH2 0x0010 -#define DEBUG_JOB 0x0020 -#define DEBUG_MAKE 0x0040 -#define DEBUG_SUFF 0x0080 -#define DEBUG_TARG 0x0100 -#define DEBUG_VAR 0x0200 -#define DEBUG_FOR 0x0400 -#define DEBUG_LOUD 0x0800 - -#define DEBUG(module) (debug & CONCAT(DEBUG_,module)) -#define DEBUGF(module,args) \ -do { \ - if (DEBUG(module)) { \ - Debug args ; \ - } \ -} while (0) -#define DEBUGM(module, args) do { \ - if (DEBUG(module)) { \ - DebugM args; \ - } \ - } while (0) - -#define ISDOT(c) ((c)[0] == '.' && (((c)[1] == '\0') || ((c)[1] == '/'))) -#define ISDOTDOT(c) ((c)[0] == '.' && ISDOT(&((c)[1]))) - -#ifndef MAX -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#endif - -void Debug(const char *, ...); -void DebugM(const char *, ...); -void Error(const char *, ...); -void Fatal(const char *, ...) __dead2; -void Punt(const char *, ...) __dead2; -void DieHorribly(void) __dead2; -void Finish(int) __dead2; -char *estrdup(const char *); -void *emalloc(size_t); -void *erealloc(void *, size_t); -int eunlink(const char *); -void print_flags(FILE *, const struct flag2str *, u_int, int); - -#endif /* util_h_b7020fdb */ Property changes on: head/usr.bin/make/util.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/usr.bin/Makefile =================================================================== --- head/usr.bin/Makefile (revision 284463) +++ head/usr.bin/Makefile (revision 284464) @@ -1,434 +1,430 @@ # From: @(#)Makefile 8.3 (Berkeley) 1/7/94 # $FreeBSD$ .include # XXX MISSING: deroff diction graph learn plot # spell spline struct xsend # XXX Use GNU versions: diff ld patch # Moved to secure: bdes # SUBDIR= ${_addr2line} \ alias \ apply \ asa \ awk \ banner \ basename \ brandelf \ bsdiff \ bzip2 \ bzip2recover \ cap_mkdb \ chat \ chpass \ cksum \ ${_clang} \ cmp \ col \ colldef \ colrm \ column \ comm \ compress \ cpuset \ csplit \ ctlstat \ cut \ ${_cxxfilt} \ dirname \ dpv \ du \ elf2aout \ ${_elfcopy} \ elfdump \ enigma \ env \ expand \ false \ fetch \ find \ fmt \ fold \ fstat \ fsync \ gcore \ gencat \ getconf \ getent \ getopt \ grep \ gzip \ head \ hexdump \ ${_iconv} \ id \ ipcrm \ ipcs \ join \ jot \ ${_kdump} \ keylogin \ keylogout \ killall \ ktrace \ ktrdump \ lam \ lastcomm \ ldd \ leave \ less \ lessecho \ lesskey \ limits \ locale \ lock \ lockf \ logger \ login \ logins \ logname \ look \ lorder \ lsvfs \ lzmainfo \ m4 \ ${_makewhatis} \ ${_man} \ mandoc \ mesg \ minigzip \ ministat \ ${_mkcsmapper} \ mkdep \ ${_mkesdb} \ mkfifo \ mkimg \ mklocale \ mktemp \ mkulzma \ mkuzip \ mt \ ncal \ netstat \ newgrp \ nfsstat \ nice \ nl \ ${_nm} \ nohup \ opieinfo \ opiekey \ opiepasswd \ pagesize \ passwd \ paste \ patch \ pathchk \ perror \ pr \ printenv \ printf \ procstat \ protect \ rctl \ ${_readelf} \ renice \ rev \ revoke \ rpcinfo \ rs \ rup \ rusers \ rwall \ script \ sed \ send-pr \ seq \ shar \ showmount \ ${_size} \ sockstat \ soelim \ sort \ split \ stat \ stdbuf \ ${_strings} \ su \ systat \ tabs \ tail \ tar \ tcopy \ tee \ ${_tests} \ time \ timeout \ tip \ top \ touch \ tput \ tr \ true \ truncate \ ${_truss} \ tset \ tsort \ tty \ uname \ unexpand \ uniq \ unzip \ units \ unvis \ uudecode \ uuencode \ vis \ vmstat \ w \ wall \ wc \ what \ whereis \ which \ whois \ write \ xargs \ xinstall \ xo \ xz \ xzdec \ yes \ ${_ypcat} \ ${_ypmatch} \ ${_ypwhich} # NB: keep these sorted by MK_* knobs .if ${MK_AT} != "no" SUBDIR+= at .endif .if ${MK_ATM} != "no" SUBDIR+= atm .endif .if ${MK_BLUETOOTH} != "no" SUBDIR+= bluetooth .endif .if ${MK_BSD_CPIO} != "no" SUBDIR+= cpio .endif .if ${MK_CALENDAR} != "no" SUBDIR+= calendar .endif .if ${MK_CLANG} != "no" _clang= clang .endif .if ${MK_EE} != "no" SUBDIR+= ee .endif .if ${MK_ELFTOOLCHAIN_TOOLS} != "no" _addr2line= addr2line _cxxfilt= cxxfilt _elfcopy= elfcopy _nm= nm _readelf= readelf _size= size _strings= strings .endif .if ${MK_FILE} != "no" SUBDIR+= file .endif .if ${MK_FINGER} != "no" SUBDIR+= finger .endif -.if ${MK_FMAKE} != "no" -SUBDIR+= make -.endif - .if ${MK_FTP} != "no" SUBDIR+= ftp .endif .if ${MK_GPL_DTC} != "yes" SUBDIR+= dtc .endif .if ${MK_GROFF} != "no" SUBDIR+= vgrind .endif .if ${MK_HESIOD} != "no" SUBDIR+= hesinfo .endif .if ${MK_ICONV} != "no" _iconv= iconv _mkcsmapper= mkcsmapper _mkesdb= mkesdb .endif .if ${MK_ISCSI} != "no" SUBDIR+= iscsictl .endif .if ${MK_KDUMP} != "no" SUBDIR+= kdump .if ${MACHINE_ARCH} != "aarch64" # ARM64TODO truss does not build SUBDIR+= truss .endif .endif .if ${MK_KERBEROS_SUPPORT} != "no" SUBDIR+= compile_et .endif .if ${MK_LDNS_UTILS} != "no" SUBDIR+= drill SUBDIR+= host .endif .if ${MK_LOCATE} != "no" SUBDIR+= locate .endif # XXX msgs? .if ${MK_MAIL} != "no" SUBDIR+= biff SUBDIR+= from SUBDIR+= mail SUBDIR+= msgs .endif .if ${MK_MAKE} != "no" SUBDIR+= bmake .endif .if ${MK_MAN_UTILS} != "no" SUBDIR+= catman .if ${MK_MANDOCDB} == "no" _makewhatis= makewhatis .endif _man= man .endif .if ${MK_NETCAT} != "no" SUBDIR+= nc .endif .if ${MK_NIS} != "no" SUBDIR+= ypcat SUBDIR+= ypmatch SUBDIR+= ypwhich .endif .if ${MK_OPENSSH} != "no" SUBDIR+= ssh-copy-id .endif .if ${MK_OPENSSL} != "no" SUBDIR+= bc SUBDIR+= chkey SUBDIR+= dc SUBDIR+= newkey .endif .if ${MK_QUOTAS} != "no" SUBDIR+= quota .endif .if ${MK_RCMDS} != "no" SUBDIR+= rlogin SUBDIR+= rsh SUBDIR+= ruptime SUBDIR+= rwho .endif .if ${MK_SENDMAIL} != "no" SUBDIR+= vacation .endif .if ${MK_TALK} != "no" SUBDIR+= talk .endif .if ${MK_TELNET} != "no" SUBDIR+= telnet .endif .if ${MK_TESTS} != "no" _tests= tests .endif .if ${MK_TEXTPROC} != "no" SUBDIR+= checknr SUBDIR+= colcrt SUBDIR+= ul .endif .if ${MK_TFTP} != "no" SUBDIR+= tftp .endif .if ${MK_TOOLCHAIN} != "no" SUBDIR+= ar SUBDIR+= c89 SUBDIR+= c99 SUBDIR+= ctags SUBDIR+= file2c .if ${MACHINE_ARCH} != "aarch64" # ARM64TODO gprof does not build SUBDIR+= gprof .endif SUBDIR+= indent SUBDIR+= lex SUBDIR+= mkstr SUBDIR+= rpcgen SUBDIR+= unifdef .if ${MACHINE_ARCH} != "aarch64" # ARM64TODO xlint does not build SUBDIR+= xlint .endif SUBDIR+= xstr SUBDIR+= yacc .endif .if ${MK_VI} != "no" SUBDIR+= vi .endif .if ${MK_VT} != "no" SUBDIR+= vtfontcvt .endif .if ${MK_USB} != "no" SUBDIR+= usbhidaction SUBDIR+= usbhidctl .endif .if ${MK_UTMPX} != "no" SUBDIR+= last SUBDIR+= users SUBDIR+= who .endif .if ${MK_SVN} == "yes" || ${MK_SVNLITE} == "yes" SUBDIR+= svn .endif .include SUBDIR:= ${SUBDIR:O} SUBDIR_PARALLEL= .include