Index: vendor/NetBSD/bmake/dist/ChangeLog =================================================================== --- vendor/NetBSD/bmake/dist/ChangeLog (revision 282731) +++ vendor/NetBSD/bmake/dist/ChangeLog (revision 282732) @@ -1,1735 +1,1748 @@ +2015-05-05 Simon J. Gerraty + + * Makefile (MAKE_VERSION): 20150505 + Merge with NetBSD make, pick up + o cond.c: be strict about lhs of comparison when evaluating .if + but less so when called from variable expansion. + o unit-tests/cond2.mk: test various error conditions + +2015-05-04 Simon J. Gerraty + + * machine.sh (MACHINE): Add Bitrig + patch from joerg@netbsd.org + 2015-04-18 Simon J. Gerraty * Makefile (MAKE_VERSION): 20150418 Merge with NetBSD make, pick up o job.c: use memmove() rather than memcpy() * unit-tests/varshell.mk: SunOS cannot handle the TERMINATED_BY_SIGNAL case, so skip it. 2015-04-11 Simon J. Gerraty * Makefile (MAKE_VERSION): 20150411 bump version - only mk/ changes. 2015-04-10 Simon J. Gerraty * Makefile (MAKE_VERSION): 20150410 Merge with NetBSD make, pick up o document different handling of '-' in jobs mode vs compat o fix jobs mode so that '-' only applies to whole job when shell lacks hasErrCtl o meta.c: use separate vars to track lcwd and latestdir (read) per process 2015-04-01 Simon J. Gerraty * Makefile (MAKE_VERSION): 20150401 Merge with NetBSD make, pick up o meta.c: close meta file in child * Makefile: use BINDIR.bmake if set. Same for MANDIR and SHAREDIR Handy for testing release candidates in various environments. 2015-03-26 Simon J. Gerraty * move initialization of savederr to block where it is used to avoid spurious warning from gcc5 2014-11-11 Simon J. Gerraty * Makefile (MAKE_VERSION): 20141111 just a cooler number 2014-11-05 Simon J. Gerraty * Makefile (MAKE_VERSION): 20141105 Merge with NetBSD make, pick up o revert major overhaul of suffix handling and POSIX compliance - too much breakage and impossible to make backwards compatible. o we still have the new unit test structure which is ok. o meta.c ensure "-- filemon" is at start of line. 2014-09-17 Simon J. Gerraty * configure.in: test that result of getconf PATH_MAX is numeric and discard if not. Apparently needed for Hurd. 2014-08-30 Simon J. Gerraty * Makefile (MAKE_VERSION): 20140830 Merge with NetBSD make, pick up o major overhaul of suffix handling o improved POSIX compliance o overhauled unit-tests 2014-06-20 Simon J. Gerraty * Makefile (MAKE_VERSION): 20140620 Merge with NetBSD make, pick up o var.c return varNoError rather than var_Error for ::= modifiers. 2014-05-22 Simon J. Gerraty * Makefile (MAKE_VERSION): 20140522 Merge with NetBSD make, pick up o var.c detect some parse errors. 2014-04-05 Simon J. Gerraty * Fix spelling errors - patch from Pedro Giffuni 2014-02-14 Simon J. Gerraty * Makefile (MAKE_VERSION): 20140214 Merge with NetBSD make, pick up o .INCLUDEFROM* o use Var_Value to get MAKEOBJDIR[PREFIX] o reduced realloc'ign in brk_string. * configure.in: add a check for compiler supporting __func__ 2014-01-03 Simon J. Gerraty * boot-strap: ignore mksrc=none 2014-01-02 Simon J. Gerraty * Makefile (DEFAULT_SYS_PATH?): use just ${prefix}/share/mk 2014-01-01 Simon J. Gerraty * Makefile (MAKE_VERSION): 20140101 * configure.in: set bmake_path_max to min(_SC_PATH_MAX,1024) * Makefile.config: defined BMAKE_PATH_MAX to bmake_path_max * make.h: use BMAKE_PATH_MAX if MAXPATHLEN not defined (needed for Hurd) * configure.in: Add AC_PREREQ and check for sysctl; patch from Andrew Shadura andrewsh at debian.org 2013-10-16 Simon J. Gerraty * Makefile (MAKE_VERSION): 20131010 * lose the const from arg to systcl to avoid problems on older BSDs. 2013-10-01 Simon J. Gerraty * Makefile (MAKE_VERSION): 20131001 Merge with NetBSD make, pick up o main.c: for NATIVE build sysctl to get MACHINE_ARCH from hw.machine_arch if necessary. o meta.c: meta_oodate - need to look at src of Link and target of Move as well. * main.c: check that CTL_HW and HW_MACHINE_ARCH exist. provide __arraycount() if needed. 2013-09-04 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130904 Merge with NetBSD make, pick up o Add VAR_INTERNAL context, so that internal setting of MAKEFILE does not override value set by makefiles. 2013-09-02 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130902 Merge with NetBSD make, pick up o CompatRunCommand: only apply shellErrFlag when errCheck is true 2013-08-28 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130828 Merge with NetBSD make, pick up o Fix VAR :sh = syntax from Will Andrews at freebsd.org o Call Job_SetPrefix() from Job_Init() so makefiles have opportunity to set .MAKE.JOB.PREFIX 2013-07-30 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130730 Merge with NetBSD make, pick up o Allow suppression of --- job -- tokens by setting .MAKE.JOB.PREFIX empty. 2013-07-16 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130716 Merge with NetBSD make, pick up o number of gmake compatibility tweaks -w for gmake style entering/leaving messages if .MAKE.LEVEL > 0 indicate it in progname "make[1]" etc. handle MAKEFLAGS containing only letters. o when overriding a GLOBAL variable on the command line, delete it from GLOBAL context so -V doesn't show the wrong value. 2013-07-06 Simon J. Gerraty * configure.in: We don't need MAKE_LEVEL_SAFE anymore. * Makefile (MAKE_VERSION): 20130706 Merge with NetBSD make, pick up o Shell_Init(): export shellErrFlag if commandShell hasErrCtl is true so that CompatRunCommand() can use it, to ensure consistent behavior with jobs mode. o use MAKE_LEVEL_ENV to define the variable to propagate .MAKE.LEVEL - currently set to MAKELEVEL (same as gmake). o meta.c: use .MAKE.META.IGNORE_PATHS to allow customization of paths to ignore. 2013-06-04 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130604 Merge with NetBSD make, pick up o job.c: JobCreatePipe: do fcntl() after any tweaking of fd's to avoid leaking descriptors. 2013-05-28 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130528 Merge with NetBSD make, pick up o var.c: cleanup some left-overs in VarHash() 2013-05-20 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130520 generate manifest from component FILES rather than have to update FILES when mk/FILES changes. 2013-05-18 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130518 Merge with NetBSD make, pick up o suff.c: don't skip all processsing for .PHONY targets else wildcard srcs do not get expanded. o var.c: expand name of variable to delete if necessary. 2013-03-30 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130330 Merge with NetBSD make, pick up o meta.c: refine the handling of .OODATE in commands. Rather than suppress command comparison for the entire script as though .NOMETA_CMP had been used, only suppress it for the one command line. This allows something like ${.OODATE:M.NOMETA_CMP} to be used to suppress comparison of a command without otherwise affecting it. o make.1: document that 2013-03-22 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130321 yes, not quite right but its a cooler number. Merge with NetBSD make, pick up o parse.c: fix ParseGmakeExport to be portable and add a unit-test. * meta.c: call meta_init() before makefiles are read and if built with filemon support set .MAKE.PATH_FILEMON to _PATH_FILEMON this let's makefiles test for support. Call meta_mode_init() to process .MAKE.MODE. 2013-03-13 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130305 Merge with NetBSD make, pick up o run .STALE: target when a dependency from .depend is missing. o job.c: add Job_RunTarget() for the above and .BEGIN 2013-03-03 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130303 Merge with NetBSD make, pick up o main.c: set .MAKE.OS to utsname.sysname o job.c: more checks for read and poll errors o var.c: lose VarChangeCase() saves 4% time 2013-03-02 Simon J. Gerraty * boot-strap: remove MAKEOBJDIRPREFIX from environment since we want to use MAKEOBJDIR 2013-01-27 Simon J. Gerraty * Merge with NetBSD make, pick up o make.1: more info on how shell commands are handled. o job.c,main.c: detect write errors to job pipes. 2013-01-25 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130123 Merge with NetBSD make, pick up o meta.c: if script uses .OODATE and meta_oodate() decides rebuild is needed, .OODATE will be empty - set it to .ALLSRC. o var.c: in debug output indicate which variabale modifiers apply to. o remove Check_Cwd logic the makefiles have been fixed. 2012-12-12 Simon J. Gerraty * makefile.in: add a simple makefile for folk who insist on ./configure; make; make install it just runs boot-strap * include mk/* to accommodate the above * boot-strap: re-work to accommodate the above mksrc defaults to $Mydir/mk allow op={configure,build,install,clean,all} add options to facilitate install * Makefile.config.in: just the bits set by configure * Makefile: bump version to 20121212 abandon Makefile.in (NetBSD Makefile) leverage mk/* instead * configure.in: ensure srcdir is absolute 2012-11-11 Simon J. Gerraty * Makefile.in (MAKE_VERSION): 20121111 fix generation of bmake.cat1 2012-11-09 Simon J. Gerraty * Makefile.in (MAKE_VERSION): 20121109 Merge with NetBSD make, pick up o make.c: MakeBuildChild: return 0 so search continues if a .ORDER dependency is detected. o unit-tests/order: test the above 2012-11-02 Simon J. Gerraty * Makefile.in (MAKE_VERSION): 20121102 Merge with NetBSD make, pick up o cond.c: allow cond_state[] to grow. In meta mode with a very large tree, we can hit the limit while processing dirdeps. 2012-10-25 Simon J. Gerraty * Makefile.in: we need to use ${srcdir} not ${.CURDIR} 2012-10-10 Simon J. Gerraty * Makefile.in (MAKE_VERSION): 20121010 o protect syntax that only bmake parses correctly. o remove auto setting of FORCE_MACHINE, use configure's --with-force-machine=whatever if that is desired. 2012-10-08 Simon J. Gerraty * Makefile.in: do not lose history from make.1 when generating bmake.1 2012-10-07 Simon J. Gerraty * Makefile.in (MAKE_VERSION): 20121007 Merge with NetBSD make, pick up o compat.c: ignore empty commands - same as jobs mode. o make.1: document meta chars that cause use of shell 2012-09-11 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120911 * bsd.after-import.mk: include Makefile.inc early and allow it to override PROG 2012-08-31 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120831 Merge with NetBSD make, pick up o cast sizeof() to int for comparison o minor make.1 tweak 2012-08-30 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120830 Merge with NetBSD make, pick up o .MAKE.EXPAND_VARIABLES knob can control default behavior of -V o debug flag -dV causes -V to show raw value regardless. 2012-07-05 Simon J. Gerraty * bsd.after-import.mk (after-import): ensure unit-tests/Makefile gets SRCTOP set. 2012-07-04 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120704 Merge with NetBSD make, pick up o Job_ParseShell should call Shell_Init if it has been previously called. * Makefile.in: set USE_META based on configure result. also .PARSEDIR is safer indicator of bmake. 2012-06-26 Simon J. Gerraty * Makefile.in: bump version to 20120626 ensure CPPFLAGS is in CFLAGS * meta.c: avoid nested externs * bsd.after-import.mk: avoid ${.CURDIR}/Makefile as target 2012-06-20 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120620 Merge with NetBSD make, pick up o make_malloc.c: avoid including make_malloc.h again * Makefile.in: avoid bmake only syntax or protect with .if defined(.MAKE.LEVEL) * bsd.after-import.mk: replace .-include with .sinclude ensure? SRCTOP gets a value * configure.in: look for filemon.h in /usr/include/dev/filemon first. 2012-06-19 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120612 Merge with NetBSD make, pick up o use MAKE_ATTR_* rather than those defined by cdefs.h or compiler for greater portability. o unit-tests/forloop: check that .for works as expected wrt number of times and with "quoted strings". 2012-06-06 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120606 Merge with NetBSD make, pick up o compat.c: use kill(2) rather than raise(3). * configure.in: look for sys/dev/filemon * bsd.after-import.mk: add a .-include "Makefile.inc" to Makefile and pass BOOTSTRAP_XTRAS to boot-strap. 2012-06-04 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120604 Merge with NetBSD make, pick up o util.c and var.c share same var for tracking if environ has been reallocated. o util.c provide getenv with setenv. * Add MAKE_LEVEL_SAFE as an alternate means of passing MAKE_LEVEL when the shell actively strips .MAKE.* from the environment. We still refer to the variable always as .MAKE.LEVEL * util.c fix bug in findenv() was finding prefix of name. * compat.c: re-raising SIGINT etc after running .INTERRUPT results in more reliable termination of all activity on many platforms. 2012-06-02 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120602 Merge with NetBSD make, pick up o for.c: handle quoted items in .for list 2012-05-30 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120530 Merge with NetBSD make, pick up o compat.c: ignore empty command. 2012-05-24 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120524 * FILES: add bsd.after-import.mk: A simple means of integrating bmake into a BSD build system. 2012-05-20 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120520 Merge with NetBSD make, pick up o increased limit for nested conditionals. 2012-05-18 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120518 Merge with NetBSD make, pick up o use _exit(2) in signal hanlder o Don't use the [dir] cache when building nodes that might have changed since the last exec. o Avoid nested extern declaration warnings. 2012-04-27 Simon J. Gerraty * meta.c (fgetLine): avoid %z - not portable. * parse.c: Since we moved include of sys/mman.h and def's of MAP_COPY etc. we got dups from a merge. 2012-04-24 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120420 Merge with NetBSD make, pick up o restore duplicate supression in .MAKE.MAKEFILES runtime saving can be significant. o Var_Subst() uses Buf_DestroyCompact() to reduce memory consumption up to 20%. 2012-04-20 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120420 Merge with NetBSD make, pick up o remove duplicate supression in .MAKE.MAKEFILES o improved dir cache behavior o gmake'ish export command 2012-03-25 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120325 Merge with NetBSD make, pick up o fix parsing of :[#] in conditionals. 2012-02-10 Simon J. Gerraty * Makefile.in: replace use of .Nx in bmake.1 with NetBSD since some systems cannot cope with .Nx 2011-11-14 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20111111 Merge with NetBSD make, pick up o debug output for .PARSEDIR and .PARSEFILE 2011-10-10 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20111010 2011-10-09 Simon J. Gerraty * boot-strap: check for an expected file in the dirs we look for. * make-bootstrap.sh: pass on LDSTATIC 2011-10-01 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20111001 Merge with NetBSD make, pick up o ensure .PREFIX is set for .PHONY and .TARGET set for .PHONY run via .END o __dead used consistently 2011-09-10 Simon J. Gerraty * Makefile.in (MAKE_VERSION): 20110909 is a better number ;-) 2011-09-05 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110905 Merge with NetBSD make, pick up o meta_oodate: ignore makeDependfile 2011-08-28 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110828 Merge with NetBSD make, pick up o silent=yes in .MAKE.MODE causes meta mode to mark targets as SILENT if a .meta file is created 2011-08-18 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110818 Merge with NetBSD make, pick up o in meta mode, if target flagged .META a missing .meta file means target is out-of-date o fixes for gcc 4.5 warnings o simplify job printing code 2011-08-09 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110808 Merge with NetBSD make, pick up o do not touch OP_SPECIAL targets when doing make -t 2011-06-22 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110622 Merge with NetBSD make, pick up o meta_oodate detect corrupted .meta file and declare oodate. * configure.in: add check for setsid 2011-06-07 Simon J. Gerraty * Merge with NetBSD make, pick up o unit-tests/modts now works on MirBSD 2011-06-04 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110606 Merge with NetBSD make, pick up o ApplyModifiers: when we parse a variable which is not the entire modifier string, or not followed by ':', do not consider it as containing modifiers. o loadfile: ensure newline at end of mapped file. 2011-05-05 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110505 Merge with NetBSD make, pick up o .MAKE.META.BAILIWICK - list of prefixes which define the scope of make's control. In meta mode, any generated file within said bailiwick, which is found to be missing, causes current target to be out-of-date. 2011-04-11 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110411 Merge with NetBSD make, pick up o when long modifiers fail to match, check sysV style. - add a test case 2011-04-10 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110410 Merge with NetBSD make, pick up o :hash - cheap 32bit hash of value o :localtime, :gmtime - use value as format string for strftime. 2011-03-30 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110330 mostly because its a cooler version. Merge with NetBSD make, pick up o NetBSD tags for meta.[ch] o job.c call meta_job_finish() after meta_job_error(). o meta_job_error() should call meta_job_finish() to ensure .meta file is closed, and safe to copy - if .ERROR target wants. meta_job_finish() is safe to call repeatedly. 2011-03-29 Simon J. Gerraty * unit-tests/modts: use printf if it is a builtin, to save us from MirBSD * Makefile.in (MAKE_VERSION): bump version to 20110329 Merge with NetBSD make, pick up o fix for use after free() in CondDoExists(). o meta_oodate() report extra commands and return earlier. 2011-03-27 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110327 Merge with NetBSD make, pick up o meta.c, if .MAKE.MODE contains curdirOk=yes allow creating .meta files in .CURDIR * boot-strap (TOOL_DIFF): aparently at least on linux distro formats the output of 'type' differently - so eat any "()" 2011-03-06 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110306 Merge with NetBSD make, pick up o meta.c, only do getcwd() once 2011-03-05 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110305 Merge with NetBSD make, pick up o correct sysV substitution handling of empty lhs and variable o correct exists() check for dir with trailing / o correct handling of modifiers for non-existant variables during evaluation of conditionals. o ensure MAP_FILE is defined. o meta.c use curdir[] now exported by main.c 2011-02-25 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110225 Merge with NetBSD make, pick up o fix for incorrect .PARSEDIR when .OBJDIR is re-computed after makefiles have been read. o fix example of :? modifier in man page. 2011-02-13 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110214 Merge with NetBSD make, pick up o meta.c handle realpath() failing when generating meta file name. * sigcompat.c: convert to ansi so we can use higher warning levels. 2011-02-07 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110207 Merge with NetBSD make, pick up o fix for bug in meta mode. 2011-01-03 Simon J. Gerraty * parse.c: SunOS 5.8 at least does not have MAP_FILE 2011-01-01 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110101 Merge with NetBSD make, pick up o use mmap(2) if available, for reading makefiles 2010-12-15 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20101215 Merge with NetBSD make, pick up o ensure meta_job_error() does not report a previous .meta file as being culprit. 2010-12-10 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20101210 Merge with NetBSD make, pick up o meta_oodate: track cwd per process, and only consider target out-of-date if missing file is outside make's CWD. Ignore files in /tmp/ etc. o to ensure unit-tests results match, need to control LC_ALL as well as LANG. o fix for parsing bug in var.c 2010-11-26 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20101126 Merge with NetBSD make, pick up o if stale dependency is an IMPSRC, search via .PATH o meta_oodate: if a referenced file is missing, target is out-of-date. o meta_oodate: if a target uses .OODATE in its commands, it (.OODATE) needs to be recomputed. o keep a pointer to youngest child node, rather than just its mtime. 2010-11-02 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20101101 2010-10-16 Simon J. Gerraty * machine.sh: like os.sh, allow for uname -p producing useless drivel 2010-09-13 Simon J. Gerraty * boot-strap: document configure knobs for meta and filemon. * Makefile.in (MAKE_VERSION): bump version to 20100911 Merge with NetBSD make, pick up o meta.c - meta mode * make-bootstrap.sh.in: handle meta.c * configure.in: add knobs for use_meta and filemon_h also, look for dirname, str[e]sep and strlcpy * util.c: add simple err[x] and warn[x] 2010-08-08 Simon J. Gerraty * boot-strap (TOOL_DIFF): set this to ensure tests use the same version of diff that configure tested * Makefile.in (MAKE_VERSION): bump version to 20100808 Merge with NetBSD make, pick up o in jobs mode, when we discover we cannot make something, call PrintOnError before exit. 2010-08-06 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100806 Merge with NetBSD make, pick up o formatting fixes for ignored errors o ensure jobs are cleaned up regardless of where wait() was called. 2010-06-28 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100618 * os.sh (MACHINE_ARCH): watch out for drivel from uname -p 2010-06-16 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100616 Merge with NetBSD make, pick up o man page update o call PrintOnError from JobFinish when we detect an error we are not ignoring. 2010-06-06 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100606 Merge with NetBSD make, pick up o man page update 2010-06-05 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100605 Merge with NetBSD make, pick up o use bmake_signal() which is a wrapper around sigaction() in place of signal() o add .export-env to allow exporting variables to environment without tracking (so no re-export when the internal value is changed). 2010-05-24 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100524 Merge with NetBSD make, pick up o fix for .info et al being greedy. 2010-05-23 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100520 Merge with NetBSD make, pick up o back to using realpath on argv[0] but only if contains '/' and does not start with '/'. 2010-05-10 Simon J. Gerraty * boot-strap: use absolute path for bmake when running tests. * Makefile.in (MAKE_VERSION): bump version to 20100510 Merge with NetBSD make, pick up o revert use of realpath on argv[0] too many corner cases. o print MAKE_PRINT_VAR_ON_ERROR before running .ERROR target. 2010-05-05 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100505 Merge with NetBSD make, pick up o fix for missed SIGCHLD when compiled with SunPRO actually for bmake, defining FORCE_POSIX_SIGNALS would have done the job. 2010-04-30 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100430 Merge with NetBSD make, pick up o fflush stdout before writing to stdout 2010-04-23 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100423 Merge with NetBSD make, pick up o updated unit tests for Haiku (this time for sure). * boot-strap: based on patch from joerg honor --with-default-sys-path better. * boot-strap: remove mention of --with-prefix-sys-path 2010-04-22 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100422 * Merge with NetBSD make, pick up o fix for vfork() on Darwin. o fix for bogus $TMPDIR. o set .MAKE.MODE=compat for -B o set .MAKE.JOBS=max_jobs for -j max_jobs o allow unit-tests to run without any *.mk o unit-tests/modmisc be more conservative in dirs presumed to exist. * boot-strap: ignore /usr/share/mk except on NetBSD. * unit-tests/Makefile.in: set LANG=C when running unit-tests to ensure sort(1) behaves as expected. 2010-04-21 Simon J. Gerraty * boot-strap: add FindHereOrAbove so we can use -m .../mk 2010-04-20 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100420 * Merge with NetBSD make, pick up o fix for variable realpath() behavior. we have to stat(2) the result to be sure. o fix for .export (all) when nested vars use :sh 2010-04-14 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100414 * Merge with NetBSD make, pick up o use realpath to resolve argv[0] (for .MAKE) if needed. o add realpath from libc. o add :tA to resolve variable via realpath(3) if possible. 2010-04-08 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100408 * Merge with NetBSD make, pick up o unit tests for .ERROR, .error o fix for .ERROR to ensure it cannot be default target. 2010-04-06 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100406 * Merge with NetBSD make, pick up o fix for compat mode "Error code" going to debug_file. o fix for .ALLSRC being populated twice. o support for .info, .warning and .error directives o .MAKE.MODE to control make's operational mode o .MAKE.MAKEFILE_PREFERENCE to control the preferred makefile name(s). o .MAKE.DEPENDFILE to control the name of the depend file o .ERROR target - run on failure. 2010-03-18 Simon J. Gerraty * make-bootstrap.sh.in: extract MAKE_VERSION from Makefile * os.sh,arch.c: patch for Haiku from joerg at netbsd 2010-03-17 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100222 * Merge with NetBSD make, pick up o better error msg for .for with mutiple inter vars * boot-strap: o use make-bootstrap.sh from joerg at netbsd to avoid the need for a native make when bootstrapping. o add "" everywhere ;-) o if /usr/share/tmac/andoc.tmac exists install nroff bmake.1 otherwise the pre-formated version. 2010-01-04 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100102 * Merge with NetBSD make, pick up: o fix for -m .../ 2009-11-18 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20091118 * Merge with NetBSD make, pick up: o .unexport o report lines that start with '.' and should have ':' (catch typo's of .el*if). 2009-10-30 Simon J. Gerraty * configure.in: Ensure that srcdir and mksrc are absolute paths. 2009-10-09 Simon J. Gerraty * Makefile.in (MAKE_VERSION): fix version to 20091007 2009-10-07 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 200910007 * Merge with NetBSD make, pick up: o fix for parsing of :S;...;...; applied to .for loop iterator appearing in a dependency line. 2009-09-09 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20090909 * Merge with NetBSD make, pick up: o fix for -C, .CURDIR and .OBJDIR * boot-strap: o allow share_dir to be set independent of prefix. o select default share_dir better when prefix ends in $HOST_TARGET o if FORCE_BSD_MK etc were set, include them in the suggested install-mk command. 2009-09-08 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20090908 * Merge with NetBSD make, pick up: o .MAKE.LEVEL for recursion tracking o fix for :M scanning \: 2009-09-03 Simon J. Gerraty * configure.in: Don't -D__EXTENSIONS__ if AC_USE_SYSTEM_EXTENSIONS says "no". 2009-08-26 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20090826 Simplify MAKE_VERSION to just the bare date. * Merge with NetBSD make, pick up: o -C directory support. o support for SIGINFO o use $TMPDIR for temp files. o child of vfork should be careful about modifying parent's state. 2009-03-26 Simon J. Gerraty * Appy some patches for MiNT from David Brownlee 2009-02-26 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20090222 * Merge with NetBSD make, pick up: o Possible null pointer de-ref in Var_Set. 2009-02-08 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20090204 * Merge with NetBSD make, pick up: o bmake_malloc et al moved to their own .c o Count both () and {} when looking for the end of a :M pattern o Change 'Buffer' so that it is the actual struct, not a pointer to it. o strlist.c - functions for processing extendable arrays of pointers to strings. o ClientData replaced with void *, so const void * can be used. o New debug flag C for DEBUG_CWD 2008-11-11 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20081111 Apply patch from Joerg Sonnenberge to configure.in: o remove some redundant checks o check for emlloc etc only in libutil and require the whole family. util.c: o remove [v]asprintf which is no longer used. 2008-11-04 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20081101 * Merge with NetBSD make, pick up: o util.c: avoid use of putenv() - christos 2008-10-30 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20081030 pick up man page tweaks. 2008-10-29 Simon J. Gerraty * Makefile.in: move processing of LIBOBJS to after is definition! thus we'll have getenv.c in SRCS only if needed. * make.1: add examples of how to use :? * Makefile.in (BMAKE_VERSION): bump version to 20081029 * Merge with NetBSD make, pick up: o fix for .END processing with -j o segfault from Parse_Error when no makefile is open o handle numeric expressions in any variable expansion o debug output now defaults to stderr, -dF to change it - apb o make now uses bmake_malloc etc so that it can build natively on A/UX - wasn't an issue for bmake, but we want to keep in sync. 2008-09-27 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20080808 * Merge with NetBSD make, pick up: o fix for PR/38840: Pierre Pronchery: make crashes while parsing long lines in Makefiles o optimizations for VarQuote by joerg o fix for PR/38756: dominik: make dumps core on invalid makefile 2008-05-15 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20080515 * Merge with NetBSD make, pick up: o fix skip setting vars in VAR_GLOBAL context, to handle cases where VAR_CMD is used for other than command line vars. 2008-05-14 Simon J. Gerraty * boot-strap (make_version): we may need to look in $prefix/share/mk for sys.mk * Makefile.in (BMAKE_VERSION): bump version to 20080514 * Merge with NetBSD make, pick up: o skip setting vars in VAR_GLOBAL context, when already set in VAR_CMD which takes precedence. 2008-03-30 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20080330 * Merge with NetBSD make, pick up: o fix for ?= when LHS contains variable reference. 2008-02-15 Simon J. Gerraty * merge some patches from NetBSD pkgsrc. * makefile.boot.in (BOOTSTRAP_SYS_PATH): Allow better control of the MAKSYSPATH used during bootstrap. * Makefile.in (BMAKE_VERSION): bump version to 20080215 * Merge with NetBSD make, pick up: o warn if non-space chars follow 'empty' in a conditional. 2008-01-18 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20080118 * Merge with NetBSD make, pick up: o consider dependencies read from .depend as optional - dsl o remember when buffer for reading makefile grows - dsl o add -dl (aka LOUD) - David O'Brien 2007-10-22 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20071022 * Merge with NetBSD make, pick up: o Allow .PATH to be used for .include "" * boot-strap: source default settings from .bmake-boot-strap.rc 2007-10-16 Simon J. Gerraty * Makefile.in: fix maninstall on various systems provided that our man.mk is used. For non-BSD systems we install the preformatted page into $MANDIR/cat1 2007-10-15 Simon J. Gerraty * boot-strap: make bmake.1 too, so maninstall works. 2007-10-14 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20071014 * Merge with NetBSD make, pick up: o revamped handling of defshell - configure no longer needs to know the content of the shells array - apb o stop Var_Subst modifying its input - apb o avoid calling ParseTrackInput too often - dsl 2007-10-11 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20071011 * Merge with NetBSD make, pick up: o fix Shell_Init for case that _BASENAME_DEFSHELL is absolute path. * sigcompat.c: some tweaks for HP-UX 11.x based on patch from Tobias Nygren * configure.in: update handling of --with-defshell to match new make behavior. --with-defshell=/usr/xpg4/bin/sh will now do what one might hope - provided the chosen shell behaves enough like sh. 2007-10-08 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20071008 * Merge with NetBSD make, pick up: o .MAKE.JOB.PREFIX - control the token output before jobs - sjg o .export/.MAKE.EXPORTED - export of variables - sjg o .MAKE.MAKEFILES - track all makefiles read - sjg o performance improvements - dsl o revamp parallel job scheduling - dsl 2006-07-28 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20060728 * Merge with NetBSD make, pick up: o extra debug info during variable and cond processing - sjg o shell definition now covers newline - rillig o minor mem leak in PrintOnError - sjg 2006-05-11 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20060511 * Merge with NetBSD make, pick up: o more memory leaks - coverity o possible overflow in ArchFindMember - coverity o extract variable modifier code out of Var_Parse() so it can be called recursively - sjg o unit-tests/moderrs - sjg 2006-04-12 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20060412 * Merge with NetBSD make, pick up: o fixes for some memory leaks - coverity o only read first sys.mk etc when searching sysIncPath - sjg * main.c (ReadMakefile): remove hack for __INTERIX that prevented setting ${MAKEFILE} - OBATA Akio 2006-03-18 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20060318 * Merge with NetBSD make, pick up: o cleanup of job.c to remove remote handling, distcc is more useful and this code was likely bit-rotting - dsl o fix for :P modifier - sjg * boot-strap: set default prefix to something reasonable (for me anyway). 2006-03-01 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20060301 * Merge with NetBSD make, pick up: o make .WAIT apply recursively, document and test case - apb o allow variable modifiers in a variable appear anywhere in modifier list, document and test case - sjg 2006-02-22 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20060222 * Merge with NetBSD make, pick up: o improved job token handling - dsl o SIG_DFL the correct signal before exec - dsl o more debug info during parsing - dsl o allow variable modifiers to be specified via variable - sjg * boot-strap: explain why we died if no mksrc 2005-11-05 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20051105 * configure.in: always set default_sys_path default is ${prefix}/share/mk - remove prefix_sys_path, anyone wanting more than above needs to set it manually. 2005-11-04 Simon J. Gerraty * boot-strap: make this a bit easier for pkgsrc folk. bootstrap still fails on IRIX64 since MACHINE_ARCH gets set to 'mips' while pkgsrc wants 'mipseb' or 'mipsel' 2005-11-02 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20051102 * job.c (JobFinish): fix likely ancient merge lossage fix from Todd Vierling. * boot-strap (srcdir): allow setting mksrc=none 2005-10-31 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20051031 * ranlib.h: skip on OSF too. (NetBSD PR 31864) 2005-10-10 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20051002 fix a silly typo 2005-10-09 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20051001 support for UnixWare and some other systems, based on patches from pkgsrc/bootstrap 2005-09-03 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20050901 * Merge with NetBSD make, pick up: o possible parse error causing us to wander off. 2005-06-06 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20050606 * Merge with NetBSD make, pick up: o :0x modifier for randomizing a list o fixes for a number of -Wuninitialized issues. 2005-05-30 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20050530 * Merge with NetBSD make, pick up: o Handle dependencies for .BEGIN, .END and .INTERRUPT * README: was seriously out of date. 2005-03-22 Simon J. Gerraty * Important to use .MAKE rather than MAKE. 2005-03-15 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20050315 * Merge with NetBSD make, pick up: o don't mistake .elsefoo for .else o use suffix-specific search path correctly o bunch of style nits 2004-05-11 Simon J. Gerraty * boot-strap: o ensure that args to --src and --with-mksrc are resolved before giving them to configure. o add -o "objdir" so that builder can control it, default is $OS as determined by os.sh o add -q to suppress all the install instructions. 2004-05-08 Simon J. Gerraty * Remove __IDSTRING() * Makefile.in (BMAKE_VERSION): bump to 20040508 * Merge with NetBSD make, pick up: o posix fixes - remove '-e' from compat mode - add support for '+' command-line prefix. o fix for handling '--' on command-line. o fix include in lst.lib/lstInt.h to simplify '-I's o we also picked up replacement of MAKE_BOOTSTRAP with !MAKE_NATIVE which is a noop, but possibly confusing. 2004-04-14 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20040414 * Merge with NetBSD make, pick up: o allow quoted strings on lhs of conditionals o issue warning when extra .else is seen o print line numer when errors encountered during parsing from string. 2004-02-20 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20040220 * Merge with NetBSD make, pick up: o fix for old :M parsing bug. o re-jigged unit-tests 2004-02-15 Simon J. Gerraty * Makefile.in (accept test): use ${.MAKE:S,^./,${.CURDIR}/,} so that './bmake -f Makefile test' works. 2004-02-14 Simon J. Gerraty * Makefile.in: (BMAKE_VERSION): bump to 20040214 * Merge with NetBSD make, pick up: o search upwards for *.mk o fix for double free of var substitution buffers o use of getopt replaced with custom code, since the usage (re-scanning) isn't posix compatible. 2004-02-12 Simon J. Gerraty * arch.c: don't include ranlib.h on ELF systems (thanks to Chuck Cranor ). 2004-01-18 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20040118 * boot-strap (while): export vars we assign to on cmdline * unit-test/Makefile.in: ternary is .PHONY 2004-01-08 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20040108 * Merge with NetBSD make, pick up: o fix for ternary modifier 2004-01-06 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20040105 * Merge with NetBSD make, pick up: o fix for cond.c to handle compound expressions better o variable expansion within sysV style replacements 2003-12-22 Simon J. Gerraty * Make portable snprintf safer - output to /dev/null first to check space needed. * Makefile.in (BMAKE_VERSION): bump version to 20031222 * Merge with NetBSD make, pick up: o -dg3 to show input graph when things go wrong. o explicitly look for makefiles in objdir if not found in curdir so that errors in .depend etc will be reported accurarely. o avoid use of -e in shell scripts in jobs mode, use '|| exit $?' instead as it more accurately reflects the expected behavior and is more consistently implemented. o avoid use of asprintf. 2003-09-28 Simon J. Gerraty * util.c: Add asprintf and vasprintf. * Makefile.in (BMAKE_VERSION): bump version to 20030928 * Merge with NetBSD make, pick up: :[] modifier - allows picking words from a variable. :tW modifier - allows treating value as one big word. W flag for :C and :S - allows treating value as one big word. 2003-09-12 Simon J. Gerraty * Merge with NetBSD make pick up -de flag to enable printing failed command. don't skip 1st two dir entries (normally . and ..) since coda does not have them. 2003-09-09 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20030909 * Merge with NetBSD make, pick up: - changes for -V '${VAR}' to print fully expanded value cf. -V VAR - CompatRunCommand now prints the command that failed. - several files got updated 3 clause Berkeley license. 2003-08-02 Simon J. Gerraty * boot-strap: Allow setting configure args on command line. 2003-07-31 Simon J. Gerraty * configure.in: add --with-defshell to allow sh or ksh to be selected as default shell. * Makefile.in: bump version to 20030731 * Merge with NetBSD make Pick up .SHELL spec for ksh and associate man page changes. Also compat mode now uses the same shell specs. 2003-07-29 Simon J. Gerraty * var.c (Var_Parse): ensure delim is initialized. * unit-tests/Makefile.in: use single quotes to avoid problems from some shells. * makefile.boot.in: Run the unit-tests as part of the bootstrap procedure. 2003-07-28 Simon J. Gerraty * unit-tests/Makefile.in: always force complaints from ${TEST_MAKE} to be from 'make'. * configure.in: add check for 'diff -u' also fix some old autoconf'isms * Makefile.in (BMAKE_VERSION): bump version to 20030728. if using GCC add -Wno-cast-qual to CFLAGS for var.o * Merge with NetBSD make Pick up fix for :ts parsing error in some cases. Pick unit-tests. 2003-07-23 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20030723. * var.c (Var_Parse): fix bug in :ts modifier, after const correctness fixes, must pass nstr to VarModify. 2003-07-14 Simon J. Gerraty * Makefile.in: BMAKE_VERSION switch to a date based version. We'll generally use the date of last import from NetBSD. * Merge with NetBSD make Pick up fixes for const-correctness, now passes WARNS=3 on NetBSD. Pick up :ts modifier, allows controlling the separator used between words in variable expansion. 2003-07-11 Simon J. Gerraty * FILES: include boot-strap and os.sh * Makefile.in: only set WARNS if we are NetBSD, the effect on FreeBSD is known to be bad. * makefile.boot.in (bootstrap): make this the default target. * Makefile.in: bump version to 3.1.19 * machine.sh: avoid A-Z with tr as it is bound to lose. 2003-07-10 Simon J. Gerraty * Merge with NetBSD make Pick up fix for PR/19781 - unhelpful error msg on unclosed ${var:foo Plus some doc fixes. 2003-04-27 Simon J. Gerraty * Merge with NetBSD make Pick up fix for PR/1523 - don't count a library as built, if there is no way to build it * Bump version to 3.1.18 2003-03-23 Simon J. Gerraty * Merge with NetBSD make Pick up fix for ParseDoSpecialSrc - we only use it if .WAIT appears in src list. 2003-03-21 Simon J. Gerraty * Merge with NetBSD make (mmm 10th anniversary!) pick up fix for .WAIT in srcs that refer to $@ or $* (PR#20828) pick up -X which tells us to not export VAR=val via setenv if we are already doing so via MAKEFLAGS. This saves valuable env space on systems like Darwin. set MAKE_VERSION to 3.1.17 * parse.c: pix up fix for suffix rules 2003-03-06 Simon J. Gerraty * Merge with NetBSD make. pick up fix for propagating -B via MAKEFLAGS. set MAKE_VERSION to 3.1.16 * Apply some patches from pkgsrc-bootstrap/bmake Originally by Grant Beattie I may have missed some - since they are based on bmake-3.1.12 2002-12-03 Simon J. Gerraty * makefile.boot.in (bmake): update install targets for those that use them, also clear MAKEFLAGS when invoking bmake.boot to avoid havoc from gmake -w. Thanks to Harlan Stenn . * bmake.cat1: update the pre-formatted man page! 2002-11-30 Simon J. Gerraty * Merge with NetBSD make. pick up fix for premature free of pointer used in call to Dir_InitCur(). set MAKE_VERSION to 3.1.15 2002-11-26 Simon J. Gerraty * configure.in: determine suitable value for MKSRC. override using --with-mksrc=PATH. * machine.sh: use `uname -p` for MACHINE_ARCH on modern SunOS systems. configs(8) will use 'sun4' as an alias for 'sparc'. 2002-11-25 Simon J. Gerraty * Merge with NetBSD make. pick up ${.PATH} pick up fix for finding ../cat.c via .PATH when .CURDIR=.. set MAKE_VERSION to 3.1.14 add configure checks for killpg and sys/socket.h 2002-09-16 Simon J. Gerraty * tag bmake-3-1-13 * makefile.boot.in (bmake): use install-mk Also setup ./mk before trying to invoke bmake.boot incase we needed install-mk to create a sys.mk for us. * configure.in: If we need to add -I${srcdir}/missing, make it an absolute path so that it works for lst.lib too. * make.h: always include sys/cdefs.h since we provide one if the host does not. * Makefile.in (install-mk): use MKSRC/install-mk which will do the right thing. use uname -p for ARCH if possible. since install-mk will setup links bsd.prog.mk -> prog.mk if needed, just .include bsd.prog.mk * Merge with NetBSD make (NetBSD-1.6) Code is ansi-C only now. Bug in handling of dotLast is fixed. Can now assign .OBJDIR and make will reset its notions of life. New modifiers :tu :tl for toUpper and toLower. Tue Oct 16 12:18:42 2001 Simon J. Gerraty * Merge with NetBSD make pick up fix for .END failure in compat mode. pick up fix for extra va_end() in ParseVErrorInternal. Thu Oct 11 13:20:06 2001 Simon J. Gerraty * configure.in: for systems that have sys/cdefs.h check if it is compatible. If not, include the one under missing, but tell it to include the native one too - necessary on Linux. * missing/sys/cdefs.h: if NEED_HOST_CDEFS_H is defined, use include_next (for gcc) to get the native sys/cdefs.h Tue Aug 21 02:29:34 2001 Simon J. Gerraty * job.c (JobFinish): Fix an earlier merge bug that resulted in leaking descriptors when using -jN. * job.c (JobPrintCommand): See if "curdir" exists before attempting to chdir(). Doing the chdir directly in make (when in compat mode) fails silently, so let the -jN version do the same. This can happen when building kernels in an object tree and playing clever games to reset .CURDIR. * Merged with NetBSD make pick up .USEBEFORE Tue Jun 26 23:45:11 2001 Simon J. Gerraty * makefile.boot.in: Give bmake.boot a MAKESYSPATH that might work. Tue Jun 12 16:48:57 2001 Simon J. Gerraty * var.c (Var_Set): Add 4th (flags) arg so VarLoopExpand can tell us not to export the iterator variable when using VAR_CMD context. Sun Jun 10 21:55:21 2001 Simon J. Gerraty * job.c (Job_CatchChildren): don't call Job_CatchOutput() here, its the wrong "fix". Sat Jun 9 00:11:24 2001 Simon J. Gerraty * Redesigned export of VAR_CMD's via MAKEFLAGS. We now simply append the variable names to .MAKEOVERRIDES, and handle duplicate suppression and quoting in ExportMAKEFLAGS using: ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@} Apart from fixing quoting bugs in previous version, this allows us to export vars to the environment by simply doing: .MAKEOVERRIDES+= PATH Merged again with NetBSD make, but the above is the only change. * configure.in: added --disable-pwd-override disable $PWD overriding getcwd() --disable-check-make-chdir disable make trying to guess when it should automatically cd ${.CURDIR} * Merge with NetBSD make, changes include: parse.c (ParseDoDependency): Spot that the syntax error is caused by an unresolved cvs/rcs conflict and say so. var.c: most of Var* functions now take a ctxt as 1st arg. now does variable substituion on rhs of sysv style modifiers. * var.c (Var_Set): exporting of command line variables (VAR_CMD) is now done here. We append the name='value' to .MAKEOVERRIDES rather than directly into MAKEFLAGS as this allows a Makefile to use .MAKEOVERRIDES= to disable this behaviour. GNU make uses a very similar mechanism. Note that in adding name='value' to .MAKEOVERRIDES we do the moral equivalent of: .MAKEOVERRIDES:= ${.MAKEOVERRIDES:Nname=*} name='val' Fri Jun 1 14:08:02 2001 Simon J. Gerraty * make-conf.h (USE_IOVEC): make it conditional on HAVE_SYS_UIO_H * Merged with NetBSD make make -dx can now be used to run commands via sh -x better error messages on exec failures. Thu May 31 01:44:54 2001 Simon J. Gerraty * Makefile.in (main.o): depends on ${SRCS} ${MAKEFILE} so that MAKE_VERSION gets updated. Also don't use ?= for MAKE_VERSION, MACHINE etc otherwise they propagate from the previous bmake. * configure.in (machine): allow --with-machine=generic to make configure use machine.sh to set MACHINE. * job.c (JobInterrupt): convert to using WAIT_T and friends. * Makefile.in: mention in bmake.1 that we use autoconf. * make.1: mention MAKE_PRINT_VAR_ON_ERROR. Wed May 30 23:17:18 2001 Simon J. Gerraty * main.c (ReadMakefile): don't set MAKEFILE if reading ".depend" as that rather defeats the usefulness of ${MAKEFILE}. * main.c (MainParseArgs): append command line variable assignments to MAKEFLAGS so that they get propagated to child make's. Apparently this is required POSIX behaviour? Its useful anyway. Tue May 29 02:20:07 2001 Simon J. Gerraty * compat.c (CompatRunCommand): don't use perror() since stdio may cause problems in child of vfork(). * compat.c, main.c: Call PrintOnError() when we are going to bail. This routine prints out the .curdir where we stopped and will also display any vars listed in ${MAKE_PRINT_VAR_ON_ERROR}. * main.c: add ${.newline} to hold a "\n" - sometimes handy in :@ expansion. * var.c: VarLoopExpand: ignore addSpace if a \n is present. * Added RCSid's for the files we've touched. Thu May 24 15:41:37 2001 Simon J. Gerraty * configure.in: Thanks to some clues from mdb@juniper.net, added autoconf magic to control setting of MACHINE, MACHINE_ARCH as well as what ends up in _PATH_DEFSYSPATH. We now have: --with-machine=MACHINE explicitly set MACHINE --with-force-machine=MACHINE set FORCE_MACHINE --with-machine_arch=MACHINE_ARCH explicitly set MACHINE_ARCH --with-default-sys-path=PATH:DIR:LIST use an explicit _PATH_DEFSYSPATH --with-prefix-sys-path=PATH:DIR:LIST prefix _PATH_PREFIX_SYSPATH --with-path-objdirprefix=PATH override _PATH_OBJDIRPREFIX If _PATH_OBJDIRPREFIX is set to "no" we won't define it. * makefile: added a pathetically simple makefile to drive bootstrapping. Running configure by hand is more useful. * Makefile.in: added MAKE_VERSION, and reworked things to be less dependent on NetBSD bsd.*.mk * pathnames.h: allow NO_PATH_OBJDIRPREFIX to stop us defining _PATH_OBJDIRPREFIX for those that don't want a default. construct _PATH_DEFSYSPATH from the info we get from configure. * main.c: allow for no _PATH_OBJDIRPREFIX, set ${MAKE_VERSION} if MAKE_VERSION is defined. * compat.c: when we bail, print out the .CURDIR we were in. Sat May 12 00:34:12 2001 Simon J. Gerraty * Merged with NetBSD make * var.c: fixed a bug in the handling of the modifier :P if the node as found but the path was null, we segfault trying to duplicate it. Mon Mar 5 16:20:33 2001 Simon J. Gerraty * Merged with NetBSD make * make.c: Make_OODate's test for a library out of date was using cmtime where it should have used mtime (my bug). * compat.c: Use perror() to tell us what really went wrong when we cannot exec a command. Fri Dec 15 10:11:08 2000 Simon J. Gerraty * Merged with NetBSD make Sat Jun 10 10:11:08 2000 Simon J. Gerraty * Merged with NetBSD make Thu Jun 1 10:11:08 2000 Simon J. Gerraty * Merged with NetBSD make Tue May 30 10:11:08 2000 Simon J. Gerraty * Merged with NetBSD make Thu Apr 27 00:07:47 2000 Simon J. Gerraty * util.c: don't provide signal() since we use sigcompat.c * Makefile.in: added a build target. * var.c (Var_Parse): added ODE modifiers :U, :D, :L, :P, :@ and :! These allow some quite clever magic. * main.c (main): added support for getenv(MAKESYSPATH). Mon Apr 2 16:25:13 2000 Simon J. Gerraty * Disable $PWD overriding getcwd() if MAKEOBJDIRPREFIX is set. This avoids objdir having a different value depending on how a directory was reached (via command line, or subdir.mk). * If FORCE_MACHINE is defined, ignore getenv("MACHINE"). Mon Apr 2 23:15:31 2000 Simon J. Gerraty * Do a chdir(${.CURDIR}) before invoking ${.MAKE} or ${.MAKE:T} if MAKEOBJDIRPREFIX is set and NOCHECKMAKECHDIR is not. I've been testing this in NetBSD's make for some weeks. * Turn Makefile into Makefile.in and make it useful. Tue Feb 29 22:08:00 2000 Simon J. Gerraty * Imported NetBSD's -current make(1) and resolve conflicts. * Applied autoconf patches from bmake v2 * Imported clean code base from NetBSD-1.0 Index: vendor/NetBSD/bmake/dist/FILES =================================================================== --- vendor/NetBSD/bmake/dist/FILES (revision 282731) +++ vendor/NetBSD/bmake/dist/FILES (revision 282732) @@ -1,165 +1,167 @@ ChangeLog FILES Makefile Makefile.config.in PSD.doc/Makefile PSD.doc/tutorial.ms README aclocal.m4 arch.c bmake.1 bmake.cat1 boot-strap bsd.after-import.mk buf.c buf.h compat.c cond.c config.h.in configure configure.in dir.c dir.h dirname.c find_lib.sh for.c getopt.c hash.c hash.h install-sh job.c job.h lst.h lst.lib/Makefile lst.lib/lstAppend.c lst.lib/lstAtEnd.c lst.lib/lstAtFront.c lst.lib/lstClose.c lst.lib/lstConcat.c lst.lib/lstDatum.c lst.lib/lstDeQueue.c lst.lib/lstDestroy.c lst.lib/lstDupl.c lst.lib/lstEnQueue.c lst.lib/lstFind.c lst.lib/lstFindFrom.c lst.lib/lstFirst.c lst.lib/lstForEach.c lst.lib/lstForEachFrom.c lst.lib/lstInit.c lst.lib/lstInsert.c lst.lib/lstInt.h lst.lib/lstIsAtEnd.c lst.lib/lstIsEmpty.c lst.lib/lstLast.c lst.lib/lstMember.c lst.lib/lstNext.c lst.lib/lstOpen.c lst.lib/lstPrev.c lst.lib/lstRemove.c lst.lib/lstReplace.c lst.lib/lstSucc.c machine.sh main.c make-bootstrap.sh.in make-conf.h make.1 make.c make.h make_malloc.c make_malloc.h makefile.in meta.c meta.h missing/sys/cdefs.h mkdeps.sh nonints.h os.sh parse.c pathnames.h ranlib.h realpath.c setenv.c sigcompat.c sprite.h str.c stresep.c strlcpy.c strlist.c strlist.h suff.c targ.c trace.c trace.h unit-tests/Makefile.in unit-tests/comment.exp unit-tests/comment.mk unit-tests/cond1.exp unit-tests/cond1.mk +unit-tests/cond2.exp +unit-tests/cond2.mk unit-tests/doterror.exp unit-tests/doterror.mk unit-tests/dotwait.exp unit-tests/dotwait.mk unit-tests/error.exp unit-tests/error.mk unit-tests/escape.exp unit-tests/escape.mk unit-tests/export-all.exp unit-tests/export-all.mk unit-tests/export-env.exp unit-tests/export-env.mk unit-tests/export.exp unit-tests/export.mk unit-tests/forloop.exp unit-tests/forloop.mk unit-tests/forsubst.exp unit-tests/forsubst.mk unit-tests/hash.exp unit-tests/hash.mk unit-tests/impsrc.exp unit-tests/impsrc.mk unit-tests/misc.exp unit-tests/misc.mk unit-tests/moderrs.exp unit-tests/moderrs.mk unit-tests/modmatch.exp unit-tests/modmatch.mk unit-tests/modmisc.exp unit-tests/modmisc.mk unit-tests/modorder.exp unit-tests/modorder.mk unit-tests/modts.exp unit-tests/modts.mk unit-tests/modword.exp unit-tests/modword.mk unit-tests/order.exp unit-tests/order.mk unit-tests/phony-end.exp unit-tests/phony-end.mk unit-tests/posix.exp unit-tests/posix.mk unit-tests/posix1.exp unit-tests/posix1.mk unit-tests/qequals.exp unit-tests/qequals.mk unit-tests/suffixes.exp unit-tests/suffixes.mk unit-tests/sunshcmd.exp unit-tests/sunshcmd.mk unit-tests/sysv.exp unit-tests/sysv.mk unit-tests/ternary.exp unit-tests/ternary.mk unit-tests/unexport-env.exp unit-tests/unexport-env.mk unit-tests/unexport.exp unit-tests/unexport.mk unit-tests/varcmd.exp unit-tests/varcmd.mk unit-tests/varmisc.exp unit-tests/varmisc.mk unit-tests/varshell.exp unit-tests/varshell.mk util.c var.c wait.h Index: vendor/NetBSD/bmake/dist/Makefile =================================================================== --- vendor/NetBSD/bmake/dist/Makefile (revision 282731) +++ vendor/NetBSD/bmake/dist/Makefile (revision 282732) @@ -1,221 +1,221 @@ -# $Id: Makefile,v 1.36 2015/04/18 19:58:53 sjg Exp $ +# $Id: Makefile,v 1.38 2015/05/05 21:58:05 sjg Exp $ # Base version on src date -MAKE_VERSION= 20150418 +MAKE_VERSION= 20150505 PROG= bmake SRCS= \ arch.c \ buf.c \ compat.c \ cond.c \ dir.c \ for.c \ hash.c \ job.c \ main.c \ make.c \ make_malloc.c \ meta.c \ parse.c \ str.c \ strlist.c \ suff.c \ targ.c \ trace.c \ util.c \ var.c # from lst.lib/ SRCS+= \ lstAppend.c \ lstAtEnd.c \ lstAtFront.c \ lstClose.c \ lstConcat.c \ lstDatum.c \ lstDeQueue.c \ lstDestroy.c \ lstDupl.c \ lstEnQueue.c \ lstFind.c \ lstFindFrom.c \ lstFirst.c \ lstForEach.c \ lstForEachFrom.c \ lstInit.c \ lstInsert.c \ lstIsAtEnd.c \ lstIsEmpty.c \ lstLast.c \ lstMember.c \ lstNext.c \ lstOpen.c \ lstPrev.c \ lstRemove.c \ lstReplace.c \ lstSucc.c # this file gets generated by configure .-include "Makefile.config" .if !empty(LIBOBJS) SRCS+= ${LIBOBJS:T:.o=.c} .endif # just in case prefix?= /usr srcdir?= ${.CURDIR} DEFAULT_SYS_PATH?= ${prefix}/share/mk CPPFLAGS+= -DUSE_META CFLAGS+= ${CPPFLAGS} CFLAGS+= -D_PATH_DEFSYSPATH=\"${DEFAULT_SYS_PATH}\" CFLAGS+= -I. -I${srcdir} ${XDEFS} -DMAKE_NATIVE CFLAGS+= ${COPTS.${.ALLSRC:M*.c:T:u}} COPTS.main.c+= "-DMAKE_VERSION=\"${MAKE_VERSION}\"" # meta mode can be useful even without filemon FILEMON_H ?= /usr/include/dev/filemon/filemon.h .if exists(${FILEMON_H}) && ${FILEMON_H:T} == "filemon.h" COPTS.meta.c += -DHAVE_FILEMON_H -I${FILEMON_H:H} .endif .PATH: ${srcdir} .PATH: ${srcdir}/lst.lib .if make(obj) || make(clean) SUBDIR+= unit-tests .endif # start-delete1 for bsd.after-import.mk # we skip a lot of this when building as part of FreeBSD etc. # list of OS's which are derrived from BSD4.4 -BSD44_LIST= NetBSD FreeBSD OpenBSD DragonFly +BSD44_LIST= NetBSD FreeBSD OpenBSD DragonFly MirBSD Bitrig # we are... OS!= uname -s # are we 4.4BSD ? isBSD44:=${BSD44_LIST:M${OS}} .if ${isBSD44} == "" MANTARGET= cat INSTALL?=${srcdir}/install-sh .if (${MACHINE} == "sun386") # even I don't have one of these anymore :-) CFLAGS+= -DPORTAR .elif (${MACHINE} != "sunos") SRCS+= sigcompat.c CFLAGS+= -DSIGNAL_FLAGS=SA_RESTART .endif .else MANTARGET?= man .endif # turn this on by default - ignored if we are root WITH_INSTALL_AS_USER= # suppress with -DWITHOUT_* OPTIONS_DEFAULT_YES+= \ AUTOCONF_MK \ INSTALL_MK \ PROG_LINK OPTIONS_DEFAULT_NO+= \ PROG_VERSION # process options now .include .if ${MK_PROG_VERSION} == "yes" PROG_NAME= ${PROG}-${MAKE_VERSION} .if ${MK_PROG_LINK} == "yes" SYMLINKS+= ${PROG}-${MAKE_VERSION} ${BINDIR}/${PROG} .endif .endif EXTRACT_MAN=no # end-delete1 MAN= ${PROG}.1 MAN1= ${MAN} .if (${PROG} != "make") CLEANFILES+= my.history .if make(${MAN}) || !exists(${srcdir}/${MAN}) my.history: ${MAKEFILE} @(echo ".Nm"; \ echo "is derived from NetBSD"; \ echo ".Xr make 1 ."; \ echo "It uses autoconf to facilitate portability to other platforms."; \ echo ".Pp") > $@ .NOPATH: ${MAN} ${MAN}: make.1 my.history @echo making $@ @sed -e 's/^.Nx/NetBSD/' -e '/^.Nm/s/make/${PROG}/' \ -e '/^.Sh HISTORY/rmy.history' \ -e '/^.Sh HISTORY/,$$s,^.Nm,make,' ${srcdir}/make.1 > $@ all beforeinstall: ${MAN} _mfromdir=. .endif .endif MANTARGET?= cat MANDEST?= ${MANDIR}/${MANTARGET}1 .if ${MANTARGET} == "cat" _mfromdir=${srcdir} .endif .include CPPFLAGS+= -DMAKE_NATIVE -DHAVE_CONFIG_H COPTS.var.c += -Wno-cast-qual COPTS.job.c += -Wno-format-nonliteral COPTS.parse.c += -Wno-format-nonliteral COPTS.var.c += -Wno-format-nonliteral # Force these SHAREDIR= ${SHAREDIR.bmake:U${prefix}/share} BINDIR= ${BINDIR.bmake:U${prefix}/bin} MANDIR= ${MANDIR.bmake:U${SHAREDIR}/man} .if !exists(.depend) ${OBJS}: config.h .endif # make sure that MAKE_VERSION gets updated. main.o: ${SRCS} ${MAKEFILE} # start-delete2 for bsd.after-import.mk .if ${MK_AUTOCONF_MK} == "yes" .include .endif SHARE_MK?=${SHAREDIR}/mk MKSRC=${srcdir}/mk INSTALL?=${srcdir}/install-sh .if ${MK_INSTALL_MK} == "yes" install: install-mk .endif beforeinstall: test -d ${DESTDIR}${BINDIR} || ${INSTALL} -m 775 -d ${DESTDIR}${BINDIR} test -d ${DESTDIR}${MANDEST} || ${INSTALL} -m 775 -d ${DESTDIR}${MANDEST} install-mk: .if exists(${MKSRC}/install-mk) test -d ${DESTDIR}${SHARE_MK} || ${INSTALL} -m 775 -d ${DESTDIR}${SHARE_MK} sh ${MKSRC}/install-mk -v -m 644 ${DESTDIR}${SHARE_MK} .else @echo need to unpack mk.tar.gz under ${srcdir} or set MKSRC; false .endif # end-delete2 # A simple unit-test driver to help catch regressions accept test: cd ${.CURDIR}/unit-tests && MAKEFLAGS= ${.MAKE} -r -m / TEST_MAKE=${TEST_MAKE:U${.OBJDIR}/${PROG:T}} ${.TARGET} Index: vendor/NetBSD/bmake/dist/cond.c =================================================================== --- vendor/NetBSD/bmake/dist/cond.c (revision 282731) +++ vendor/NetBSD/bmake/dist/cond.c (revision 282732) @@ -1,1413 +1,1434 @@ -/* $NetBSD: cond.c,v 1.67 2012/11/03 13:59:27 christos Exp $ */ +/* $NetBSD: cond.c,v 1.68 2015/05/05 21:51:09 sjg Exp $ */ /* * Copyright (c) 1988, 1989, 1990 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. */ /* * 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. */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: cond.c,v 1.67 2012/11/03 13:59:27 christos Exp $"; +static char rcsid[] = "$NetBSD: cond.c,v 1.68 2015/05/05 21:51:09 sjg Exp $"; #else #include #ifndef lint #if 0 static char sccsid[] = "@(#)cond.c 8.2 (Berkeley) 1/2/94"; #else -__RCSID("$NetBSD: cond.c,v 1.67 2012/11/03 13:59:27 christos Exp $"); +__RCSID("$NetBSD: cond.c,v 1.68 2015/05/05 21:51:09 sjg Exp $"); #endif #endif /* not lint */ #endif /*- * cond.c -- * Functions to handle conditionals in a makefile. * * Interface: * Cond_Eval Evaluate the conditional in the passed line. * */ #include #include /* For strtoul() error checking */ #include "make.h" #include "hash.h" #include "dir.h" #include "buf.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 -> commands(name) * T -> symbol * T -> $(varspec) op value * T -> $(varspec) == "string" * T -> $(varspec) != "string" * T -> "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 TOK_AND for '&' and '&&', TOK_OR for '|' and '||', * TOK_NOT for '!', TOK_LPAREN for '(', TOK_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 TOK_TRUE * or TOK_FALSE. * * TOK_FALSE is 0 and TOK_TRUE 1 so we can directly assign C comparisons. * * All Non-Terminal functions (CondE, CondF and CondT) return TOK_ERROR on * error. */ typedef enum { TOK_FALSE = 0, TOK_TRUE = 1, TOK_AND, TOK_OR, TOK_NOT, TOK_LPAREN, TOK_RPAREN, TOK_EOF, TOK_NONE, TOK_ERROR } Token; /*- * 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 *); static Boolean CondDoDefined(int, const char *); static int CondStrMatch(const void *, const void *); static Boolean CondDoMake(int, const char *); static Boolean CondDoExists(int, const char *); static Boolean CondDoTarget(int, const char *); static Boolean CondDoCommands(int, const char *); static Boolean CondCvtArg(char *, double *); static Token CondToken(Boolean); static Token CondT(Boolean); static Token CondF(Boolean); static Token CondE(Boolean); static int do_Cond_EvalExpression(Boolean *); static const struct If { const char *form; /* Form of if */ int formlen; /* Length of form */ Boolean doNot; /* TRUE if default function should be negated */ Boolean (*defProc)(int, const char *); /* Default function to apply */ } ifs[] = { { "def", 3, FALSE, CondDoDefined }, { "ndef", 4, TRUE, CondDoDefined }, { "make", 4, FALSE, CondDoMake }, { "nmake", 5, TRUE, CondDoMake }, { "", 0, FALSE, CondDoDefined }, { NULL, 0, FALSE, NULL } }; static const struct If *if_info; /* Info for current statement */ static char *condExpr; /* The expression to parse */ static Token condPushBack=TOK_NONE; /* Single push-back token used in * parsing */ static unsigned int cond_depth = 0; /* current .if nesting level */ static unsigned int cond_min_depth = 0; /* depth at makefile open */ +/* + * Indicate when we should be strict about lhs of comparisons. + * TRUE when Cond_EvalExpression is called from Cond_Eval (.if etc) + * FALSE when Cond_EvalExpression is called from var.c:ApplyModifiers + * since lhs is already expanded and we cannot tell if + * it was a variable reference or not. + */ +static Boolean lhsStrict; + static int istoken(const char *str, const char *tok, size_t len) { return strncmp(str, tok, len) == 0 && !isalpha((unsigned char)str[len]); } /*- *----------------------------------------------------------------------- * CondPushBack -- * Push back the most recent token read. We only need one level of * this, so the thing is just stored in 'condPushback'. * * Input: * t Token to push back into the "stream" * * Results: * None. * * Side Effects: * condPushback is overwritten. * *----------------------------------------------------------------------- */ static void CondPushBack(Token t) { condPushBack = t; } /*- *----------------------------------------------------------------------- * CondGetArg -- * Find the argument of a built-in function. * * Input: * parens TRUE if arg should be 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) { char *cp; int argLen; Buffer buf; int paren_depth; char ch; cp = *linePtr; if (func != NULL) /* Skip opening '(' - verfied by caller */ 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 = NULL; 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_Init(&buf, 16); paren_depth = 0; for (;;) { ch = *cp; if (ch == 0 || ch == ' ' || ch == '\t') break; if ((ch == '&' || ch == '|') && paren_depth == 0) break; 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; int len; void *freeIt; cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &freeIt); Buf_AddBytes(&buf, strlen(cp2), cp2); if (freeIt) free(freeIt); cp += len; continue; } if (ch == '(') paren_depth++; else if (ch == ')' && --paren_depth < 0) break; Buf_AddByte(&buf, *cp); cp++; } *argPtr = Buf_GetAll(&buf, &argLen); Buf_Destroy(&buf, FALSE); while (*cp == ' ' || *cp == '\t') { cp++; } if (func != NULL && *cp++ != ')') { Parse_Error(PARSE_WARNING, "Missing closing parenthesis for %s()", func); return (0); } *linePtr = cp; return (argLen); } /*- *----------------------------------------------------------------------- * CondDoDefined -- * Handle the 'defined' function for conditionals. * * Results: * TRUE if the given variable is defined. * * Side Effects: * None. * *----------------------------------------------------------------------- */ static Boolean CondDoDefined(int argLen MAKE_ATTR_UNUSED, const char *arg) { char *p1; Boolean result; if (Var_Value(arg, VAR_CMD, &p1) != NULL) { result = TRUE; } else { result = FALSE; } if (p1) free(p1); return (result); } /*- *----------------------------------------------------------------------- * CondStrMatch -- * Front-end for Str_Match so it returns 0 on match and non-zero * on mismatch. Callback function for CondDoMake via Lst_Find * * Results: * 0 if string matches pattern * * Side Effects: * None * *----------------------------------------------------------------------- */ static int CondStrMatch(const void *string, const void *pattern) { return(!Str_Match(string, pattern)); } /*- *----------------------------------------------------------------------- * CondDoMake -- * Handle the 'make' function for conditionals. * * Results: * TRUE if the given target is being made. * * Side Effects: * None. * *----------------------------------------------------------------------- */ static Boolean CondDoMake(int argLen MAKE_ATTR_UNUSED, const char *arg) { return Lst_Find(create, arg, CondStrMatch) != NULL; } /*- *----------------------------------------------------------------------- * CondDoExists -- * See if the given file exists. * * Results: * TRUE if the file exists and FALSE if it does not. * * Side Effects: * None. * *----------------------------------------------------------------------- */ static Boolean CondDoExists(int argLen MAKE_ATTR_UNUSED, const char *arg) { Boolean result; char *path; path = Dir_FindFile(arg, dirSearchPath); if (DEBUG(COND)) { fprintf(debug_file, "exists(%s) result is \"%s\"\n", arg, path ? path : ""); } if (path != NULL) { result = TRUE; free(path); } else { result = FALSE; } 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. * * Side Effects: * None. * *----------------------------------------------------------------------- */ static Boolean CondDoTarget(int argLen MAKE_ATTR_UNUSED, const char *arg) { GNode *gn; gn = Targ_FindNode(arg, TARG_NOCREATE); return (gn != NULL) && !OP_NOP(gn->type); } /*- *----------------------------------------------------------------------- * CondDoCommands -- * See if the given node exists and is an actual target with commands * associated with it. * * Results: * TRUE if the node exists as a target and has commands associated with * it and FALSE if it does not. * * Side Effects: * None. * *----------------------------------------------------------------------- */ static Boolean CondDoCommands(int argLen MAKE_ATTR_UNUSED, const char *arg) { GNode *gn; gn = Targ_FindNode(arg, TARG_NOCREATE); return (gn != NULL) && !OP_NOP(gn->type) && !Lst_IsEmpty(gn->commands); } /*- *----------------------------------------------------------------------- * CondCvtArg -- * Convert the given number into a double. * We try a base 10 or 16 integer conversion first, if that fails * then we try a floating point conversion instead. * * Results: * Sets 'value' to double value of string. * Returns 'true' if the convertion suceeded * *----------------------------------------------------------------------- */ static Boolean CondCvtArg(char *str, double *value) { char *eptr, ech; unsigned long l_val; double d_val; errno = 0; l_val = strtoul(str, &eptr, str[1] == 'x' ? 16 : 10); ech = *eptr; if (ech == 0 && errno != ERANGE) { d_val = str[0] == '-' ? -(double)-l_val : (double)l_val; } else { if (ech != 0 && ech != '.' && ech != 'e' && ech != 'E') return FALSE; d_val = strtod(str, &eptr); if (*eptr) return FALSE; } *value = d_val; return TRUE; } /*- *----------------------------------------------------------------------- * CondGetString -- * Get a string from a variable reference or an optionally quoted * string. This is called for the lhs and rhs of string compares. * * Results: * Sets freeIt if needed, * Sets quoted if string was quoted, * Returns NULL on error, * else returns string - absent any quotes. * * Side Effects: * Moves condExpr to end of this token. * * *----------------------------------------------------------------------- */ /* coverity:[+alloc : arg-*2] */ static char * -CondGetString(Boolean doEval, Boolean *quoted, void **freeIt) +CondGetString(Boolean doEval, Boolean *quoted, void **freeIt, Boolean strictLHS) { Buffer buf; char *cp; char *str; int len; int qt; char *start; Buf_Init(&buf, 0); str = NULL; *freeIt = NULL; *quoted = qt = *condExpr == '"' ? 1 : 0; if (qt) condExpr++; for (start = condExpr; *condExpr && str == NULL; condExpr++) { switch (*condExpr) { case '\\': if (condExpr[1] != '\0') { condExpr++; Buf_AddByte(&buf, *condExpr); } break; case '"': if (qt) { condExpr++; /* we don't want the quotes */ goto got_str; } else Buf_AddByte(&buf, *condExpr); /* likely? */ break; case ')': case '!': case '=': case '>': case '<': case ' ': case '\t': if (!qt) goto got_str; else Buf_AddByte(&buf, *condExpr); break; case '$': /* if we are in quotes, then an undefined variable is ok */ str = Var_Parse(condExpr, VAR_CMD, (qt ? 0 : doEval), &len, freeIt); if (str == var_Error) { if (*freeIt) { free(*freeIt); *freeIt = NULL; } /* * Even if !doEval, we still report syntax errors, which * is what getting var_Error back with !doEval means. */ str = NULL; goto cleanup; } condExpr += len; /* * If the '$' was first char (no quotes), and we are * followed by space, the operator or end of expression, * we are done. */ if ((condExpr == start + len) && (*condExpr == '\0' || isspace((unsigned char) *condExpr) || strchr("!=><)", *condExpr))) { goto cleanup; } /* * Nope, we better copy str to buf */ for (cp = str; *cp; cp++) { Buf_AddByte(&buf, *cp); } if (*freeIt) { free(*freeIt); *freeIt = NULL; } str = NULL; /* not finished yet */ condExpr--; /* don't skip over next char */ break; default: + if (strictLHS && !qt && *start != '$' && + !isdigit((unsigned char) *start)) { + /* lhs must be quoted, a variable reference or number */ + if (*freeIt) { + free(*freeIt); + *freeIt = NULL; + } + str = NULL; + goto cleanup; + } Buf_AddByte(&buf, *condExpr); break; } } got_str: str = Buf_GetAll(&buf, NULL); *freeIt = str; cleanup: Buf_Destroy(&buf, FALSE); return str; } /*- *----------------------------------------------------------------------- * 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 TOK_NONE if it is used. * *----------------------------------------------------------------------- */ static Token compare_expression(Boolean doEval) { Token t; char *lhs; char *rhs; char *op; void *lhsFree; void *rhsFree; Boolean lhsQuoted; Boolean rhsQuoted; double left, right; t = TOK_ERROR; rhs = NULL; lhsFree = rhsFree = FALSE; lhsQuoted = rhsQuoted = FALSE; /* * Parse the variable spec and skip over it, saving its * value in lhs. */ - lhs = CondGetString(doEval, &lhsQuoted, &lhsFree); + lhs = CondGetString(doEval, &lhsQuoted, &lhsFree, lhsStrict); if (!lhs) goto done; /* * 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; } break; default: if (!doEval) { t = TOK_FALSE; goto done; } /* For .ifxxx "..." check for non-empty string. */ if (lhsQuoted) { t = lhs[0] != 0; goto done; } /* For .ifxxx compare against zero */ if (CondCvtArg(lhs, &left)) { t = left != 0.0; goto done; } /* For .if ${...} check for non-empty string (defProc is ifdef). */ if (if_info->form[0] == 0) { t = lhs[0] != 0; goto done; } /* Otherwise action default test ... */ t = if_info->defProc(strlen(lhs), lhs) != if_info->doNot; goto done; } while (isspace((unsigned char)*condExpr)) condExpr++; if (*condExpr == '\0') { Parse_Error(PARSE_WARNING, "Missing right-hand-side of operator"); goto done; } - rhs = CondGetString(doEval, &rhsQuoted, &rhsFree); + rhs = CondGetString(doEval, &rhsQuoted, &rhsFree, FALSE); if (!rhs) goto done; if (rhsQuoted || lhsQuoted) { do_string_compare: if (((*op != '!') && (*op != '=')) || (op[1] != '=')) { Parse_Error(PARSE_WARNING, "String comparison operator should be either == or !="); goto done; } if (DEBUG(COND)) { fprintf(debug_file, "lhs = \"%s\", rhs = \"%s\", op = %.2s\n", lhs, rhs, op); } /* * Null-terminate rhs and perform the comparison. * t is set to the result. */ if (*op == '=') { t = strcmp(lhs, rhs) == 0; } else { t = strcmp(lhs, rhs) != 0; } } else { /* * rhs is either a float or an integer. Convert both the * lhs and the rhs to a double and compare the two. */ if (!CondCvtArg(lhs, &left) || !CondCvtArg(rhs, &right)) goto do_string_compare; if (DEBUG(COND)) { fprintf(debug_file, "left = %f, right = %f, op = %.2s\n", left, right, op); } switch(op[0]) { case '!': if (op[1] != '=') { Parse_Error(PARSE_WARNING, "Unknown operator"); goto done; } t = (left != right); break; case '=': if (op[1] != '=') { Parse_Error(PARSE_WARNING, "Unknown operator"); goto done; } t = (left == right); break; case '<': if (op[1] == '=') { t = (left <= right); } else { t = (left < right); } break; case '>': if (op[1] == '=') { t = (left >= right); } else { t = (left > right); } break; } } done: if (lhsFree) free(lhsFree); if (rhsFree) free(rhsFree); return t; } static int get_mpt_arg(char **linePtr, char **argPtr, const char *func MAKE_ATTR_UNUSED) { /* * Use Var_Parse to parse the spec in parens and return * TOK_TRUE if the resulting string is empty. */ int length; void *freeIt; char *val; char *cp = *linePtr; /* We do all the work here and return the result as the length */ *argPtr = NULL; val = Var_Parse(cp - 1, VAR_CMD, FALSE, &length, &freeIt); /* * Advance *linePtr to beyond the closing ). Note that * we subtract one because 'length' is calculated from 'cp - 1'. */ *linePtr = cp - 1 + length; if (val == var_Error) { free(freeIt); return -1; } /* A variable is empty when it just contains spaces... 4/15/92, christos */ while (isspace(*(unsigned char *)val)) val++; /* * For consistency with the other functions we can't generate the * true/false here. */ length = *val ? 2 : 1; if (freeIt) free(freeIt); return length; } static Boolean CondDoEmpty(int arglen, const char *arg MAKE_ATTR_UNUSED) { return arglen == 1; } static Token compare_function(Boolean doEval) { static const struct fn_def { const char *fn_name; int fn_name_len; int (*fn_getarg)(char **, char **, const char *); Boolean (*fn_proc)(int, const char *); } fn_defs[] = { { "defined", 7, CondGetArg, CondDoDefined }, { "make", 4, CondGetArg, CondDoMake }, { "exists", 6, CondGetArg, CondDoExists }, { "empty", 5, get_mpt_arg, CondDoEmpty }, { "target", 6, CondGetArg, CondDoTarget }, { "commands", 8, CondGetArg, CondDoCommands }, { NULL, 0, NULL, NULL }, }; const struct fn_def *fn_def; Token t; char *arg = NULL; int arglen; char *cp = condExpr; char *cp1; for (fn_def = fn_defs; fn_def->fn_name != NULL; fn_def++) { if (!istoken(cp, fn_def->fn_name, fn_def->fn_name_len)) continue; cp += fn_def->fn_name_len; /* There can only be whitespace before the '(' */ while (isspace(*(unsigned char *)cp)) cp++; if (*cp != '(') break; arglen = fn_def->fn_getarg(&cp, &arg, fn_def->fn_name); if (arglen <= 0) { condExpr = cp; return arglen < 0 ? TOK_ERROR : TOK_FALSE; } /* Evaluate the argument using the required function. */ t = !doEval || fn_def->fn_proc(arglen, arg); if (arg) free(arg); condExpr = cp; return t; } /* Push anything numeric through the compare expression */ cp = condExpr; if (isdigit((unsigned char)cp[0]) || strchr("+-", cp[0])) return compare_expression(doEval); /* * Most likely we have a naked token to apply the default function to. * However ".if a == b" gets here when the "a" is unquoted and doesn't * start with a '$'. This surprises people. * If what follows the function argument is a '=' or '!' then the syntax * would be invalid if we did "defined(a)" - so instead treat as an * expression. */ arglen = CondGetArg(&cp, &arg, NULL); for (cp1 = cp; isspace(*(unsigned char *)cp1); cp1++) continue; if (*cp1 == '=' || *cp1 == '!') return compare_expression(doEval); condExpr = cp; /* * Evaluate the argument using the default function. * This path always treats .if as .ifdef. To get here the character * after .if must have been taken literally, so the argument cannot * be empty - even if it contained a variable expansion. */ t = !doEval || if_info->defProc(arglen, arg) != if_info->doNot; if (arg) free(arg); return t; } static Token CondToken(Boolean doEval) { Token t; t = condPushBack; if (t != TOK_NONE) { condPushBack = TOK_NONE; return t; } while (*condExpr == ' ' || *condExpr == '\t') { condExpr++; } switch (*condExpr) { case '(': condExpr++; return TOK_LPAREN; case ')': condExpr++; return TOK_RPAREN; case '|': if (condExpr[1] == '|') { condExpr++; } condExpr++; return TOK_OR; case '&': if (condExpr[1] == '&') { condExpr++; } condExpr++; return TOK_AND; case '!': condExpr++; return TOK_NOT; case '#': case '\n': case '\0': return TOK_EOF; case '"': case '$': return compare_expression(doEval); default: return compare_function(doEval); } } /*- *----------------------------------------------------------------------- * CondT -- * Parse a single term in the expression. This consists of a terminal * symbol or TOK_NOT and a terminal symbol (not including the binary * operators): * T -> defined(variable) | make(target) | exists(file) | symbol * T -> ! T | ( E ) * * Results: * TOK_TRUE, TOK_FALSE or TOK_ERROR. * * Side Effects: * Tokens are consumed. * *----------------------------------------------------------------------- */ static Token CondT(Boolean doEval) { Token t; t = CondToken(doEval); if (t == TOK_EOF) { /* * If we reached the end of the expression, the expression * is malformed... */ t = TOK_ERROR; } else if (t == TOK_LPAREN) { /* * T -> ( E ) */ t = CondE(doEval); if (t != TOK_ERROR) { if (CondToken(doEval) != TOK_RPAREN) { t = TOK_ERROR; } } } else if (t == TOK_NOT) { t = CondT(doEval); if (t == TOK_TRUE) { t = TOK_FALSE; } else if (t == TOK_FALSE) { t = TOK_TRUE; } } return (t); } /*- *----------------------------------------------------------------------- * CondF -- * Parse a conjunctive factor (nice name, wot?) * F -> T && F | T * * Results: * TOK_TRUE, TOK_FALSE or TOK_ERROR * * Side Effects: * Tokens are consumed. * *----------------------------------------------------------------------- */ static Token CondF(Boolean doEval) { Token l, o; l = CondT(doEval); if (l != TOK_ERROR) { o = CondToken(doEval); if (o == TOK_AND) { /* * F -> T && F * * If T is TOK_FALSE, the whole thing will be TOK_FALSE, but we have to * parse the r.h.s. anyway (to throw it away). * If T is TOK_TRUE, the result is the r.h.s., be it an TOK_ERROR or no. */ if (l == TOK_TRUE) { l = CondF(doEval); } else { (void)CondF(FALSE); } } else { /* * F -> T */ CondPushBack(o); } } return (l); } /*- *----------------------------------------------------------------------- * CondE -- * Main expression production. * E -> F || E | F * * Results: * TOK_TRUE, TOK_FALSE or TOK_ERROR. * * Side Effects: * Tokens are, of course, consumed. * *----------------------------------------------------------------------- */ static Token CondE(Boolean doEval) { Token l, o; l = CondF(doEval); if (l != TOK_ERROR) { o = CondToken(doEval); if (o == TOK_OR) { /* * E -> F || E * * A similar thing occurs for ||, except that here we make sure * the l.h.s. is TOK_FALSE before we bother to evaluate the r.h.s. * Once again, if l is TOK_FALSE, the result is the r.h.s. and once * again if l is TOK_TRUE, we parse the r.h.s. to throw it away. */ if (l == TOK_FALSE) { l = CondE(doEval); } else { (void)CondE(FALSE); } } else { /* * E -> F */ CondPushBack(o); } } return (l); } /*- *----------------------------------------------------------------------- * Cond_EvalExpression -- * Evaluate an expression in the passed line. The expression * consists of &&, ||, !, make(target), defined(variable) * and parenthetical groupings thereof. * * Results: * COND_PARSE if the condition was valid grammatically * COND_INVALID if not a valid conditional. * * (*value) is set to the boolean value of the condition * * Side Effects: * None. * *----------------------------------------------------------------------- */ int -Cond_EvalExpression(const struct If *info, char *line, Boolean *value, int eprint) +Cond_EvalExpression(const struct If *info, char *line, Boolean *value, int eprint, Boolean strictLHS) { static const struct If *dflt_info; const struct If *sv_if_info = if_info; char *sv_condExpr = condExpr; Token sv_condPushBack = condPushBack; int rval; + lhsStrict = strictLHS; + while (*line == ' ' || *line == '\t') line++; if (info == NULL && (info = dflt_info) == NULL) { /* Scan for the entry for .if - it can't be first */ for (info = ifs; ; info++) if (info->form[0] == 0) break; dflt_info = info; } if_info = info != NULL ? info : ifs + 4; condExpr = line; condPushBack = TOK_NONE; rval = do_Cond_EvalExpression(value); if (rval == COND_INVALID && eprint) Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", line); if_info = sv_if_info; condExpr = sv_condExpr; condPushBack = sv_condPushBack; return rval; } static int do_Cond_EvalExpression(Boolean *value) { switch (CondE(TRUE)) { case TOK_TRUE: if (CondToken(TRUE) == TOK_EOF) { *value = TRUE; return COND_PARSE; } break; case TOK_FALSE: if (CondToken(TRUE) == TOK_EOF) { *value = FALSE; return COND_PARSE; } break; default: case TOK_ERROR: break; } return COND_INVALID; } /*- *----------------------------------------------------------------------- * Cond_Eval -- * Evaluate the conditional in the passed line. The line * looks like this: * . * where is any of if, ifmake, ifnmake, ifdef, * ifndef, elif, elifmake, elifnmake, elifdef, elifndef * and consists of &&, ||, !, make(target), defined(variable) * and parenthetical groupings thereof. * * Input: * line Line to parse * * Results: * COND_PARSE if should parse lines after the conditional * COND_SKIP if should skip lines after the conditional * COND_INVALID if not a valid conditional. * * Side Effects: * None. * * Note that the states IF_ACTIVE and ELSE_ACTIVE are only different in order * to detect splurious .else lines (as are SKIP_TO_ELSE and SKIP_TO_ENDIF) * otherwise .else could be treated as '.elif 1'. * *----------------------------------------------------------------------- */ int Cond_Eval(char *line) { #define MAXIF 128 /* maximum depth of .if'ing */ #define MAXIF_BUMP 32 /* how much to grow by */ enum if_states { IF_ACTIVE, /* .if or .elif part active */ ELSE_ACTIVE, /* .else part active */ SEARCH_FOR_ELIF, /* searching for .elif/else to execute */ SKIP_TO_ELSE, /* has been true, but not seen '.else' */ SKIP_TO_ENDIF /* nothing else to execute */ }; static enum if_states *cond_state = NULL; static unsigned int max_if_depth = MAXIF; const struct If *ifp; Boolean isElif; Boolean value; int level; /* Level at which to report errors. */ enum if_states state; level = PARSE_FATAL; if (!cond_state) { cond_state = bmake_malloc(max_if_depth * sizeof(*cond_state)); cond_state[0] = IF_ACTIVE; } /* skip leading character (the '.') and any whitespace */ for (line++; *line == ' ' || *line == '\t'; line++) continue; /* Find what type of if we're dealing with. */ if (line[0] == 'e') { if (line[1] != 'l') { if (!istoken(line + 1, "ndif", 4)) return COND_INVALID; /* End of conditional section */ if (cond_depth == cond_min_depth) { Parse_Error(level, "if-less endif"); return COND_PARSE; } /* Return state for previous conditional */ cond_depth--; return cond_state[cond_depth] <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP; } /* Quite likely this is 'else' or 'elif' */ line += 2; if (istoken(line, "se", 2)) { /* It is else... */ if (cond_depth == cond_min_depth) { Parse_Error(level, "if-less else"); return COND_PARSE; } state = cond_state[cond_depth]; switch (state) { case SEARCH_FOR_ELIF: state = ELSE_ACTIVE; break; case ELSE_ACTIVE: case SKIP_TO_ENDIF: Parse_Error(PARSE_WARNING, "extra else"); /* FALLTHROUGH */ default: case IF_ACTIVE: case SKIP_TO_ELSE: state = SKIP_TO_ENDIF; break; } cond_state[cond_depth] = state; return state <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP; } /* Assume for now it is an elif */ isElif = TRUE; } else isElif = FALSE; if (line[0] != 'i' || line[1] != 'f') /* Not an ifxxx or elifxxx line */ return COND_INVALID; /* * Figure out what sort of conditional it is -- what its default * function is, etc. -- by looking in the table of valid "ifs" */ line += 2; for (ifp = ifs; ; ifp++) { if (ifp->form == NULL) return COND_INVALID; if (istoken(ifp->form, line, ifp->formlen)) { line += ifp->formlen; break; } } /* Now we know what sort of 'if' it is... */ if (isElif) { if (cond_depth == cond_min_depth) { Parse_Error(level, "if-less elif"); return COND_PARSE; } state = cond_state[cond_depth]; if (state == SKIP_TO_ENDIF || state == ELSE_ACTIVE) { Parse_Error(PARSE_WARNING, "extra elif"); cond_state[cond_depth] = SKIP_TO_ENDIF; return COND_SKIP; } if (state != SEARCH_FOR_ELIF) { /* Either just finished the 'true' block, or already SKIP_TO_ELSE */ cond_state[cond_depth] = SKIP_TO_ELSE; return COND_SKIP; } } else { /* Normal .if */ if (cond_depth + 1 >= max_if_depth) { /* * This is rare, but not impossible. * In meta mode, dirdeps.mk (only runs at level 0) * can need more than the default. */ max_if_depth += MAXIF_BUMP; cond_state = bmake_realloc(cond_state, max_if_depth * sizeof(*cond_state)); } state = cond_state[cond_depth]; cond_depth++; if (state > ELSE_ACTIVE) { /* If we aren't parsing the data, treat as always false */ cond_state[cond_depth] = SKIP_TO_ELSE; return COND_SKIP; } } /* And evaluate the conditional expresssion */ - if (Cond_EvalExpression(ifp, line, &value, 1) == COND_INVALID) { + if (Cond_EvalExpression(ifp, line, &value, 1, TRUE) == COND_INVALID) { /* Syntax error in conditional, error message already output. */ /* Skip everything to matching .endif */ cond_state[cond_depth] = SKIP_TO_ELSE; return COND_SKIP; } if (!value) { cond_state[cond_depth] = SEARCH_FOR_ELIF; return COND_SKIP; } cond_state[cond_depth] = IF_ACTIVE; return COND_PARSE; } /*- *----------------------------------------------------------------------- * Cond_End -- * Make sure everything's clean at the end of a makefile. * * Results: * None. * * Side Effects: * Parse_Error will be called if open conditionals are around. * *----------------------------------------------------------------------- */ void Cond_restore_depth(unsigned int saved_depth) { int open_conds = cond_depth - cond_min_depth; if (open_conds != 0 || saved_depth > cond_depth) { Parse_Error(PARSE_FATAL, "%d open conditional%s", open_conds, open_conds == 1 ? "" : "s"); cond_depth = cond_min_depth; } cond_min_depth = saved_depth; } unsigned int Cond_save_depth(void) { int depth = cond_min_depth; cond_min_depth = cond_depth; return depth; } Index: vendor/NetBSD/bmake/dist/machine.sh =================================================================== --- vendor/NetBSD/bmake/dist/machine.sh (revision 282731) +++ vendor/NetBSD/bmake/dist/machine.sh (revision 282732) @@ -1,96 +1,100 @@ : # derrived from /etc/rc_d/os.sh # RCSid: -# $Id: machine.sh,v 1.16 2010/10/17 00:05:51 sjg Exp $ +# $Id: machine.sh,v 1.17 2015/05/05 00:10:54 sjg Exp $ # # @(#) Copyright (c) 1994-2002 Simon J. Gerraty # # This file is provided in the hope that it will # be of use. There is absolutely NO WARRANTY. # Permission to copy, redistribute or otherwise # use this file is hereby granted provided that # the above copyright notice and this notice are # left intact. # # Please send copies of changes and bug-fixes to: # sjg@crufty.net # OS=`uname` OSREL=`uname -r` OSMAJOR=`IFS=.; set $OSREL; echo $1` machine=`uname -p 2>/dev/null || uname -m` MACHINE= # there is at least one case of `uname -p` outputting # a bunch of usless drivel case "$machine" in unknown|*[!A-Za-z0-9_-]*) machine=`uname -m` ;; esac # Great! Solaris keeps moving arch(1) # we need this here, and it is not always available... Which() { # some shells cannot correctly handle `IFS` # in conjunction with the for loop. _dirs=`IFS=:; echo ${2:-$PATH}` for d in $_dirs do test -x $d/$1 && { echo $d/$1; break; } done } case $OS in OpenBSD) MACHINE=$OS$OSMAJOR.$machine arch=`Which arch /usr/bin:/usr/ucb:$PATH` MACHINE_ARCH=`$arch -s`; + ;; +Bitrig) + MACHINE=$OS$OSMAJOR.$machine + MACHINE_ARCH=`uname -m`; ;; *BSD) MACHINE=$OS$OSMAJOR.$machine ;; SunOS) arch=`Which arch /usr/bin:/usr/ucb:$PATH` test "$arch" && machine_arch=`$arch` case "$OSREL" in 4.0*) MACHINE_ARCH=$machine_arch MACHINE=$machine_arch;; 4*) MACHINE_ARCH=$machine_arch;; esac ;; HP-UX) MACHINE_ARCH=`IFS="/-."; set $machine; echo $1` ;; Interix) MACHINE=i386 MACHINE_ARCH=i386 ;; UnixWare) OSREL=`uname -v` OSMAJOR=`IFS=.; set $OSREL; echo $1` MACHINE_ARCH=`uname -m` ;; Linux) case "$machine" in i?86) MACHINE_ARCH=i386;;# does anyone really care about 686 vs 586? esac ;; esac MACHINE=${MACHINE:-$OS$OSMAJOR} MACHINE_ARCH=${MACHINE_ARCH:-$machine} ( case "$0" in arch*) echo $MACHINE_ARCH;; *) case "$1" in "") echo $MACHINE;; *) echo $MACHINE_ARCH;; esac ;; esac ) | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz Index: vendor/NetBSD/bmake/dist/mk/ChangeLog =================================================================== --- vendor/NetBSD/bmake/dist/mk/ChangeLog (revision 282731) +++ vendor/NetBSD/bmake/dist/mk/ChangeLog (revision 282732) @@ -1,942 +1,948 @@ +2015-04-30 Simon J. Gerraty + + * install-mk (MK_VERSION): 20150430 + + * dirdeps.mk: fix _count_dirdeps for non-cache case. + 2015-04-16 Simon J. Gerraty * install-mk (MK_VERSION): 20150411 bump version * own.mk: put AUTO_OBJ in OPTIONS_DEFAULT_NO rather than YES. it is here mainly for documentation purposes, since if using auto.obj.mk it is better done via sys.mk 2015-04-01 Simon J. Gerraty * install-mk (MK_VERSION): 20150401 * meta2deps.sh: support @list * meta2deps.py: updates from Juniper o add EXCLUDES o skip bogus input files. o treat 'M' and 'L' as both an 'R' and a 'W' 2015-03-03 Simon J. Gerraty * install-mk (MK_VERSION): 20150303 * dirdeps.mk: if MK_DIRDEPS_CACHE is yes, use dirdeps-cache which is built via sub-make so we have a .meta file to tell if it is out-of-date. The dirdeps-cache contains the same dependency rules that we normaly construct on the fly. This adds a few seconds overhead when the cache is out of date, but for a large target, the savings can be significant (10-20min). 2014-11-18 Simon J. Gerraty * install-mk (MK_VERSION): 20141118 * meta.stage.mk: add stale_staged * dirdeps.mk (_DIRDEP_USE_LEVEL): allow this to be tweaked only useful under very rare conditions such as FreeBSD's make universe. * auto.obj.mk: Allow MK_AUTO_OBJ to set MKOBJDIRS=auto 2014-11-11 Simon J. Gerraty * install-mk (MK_VERSION): 20141111 * mkopt.sh: use consistent semantics for _mk_opt and _mk_opts 2014-11-09 Simon J. Gerraty * FILES: include mkopt.sh which allows handling options in shell scripts in a manner compatible with options.mk 2014-10-12 Simon J. Gerraty * meta.stage.mk: ensure only _STAGED_DIRS under objroot are used for GENDIRDEPS_FILTER to avoid surprises. 2014-10-10 Simon J. Gerraty * dirdeps.mk (NSkipHostDir): this needs SRCTOP prepended since by the time it is applied to __depdirs they have. * dirdeps.mk fix filtering of _machines since M_dep_qual_fixes expects patterns like *.${MACHINE} * cython.mk (pyprefix?): use pyprefix to find python bits since prefix might be something else (where we install our stuff) 2014-09-11 Simon J. Gerraty * install-mk (MK_VERSION): 20140911 * dirdeps.mk: add bootstrap target to simplify adding support for new MACHINE. 2014-09-01 Simon J. Gerraty * gendirdeps.mk: Add handling of GENDIRDEPS_FILTER_DIR_VARS and GENDIRDEPS_FILTER_VARS to make it easier to produce sharable Makefile.depend files. 2014-08-28 Simon J. Gerraty * install-mk (MK_VERSION): 20140828 * cython.mk: capture logic for building python extension modules with Cython. 2014-08-08 Simon J. Gerraty * meta.stage.mk (_STAGE_AS_BASENAME_USE): Add StageAs variant 2014-08-02 Simon J. Gerraty * install-mk (MK_VERSION): 20140801 * dep.mk: use explicit MKDEP_MK rather than overload MKDEP to identify the autodep.mk variant. * sys.dependfile.mk: delete .MAKE.DEPENDFILE if its initial value does not match .MAKE.DEPENDFILE_PREFIX * meta.autodep.mk: if _bootstrap_dirdeps add RELDIR to DIRDEPS 2014-05-22 Simon J. Gerraty * install-mk (MK_VERSION): 20140522 * lib.mk: use CC to link shlib for linux too patch from Brendan MacDonell 2014-05-05 Simon J. Gerraty * meta.autodep.mk: add _reldir_{finish,failed} for gathering stats if WITH_META_STATS is defined. 2014-05-02 Simon J. Gerraty * dirdeps.mk: accept -DWITHOUT_DIRDEPS (same a as -DNO_DIRDEPS) to supress dirdeps outside of .CURDIR. 2014-04-05 Simon J. Gerraty * Fix spelling errors - patch from Pedro Giffuni 2014-03-14 Simon J. Gerraty * install-mk (MK_VERSION): 20140314 * dirdeps.mk (beforedirdeps): a handy hook * dirdeps.mk (DIRDEP_MAKE): allow the actual command we run to visit leaf dirs to be intercepted (eg. for distributed build). * dirdeps.mk (__depdirs): ensure // don't sneak in * gendirdeps.mk (DIRDEPS): ensure // don't sneak in 2014-02-21 Simon J. Gerraty * rst2htm.mk (RST2PDF): add support for rst2pdf 2014-02-14 Simon J. Gerraty * install-mk (MK_VERSION): bump version * dirdeps.mk (_last_dependfile): use .INCLUDEDFROMFILE if available. 2014-02-10 Simon J. Gerraty * options.mk: avoid :U so this isn't bmake dependent 2014-02-09 Simon J. Gerraty * options.mk: cleanup and simplify semanitcs NO_* dominates all, if both WITH_* and WITHOUT_* are defined then result is DOMINATE_* which defaults to "no". Ie. WITHOUT_ normally wins. 2013-12-12 Simon J. Gerraty * install-mk (MK_VERSION): bump version * meta2deps.py: convert to print function for python3 compat. we also need to open files with mode 'r' rather than 'rb' otherwise we get bytes instead of strings. 2013-10-10 Simon J. Gerraty * install-mk (MK_VERSION): bump version * dirdeps.mk: when TARGET_SPEC_VARS is more than just MACHINE apply the same filtering (M_dep_qual_fixes) when setting _machines as _build_dirs. Also fix the filtering of Makefile.depend files - for reporting what we are looking for (M_dep_qual_fixes can get confused by Makefile.depend) Add some more debug info. 2013-09-04 Simon J. Gerraty * gendirdeps.mk (_objtops): fix typo also while processing M2D_OBJROOTS to gather qualdir_list qualify $ql with loop iterator to ensure correct results. 2013-08-01 Simon J. Gerraty * install-mk (MK_VERSION): 20130801 * libs.mk: update to match progs.mk 2013-07-26 Simon J. Gerraty * install-mk (MK_VERSION): 20130726 some updates from Juniper and FreeBSD o meta2deps.py: indicate file and line number when we hit parse errors also allow @file to provide huge list of .meta files. * meta2deps.py: add try_parse() to cleanup the above. 2013-07-16 Simon J. Gerraty * install-mk (MK_VERSION): 20130716 * own.mk: add GPROG as an option * prog.mk: honor MK_GPROF==yes 2013-05-10 Simon J. Gerraty * install-mk (MK_VERSION): 20130505 * gendirdeps.mk, meta2deps.py, meta2deps.sh: handle $TARGET_SPEC for when $MACHINE isn't enough for objdir distinction. Bring meta2deps.sh closer to par with meta2deps.py. 2013-04-18 Simon J. Gerraty * meta.stage.mk: set INSTALL to STAGE_INSTALL when making 'all' also if the target 'beforeinstall' exists, make it depend on .dirdep (incase it uses STAGE_INSTALL). 2013-04-17 Simon J. Gerraty * install-mk (MK_VERSION): 20130401 ;-) * meta.stage.mk (STAGE_INSTALL_SH): add stage-install.sh as wrapper around install(1). * options.mk (OPTION_PREFIX): Allow a prefix other than MK_ 2013-03-30 Simon J. Gerraty * meta2deps.py (MetaFile.__init__): ensure self.cwd is initialized. * install-mk (MK_VERSION): bump version 2013-03-21 Simon J. Gerraty * install-mk (MK_VERSION): bump version * gendirdeps.mk: do not apply :tA to DPADD entries, since we lose any trailing /., rather apply :tA only when needed. * gendirdeps.mk: better mimic meta2deps handling of .dirdep files. * meta.stage.mk (LN_CP_SCRIPT): Add LnCp to do the ln||cp dance consistently. * dirdeps.mk: better describe the dance in sys.mk for TARGET_SPEC. 2013-03-18 Simon J. Gerraty * gendirdeps.mk: revert the dance around .MAKE.DEPENDFILE_DEFAULT it is simpler to just not update when say building for "host" (where we know we apply filters to DIRDEPS), and using a non-machine qualified dependfile. 2013-03-16 Simon J. Gerraty * dirdeps.mk: improve DIRDEPS filtering by allowing DEP_SKIP_DIR and DEP_DIRDEPS_FILTER to vary by DEP_MACHINE and DEP_TARGET_SPEC * gendirdeps.mk: ensure _objroot has trailing / if it needs it. * meta2deps.py: if machine is "host", then also trim self.host_target from any OBJROOTS. 2013-03-11 Simon J. Gerraty * gendirdeps.mk: if .MAKE.DEPENDFILE_DEFAULT is not machine qualified but _DEPENDFILE is, and .MAKE.DEPENDFILE_DEFAULT exists but _DEPENDFILE does not, compare the new _DEPENDFILE against .MAKE.DEPENDFILE_DEFAULT and discard if the same. 2013-03-08 Simon J. Gerraty * meta.stage.mk: use STAGE_TARGETS to control .ORDER and hook to all: via staging: 2013-03-07 Simon J. Gerraty * sys.dependfile.mk (.MAKE.DEPENDFILE_DEFAULT): use a separate variable for the default .MAKE.DEPENDFILE value so that it can be controlled independently of .MAKE.DEPENDFILE_PREFERENCE * meta.stage.mk: throw error if cp fails etc. Stage*() return early if passed no args. .ORDER stage_* 2013-03-03 Simon J. Gerraty * install-mk (MK_VERSION): bump version * gendirdeps.mk: handle multiple M2D_OBJROOTS better. 2013-02-10 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20130210 * import latest dirdeps.mk, gendirdeps.mk and meta2deps.py from Juniper. o dirdeps.mk now fully supports TARGET_SPEC consisting of more than just MACHINE. o no longer use DEP_MACHINE from Makefile.depend* so remove it. 2013-01-23 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20130123 * meta.stage.mk: add stage_links (hard links). if doing hard links, we add dest to link as well. Default the stage dir for [sym]links to STAGE_OBJTOP since these are typically specified as absolute paths. Add -m "mode" flag to StageFiles and StageAs. 2012-11-11 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20121111 * autoconf.mk: avoid meta mode seeing changed commands for config.status * meta.autodep.mk: pass resolved MAKESYSPATH to gendirdeps in case we were found via .../mk * sys.clean-env.mk: move it from examples, we and others use it "as is". * FILES: add srctop.mk and options.mk * own.mk: convert to using options.mk which is modeled after FreeBSD's handling of MK_* but more flexible. This allows MK_* for boolean knobs to not be confused with MK* which can be commands. * examples/sys.clean-env.mk: add WITH[OUT]_ to MAKE_ENV_SAVE_PREFIX_LIST. Mention that HOME=/var/empty might be a good idea. 2012-11-08 Simon J. Gerraty * sys.dependfile.mk: if not depend file exists, $MACHINE specific ones are supported but not the default, check if any exist and follow suit. 2012-11-06 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20121106 2012-11-05 Simon J. Gerraty * import latest dirdeps.mk and meta2deps.py from Juniper. * progs.mk: add MAN and CXXFLAGS to PROG_VARS also add PROGS_TARGETS and pass on PROG_CXX if it seems appropriate. 2012-11-04 Simon J. Gerraty * meta.stage.mk: update CLEANFILES remove redundant cp of .dirdep from STAGE_AS_SCRIPT. * progs.mk: Add LDADD to PROG_VARS 2012-10-12 Simon J. Gerraty * meta.stage.mk (STAGE_DIR_FILTER): track dirs we stage to in _STAGED_DIRS so that these can be turned into filters for GENDIRDEPS_FILTER. 2012-10-10 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20121010 * meta.stage.mk (STAGE_DIRDEP_SCRIPT): check that an existing target.dirdep matches .dirdep 2012-08-08 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20120808 * import latest meta2deps.py from Juniper. 2012-07-11 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20120711 * dep.mk: add explicit dependencies on SRCS after applying SRCS_DEP_FILTER * meta.autodep.mk: add explicit dependencies on SRCS after applying SRCS_DEP_FILTER * meta.autodep.mk: ensure GENDIRDEPS_FILTER is exported if needed. 2012-06-26 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20120626 * meta.sys.mk: ignore PYTHON if it does not exist compare ${.MAKE.DEPENDFILE:E} against ${MACHINE} is more reliable. * meta.stage.mk: examine .MAKE.DEPENDFILE_PREFERENCE for any entries ending in .${MACHINE} to decide if qualified _dirdep is needed. * gendirdeps.mk: only produce unqualified deps if no .MAKE.DEPENDFILE_PREFERENCE ends in .${MACHINE} * meta.subdir.mk: apply SUBDIREPS_FILTER 2012-04-20 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20120420 * add sys.dependfile.mk so we can experiment with .MAKE.DEPENDFILE_PREFERENCE * meta.autodep.mk: _DEPENDFILE is precious! 2012-03-15 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20120315 * install-new.mk: avoid being interrupted 2012-02-26 Simon J. Gerraty * man.mk: MAN might have multiple values so be careful with exists(). 2012-01-19 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20120112 * fix examples/sys.clean-env.mk so that MAKEOBJDIR is handled as: MAKEOBJDIR='${.CURDIR:S,${SRCTOP},${OBJTOP},}' 2011-12-03 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20111201 * import dirdeps.mk from Juniper sjg@ o more consistent handling of DEP_MACHINE, especially when dealing with an odd Makefile.depend, when normally using Makefile.depend.${MACHINE} 2011-11-22 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20111122 * meta.autodep.mk: add some debug output, be more crisp about updating. Use ${.ALLTARGETS:M*.o} as a clue for .depend 2011-11-13 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20111111 it's too cool to miss * import meta* updates from Juniper sjg@ o dirdeps.mk set DEP_MACHINE for Makefile.depend (when we are normally using Makefile.depend.${MACHINE}), handy for read-only manually maintained dependencies. o meta2deps.py add a clear 'ERROR:' token if an exception is raised. o gendirdeps.mk if ERROR: from meta2deps.py do not update anything. 2011-10-30 Simon J. Gerraty * install-new.mk separate the cmp and copy logic to its own function. 2011-10-28 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20111028 * sys.mk: include auto.obj.mk if MKOBJDIRS is set to auto * subdir.mk: ensure _SUBDIRUSE is provided * meta.autodep.mk: remove dependency of gendirdeps.mk on auto.obj.mk * meta.subdir.mk: always allow for Makefile.depend 2011-10-10 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20111010 o minor tweak to *dirdeps.mk from Juniper sjg@ 2011-10-01 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20111001 o add meta2deps.py from Juniper sjg@ o tweak gendirdeps.mk to work with meta2deps.py when not cross-building * autoconf.mk: add autoconf-input as a hook for regenerating AUTOCONF_INPUTS (configure). 2011-08-24 Simon J. Gerraty * meta.autodep.mk: if we do not have OBJS, .depend isn't a useful trigger for updating Makefile.depend* 2011-08-08 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20110808 * obj.mk: minor cleanup * auto.obj.mk: improve description of Mkdirs and honor NO_OBJ too. 2011-08-01 Simon J. Gerraty * auto.obj.mk (.OBJDIR): throw an error if we cannot use the specified dir. 2011-06-28 Simon J. Gerraty * meta.autodep.mk: if XMAKE_META_FILE is set the makefile uses a foreign make, and so dependencies can only be gathered from a clean tree build. 2011-06-24 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20110622 * meta.autodep.mk: improve bootstraping 2011-06-10 Simon J. Gerraty * yacc.mk: handle the corner case of .c being removed while .h remains. 2011-06-08 Simon J. Gerraty * yacc.mk: do .y.h and .y.c separately 2011-06-04 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20110606 * don't store SRC_DIRDEPS in Makefile.depend* by default not everyone needs it. 2011-05-04 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20110505 first release including meta mode makefiles 2011-05-02 Simon J. Gerraty * meta.stage.mk: add STAGE_AS_SETS and stage_as for things that need to be staged with different names. 2011-05-01 Simon J. Gerraty * meta.stage.mk: add notion of STAGE_SETS so a makefile can stage to multiple dirs 2011-04-03 Simon J. Gerraty * rst2htm.mk: convert rst to s5 (slides) or plain html depending on target name. 2011-03-30 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20110330 2011-03-29 Simon J. Gerraty * sys.mk (_DEBUG_MAKE_FLAGS): use indirection so that DEBUG_MAKE_FLAGS0 can be used to debug level 0 only and DEBUG_MAKE_FLAGS for the rest. * sys.mk: re-define M_whence in terms of M_type. M_type is useful for checking if something is a builtin. 2011-03-16 Simon J. Gerraty * meta.stage.mk: add stage_symlinks and leverage StageLinks for stage_libs 2011-03-10 Simon J. Gerraty * dirdeps.mk: correct value for _depdir_files depends on .MAKE.DEPENDFILE Add our copyright - just to make it clear we have frobbed this quite a bit. DEP_MACHINE needs to be set to MACHINE each time, if using only Makefile.depend (cf. Makefile.depend.${MACHINE}) * meta.stage.mk: meta mode version of staging * init.mk, final.mk: include local.*.mk to simplify customization 2011-03-03 Simon J. Gerraty * auto.obj.mk: just because we are doing mk destroy, we should still set .OBJDIR correctly if it exists. * install-mk (mksrc): do not exclude meta.sys.mk 2011-03-01 Simon J. Gerraty * host-target.mk: set/export _HOST_ARCH etc separately, catch junk resulting from uname -p, so we can find sys/Linux.mk correctly. 2011-02-18 Simon J. Gerraty * meta.sys.mk: throw an error if /dev/filemon is missing and we expected to be updating Makefile.depend* 2011-02-14 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20110214 * meta.subdir.mk: add support for -DBOOTSTRAP_DEPENDFILES 2010-09-25 Simon J. Gerraty * meta.sys.mk: not valid for older bmake 2010-09-24 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20100919 include dirdeps.mk et al from Juniper Networks, for meta mode - requires filemon(9). * sys.mk, subdir.mk: Add hooks for meta mode. we do this as meta.sys.mk, meta.autodep.mk and meta.subdir.mk to make turning it on/off simple. 2010-06-16 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20100616 * fix typo in sys.mk 2010-06-12 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20100612 * lib.mk: remove duplicate addition to SOBJS 2010-06-10 Simon J. Gerraty * sys.mk: Add a means of selectively turning on debug flags. Eg. DEBUG_MAKE_FLAGS=-dv DEBUG_MAKE_DIRS="*lib/sjg" will act as if we did make -dv if .CURDIR ends in lib/sjg DEBUG_MAKE_SYS_DIRS does the same thing, but we set the flags at the start of sys.mk rather than the end. This only makes sense for leaf dirs, so we check that .MAKE.LEVEL > 0 2010-06-09 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20100608 * sys.mk: include sys.env.mk later so it can use M_ListToSkip et al. * examples/sys.clean-env.mk: require MAKE_VERIONS >= 20100606 also make it easier for folk to tweak 2010-06-08 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20100606 do not install examples/* * FILES: add examples/sys.clean-env.mk * examples/sys.clean-env.mk: use .export-env to handle MAKEOBJDIR this requires bmake-20100606 or later to work. 2010-05-13 Simon J. Gerraty * sys.mk (M_tA): better simulate the result of :tA if not available. 2010-05-04 Simon J. Gerraty * sys.mk: canonicalize MAKE_VERSION old versions reported bmake- build- whereas we only care about 2010-04-25 Simon J. Gerraty * install-mk: just warn about FORCE_{BSD,SYS}_MK being ignored * lib.mk: we only build the shared lib if SHLIB_FULLVERSION is !empty 2010-04-22 Simon J. Gerraty * dpadd.mk: use LDADD_* if defined. 2010-04-21 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20100420 * sys/NetBSD.mk: add MACHINE_CPU to keep netbsd makefiles happy * autoconf.mk allow AUTO_AUTOCONF 2010-04-19 Simon J. Gerraty * obj.mk: add objwarn to keep freebsd makefiles happy * auto.obj.mk: ensure Mkdirs is available. * FILES: add auto.dep.mk - a simpler version of autodep.mk * dep.mk: auto.dep.mk does not do 'make depend' so ignore it if asked to do that. fix/simplify the tests for when to run mkdep. * auto.dep.mk: add some explanation of how/what we do. * autodep.mk: skip the .OPTIONAL frobbing of .depend bmake's FROM_DEPEND flag makes it redundant. 2010-04-13 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20100404 * subdir.mk: protect from multiple inclusion using _SUBDIRUSE. * obj.mk: protect from multiple inclusion even as bsd.obj.mk Also create a target _SUBDIRUSE so that we can be used without subdir.mk 2010-04-12 Simon J. Gerraty * dep.mk: use <> when .including so can override. 2010-01-11 Simon J. Gerraty * lib.mk (SHLIB_LINKS): ensure a string comparison. 2010-01-04 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20100102 * own.mk: ensure PRINTOBJDIR works * autoconf.mk: pass on CONFIGURE_ARGS * init.mk: handle COPTS.${.IMPSRC:T} etc. * lib.mk: allow sys.mk to control SHLIB_FULLVERSION fix handling of symlinks for darwin * libnames.mk: add DSHLIBEXT for libs which only exist as shared. * man.mk: suppress chown when not root. * rst2htm.mk: allow srcs from multiple locations. * sys.mk: M_whence, stop after 1st line of output. * sys/Darwin.mk: Use .dylib for DSHLIBEXT and HOST_LIBEXT * sys/SunOS.mk: we need to export PATH 2009-12-23 Simon J. Gerraty * install-mk (MK_VERSION): bump version include rst2htm.mk 2009-12-17 Simon J. Gerraty * sys.mk,libnames.mk add .-include this allows local customization without the need to edit the distributed files. 2009-12-14 Simon J. Gerraty * dpadd.mk (__dpadd_libdirs): order -L's to avoid picking up older versions already installed. 2009-12-13 Simon J. Gerraty * stage.mk (.stage-install): generalize lib.mk's .libinstall * rules.mk rules for generic Makefile. * inc.mk install for includes. 2009-12-11 Simon J. Gerraty * sys/NetBSD.mk (MAKE_VERSION): some of our *.mk want to check this, so provide it if using native make. 2009-12-10 Simon J. Gerraty * FILES: move all the platform *.sys.mk files to sys/*.mk * Rename Generic.sys.mk to sys.mk - we always want it. 2009-11-17 Simon J. Gerraty * install-mk (MK_VERSION): bump version * host-target.mk: only export the expensive stuff * Generic.sys.mk (sys_mk): for SunOS we need to look for ${HOST_OS}.${HOST_OSMAJOR} too! 2009-11-07 Simon J. Gerraty * install-mk (MK_VERSION): bump version * lib.mk: if sys.mk doesn't give us an lorder, don't use it. based on patch from Greg Olszewski. * Generic.sys.mk: if we have nothing to work with set LORDER etc only if we can find it. 2009-09-08 Simon J. Gerraty * install-mk (MK_VERSION): bump version * man.mk: cleanman: remove CLEANMAN if defined. 2009-09-04 Simon J. Gerraty * SunOS.5.sys.mk (CC): Use ?= like the other *sys.mk 2009-07-17 Simon J. Gerraty * install-mk (MK_VERSION): bump version include auto.obj.mk 2009-03-26 Simon J. Gerraty * prog.mk,lib.mk: ensure test of USE_DPADD_MK doesn't fail. 2008-11-11 Simon J. Gerraty * install-mk (MK_VERSION): bump version man.mk: ensure we generate *.cat1 etc in . 2008-07-16 Simon J. Gerraty * install-mk (MK_VERSION): bump version add prlist.mk 2007-11-25 Simon J. Gerraty * Generic.sys.mk: Allow os specific sys.mk to be in a subdir of ${.PARSEDIR} 2007-11-22 Simon J. Gerraty * install-mk (MK_VERSION): bump version * general cleanup * dpadd.mk introduce DPMAGIC_LIBS_* 2007-04-30 Simon J. Gerraty * install-mk (MK_VERSION): bump version * libs.mk, progs.mk, autodep.mk: allow for per lib/prog depend files and ensure clean is called for each lib/prog. 2007-03-27 Simon J. Gerraty * autodep.mk (.depend): delete lines that do not start with space and do not contain ':' 2007-02-16 Simon J. Gerraty * autodep.mk (.depend): gcc may wrap lines if pathnames are long so make sure the transform for .OPTIONAL copes. 2007-02-03 Simon J. Gerraty * install-mk (MK_VERSION): bump version * own.mk: make sure RM and LN are defined. * obj.mk: fix a typo, and objlink target. 2006-12-30 Simon J. Gerraty * install-mk (MK_VERSION): bump version * added libs.mk - analogous to progs.mk make both of them always inlcude {lib,prog}.mk 2006-12-28 Simon J. Gerraty * progs.mk: add a means of building multiple apps in one dir. 2006-11-26 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20061126 * warnings.mk: detect invalid WARNINGS_SET * warnings.mk: use ${.TARGET:T:R}.o when looking for target specific warnings. * For .cc sources, turn off warnings that g++ vomits on. 2006-11-08 Simon J. Gerraty * own.mk: if __initialized__ target doesn't exist and we are FreeBSD we got here directly from sys.mk 2006-11-06 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20061106 add scripts.mk 2006-03-18 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20060318 * autodep.mk: avoid := when modifying OBJS into __dependsrcs 2006-03-02 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20060302 * autodep.mk: use -MF et al to help gcc+ccache DTRT. 2006-03-01 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20060301 * autodep.mk (.depend): if MAKE_VERSION is newer than 20050530 we can make .END depend on .depend and make .depend depend on __depsrcs that exist. * dpadd.mk: add SRC_PATHADD 2005-11-04 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20051104 * prog.mk: remove all the LIBC?= junk, use .-include libnames.mk instead (none by default). also if USE_DPADD_MK is set, include that. 2005-10-09 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20051001 Add UnixWare.sys.mk from Klaus Heinz. 2005-04-05 Simon J. Gerraty * install-mk: always install *.sys.mk and if need be symlink one to sys.mk 2005-03-22 Simon J. Gerraty * subdir.mk, own.mk: use .MAKE rather than MAKE 2004-02-15 Simon J. Gerraty * own.mk: don't use NetBSD's _SRC_TOP_ it can cause confusion. Also don't take just 'mk' as a srctop indicator. 2004-02-14 Simon J. Gerraty * warnings.mk: overhauled, now very powerful. 2004-02-03 Simon J. Gerraty * Generic.sys.mk: need to use ${.PARSEDIR} with exists(). 2004-02-01 Simon J. Gerraty * install-mk (MK_VERSION): bump version to 20040201 * extract HOST_TARGET stuff to host-target.mk so own.mk and Generic.sys.mk can share. * fix typo in autodep.mk _SUBDIRUSE not _SUBDIR. 2003-09-30 Simon J. Gerraty * install-mk (MK_VERSION): 20030930 * rename generic.sys.mk to Generic.sys.mk so that it does not get installed (unless being used as sys.mk) * set OS and ROOT_GROUP for those that we know the value. for others (eg. Generic.sys.mk) wrap the != in an .ifndef so we don't do it again for each sub-make. 2003-09-28 Simon J. Gerraty * install-mk (MK_VERSION): 20030928 Add some extra *.sys.mk from bootstrap-pkgsrc some of these likely still need work. Make everything default to root:wheel ownership, sys.mk can set ROOT_GROUP accordingly. 2003-08-07 Simon J. Gerraty * install-mk: if FORCE_BSD_MK={cp,ln} use the ones in SYS_MK_DIR not the portable ones. 2003-07-31 Simon J. Gerraty * install-mk: add ability to use cp -f when updating destination .mk files. Also now possible to play games with FORCE_SYS_MK=ln etc on *BSD machines to link /usr/share/mk/sys.mk into dest - not recommended unless you seriously want to. 2003-07-28 Simon J. Gerraty * own.mk (IMPFLAGS): add support for COPTS.${IMPSRC:T} etc for semi-compatability with NetBSD. 2003-07-23 Simon J. Gerraty * install-mk: add a version indicator 2003-07-22 Simon J. Gerraty * prog.mk: don't try and use ${LIBCRT0} if its /dev/null * install-mk: Allow FORCE_SYS_MK to come from env Index: vendor/NetBSD/bmake/dist/mk/dirdeps.mk =================================================================== --- vendor/NetBSD/bmake/dist/mk/dirdeps.mk (revision 282731) +++ vendor/NetBSD/bmake/dist/mk/dirdeps.mk (revision 282732) @@ -1,642 +1,643 @@ -# $Id: dirdeps.mk,v 1.49 2015/03/11 21:39:28 sjg Exp $ +# $Id: dirdeps.mk,v 1.51 2015/05/06 06:07:30 sjg Exp $ # Copyright (c) 2010-2013, Juniper Networks, Inc. # 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 THE COPYRIGHT HOLDERS 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 COPYRIGHT # OWNER 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. # Much of the complexity here is for supporting cross-building. # If a tree does not support that, simply using plain Makefile.depend # should provide sufficient clue. # Otherwise the recommendation is to use Makefile.depend.${MACHINE} # as expected below. # Note: this file gets multiply included. # This is what we do with DIRDEPS # DIRDEPS: # This is a list of directories - relative to SRCTOP, it is # normally only of interest to .MAKE.LEVEL 0. # In some cases the entry may be qualified with a . # or . suffix (see TARGET_SPEC_VARS below), # for example to force building something for the pseudo # machines "host" or "common" regardless of current ${MACHINE}. # # All unqualified entries end up being qualified with .${TARGET_SPEC} # and partially qualified (if TARGET_SPEC_VARS has multiple # entries) are also expanded to a full .. # The _DIRDEP_USE target uses the suffix to set TARGET_SPEC # correctly when visiting each entry. # # The fully qualified directory entries are used to construct a # dependency graph that will drive the build later. # # Also, for each fully qualified directory target, we will search # using ${.MAKE.DEPENDFILE_PREFERENCE} to find additional # dependencies. We use Makefile.depend (default value for # .MAKE.DEPENDFILE_PREFIX) to refer to these makefiles to # distinguish them from others. # # Each Makefile.depend file sets DEP_RELDIR to be the # the RELDIR (path relative to SRCTOP) for its directory, and # since each Makefile.depend file includes dirdeps.mk, this # processing is recursive and results in .MAKE.LEVEL 0 learning the # dependencies of the tree wrt the initial directory (_DEP_RELDIR). # # BUILD_AT_LEVEL0 # Indicates whether .MAKE.LEVEL 0 builds anything: # if "no" sub-makes are used to build everything, # if "yes" sub-makes are only used to build for other machines. # It is best to use "no", but this can require fixing some # makefiles to not do anything at .MAKE.LEVEL 0. # # TARGET_SPEC_VARS # The default value is just MACHINE, and for most environments # this is sufficient. The _DIRDEP_USE target actually sets # both MACHINE and TARGET_SPEC to the suffix of the current # target so that in the general case TARGET_SPEC can be ignored. # # If more than MACHINE is needed then sys.mk needs to decompose # TARGET_SPEC and set the relevant variables accordingly. # It is important that MACHINE be included in and actually be # the first member of TARGET_SPEC_VARS. This allows other # variables to be considered optional, and some of the treatment # below relies on MACHINE being the first entry. # Note: TARGET_SPEC cannot contain any '.'s so the target # triple used by compiler folk won't work (directly anyway). # # For example: # # # Always list MACHINE first, # # other variables might be optional. # TARGET_SPEC_VARS = MACHINE TARGET_OS # .if ${TARGET_SPEC:Uno:M*,*} != "" # _tspec := ${TARGET_SPEC:S/,/ /g} # MACHINE := ${_tspec:[1]} # TARGET_OS := ${_tspec:[2]} # # etc. # # We need to stop that TARGET_SPEC affecting any submakes # # and deal with MACHINE=${TARGET_SPEC} in the environment. # TARGET_SPEC = # # export but do not track # .export-env TARGET_SPEC # .export ${TARGET_SPEC_VARS} # .for v in ${TARGET_SPEC_VARS:O:u} # .if empty($v) # .undef $v # .endif # .endfor # .endif # # make sure we know what TARGET_SPEC is # # as we may need it to find Makefile.depend* # TARGET_SPEC = ${TARGET_SPEC_VARS:@v@${$v:U}@:ts,} # # touch this at your peril _DIRDEP_USE_LEVEL?= 0 .if ${.MAKE.LEVEL} == ${_DIRDEP_USE_LEVEL} # only the first instance is interested in all this # First off, we want to know what ${MACHINE} to build for. # This can be complicated if we are using a mixture of ${MACHINE} specific # and non-specific Makefile.depend* .if !target(_DIRDEP_USE) # do some setup we only need once _CURDIR ?= ${.CURDIR} _OBJDIR ?= ${.OBJDIR} now_utc = ${%s:L:gmtime} .if !defined(start_utc) start_utc := ${now_utc} .endif # make sure these are empty to start with _DEP_TARGET_SPEC = _DIRDEP_CHECKED = # If TARGET_SPEC_VARS is other than just MACHINE # it should be set by sys.mk or similar by now. # TARGET_SPEC must not contain any '.'s. TARGET_SPEC_VARS ?= MACHINE # this is what we started with TARGET_SPEC = ${TARGET_SPEC_VARS:@v@${$v:U}@:ts,} # this is what we mostly use below DEP_TARGET_SPEC = ${TARGET_SPEC_VARS:S,^,DEP_,:@v@${$v:U}@:ts,} # make sure we have defaults .for v in ${TARGET_SPEC_VARS} DEP_$v ?= ${$v} .endfor .if ${TARGET_SPEC_VARS:[#]} > 1 # Ok, this gets more complex (putting it mildly). # In order to stay sane, we need to ensure that all the build_dirs # we compute below are fully qualified wrt DEP_TARGET_SPEC. # The makefiles may only partially specify (eg. MACHINE only), # so we need to construct a set of modifiers to fill in the gaps. # jot 10 should output 1 2 3 .. 10 JOT ?= jot _tspec_x := ${${JOT} ${TARGET_SPEC_VARS:[#]}:L:sh} # this handles unqualified entries M_dep_qual_fixes = C;(/[^/.,]+)$$;\1.$${DEP_TARGET_SPEC}; # there needs to be at least one item missing for these to make sense .for i in ${_tspec_x:[2..-1]} _tspec_m$i := ${TARGET_SPEC_VARS:[2..$i]:@w@[^,]+@:ts,} _tspec_a$i := ,${TARGET_SPEC_VARS:[$i..-1]:@v@$$$${DEP_$v}@:ts,} M_dep_qual_fixes += C;(\.${_tspec_m$i})$$;\1${_tspec_a$i}; .endfor .else # A harmless? default. M_dep_qual_fixes = U .endif .if !defined(.MAKE.DEPENDFILE_PREFERENCE) # .MAKE.DEPENDFILE_PREFERENCE makes the logic below neater? # you really want this set by sys.mk or similar .MAKE.DEPENDFILE_PREFERENCE = ${_CURDIR}/${.MAKE.DEPENDFILE:T} .if ${.MAKE.DEPENDFILE:E} == "${TARGET_SPEC}" .if ${TARGET_SPEC} != ${MACHINE} .MAKE.DEPENDFILE_PREFERENCE += ${_CURDIR}/${.MAKE.DEPENDFILE:T:R}.$${MACHINE} .endif .MAKE.DEPENDFILE_PREFERENCE += ${_CURDIR}/${.MAKE.DEPENDFILE:T:R} .endif .endif _default_dependfile := ${.MAKE.DEPENDFILE_PREFERENCE:[1]:T} _machine_dependfiles := ${.MAKE.DEPENDFILE_PREFERENCE:T:M*${MACHINE}*} # for machine specific dependfiles we require ${MACHINE} to be at the end # also for the sake of sanity we require a common prefix .if !defined(.MAKE.DEPENDFILE_PREFIX) # knowing .MAKE.DEPENDFILE_PREFIX helps .if !empty(_machine_dependfiles) .MAKE.DEPENDFILE_PREFIX := ${_machine_dependfiles:[1]:T:R} .else .MAKE.DEPENDFILE_PREFIX := ${_default_dependfile:T} .endif .endif # this is how we identify non-machine specific dependfiles N_notmachine := ${.MAKE.DEPENDFILE_PREFERENCE:E:N*${MACHINE}*:${M_ListToSkip}} .endif # !target(_DIRDEP_USE) # if we were included recursively _DEP_TARGET_SPEC should be valid. .if empty(_DEP_TARGET_SPEC) # we may or may not have included a dependfile yet .if defined(.INCLUDEDFROMFILE) _last_dependfile := ${.INCLUDEDFROMFILE:M${.MAKE.DEPENDFILE_PREFIX}*} .else _last_dependfile := ${.MAKE.MAKEFILES:M*/${.MAKE.DEPENDFILE_PREFIX}*:[-1]} .endif .if ${_debug_reldir:U0} .info ${DEP_RELDIR}.${DEP_TARGET_SPEC}: _last_dependfile='${_last_dependfile}' .endif .if empty(_last_dependfile) || ${_last_dependfile:E:${N_notmachine}} == "" # this is all we have to work with DEP_MACHINE = ${TARGET_MACHINE:U${MACHINE}} _DEP_TARGET_SPEC := ${DEP_TARGET_SPEC} .else _DEP_TARGET_SPEC = ${_last_dependfile:${M_dep_qual_fixes:ts:}:E} .endif .if !empty(_last_dependfile) # record that we've read dependfile for this _DIRDEP_CHECKED += ${_CURDIR}.${TARGET_SPEC} .endif .endif # by now _DEP_TARGET_SPEC should be set, parse it. .if ${TARGET_SPEC_VARS:[#]} > 1 # we need to parse DEP_MACHINE may or may not contain more info _tspec := ${_DEP_TARGET_SPEC:S/,/ /g} .for i in ${_tspec_x} DEP_${TARGET_SPEC_VARS:[$i]} := ${_tspec:[$i]} .endfor .for v in ${TARGET_SPEC_VARS:O:u} .if empty(DEP_$v) .undef DEP_$v .endif .endfor .else DEP_MACHINE := ${_DEP_TARGET_SPEC} .endif # pickup customizations # as below you can use !target(_DIRDEP_USE) to protect things # which should only be done once. .-include "local.dirdeps.mk" # the first time we are included the _DIRDEP_USE target will not be defined # we can use this as a clue to do initialization and other one time things. .if !target(_DIRDEP_USE) # make sure this target exists dirdeps: beforedirdeps .WAIT beforedirdeps: # We normally expect to be included by Makefile.depend.* # which sets the DEP_* macros below. DEP_RELDIR ?= ${RELDIR} # this can cause lots of output! # set to a set of glob expressions that might match RELDIR DEBUG_DIRDEPS ?= no # remember the initial value of DEP_RELDIR - we test for it below. _DEP_RELDIR := ${DEP_RELDIR} # things we skip for host tools SKIP_HOSTDIR ?= NSkipHostDir = ${SKIP_HOSTDIR:N*.host*:S,$,.host*,:N.host*:S,^,${SRCTOP}/,:${M_ListToSkip}} # things we always skip # SKIP_DIRDEPS allows for adding entries on command line. SKIP_DIR += .host *.WAIT ${SKIP_DIRDEPS} SKIP_DIR.host += ${SKIP_HOSTDIR} DEP_SKIP_DIR = ${SKIP_DIR} \ ${SKIP_DIR.${DEP_TARGET_SPEC}:U} \ ${SKIP_DIR.${DEP_MACHINE}:U} \ ${SKIP_DIRDEPS.${DEP_MACHINE}:U} NSkipDir = ${DEP_SKIP_DIR:${M_ListToSkip}} .if defined(NO_DIRDEPS) || defined(NODIRDEPS) || defined(WITHOUT_DIRDEPS) # confine ourselves to the original dir DIRDEPS_FILTER += M${_DEP_RELDIR}* .endif # this is what we run below DIRDEP_MAKE?= ${.MAKE} # we suppress SUBDIR when visiting the leaves # we assume sys.mk will set MACHINE_ARCH # you can add extras to DIRDEP_USE_ENV # if there is no makefile in the target directory, we skip it. _DIRDEP_USE: .USE .MAKE @for m in ${.MAKE.MAKEFILE_PREFERENCE}; do \ test -s ${.TARGET:R}/$$m || continue; \ echo "${TRACER}Checking ${.TARGET:R} for ${.TARGET:E} ..."; \ MACHINE_ARCH= NO_SUBDIR=1 ${DIRDEP_USE_ENV} \ TARGET_SPEC=${.TARGET:E} \ MACHINE=${.TARGET:E} \ ${DIRDEP_MAKE} -C ${.TARGET:R} || exit 1; \ break; \ done .ifdef ALL_MACHINES # this is how you limit it to only the machines we have been built for # previously. .if empty(ONLY_MACHINE_LIST) .if !empty(ALL_MACHINE_LIST) # ALL_MACHINE_LIST is the list of all legal machines - ignore anything else _machine_list != cd ${_CURDIR} && 'ls' -1 ${ALL_MACHINE_LIST:O:u:@m@${.MAKE.DEPENDFILE:T:R}.$m@} 2> /dev/null; echo .else _machine_list != 'ls' -1 ${_CURDIR}/${.MAKE.DEPENDFILE_PREFIX}.* 2> /dev/null; echo .endif _only_machines := ${_machine_list:${NIgnoreFiles:UN*.bak}:E:O:u} .else _only_machines := ${ONLY_MACHINE_LIST} .endif .if empty(_only_machines) # we must be boot-strapping _only_machines := ${TARGET_MACHINE:U${ALL_MACHINE_LIST:U${DEP_MACHINE}}} .endif .else # ! ALL_MACHINES # if ONLY_MACHINE_LIST is set, we are limited to that # if TARGET_MACHINE is set - it is really the same as ONLY_MACHINE_LIST # otherwise DEP_MACHINE is it - so DEP_MACHINE will match. _only_machines := ${ONLY_MACHINE_LIST:U${TARGET_MACHINE:U${DEP_MACHINE}}:M${DEP_MACHINE}} .endif .if !empty(NOT_MACHINE_LIST) _only_machines := ${_only_machines:${NOT_MACHINE_LIST:${M_ListToSkip}}} .endif # make sure we have a starting place? DIRDEPS ?= ${RELDIR} .endif # target # if repeatedly building the same target, # we can avoid the overhead of re-computing the tree dependencies. MK_DIRDEPS_CACHE ?= no BUILD_DIRDEPS_CACHE ?= no BUILD_DIRDEPS ?= yes .if !defined(NO_DIRDEPS) .if ${MK_DIRDEPS_CACHE} == "yes" # this is where we will cache all our work -DIRDEPS_CACHE?= ${_OBJDIR}/dirdeps.cache${.TARGETS:Nall:O:u:ts-:S,^,.,:N.} +DIRDEPS_CACHE?= ${_OBJDIR}/dirdeps.cache${.TARGETS:Nall:O:u:ts-:S,/,_,g:S,^,.,:N.} # just ensure this exists build-dirdeps: M_oneperline = @x@\\${.newline} $$x@ .if ${BUILD_DIRDEPS_CACHE} == "no" .if !target(dirdeps-cached) # we do this via sub-make BUILD_DIRDEPS = no dirdeps: dirdeps-cached dirdeps-cached: ${DIRDEPS_CACHE} .MAKE @echo "${TRACER}Using ${DIRDEPS_CACHE}" @MAKELEVEL=${.MAKE.LEVEL} ${.MAKE} -C ${_CURDIR} -f ${DIRDEPS_CACHE} \ dirdeps MK_DIRDEPS_CACHE=no BUILD_DIRDEPS=no # these should generally do BUILD_DIRDEPS_MAKEFILE ?= ${MAKEFILE} BUILD_DIRDEPS_TARGETS ?= ${.TARGETS} # we need the .meta file to ensure we update if # any of the Makefile.depend* changed. # We do not want to compare the command line though. ${DIRDEPS_CACHE}: .META .NOMETA_CMP +@{ echo '# Autogenerated - do NOT edit!'; echo; \ echo 'BUILD_DIRDEPS=no'; echo; \ echo '.include '; \ } > ${.TARGET}.new +@MAKELEVEL=${.MAKE.LEVEL} DIRDEPS_CACHE=${DIRDEPS_CACHE} \ DIRDEPS="${DIRDEPS}" \ MAKEFLAGS= ${.MAKE} -C ${_CURDIR} -f ${BUILD_DIRDEPS_MAKEFILE} \ ${BUILD_DIRDEPS_TARGETS} BUILD_DIRDEPS_CACHE=yes \ 3>&1 1>&2 | sed 's,${SRCTOP},$${SRCTOP},g' >> ${.TARGET}.new && \ mv ${.TARGET}.new ${.TARGET} .endif .elif !target(_count_dirdeps) # we want to capture the dirdeps count in the cache .END: _count_dirdeps _count_dirdeps: .NOMETA @echo '.info $${.newline}$${TRACER}Makefiles read: total=${.MAKE.MAKEFILES:[#]} depend=${.MAKE.MAKEFILES:M*depend*:[#]} dirdeps=${.ALLTARGETS:M${SRCTOP}*:O:u:[#]}' >&3 .endif -.endif -.elif !target(_count_dirdeps) +.elif !make(dirdeps) && !target(_count_dirdeps) beforedirdeps: _count_dirdeps _count_dirdeps: .NOMETA @echo "${TRACER}Makefiles read: total=${.MAKE.MAKEFILES:[#]} depend=${.MAKE.MAKEFILES:M*depend*:[#]} dirdeps=${.ALLTARGETS:M${SRCTOP}*:O:u:[#]} seconds=`expr ${now_utc} - ${start_utc}`" .endif +.endif + .if ${BUILD_DIRDEPS} == "yes" .if ${DEBUG_DIRDEPS:@x@${DEP_RELDIR:M$x}${${DEP_RELDIR}.${DEP_MACHINE}:L:M$x}@} != "" _debug_reldir = 1 .else _debug_reldir = 0 .endif .if ${DEBUG_DIRDEPS:@x@${DEP_RELDIR:M$x}${${DEP_RELDIR}.depend:L:M$x}@} != "" _debug_search = 1 .else _debug_search = 0 .endif # the rest is done repeatedly for every Makefile.depend we read. # if we are anything but the original dir we care only about the # machine type we were included for.. .if ${DEP_RELDIR} == "." _this_dir := ${SRCTOP} .else _this_dir := ${SRCTOP}/${DEP_RELDIR} .endif # on rare occasions, there can be a need for extra help _dep_hack := ${_this_dir}/${.MAKE.DEPENDFILE_PREFIX}.inc .-include "${_dep_hack}" .if ${DEP_RELDIR} != ${_DEP_RELDIR} || ${DEP_TARGET_SPEC} != ${TARGET_SPEC} # this should be all _machines := ${DEP_MACHINE} .else # this is the machine list we actually use below _machines := ${_only_machines} .if defined(HOSTPROG) || ${DEP_MACHINE} == "host" # we need to build this guy's dependencies for host as well. _machines += host .endif _machines := ${_machines:O:u} .endif .if ${TARGET_SPEC_VARS:[#]} > 1 # we need to tweak _machines _dm := ${DEP_MACHINE} # apply the same filtering that we do when qualifying DIRDEPS. # M_dep_qual_fixes expects .${MACHINE}* so add (and remove) '.' _machines := ${_machines:@DEP_MACHINE@${DEP_TARGET_SPEC}@:S,^,.,:${M_dep_qual_fixes:ts:}:O:u:S,^.,,} DEP_MACHINE := ${_dm} .endif # reset each time through _build_dirs = .if ${DEP_RELDIR} == ${_DEP_RELDIR} # pickup other machines for this dir if necessary .if ${BUILD_AT_LEVEL0:Uyes} == "no" _build_dirs += ${_machines:@m@${_CURDIR}.$m@} .else _build_dirs += ${_machines:N${DEP_TARGET_SPEC}:@m@${_CURDIR}.$m@} .if ${DEP_TARGET_SPEC} == ${TARGET_SPEC} # pickup local dependencies now .-include <.depend> .endif .endif .endif .if ${_debug_reldir} .info ${DEP_RELDIR}.${DEP_TARGET_SPEC}: DIRDEPS='${DIRDEPS}' .info ${DEP_RELDIR}.${DEP_TARGET_SPEC}: _machines='${_machines}' .endif .if !empty(DIRDEPS) # these we reset each time through as they can depend on DEP_MACHINE DEP_DIRDEPS_FILTER = \ ${DIRDEPS_FILTER.${DEP_TARGET_SPEC}:U} \ ${DIRDEPS_FILTER.${DEP_MACHINE}:U} \ ${DIRDEPS_FILTER:U} .if empty(DEP_DIRDEPS_FILTER) # something harmless DEP_DIRDEPS_FILTER = U .endif # this is what we start with __depdirs := ${DIRDEPS:${NSkipDir}:${DEP_DIRDEPS_FILTER:ts:}:C,//+,/,g:O:u:@d@${SRCTOP}/$d@} # some entries may be qualified with . # the :M*/*/*.* just tries to limit the dirs we check to likely ones. # the ${d:E:M*/*} ensures we don't consider junos/usr.sbin/mgd __qual_depdirs := ${__depdirs:M*/*/*.*:@d@${exists($d):?:${"${d:E:M*/*}":?:${exists(${d:R}):?$d:}}}@} __unqual_depdirs := ${__depdirs:${__qual_depdirs:Uno:${M_ListToSkip}}} .if ${DEP_RELDIR} == ${_DEP_RELDIR} # if it was called out - we likely need it. __hostdpadd := ${DPADD:U.:M${HOST_OBJTOP}/*:S,${HOST_OBJTOP}/,,:H:${NSkipDir}:${DIRDEPS_FILTER:ts:}:S,$,.host,:N.*:@d@${SRCTOP}/$d@} __qual_depdirs += ${__hostdpadd} .endif .if ${_debug_reldir} .info depdirs=${__depdirs} .info qualified=${__qual_depdirs} .info unqualified=${__unqual_depdirs} .endif # _build_dirs is what we will feed to _DIRDEP_USE _build_dirs += \ ${__qual_depdirs:M*.host:${NSkipHostDir}:N.host} \ ${__qual_depdirs:N*.host} \ ${_machines:Mhost*:@m@${__unqual_depdirs:@d@$d.$m@}@:${NSkipHostDir}:N.host} \ ${_machines:Nhost*:@m@${__unqual_depdirs:@d@$d.$m@}@} # qualify everything now _build_dirs := ${_build_dirs:${M_dep_qual_fixes:ts:}:O:u} .endif # empty DIRDEPS # Normally if doing make -V something, # we do not want to waste time chasing DIRDEPS # but if we want to count the number of Makefile.depend* read, we do. .if ${.MAKEFLAGS:M-V${_V_READ_DIRDEPS}} == "" .if !empty(_build_dirs) .if ${BUILD_DIRDEPS_CACHE} == "yes" x!= { echo; echo '\# ${DEP_RELDIR}.${DEP_TARGET_SPEC}'; \ echo 'dirdeps: ${_build_dirs:${M_oneperline}}'; echo; } >&3; echo x!= { ${_build_dirs:@x@${target($x):?:echo '$x: _DIRDEP_USE';}@} echo; } >&3; echo .else # this makes it all happen dirdeps: ${_build_dirs} .endif ${_build_dirs}: _DIRDEP_USE .if ${_debug_reldir} .info ${DEP_RELDIR}.${DEP_TARGET_SPEC}: needs: ${_build_dirs} .endif # this builds the dependency graph .for m in ${_machines} # it would be nice to do :N${.TARGET} .if !empty(__qual_depdirs) .for q in ${__qual_depdirs:${M_dep_qual_fixes:ts:}:E:O:u:N$m} .if ${_debug_reldir} || ${DEBUG_DIRDEPS:@x@${${DEP_RELDIR}.$m:L:M$x}${${DEP_RELDIR}.$q:L:M$x}@} != "" .info ${DEP_RELDIR}.$m: graph: ${_build_dirs:M*.$q} .endif .if ${BUILD_DIRDEPS_CACHE} == "yes" x!= { echo; echo '${_this_dir}.$m: ${_build_dirs:M*.$q:${M_oneperline}}'; echo; } >&3; echo .else ${_this_dir}.$m: ${_build_dirs:M*.$q} .endif .endfor .endif .if ${_debug_reldir} .info ${DEP_RELDIR}.$m: graph: ${_build_dirs:M*.$m:N${_this_dir}.$m} .endif .if ${BUILD_DIRDEPS_CACHE} == "yes" x!= { echo; echo '${_this_dir}.$m: ${_build_dirs:M*.$m:N${_this_dir}.$m:${M_oneperline}}'; echo; } >&3; echo .else ${_this_dir}.$m: ${_build_dirs:M*.$m:N${_this_dir}.$m} .endif .endfor .endif # Now find more dependencies - and recurse. .for d in ${_build_dirs} .if ${_DIRDEP_CHECKED:M$d} == "" # once only _DIRDEP_CHECKED += $d .if ${_debug_search} .info checking $d .endif # Note: _build_dirs is fully qualifed so d:R is always the directory .if exists(${d:R}) # Warning: there is an assumption here that MACHINE is always # the first entry in TARGET_SPEC_VARS. # If TARGET_SPEC and MACHINE are insufficient, you have a problem. _m := ${.MAKE.DEPENDFILE_PREFERENCE:T:S;${TARGET_SPEC}$;${d:E};:S;${MACHINE};${d:E:C/,.*//};:@m@${exists(${d:R}/$m):?${d:R}/$m:}@:[1]} .if !empty(_m) # M_dep_qual_fixes isn't geared to Makefile.depend _qm := ${_m:C;(\.depend)$;\1.${d:E};:${M_dep_qual_fixes:ts:}} .if ${_debug_search} .info Looking for ${_qm} .endif # we pass _DEP_TARGET_SPEC to tell the next step what we want _DEP_TARGET_SPEC := ${d:E} # some makefiles may still look at this _DEP_MACHINE := ${d:E:C/,.*//} .if ${_debug_reldir} && ${_qm} != ${_m} .info loading ${_m} for ${d:E} .endif .include <${_m}> .endif .endif .endif .endfor .endif # -V .endif # BUILD_DIRDEPS .elif ${.MAKE.LEVEL} > 42 .error You should have stopped recursing by now. .else _DEP_RELDIR := ${DEP_RELDIR} # pickup local dependencies .-include <.depend> .endif # bootstrapping new dependencies made easy? .if make(bootstrap*) && !target(bootstrap) .if exists(${.CURDIR}/${.MAKE.DEPENDFILE:T}) # stop here ${.TARGETS:Mboot*}: .else # find a Makefile.depend to use as _src _src != cd ${.CURDIR} && for m in ${.MAKE.DEPENDFILE_PREFERENCE:T:S,${MACHINE},*,}; do test -s $$m || continue; echo $$m; break; done; echo .if empty(_src) .error cannot find any of ${.MAKE.DEPENDFILE_PREFERENCE:T} .endif _src?= ${.MAKE.DEPENDFILE:T} bootstrap-this: .NOTMAIN @echo Bootstrapping ${RELDIR}/${.MAKE.DEPENDFILE:T} from ${_src:T} (cd ${.CURDIR} && sed 's,${_src:E},${MACHINE},g' ${_src} > ${.MAKE.DEPENDFILE:T}) bootstrap: bootstrap-recurse bootstrap-recurse: bootstrap-this _mf := ${.PARSEFILE} bootstrap-recurse: .NOTMAIN .MAKE @cd ${SRCTOP} && \ for d in `cd ${RELDIR} && ${.MAKE} -B -f ${"${.MAKEFLAGS:M-n}":?${_src}:${.MAKE.DEPENDFILE:T}} -V DIRDEPS`; do \ test -d $$d || d=$${d%.*}; \ test -d $$d || continue; \ echo "Checking $$d for bootstrap ..."; \ (cd $$d && ${.MAKE} -f ${_mf} bootstrap-recurse); \ done .endif .endif Index: vendor/NetBSD/bmake/dist/mk/install-mk =================================================================== --- vendor/NetBSD/bmake/dist/mk/install-mk (revision 282731) +++ vendor/NetBSD/bmake/dist/mk/install-mk (revision 282732) @@ -1,185 +1,185 @@ : # NAME: # install-mk - install mk files # # SYNOPSIS: # install-mk [options] [var=val] [dest] # # DESCRIPTION: # This tool installs mk files in a semi-intelligent manner into # "dest". # # Options: # # -n just say what we want to do, but don't touch anything. # # -f use -f when copying sys,mk. # # -v be verbose # # -q be quiet # # -m "mode" # Use "mode" for installed files (444). # # -o "owner" # Use "owner" for installed files. # # -g "group" # Use "group" for installed files. # # var=val # Set "var" to "val". See below. # # All our *.mk files are copied to "dest" with appropriate # ownership and permissions. # # By default if a sys.mk can be found in a standard location # (that bmake will find) then no sys.mk will be put in "dest". # # SKIP_SYS_MK: # If set, we will avoid installing our 'sys.mk' # This is probably a bad idea. # # SKIP_BSD_MK: # If set, we will skip making bsd.*.mk links to *.mk # # sys.mk: # # By default (and provided we are not installing to the system # mk dir - '/usr/share/mk') we install our own 'sys.mk' which # includes a sys specific file, or a generic one. # # # AUTHOR: # Simon J. Gerraty # RCSid: -# $Id: install-mk,v 1.109 2015/04/16 16:59:00 sjg Exp $ +# $Id: install-mk,v 1.110 2015/05/01 06:37:49 sjg Exp $ # # @(#) Copyright (c) 1994 Simon J. Gerraty # # This file is provided in the hope that it will # be of use. There is absolutely NO WARRANTY. # Permission to copy, redistribute or otherwise # use this file is hereby granted provided that # the above copyright notice and this notice are # left intact. # # Please send copies of changes and bug-fixes to: # sjg@crufty.net # -MK_VERSION=20150411 +MK_VERSION=20150430 OWNER= GROUP= MODE=444 BINMODE=555 ECHO=: SKIP= cp_f=-f while : do case "$1" in *=*) eval "$1"; shift;; +f) cp_f=; shift;; -f) cp_f=-f; shift;; -m) MODE=$2; shift 2;; -o) OWNER=$2; shift 2;; -g) GROUP=$2; shift 2;; -v) ECHO=echo; shift;; -q) ECHO=:; shift;; -n) ECHO=echo SKIP=:; shift;; --) shift; break;; *) break;; esac done case $# in 0) echo "$0 [options] []" echo "eg." echo "$0 -o bin -g bin -m 444 /usr/local/share/mk" exit 1 ;; esac dest=$1 os=${2:-`uname`} osrel=${3:-`uname -r`} Do() { $ECHO "$@" $SKIP "$@" } Error() { echo "ERROR: $@" >&2 exit 1 } Warning() { echo "WARNING: $@" >&2 } [ "$FORCE_SYS_MK" ] && Warning "ignoring: FORCE_{BSD,SYS}_MK (no longer supported)" SYS_MK_DIR=${SYS_MK_DIR:-/usr/share/mk} SYS_MK=${SYS_MK:-$SYS_MK_DIR/sys.mk} realpath() { [ -d $1 ] && cd $1 && 'pwd' && return echo $1 } if [ -s $SYS_MK -a -d $dest ]; then # if this is a BSD system we don't want to touch $SYS_MK dest=`realpath $dest` sys_mk_dir=`realpath $SYS_MK_DIR` if [ $dest = $sys_mk_dir ]; then case "$os" in *BSD*) SKIP_SYS_MK=: SKIP_BSD_MK=: ;; *) # could be fake? if [ ! -d $dest/sys -a ! -s $dest/Generic.sys.mk ]; then SKIP_SYS_MK=: # play safe SKIP_BSD_MK=: fi ;; esac fi fi [ -d $dest/sys ] || Do mkdir -p $dest/sys [ -d $dest/sys ] || Do mkdir $dest/sys || exit 1 [ -z "$SKIP" ] && dest=`realpath $dest` cd `dirname $0` mksrc=`'pwd'` if [ $mksrc = $dest ]; then SKIP_MKFILES=: else # we do not install the examples mk_files=`grep '^[a-z].*\.mk' FILES | egrep -v '(examples/|^sys\.mk|sys/)'` mk_scripts=`egrep '^[a-z].*\.(sh|py)' FILES | egrep -v '/'` sys_mk_files=`grep 'sys/.*\.mk' FILES` SKIP_MKFILES= [ -z "$SKIP_SYS_MK" ] && mk_files="sys.mk $mk_files" fi $SKIP_MKFILES Do cp $cp_f $mk_files $dest $SKIP_MKFILES Do cp $cp_f $sys_mk_files $dest/sys $SKIP_MKFILES Do cp $cp_f $mk_scripts $dest $SKIP cd $dest $SKIP_MKFILES Do chmod $MODE $mk_files $sys_mk_files $SKIP_MKFILES Do chmod $BINMODE $mk_scripts [ "$GROUP" ] && $SKIP_MKFILES Do chgrp $GROUP $mk_files $sys_mk_files [ "$OWNER" ] && $SKIP_MKFILES Do chown $OWNER $mk_files $sys_mk_files # if this is a BSD system the bsd.*.mk should exist and be used. if [ -z "$SKIP_BSD_MK" ]; then for f in dep doc init lib links man nls obj own prog subdir do b=bsd.$f.mk [ -s $b ] || Do ln -s $f.mk $b done fi exit 0 Index: vendor/NetBSD/bmake/dist/nonints.h =================================================================== --- vendor/NetBSD/bmake/dist/nonints.h (revision 282731) +++ vendor/NetBSD/bmake/dist/nonints.h (revision 282732) @@ -1,199 +1,199 @@ -/* $NetBSD: nonints.h,v 1.67 2014/09/07 20:55:34 joerg Exp $ */ +/* $NetBSD: nonints.h,v 1.68 2015/05/05 21:51:09 sjg Exp $ */ /*- * 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. * * from: @(#)nonints.h 8.3 (Berkeley) 3/19/94 */ /*- * 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. * * from: @(#)nonints.h 8.3 (Berkeley) 3/19/94 */ /* arch.c */ ReturnStatus Arch_ParseArchive(char **, Lst, GNode *); void Arch_Touch(GNode *); void Arch_TouchLib(GNode *); time_t Arch_MTime(GNode *); time_t Arch_MemMTime(GNode *); void Arch_FindLib(GNode *, Lst); Boolean Arch_LibOODate(GNode *); void Arch_Init(void); void Arch_End(void); int Arch_IsLib(GNode *); /* compat.c */ int CompatRunCommand(void *, void *); void Compat_Run(Lst); int Compat_Make(void *, void *); /* cond.c */ struct If; -int Cond_EvalExpression(const struct If *, char *, Boolean *, int); +int Cond_EvalExpression(const struct If *, char *, Boolean *, int, Boolean); int Cond_Eval(char *); void Cond_restore_depth(unsigned int); unsigned int Cond_save_depth(void); /* for.c */ int For_Eval(char *); int For_Accum(char *); void For_Run(int); /* job.c */ #ifdef WAIT_T void JobReapChild(pid_t, WAIT_T, Boolean); #endif /* main.c */ void Main_ParseArgLine(const char *); void MakeMode(const char *); int main(int, char **); char *Cmd_Exec(const char *, const char **); void Error(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2); void Fatal(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2) MAKE_ATTR_DEAD; void Punt(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2) MAKE_ATTR_DEAD; void DieHorribly(void) MAKE_ATTR_DEAD; int PrintAddr(void *, void *); void Finish(int) MAKE_ATTR_DEAD; int eunlink(const char *); void execError(const char *, const char *); char *getTmpdir(void); Boolean getBoolean(const char *, Boolean); /* parse.c */ void Parse_Error(int, const char *, ...) MAKE_ATTR_PRINTFLIKE(2, 3); Boolean Parse_AnyExport(void); Boolean Parse_IsVar(char *); void Parse_DoVar(char *, GNode *); void Parse_AddIncludeDir(char *); void Parse_File(const char *, int); void Parse_Init(void); void Parse_End(void); void Parse_SetInput(const char *, int, int, char *(*)(void *, size_t *), void *); Lst Parse_MainName(void); /* str.c */ char *str_concat(const char *, const char *, int); char **brk_string(const char *, int *, Boolean, char **); char *Str_FindSubstring(const char *, const char *); int Str_Match(const char *, const char *); char *Str_SYSVMatch(const char *, const char *, int *len); void Str_SYSVSubst(Buffer *, char *, char *, int); /* suff.c */ void Suff_ClearSuffixes(void); Boolean Suff_IsTransform(char *); GNode *Suff_AddTransform(char *); int Suff_EndTransform(void *, void *); void Suff_AddSuffix(char *, GNode **); Lst Suff_GetPath(char *); void Suff_DoPaths(void); void Suff_AddInclude(char *); void Suff_AddLib(char *); void Suff_FindDeps(GNode *); Lst Suff_FindPath(GNode *); void Suff_SetNull(char *); void Suff_Init(void); void Suff_End(void); void Suff_PrintAll(void); /* targ.c */ void Targ_Init(void); void Targ_End(void); Lst Targ_List(void); GNode *Targ_NewGN(const char *); GNode *Targ_FindNode(const char *, int); Lst Targ_FindList(Lst, int); Boolean Targ_Ignore(GNode *); Boolean Targ_Silent(GNode *); Boolean Targ_Precious(GNode *); void Targ_SetMain(GNode *); int Targ_PrintCmd(void *, void *); int Targ_PrintNode(void *, void *); char *Targ_FmtTime(time_t); void Targ_PrintType(int); void Targ_PrintGraph(int); void Targ_Propagate(void); void Targ_Propagate_Wait(void); /* var.c */ void Var_Delete(const char *, GNode *); void Var_Set(const char *, const char *, GNode *, int); void Var_Append(const char *, const char *, GNode *); Boolean Var_Exists(const char *, GNode *); char *Var_Value(const char *, GNode *, char **); char *Var_Parse(const char *, GNode *, Boolean, int *, void **); char *Var_Subst(const char *, const char *, GNode *, Boolean); char *Var_GetTail(const char *); char *Var_GetHead(const char *); void Var_Init(void); void Var_End(void); void Var_Dump(GNode *); void Var_ExportVars(void); void Var_Export(char *, int); void Var_UnExport(char *); /* util.c */ void (*bmake_signal(int, void (*)(int)))(int); Index: vendor/NetBSD/bmake/dist/unit-tests/Makefile.in =================================================================== --- vendor/NetBSD/bmake/dist/unit-tests/Makefile.in (revision 282731) +++ vendor/NetBSD/bmake/dist/unit-tests/Makefile.in (revision 282732) @@ -1,150 +1,151 @@ -# $Id: Makefile.in,v 1.46 2014/11/06 01:47:57 sjg Exp $ +# $Id: Makefile.in,v 1.47 2015/05/05 21:58:06 sjg Exp $ # -# $NetBSD: Makefile,v 1.51 2014/10/20 23:21:11 sjg Exp $ +# $NetBSD: Makefile,v 1.52 2015/05/05 21:51:09 sjg Exp $ # # Unit tests for make(1) # The main targets are: # # all: run all the tests # test: run 'all', and compare to expected results # accept: move generated output to expected results # # Adding a test case. # Each feature should get its own set of tests in its own suitably # named makefile (*.mk), with its own set of expected results (*.exp), # and it should be added to the TESTNAMES list. # srcdir= @srcdir@ .MAIN: all UNIT_TESTS:= ${srcdir} .PATH: ${UNIT_TESTS} # Each test is in a sub-makefile. # Keep the list sorted. TESTNAMES= \ comment \ cond1 \ + cond2 \ error \ export \ export-all \ export-env \ doterror \ dotwait \ forloop \ forsubst \ hash \ misc \ moderrs \ modmatch \ modmisc \ modorder \ modts \ modword \ order \ posix \ qequals \ sunshcmd \ sysv \ ternary \ unexport \ unexport-env \ varcmd \ varmisc \ varshell # these tests were broken by referting POSIX chanegs STRICT_POSIX_TESTS = \ escape \ impsrc \ phony-end \ posix1 \ suffixes # Override make flags for certain tests flags.doterror= flags.order=-j1 OUTFILES= ${TESTNAMES:S/$/.out/} all: ${OUTFILES} CLEANFILES += *.rawout *.out *.status *.tmp *.core *.tmp CLEANFILES += obj*.[och] lib*.a # posix1.mk CLEANFILES += issue* .[ab]* # suffixes.mk CLEANRECURSIVE += dir dummy # posix1.mk clean: rm -f ${CLEANFILES} .if !empty(CLEANRECURSIVE) rm -rf ${CLEANRECURSIVE} .endif TEST_MAKE?= ${.MAKE} TOOL_SED?= sed TOOL_TR?= tr TOOL_DIFF?= diff DIFF_FLAGS?= @diff_u@ .if defined(.PARSEDIR) # ensure consistent results from sort(1) LC_ALL= C LANG= C .export LANG LC_ALL .endif # some tests need extra post-processing SED_CMDS.varshell = -e 's,^[a-z]*sh: ,,' \ -e '/command/s,No such.*,not found,' # the tests are actually done with sub-makes. .SUFFIXES: .mk .rawout .out .mk.rawout: @echo ${TEST_MAKE} ${flags.${.TARGET:R}:U-k} -f ${.IMPSRC} -@cd ${.OBJDIR} && \ { ${TEST_MAKE} ${flags.${.TARGET:R}:U-k} -f ${.IMPSRC} \ 2>&1 ; echo $$? >${.TARGET:R}.status ; } > ${.TARGET}.tmp @mv ${.TARGET}.tmp ${.TARGET} # We always pretend .MAKE was called 'make' # and strip ${.CURDIR}/ from the output # and replace anything after 'stopped in' with unit-tests # so the results can be compared. .rawout.out: @echo postprocess ${.TARGET} @${TOOL_SED} -e 's,^${TEST_MAKE:T:C/\./\\\./g}[][0-9]*:,make:,' \ -e 's,${TEST_MAKE:C/\./\\\./g},make,' \ -e '/stopped/s, /.*, unit-tests,' \ -e 's,${.CURDIR:C/\./\\\./g}/,,g' \ -e 's,${UNIT_TESTS:C/\./\\\./g}/,,g' ${SED_CMDS.${.TARGET:T:R}} \ < ${.IMPSRC} > ${.TARGET}.tmp @echo "exit status `cat ${.TARGET:R}.status`" >> ${.TARGET}.tmp @mv ${.TARGET}.tmp ${.TARGET} # Compare all output files test: ${OUTFILES} .PHONY @failed= ; \ for test in ${TESTNAMES}; do \ ${TOOL_DIFF} -u ${UNIT_TESTS}/$${test}.exp $${test}.out \ || failed="$${failed}$${failed:+ }$${test}" ; \ done ; \ if [ -n "$${failed}" ]; then \ echo "Failed tests: $${failed}" ; false ; \ else \ echo "All tests passed" ; \ fi accept: @for test in ${TESTNAMES}; do \ cmp -s ${UNIT_TESTS}/$${test}.exp $${test}.out \ || { echo "Replacing $${test}.exp" ; \ cp $${test}.out ${UNIT_TESTS}/$${test}.exp ; } \ done .if exists(${TEST_MAKE}) ${TESTNAMES:S/$/.rawout/}: ${TEST_MAKE} .endif .-include Index: vendor/NetBSD/bmake/dist/unit-tests/cond2.exp =================================================================== --- vendor/NetBSD/bmake/dist/unit-tests/cond2.exp (nonexistent) +++ vendor/NetBSD/bmake/dist/unit-tests/cond2.exp (revision 282732) @@ -0,0 +1,7 @@ +make: Bad conditional expression ` == "empty"' in == "empty"?oops:ok +make: "cond2.mk" line 13: Malformed conditional ({TEST_TYPO} == "Ok") +TEST_NOT_SET is empty or not defined +make: "cond2.mk" line 20: Malformed conditional (${TEST_NOT_SET} == "empty") +make: Fatal errors encountered -- cannot continue +make: stopped in unit-tests +exit status 1 Index: vendor/NetBSD/bmake/dist/unit-tests/cond2.mk =================================================================== --- vendor/NetBSD/bmake/dist/unit-tests/cond2.mk (nonexistent) +++ vendor/NetBSD/bmake/dist/unit-tests/cond2.mk (revision 282732) @@ -0,0 +1,25 @@ +# $Id: cond2.mk,v 1.1.1.1 2015/05/05 21:53:13 sjg Exp $ + +TEST_UNAME_S= NetBSD + +# this should be ok +X:= ${${TEST_UNAME_S} == "NetBSD":?Ok:fail} +.if $X == "Ok" +Y= good +.endif +# expect: Bad conditional expression ` == "empty"' in == "empty"?oops:ok +X:= ${${TEST_NOT_SET} == "empty":?oops:ok} +# expect: Malformed conditional ({TEST_TYPO} == "Ok") +.if {TEST_TYPO} == "Ok" +Y= oops +.endif +.if empty(TEST_NOT_SET) +Y!= echo TEST_NOT_SET is empty or not defined >&2; echo +.endif +# expect: Malformed conditional (${TEST_NOT_SET} == "empty") +.if ${TEST_NOT_SET} == "empty" +Y= oops +.endif + +all: + @echo $@ Property changes on: vendor/NetBSD/bmake/dist/unit-tests/cond2.mk ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/NetBSD/bmake/dist/var.c =================================================================== --- vendor/NetBSD/bmake/dist/var.c (revision 282731) +++ vendor/NetBSD/bmake/dist/var.c (revision 282732) @@ -1,4193 +1,4193 @@ -/* $NetBSD: var.c,v 1.191 2014/09/14 02:32:51 dholland Exp $ */ +/* $NetBSD: var.c,v 1.192 2015/05/05 21:51:09 sjg Exp $ */ /* * 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. */ /* * 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. */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: var.c,v 1.191 2014/09/14 02:32:51 dholland Exp $"; +static char rcsid[] = "$NetBSD: var.c,v 1.192 2015/05/05 21:51:09 sjg Exp $"; #else #include #ifndef lint #if 0 static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94"; #else -__RCSID("$NetBSD: var.c,v 1.191 2014/09/14 02:32:51 dholland Exp $"); +__RCSID("$NetBSD: var.c,v 1.192 2015/05/05 21:51:09 sjg Exp $"); #endif #endif /* not lint */ #endif /*- * 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 #ifndef NO_REGEX #include #include #endif #include #include #include #include #include #include "make.h" #include "buf.h" #include "dir.h" #include "job.h" extern int makelevel; /* * This lets us tell if we have replaced the original environ * (which we cannot free). */ char **savedEnv = NULL; /* * 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 'errnum' 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. */ GNode *VAR_INTERNAL; /* variables from make itself */ GNode *VAR_GLOBAL; /* variables from the makefile */ GNode *VAR_CMD; /* variables defined on the command-line */ #define FIND_CMD 0x1 /* look in VAR_CMD when searching */ #define FIND_GLOBAL 0x2 /* look in VAR_GLOBAL as well */ #define FIND_ENV 0x4 /* look in the environment also */ typedef struct Var { char *name; /* the variable's name */ 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_FROM_ENV 2 /* Variable comes from the environment */ #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_KEEP 8 /* Variable is VAR_JUNK, but we found * a use for it in some modifier and * the value is therefore valid */ #define VAR_EXPORTED 16 /* Variable is exported */ #define VAR_REEXPORT 32 /* Indicate if var needs re-export. * This would be true if it contains $'s */ #define VAR_FROM_CMD 64 /* Variable came from command line */ } Var; /* * Exporting vars is expensive so skip it if we can */ #define VAR_EXPORTED_NONE 0 #define VAR_EXPORTED_YES 1 #define VAR_EXPORTED_ALL 2 static int var_exportedVars = VAR_EXPORTED_NONE; /* * We pass this to Var_Export when doing the initial export * or after updating an exported var. */ #define VAR_EXPORT_PARENT 1 /* Var*Pattern 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 */ #define VAR_NOSUBST 0x20 /* don't expand vars in VarGetPattern */ /* Var_Set flags */ #define VAR_NO_EXPORT 0x01 /* do not export */ typedef struct { /* * The following fields are set by Var_Parse() when it * encounters modifiers that need to keep state for use by * subsequent modifiers within the same variable expansion. */ Byte varSpace; /* Word separator in expansions */ Boolean oneBigWord; /* TRUE if we will treat the variable as a * single big word, even if it contains * embedded spaces (as opposed to the * usual behaviour of treating it as * several space-separated words). */ } Var_Parse_State; /* struct passed as 'void *' to VarSubstitute() for ":S/lhs/rhs/", * to VarSYSVMatch() for ":lhs=rhs". */ typedef struct { const char *lhs; /* String to match */ int leftLen; /* Length of string */ const char *rhs; /* Replacement string (w/ &'s removed) */ int rightLen; /* Length of replacement */ int flags; } VarPattern; /* struct passed as 'void *' to VarLoopExpand() for ":@tvar@str@" */ typedef struct { GNode *ctxt; /* variable context */ char *tvar; /* name of temp var */ int tvarLen; char *str; /* string to expand */ int strLen; int errnum; /* errnum for not defined */ } VarLoop_t; #ifndef NO_REGEX /* struct passed as 'void *' to VarRESubstitute() for ":C///" */ typedef struct { regex_t re; int nsub; regmatch_t *matches; char *replace; int flags; } VarREPattern; #endif /* struct passed to VarSelectWords() for ":[start..end]" */ typedef struct { int start; /* first word to select */ int end; /* last word to select */ } VarSelectWords_t; static Var *VarFind(const char *, GNode *, int); static void VarAdd(const char *, const char *, GNode *); static Boolean VarHead(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *); static Boolean VarTail(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *); static Boolean VarSuffix(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *); static Boolean VarRoot(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *); static Boolean VarMatch(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *); #ifdef SYSVVARSUB static Boolean VarSYSVMatch(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *); #endif static Boolean VarNoMatch(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *); #ifndef NO_REGEX static void VarREError(int, regex_t *, const char *); static Boolean VarRESubstitute(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *); #endif static Boolean VarSubstitute(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *); static Boolean VarLoopExpand(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *); static char *VarGetPattern(GNode *, Var_Parse_State *, int, const char **, int, int *, int *, VarPattern *); static char *VarQuote(char *); static char *VarHash(char *); static char *VarModify(GNode *, Var_Parse_State *, const char *, Boolean (*)(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *), void *); static char *VarOrder(const char *, const char); static char *VarUniq(const char *); static int VarWordCompare(const void *, const void *); static void VarPrintVar(void *); #define BROPEN '{' #define BRCLOSE '}' #define PROPEN '(' #define PRCLOSE ')' /*- *----------------------------------------------------------------------- * VarFind -- * Find the given variable in the given context and any other contexts * indicated. * * Input: * name name to find * ctxt context in which to find it * flags FIND_GLOBAL set means to look in the * VAR_GLOBAL context as well. FIND_CMD set means * to look in the VAR_CMD context also. FIND_ENV * set means to look in the environment * * Results: * A pointer to the structure describing the desired variable or * NULL if the variable does not exist. * * Side Effects: * None *----------------------------------------------------------------------- */ static Var * VarFind(const char *name, GNode *ctxt, int flags) { Hash_Entry *var; Var *v; /* * 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. */ if (*name == '.' && isupper((unsigned char) name[1])) switch (name[1]) { case 'A': if (!strcmp(name, ".ALLSRC")) name = ALLSRC; if (!strcmp(name, ".ARCHIVE")) name = ARCHIVE; break; case 'I': if (!strcmp(name, ".IMPSRC")) name = IMPSRC; break; case 'M': if (!strcmp(name, ".MEMBER")) name = MEMBER; break; case 'O': if (!strcmp(name, ".OODATE")) name = OODATE; break; case 'P': if (!strcmp(name, ".PREFIX")) name = PREFIX; break; case 'T': if (!strcmp(name, ".TARGET")) name = TARGET; break; } #ifdef notyet /* for compatibility with gmake */ if (name[0] == '^' && name[1] == '\0') name = ALLSRC; #endif /* * 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' */ var = Hash_FindEntry(&ctxt->context, name); if ((var == NULL) && (flags & FIND_CMD) && (ctxt != VAR_CMD)) { var = Hash_FindEntry(&VAR_CMD->context, name); } if (!checkEnvFirst && (var == NULL) && (flags & FIND_GLOBAL) && (ctxt != VAR_GLOBAL)) { var = Hash_FindEntry(&VAR_GLOBAL->context, name); if ((var == NULL) && (ctxt != VAR_INTERNAL)) { /* VAR_INTERNAL is subordinate to VAR_GLOBAL */ var = Hash_FindEntry(&VAR_INTERNAL->context, name); } } if ((var == NULL) && (flags & FIND_ENV)) { char *env; if ((env = getenv(name)) != NULL) { int len; v = bmake_malloc(sizeof(Var)); v->name = bmake_strdup(name); len = strlen(env); Buf_Init(&v->val, len + 1); Buf_AddBytes(&v->val, len, env); v->flags = VAR_FROM_ENV; return (v); } else if (checkEnvFirst && (flags & FIND_GLOBAL) && (ctxt != VAR_GLOBAL)) { var = Hash_FindEntry(&VAR_GLOBAL->context, name); if ((var == NULL) && (ctxt != VAR_INTERNAL)) { var = Hash_FindEntry(&VAR_INTERNAL->context, name); } if (var == NULL) { return NULL; } else { return ((Var *)Hash_GetValue(var)); } } else { return NULL; } } else if (var == NULL) { return NULL; } else { return ((Var *)Hash_GetValue(var)); } } /*- *----------------------------------------------------------------------- * VarFreeEnv -- * If the variable is an environment variable, free it * * Input: * v the variable * destroy true if the value buffer should be destroyed. * * Results: * 1 if it is an environment variable 0 ow. * * Side Effects: * The variable is free'ed if it is an environent variable. *----------------------------------------------------------------------- */ static Boolean VarFreeEnv(Var *v, Boolean destroy) { if ((v->flags & VAR_FROM_ENV) == 0) return FALSE; free(v->name); Buf_Destroy(&v->val, destroy); free(v); return TRUE; } /*- *----------------------------------------------------------------------- * VarAdd -- * Add a new variable of name name and value val to the given context * * Input: * name name of variable to add * val value to set it to * ctxt context in which to set it * * Results: * None * * 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 void VarAdd(const char *name, const char *val, GNode *ctxt) { Var *v; int len; Hash_Entry *h; v = bmake_malloc(sizeof(Var)); len = val ? strlen(val) : 0; Buf_Init(&v->val, len+1); Buf_AddBytes(&v->val, len, val); v->flags = 0; h = Hash_CreateEntry(&ctxt->context, name, NULL); Hash_SetValue(h, v); v->name = h->name; if (DEBUG(VAR)) { fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val); } } /*- *----------------------------------------------------------------------- * Var_Delete -- * Remove a variable from a context. * * Results: * None. * * Side Effects: * The Var structure is removed and freed. * *----------------------------------------------------------------------- */ void Var_Delete(const char *name, GNode *ctxt) { Hash_Entry *ln; char *cp; if (strchr(name, '$')) { cp = Var_Subst(NULL, name, VAR_GLOBAL, 0); } else { cp = (char *)name; } ln = Hash_FindEntry(&ctxt->context, cp); if (DEBUG(VAR)) { fprintf(debug_file, "%s:delete %s%s\n", ctxt->name, cp, ln ? "" : " (not found)"); } if (cp != name) { free(cp); } if (ln != NULL) { Var *v; v = (Var *)Hash_GetValue(ln); if ((v->flags & VAR_EXPORTED)) { unsetenv(v->name); } if (strcmp(MAKE_EXPORTED, v->name) == 0) { var_exportedVars = VAR_EXPORTED_NONE; } if (v->name != ln->name) free(v->name); Hash_DeleteEntry(&ctxt->context, ln); Buf_Destroy(&v->val, TRUE); free(v); } } /* * Export a var. * We ignore make internal variables (those which start with '.') * Also we jump through some hoops to avoid calling setenv * more than necessary since it can leak. * We only manipulate flags of vars if 'parent' is set. */ static int Var_Export1(const char *name, int parent) { char tmp[BUFSIZ]; Var *v; char *val = NULL; int n; if (*name == '.') return 0; /* skip internals */ if (!name[1]) { /* * A single char. * If it is one of the vars that should only appear in * local context, skip it, else we can get Var_Subst * into a loop. */ switch (name[0]) { case '@': case '%': case '*': case '!': return 0; } } v = VarFind(name, VAR_GLOBAL, 0); if (v == NULL) { return 0; } if (!parent && (v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED) { return 0; /* nothing to do */ } val = Buf_GetAll(&v->val, NULL); if (strchr(val, '$')) { if (parent) { /* * Flag this as something we need to re-export. * No point actually exporting it now though, * the child can do it at the last minute. */ v->flags |= (VAR_EXPORTED|VAR_REEXPORT); return 1; } if (v->flags & VAR_IN_USE) { /* * We recursed while exporting in a child. * This isn't going to end well, just skip it. */ return 0; } n = snprintf(tmp, sizeof(tmp), "${%s}", name); if (n < (int)sizeof(tmp)) { val = Var_Subst(NULL, tmp, VAR_GLOBAL, 0); setenv(name, val, 1); free(val); } } else { if (parent) { v->flags &= ~VAR_REEXPORT; /* once will do */ } if (parent || !(v->flags & VAR_EXPORTED)) { setenv(name, val, 1); } } /* * This is so Var_Set knows to call Var_Export again... */ if (parent) { v->flags |= VAR_EXPORTED; } return 1; } /* * This gets called from our children. */ void Var_ExportVars(void) { char tmp[BUFSIZ]; Hash_Entry *var; Hash_Search state; Var *v; char *val; int n; /* * Several make's support this sort of mechanism for tracking * recursion - but each uses a different name. * We allow the makefiles to update MAKELEVEL and ensure * children see a correctly incremented value. */ snprintf(tmp, sizeof(tmp), "%d", makelevel + 1); setenv(MAKE_LEVEL_ENV, tmp, 1); if (VAR_EXPORTED_NONE == var_exportedVars) return; if (VAR_EXPORTED_ALL == var_exportedVars) { /* * Ouch! This is crazy... */ for (var = Hash_EnumFirst(&VAR_GLOBAL->context, &state); var != NULL; var = Hash_EnumNext(&state)) { v = (Var *)Hash_GetValue(var); Var_Export1(v->name, 0); } return; } /* * We have a number of exported vars, */ n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}"); if (n < (int)sizeof(tmp)) { char **av; char *as; int ac; int i; val = Var_Subst(NULL, tmp, VAR_GLOBAL, 0); av = brk_string(val, &ac, FALSE, &as); for (i = 0; i < ac; i++) { Var_Export1(av[i], 0); } free(val); free(as); free(av); } } /* * This is called when .export is seen or * .MAKE.EXPORTED is modified. * It is also called when any exported var is modified. */ void Var_Export(char *str, int isExport) { char *name; char *val; char **av; char *as; int track; int ac; int i; if (isExport && (!str || !str[0])) { var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */ return; } if (strncmp(str, "-env", 4) == 0) { track = 0; str += 4; } else { track = VAR_EXPORT_PARENT; } val = Var_Subst(NULL, str, VAR_GLOBAL, 0); av = brk_string(val, &ac, FALSE, &as); for (i = 0; i < ac; i++) { name = av[i]; if (!name[1]) { /* * A single char. * If it is one of the vars that should only appear in * local context, skip it, else we can get Var_Subst * into a loop. */ switch (name[0]) { case '@': case '%': case '*': case '!': continue; } } if (Var_Export1(name, track)) { if (VAR_EXPORTED_ALL != var_exportedVars) var_exportedVars = VAR_EXPORTED_YES; if (isExport && track) { Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL); } } } free(val); free(as); free(av); } /* * This is called when .unexport[-env] is seen. */ extern char **environ; void Var_UnExport(char *str) { char tmp[BUFSIZ]; char *vlist; char *cp; Boolean unexport_env; int n; if (!str || !str[0]) { return; /* assert? */ } vlist = NULL; str += 8; unexport_env = (strncmp(str, "-env", 4) == 0); if (unexport_env) { char **newenv; cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */ if (environ == savedEnv) { /* we have been here before! */ newenv = bmake_realloc(environ, 2 * sizeof(char *)); } else { if (savedEnv) { free(savedEnv); savedEnv = NULL; } newenv = bmake_malloc(2 * sizeof(char *)); } if (!newenv) return; /* Note: we cannot safely free() the original environ. */ environ = savedEnv = newenv; newenv[0] = NULL; newenv[1] = NULL; setenv(MAKE_LEVEL_ENV, cp, 1); } else { for (; *str != '\n' && isspace((unsigned char) *str); str++) continue; if (str[0] && str[0] != '\n') { vlist = str; } } if (!vlist) { /* Using .MAKE.EXPORTED */ n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}"); if (n < (int)sizeof(tmp)) { vlist = Var_Subst(NULL, tmp, VAR_GLOBAL, 0); } } if (vlist) { Var *v; char **av; char *as; int ac; int i; av = brk_string(vlist, &ac, FALSE, &as); for (i = 0; i < ac; i++) { v = VarFind(av[i], VAR_GLOBAL, 0); if (!v) continue; if (!unexport_env && (v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED) { unsetenv(v->name); } v->flags &= ~(VAR_EXPORTED|VAR_REEXPORT); /* * If we are unexporting a list, * remove each one from .MAKE.EXPORTED. * If we are removing them all, * just delete .MAKE.EXPORTED below. */ if (vlist == str) { n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":N%s}", v->name); if (n < (int)sizeof(tmp)) { cp = Var_Subst(NULL, tmp, VAR_GLOBAL, 0); Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL, 0); free(cp); } } } free(as); free(av); if (vlist != str) { Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); free(vlist); } } } /*- *----------------------------------------------------------------------- * Var_Set -- * Set the variable name to the value val in the given context. * * Input: * name name of variable to set * val value to give to the variable * ctxt context in which to set it * * Results: * None. * * 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 $(<). * If the context is VAR_GLOBAL though, we check if the variable * was set in VAR_CMD from the command line and skip it if so. *----------------------------------------------------------------------- */ void Var_Set(const char *name, const char *val, GNode *ctxt, int flags) { Var *v; char *expanded_name = NULL; /* * 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... */ if (strchr(name, '$') != NULL) { expanded_name = Var_Subst(NULL, name, ctxt, 0); if (expanded_name[0] == 0) { if (DEBUG(VAR)) { fprintf(debug_file, "Var_Set(\"%s\", \"%s\", ...) " "name expands to empty string - ignored\n", name, val); } free(expanded_name); return; } name = expanded_name; } if (ctxt == VAR_GLOBAL) { v = VarFind(name, VAR_CMD, 0); if (v != NULL) { if ((v->flags & VAR_FROM_CMD)) { if (DEBUG(VAR)) { fprintf(debug_file, "%s:%s = %s ignored!\n", ctxt->name, name, val); } goto out; } VarFreeEnv(v, TRUE); } } v = VarFind(name, ctxt, 0); if (v == NULL) { if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) { /* * This var would normally prevent the same name being added * to VAR_GLOBAL, so delete it from there if needed. * Otherwise -V name may show the wrong value. */ Var_Delete(name, VAR_GLOBAL); } VarAdd(name, val, ctxt); } else { Buf_Empty(&v->val); Buf_AddBytes(&v->val, strlen(val), val); if (DEBUG(VAR)) { fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val); } if ((v->flags & VAR_EXPORTED)) { Var_Export1(name, VAR_EXPORT_PARENT); } } /* * Any variables given on the command line are automatically exported * to the environment (as per POSIX standard) */ if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) { if (v == NULL) { /* we just added it */ v = VarFind(name, ctxt, 0); } if (v != NULL) v->flags |= VAR_FROM_CMD; /* * If requested, don't export these in the environment * individually. We still put them in MAKEOVERRIDES so * that the command-line settings continue to override * Makefile settings. */ if (varNoExportEnv != TRUE) setenv(name, val, 1); Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL); } out: if (expanded_name != NULL) free(expanded_name); if (v != NULL) VarFreeEnv(v, TRUE); } /*- *----------------------------------------------------------------------- * Var_Append -- * The variable of the given name has the given value appended to it in * the given context. * * Input: * name name of variable to modify * val String to append to it * ctxt Context in which this should occur * * Results: * None * * 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; Hash_Entry *h; char *expanded_name = NULL; if (strchr(name, '$') != NULL) { expanded_name = Var_Subst(NULL, name, ctxt, 0); if (expanded_name[0] == 0) { if (DEBUG(VAR)) { fprintf(debug_file, "Var_Append(\"%s\", \"%s\", ...) " "name expands to empty string - ignored\n", name, val); } free(expanded_name); return; } name = expanded_name; } v = VarFind(name, ctxt, (ctxt == VAR_GLOBAL) ? FIND_ENV : 0); if (v == NULL) { VarAdd(name, val, ctxt); } else { Buf_AddByte(&v->val, ' '); Buf_AddBytes(&v->val, strlen(val), val); if (DEBUG(VAR)) { fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, Buf_GetAll(&v->val, NULL)); } if (v->flags & VAR_FROM_ENV) { /* * If the original variable came from the environment, we * have to install it in the global context (we could place * it in the environment, but then we should provide a way to * export other variables...) */ v->flags &= ~VAR_FROM_ENV; h = Hash_CreateEntry(&ctxt->context, name, NULL); Hash_SetValue(h, v); } } if (expanded_name != NULL) free(expanded_name); } /*- *----------------------------------------------------------------------- * Var_Exists -- * See if the given variable exists. * * Input: * name Variable to find * ctxt Context in which to start search * * Results: * TRUE if it does, FALSE if it doesn't * * Side Effects: * None. * *----------------------------------------------------------------------- */ Boolean Var_Exists(const char *name, GNode *ctxt) { Var *v; char *cp; if ((cp = strchr(name, '$')) != NULL) { cp = Var_Subst(NULL, name, ctxt, FALSE); } v = VarFind(cp ? cp : name, ctxt, FIND_CMD|FIND_GLOBAL|FIND_ENV); if (cp != NULL) { free(cp); } if (v == NULL) { return(FALSE); } else { (void)VarFreeEnv(v, TRUE); } return(TRUE); } /*- *----------------------------------------------------------------------- * Var_Value -- * Return the value of the named variable in the given context * * Input: * name name to find * ctxt context in which to search for it * * Results: * The value if the variable exists, NULL if it doesn't * * Side Effects: * None *----------------------------------------------------------------------- */ char * Var_Value(const char *name, GNode *ctxt, char **frp) { Var *v; v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); *frp = NULL; if (v != NULL) { char *p = (Buf_GetAll(&v->val, NULL)); if (VarFreeEnv(v, FALSE)) *frp = p; return p; } else { return NULL; } } /*- *----------------------------------------------------------------------- * VarHead -- * Remove the tail of the given word and place the result in the given * buffer. * * Input: * word Word to trim * addSpace True if need to add a space to the buffer * before sticking in the head * buf Buffer in which to store it * * 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(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, char *word, Boolean addSpace, Buffer *buf, void *dummy) { char *slash; slash = strrchr(word, '/'); if (slash != NULL) { if (addSpace && vpstate->varSpace) { Buf_AddByte(buf, vpstate->varSpace); } *slash = '\0'; Buf_AddBytes(buf, strlen(word), word); *slash = '/'; return (TRUE); } else { /* * If no directory part, give . (q.v. the POSIX standard) */ if (addSpace && vpstate->varSpace) Buf_AddByte(buf, vpstate->varSpace); Buf_AddByte(buf, '.'); } return(dummy ? TRUE : TRUE); } /*- *----------------------------------------------------------------------- * VarTail -- * Remove the head of the given word and place the result in the given * buffer. * * Input: * word Word to trim * addSpace True if need to add a space to the buffer * before adding the tail * buf Buffer in which to store it * * 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(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, char *word, Boolean addSpace, Buffer *buf, void *dummy) { char *slash; if (addSpace && vpstate->varSpace) { Buf_AddByte(buf, vpstate->varSpace); } slash = strrchr(word, '/'); if (slash != NULL) { *slash++ = '\0'; Buf_AddBytes(buf, strlen(slash), slash); slash[-1] = '/'; } else { Buf_AddBytes(buf, strlen(word), word); } return (dummy ? TRUE : TRUE); } /*- *----------------------------------------------------------------------- * VarSuffix -- * Place the suffix of the given word in the given buffer. * * Input: * word Word to trim * addSpace TRUE if need to add a space before placing the * suffix in the buffer * buf Buffer in which to store it * * 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(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, char *word, Boolean addSpace, Buffer *buf, void *dummy) { char *dot; dot = strrchr(word, '.'); if (dot != NULL) { if (addSpace && vpstate->varSpace) { Buf_AddByte(buf, vpstate->varSpace); } *dot++ = '\0'; Buf_AddBytes(buf, strlen(dot), dot); dot[-1] = '.'; addSpace = TRUE; } return (dummy ? addSpace : addSpace); } /*- *----------------------------------------------------------------------- * VarRoot -- * Remove the suffix of the given word and place the result in the * buffer. * * Input: * word Word to trim * addSpace TRUE if need to add a space to the buffer * before placing the root in it * buf Buffer in which to store it * * 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(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, char *word, Boolean addSpace, Buffer *buf, void *dummy) { char *dot; if (addSpace && vpstate->varSpace) { Buf_AddByte(buf, vpstate->varSpace); } dot = strrchr(word, '.'); if (dot != NULL) { *dot = '\0'; Buf_AddBytes(buf, strlen(word), word); *dot = '.'; } else { Buf_AddBytes(buf, strlen(word), word); } return (dummy ? TRUE : TRUE); } /*- *----------------------------------------------------------------------- * VarMatch -- * Place the word in the buffer if it matches the given pattern. * Callback function for VarModify to implement the :M modifier. * * Input: * word Word to examine * addSpace TRUE if need to add a space to the buffer * before adding the word, if it matches * buf Buffer in which to store it * pattern Pattern 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(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, char *word, Boolean addSpace, Buffer *buf, void *pattern) { if (DEBUG(VAR)) fprintf(debug_file, "VarMatch [%s] [%s]\n", word, (char *)pattern); if (Str_Match(word, (char *)pattern)) { if (addSpace && vpstate->varSpace) { Buf_AddByte(buf, vpstate->varSpace); } addSpace = TRUE; Buf_AddBytes(buf, strlen(word), word); } return(addSpace); } #ifdef SYSVVARSUB /*- *----------------------------------------------------------------------- * VarSYSVMatch -- * Place the word in the buffer if it matches the given pattern. * Callback function for VarModify to implement the System V % * modifiers. * * Input: * word Word to examine * addSpace TRUE if need to add a space to the buffer * before adding the word, if it matches * buf Buffer in which to store it * patp Pattern 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 VarSYSVMatch(GNode *ctx, Var_Parse_State *vpstate, char *word, Boolean addSpace, Buffer *buf, void *patp) { int len; char *ptr; VarPattern *pat = (VarPattern *)patp; char *varexp; if (addSpace && vpstate->varSpace) Buf_AddByte(buf, vpstate->varSpace); addSpace = TRUE; if ((ptr = Str_SYSVMatch(word, pat->lhs, &len)) != NULL) { varexp = Var_Subst(NULL, pat->rhs, ctx, 0); Str_SYSVSubst(buf, varexp, ptr, len); free(varexp); } else { Buf_AddBytes(buf, strlen(word), word); } return(addSpace); } #endif /*- *----------------------------------------------------------------------- * VarNoMatch -- * Place the word in the buffer if it doesn't match the given pattern. * Callback function for VarModify to implement the :N modifier. * * Input: * word Word to examine * addSpace TRUE if need to add a space to the buffer * before adding the word, if it matches * buf Buffer in which to store it * pattern Pattern 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 VarNoMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, char *word, Boolean addSpace, Buffer *buf, void *pattern) { if (!Str_Match(word, (char *)pattern)) { if (addSpace && vpstate->varSpace) { Buf_AddByte(buf, vpstate->varSpace); } addSpace = TRUE; Buf_AddBytes(buf, strlen(word), word); } return(addSpace); } /*- *----------------------------------------------------------------------- * VarSubstitute -- * Perform a string-substitution on the given word, placing the * result in the passed buffer. * * Input: * word Word to modify * addSpace True if space should be added before * other characters * buf Buffer for result * patternp Pattern for substitution * * Results: * TRUE if a space is needed before more characters are added. * * Side Effects: * None. * *----------------------------------------------------------------------- */ static Boolean VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, char *word, Boolean addSpace, Buffer *buf, void *patternp) { int wordLen; /* Length of word */ char *cp; /* General pointer */ VarPattern *pattern = (VarPattern *)patternp; wordLen = strlen(word); if ((pattern->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) != (VAR_SUB_ONE|VAR_SUB_MATCHED)) { /* * Still substituting -- break it down into simple anchored cases * and if none of them fits, perform the general substitution case. */ if ((pattern->flags & VAR_MATCH_START) && (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) { /* * Anchored at start and beginning of word matches pattern */ if ((pattern->flags & VAR_MATCH_END) && (wordLen == pattern->leftLen)) { /* * 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 (pattern->rightLen != 0) { if (addSpace && vpstate->varSpace) { Buf_AddByte(buf, vpstate->varSpace); } addSpace = TRUE; Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); } pattern->flags |= VAR_SUB_MATCHED; } 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 ((pattern->rightLen + wordLen - pattern->leftLen) != 0){ if (addSpace && vpstate->varSpace) { Buf_AddByte(buf, vpstate->varSpace); } addSpace = TRUE; } Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); Buf_AddBytes(buf, wordLen - pattern->leftLen, (word + pattern->leftLen)); pattern->flags |= VAR_SUB_MATCHED; } } 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 - pattern->leftLen); if ((cp >= word) && (strncmp(cp, pattern->lhs, pattern->leftLen) == 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) + pattern->rightLen) != 0) { if (addSpace && vpstate->varSpace) { Buf_AddByte(buf, vpstate->varSpace); } addSpace = TRUE; } Buf_AddBytes(buf, cp - word, word); Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); pattern->flags |= VAR_SUB_MATCHED; } 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 * String_FindSubstring, 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; int origSize; done = FALSE; origSize = Buf_Size(buf); while (!done) { cp = Str_FindSubstring(word, pattern->lhs); if (cp != NULL) { if (addSpace && (((cp - word) + pattern->rightLen) != 0)){ Buf_AddByte(buf, vpstate->varSpace); addSpace = FALSE; } Buf_AddBytes(buf, cp-word, word); Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); wordLen -= (cp - word) + pattern->leftLen; word = cp + pattern->leftLen; if (wordLen == 0) { done = TRUE; } if ((pattern->flags & VAR_SUB_GLOBAL) == 0) { done = TRUE; } pattern->flags |= VAR_SUB_MATCHED; } else { done = TRUE; } } if (wordLen != 0) { if (addSpace && vpstate->varSpace) { Buf_AddByte(buf, vpstate->varSpace); } Buf_AddBytes(buf, wordLen, 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); } return (addSpace); } nosub: if (addSpace && vpstate->varSpace) { Buf_AddByte(buf, vpstate->varSpace); } Buf_AddBytes(buf, wordLen, word); return(TRUE); } #ifndef NO_REGEX /*- *----------------------------------------------------------------------- * VarREError -- * Print the error caused by a regcomp or regexec call. * * Results: * None. * * Side Effects: * An error gets printed. * *----------------------------------------------------------------------- */ static void VarREError(int errnum, regex_t *pat, const char *str) { char *errbuf; int errlen; errlen = regerror(errnum, pat, 0, 0); errbuf = bmake_malloc(errlen); regerror(errnum, pat, errbuf, errlen); Error("%s: %s", str, errbuf); free(errbuf); } /*- *----------------------------------------------------------------------- * VarRESubstitute -- * Perform a regex substitution on the given word, placing the * result in the passed buffer. * * Results: * TRUE if a space is needed before more characters are added. * * Side Effects: * None. * *----------------------------------------------------------------------- */ static Boolean VarRESubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, char *word, Boolean addSpace, Buffer *buf, void *patternp) { VarREPattern *pat; int xrv; char *wp; char *rp; int added; int flags = 0; #define MAYBE_ADD_SPACE() \ if (addSpace && !added) \ Buf_AddByte(buf, ' '); \ 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, wp); } for (rp = pat->replace; *rp; rp++) { if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) { MAYBE_ADD_SPACE(); Buf_AddByte(buf,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, subbuf); } } else { MAYBE_ADD_SPACE(); Buf_AddByte(buf, *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, *wp); wp++; } if (*wp) goto tryagain; } if (*wp) { MAYBE_ADD_SPACE(); Buf_AddBytes(buf, strlen(wp), wp); } break; default: VarREError(xrv, &pat->re, "Unexpected regex error"); /* fall through */ case REG_NOMATCH: if (*wp) { MAYBE_ADD_SPACE(); Buf_AddBytes(buf,strlen(wp),wp); } break; } return(addSpace||added); } #endif /*- *----------------------------------------------------------------------- * VarLoopExpand -- * Implements the :@@@ modifier of ODE make. * We set the temp variable named in pattern.lhs to word and expand * pattern.rhs storing the result in the passed buffer. * * Input: * word Word to modify * addSpace True if space should be added before * other characters * buf Buffer for result * pattern Datafor substitution * * Results: * TRUE if a space is needed before more characters are added. * * Side Effects: * None. * *----------------------------------------------------------------------- */ static Boolean VarLoopExpand(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, char *word, Boolean addSpace, Buffer *buf, void *loopp) { VarLoop_t *loop = (VarLoop_t *)loopp; char *s; int slen; if (word && *word) { Var_Set(loop->tvar, word, loop->ctxt, VAR_NO_EXPORT); s = Var_Subst(NULL, loop->str, loop->ctxt, loop->errnum); if (s != NULL && *s != '\0') { if (addSpace && *s != '\n') Buf_AddByte(buf, ' '); Buf_AddBytes(buf, (slen = strlen(s)), s); addSpace = (slen > 0 && s[slen - 1] != '\n'); free(s); } } return addSpace; } /*- *----------------------------------------------------------------------- * VarSelectWords -- * Implements the :[start..end] modifier. * This is a special case of VarModify since we want to be able * to scan the list backwards if start > end. * * Input: * str String whose words should be trimmed * seldata words to select * * Results: * A string of all the words selected. * * Side Effects: * None. * *----------------------------------------------------------------------- */ static char * VarSelectWords(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, const char *str, VarSelectWords_t *seldata) { Buffer buf; /* Buffer for the new string */ Boolean addSpace; /* TRUE if need to add a space to the * buffer before adding the trimmed * word */ char **av; /* word list */ char *as; /* word list memory */ int ac, i; int start, end, step; Buf_Init(&buf, 0); addSpace = FALSE; if (vpstate->oneBigWord) { /* fake what brk_string() would do if there were only one word */ ac = 1; av = bmake_malloc((ac + 1) * sizeof(char *)); as = bmake_strdup(str); av[0] = as; av[1] = NULL; } else { av = brk_string(str, &ac, FALSE, &as); } /* * Now sanitize seldata. * If seldata->start or seldata->end are negative, convert them to * the positive equivalents (-1 gets converted to argc, -2 gets * converted to (argc-1), etc.). */ if (seldata->start < 0) seldata->start = ac + seldata->start + 1; if (seldata->end < 0) seldata->end = ac + seldata->end + 1; /* * We avoid scanning more of the list than we need to. */ if (seldata->start > seldata->end) { start = MIN(ac, seldata->start) - 1; end = MAX(0, seldata->end - 1); step = -1; } else { start = MAX(0, seldata->start - 1); end = MIN(ac, seldata->end); step = 1; } for (i = start; (step < 0 && i >= end) || (step > 0 && i < end); i += step) { if (av[i] && *av[i]) { if (addSpace && vpstate->varSpace) { Buf_AddByte(&buf, vpstate->varSpace); } Buf_AddBytes(&buf, strlen(av[i]), av[i]); addSpace = TRUE; } } free(as); free(av); return Buf_Destroy(&buf, FALSE); } /*- * VarRealpath -- * Replace each word with the result of realpath() * if successful. */ static Boolean VarRealpath(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, char *word, Boolean addSpace, Buffer *buf, void *patternp MAKE_ATTR_UNUSED) { struct stat st; char rbuf[MAXPATHLEN]; char *rp; if (addSpace && vpstate->varSpace) { Buf_AddByte(buf, vpstate->varSpace); } addSpace = TRUE; rp = realpath(word, rbuf); if (rp && *rp == '/' && stat(rp, &st) == 0) word = rp; Buf_AddBytes(buf, strlen(word), word); return(addSpace); } /*- *----------------------------------------------------------------------- * VarModify -- * Modify each of the words of the passed string using the given * function. Used to implement all modifiers. * * Input: * str String whose words should be trimmed * modProc Function to use to modify them * datum Datum to pass it * * Results: * A string of all the words modified appropriately. * * Side Effects: * None. * *----------------------------------------------------------------------- */ static char * VarModify(GNode *ctx, Var_Parse_State *vpstate, const char *str, Boolean (*modProc)(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *), void *datum) { Buffer buf; /* Buffer for the new string */ Boolean addSpace; /* TRUE if need to add a space to the * buffer before adding the trimmed * word */ char **av; /* word list */ char *as; /* word list memory */ int ac, i; Buf_Init(&buf, 0); addSpace = FALSE; if (vpstate->oneBigWord) { /* fake what brk_string() would do if there were only one word */ ac = 1; av = bmake_malloc((ac + 1) * sizeof(char *)); as = bmake_strdup(str); av[0] = as; av[1] = NULL; } else { av = brk_string(str, &ac, FALSE, &as); } for (i = 0; i < ac; i++) { addSpace = (*modProc)(ctx, vpstate, av[i], addSpace, &buf, datum); } free(as); free(av); return Buf_Destroy(&buf, FALSE); } static int VarWordCompare(const void *a, const void *b) { int r = strcmp(*(const char * const *)a, *(const char * const *)b); return r; } /*- *----------------------------------------------------------------------- * VarOrder -- * Order the words in the string. * * Input: * str String whose words should be sorted. * otype How to order: s - sort, x - random. * * Results: * A string containing the words ordered. * * Side Effects: * None. * *----------------------------------------------------------------------- */ static char * VarOrder(const char *str, const char otype) { Buffer buf; /* Buffer for the new string */ char **av; /* word list [first word does not count] */ char *as; /* word list memory */ int ac, i; Buf_Init(&buf, 0); av = brk_string(str, &ac, FALSE, &as); if (ac > 0) switch (otype) { case 's': /* sort alphabetically */ qsort(av, ac, sizeof(char *), VarWordCompare); break; case 'x': /* randomize */ { int rndidx; char *t; /* * We will use [ac..2] range for mod factors. This will produce * random numbers in [(ac-1)..0] interval, and minimal * reasonable value for mod factor is 2 (the mod 1 will produce * 0 with probability 1). */ for (i = ac-1; i > 0; i--) { rndidx = random() % (i + 1); if (i != rndidx) { t = av[i]; av[i] = av[rndidx]; av[rndidx] = t; } } } } /* end of switch */ for (i = 0; i < ac; i++) { Buf_AddBytes(&buf, strlen(av[i]), av[i]); if (i != ac - 1) Buf_AddByte(&buf, ' '); } free(as); free(av); return Buf_Destroy(&buf, FALSE); } /*- *----------------------------------------------------------------------- * VarUniq -- * Remove adjacent duplicate words. * * Input: * str String whose words should be sorted * * Results: * A string containing the resulting words. * * Side Effects: * None. * *----------------------------------------------------------------------- */ static char * VarUniq(const char *str) { Buffer buf; /* Buffer for new string */ char **av; /* List of words to affect */ char *as; /* Word list memory */ int ac, i, j; Buf_Init(&buf, 0); av = brk_string(str, &ac, FALSE, &as); if (ac > 1) { for (j = 0, i = 1; i < ac; i++) if (strcmp(av[i], av[j]) != 0 && (++j != i)) av[j] = av[i]; ac = j + 1; } for (i = 0; i < ac; i++) { Buf_AddBytes(&buf, strlen(av[i]), av[i]); if (i != ac - 1) Buf_AddByte(&buf, ' '); } free(as); free(av); return Buf_Destroy(&buf, FALSE); } /*- *----------------------------------------------------------------------- * VarGetPattern -- * 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 unless flags * has VAR_NOSUBST set). * 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. * * Side Effects: * None. *----------------------------------------------------------------------- */ static char * VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, int errnum, const char **tstr, int delim, int *flags, int *length, VarPattern *pattern) { const char *cp; char *rstr; Buffer buf; int junk; Buf_Init(&buf, 0); if (length == NULL) length = &junk; #define IS_A_MATCH(cp, delim) \ ((cp[0] == '\\') && ((cp[1] == delim) || \ (cp[1] == '\\') || (cp[1] == '$') || (pattern && (cp[1] == '&')))) /* * 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. */ for (cp = *tstr; *cp && (*cp != delim); cp++) { if (IS_A_MATCH(cp, delim)) { Buf_AddByte(&buf, cp[1]); cp++; } else if (*cp == '$') { if (cp[1] == delim) { if (flags == NULL) Buf_AddByte(&buf, *cp); else /* * Unescaped $ at end of pattern => anchor * pattern at end. */ *flags |= VAR_MATCH_END; } else { if (flags == NULL || (*flags & VAR_NOSUBST) == 0) { char *cp2; int len; void *freeIt; /* * If unescaped dollar sign not before the * delimiter, assume it's a variable * substitution and recurse. */ cp2 = Var_Parse(cp, ctxt, errnum, &len, &freeIt); Buf_AddBytes(&buf, strlen(cp2), cp2); if (freeIt) free(freeIt); cp += len - 1; } else { const char *cp2 = &cp[1]; if (*cp2 == PROPEN || *cp2 == BROPEN) { /* * Find the end of this variable reference * and suck it in without further ado. * It will be interperated later. */ int have = *cp2; int want = (*cp2 == PROPEN) ? PRCLOSE : BRCLOSE; int depth = 1; for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) { if (cp2[-1] != '\\') { if (*cp2 == have) ++depth; if (*cp2 == want) --depth; } } Buf_AddBytes(&buf, cp2 - cp, cp); cp = --cp2; } else Buf_AddByte(&buf, *cp); } } } else if (pattern && *cp == '&') Buf_AddBytes(&buf, pattern->leftLen, pattern->lhs); else Buf_AddByte(&buf, *cp); } if (*cp != delim) { *tstr = cp; *length = 0; return NULL; } *tstr = ++cp; *length = Buf_Size(&buf); rstr = Buf_Destroy(&buf, FALSE); if (DEBUG(VAR)) fprintf(debug_file, "Modifier pattern: \"%s\"\n", rstr); return rstr; } /*- *----------------------------------------------------------------------- * VarQuote -- * Quote shell meta-characters in the string * * Results: * The quoted string * * Side Effects: * None. * *----------------------------------------------------------------------- */ static char * VarQuote(char *str) { Buffer buf; /* This should cover most shells :-( */ static const char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~"; const char *newline; size_t len, nlen; if ((newline = Shell_GetNewline()) == NULL) newline = "\\\n"; nlen = strlen(newline); Buf_Init(&buf, 0); while (*str != '\0') { if ((len = strcspn(str, meta)) != 0) { Buf_AddBytes(&buf, len, str); str += len; } else if (*str == '\n') { Buf_AddBytes(&buf, nlen, newline); ++str; } else { Buf_AddByte(&buf, '\\'); Buf_AddByte(&buf, *str); ++str; } } str = Buf_Destroy(&buf, FALSE); if (DEBUG(VAR)) fprintf(debug_file, "QuoteMeta: [%s]\n", str); return str; } /*- *----------------------------------------------------------------------- * VarHash -- * Hash the string using the MurmurHash3 algorithm. * Output is computed using 32bit Little Endian arithmetic. * * Input: * str String to modify * * Results: * Hash value of str, encoded as 8 hex digits. * * Side Effects: * None. * *----------------------------------------------------------------------- */ static char * VarHash(char *str) { static const char hexdigits[16] = "0123456789abcdef"; Buffer buf; size_t len, len2; unsigned char *ustr = (unsigned char *)str; uint32_t h, k, c1, c2; h = 0x971e137bU; c1 = 0x95543787U; c2 = 0x2ad7eb25U; len2 = strlen(str); for (len = len2; len; ) { k = 0; switch (len) { default: k = (ustr[3] << 24) | (ustr[2] << 16) | (ustr[1] << 8) | ustr[0]; len -= 4; ustr += 4; break; case 3: k |= (ustr[2] << 16); case 2: k |= (ustr[1] << 8); case 1: k |= ustr[0]; len = 0; } c1 = c1 * 5 + 0x7b7d159cU; c2 = c2 * 5 + 0x6bce6396U; k *= c1; k = (k << 11) ^ (k >> 21); k *= c2; h = (h << 13) ^ (h >> 19); h = h * 5 + 0x52dce729U; h ^= k; } h ^= len2; h *= 0x85ebca6b; h ^= h >> 13; h *= 0xc2b2ae35; h ^= h >> 16; Buf_Init(&buf, 0); for (len = 0; len < 8; ++len) { Buf_AddByte(&buf, hexdigits[h & 15]); h >>= 4; } return Buf_Destroy(&buf, FALSE); } static char * VarStrftime(const char *fmt, int zulu) { char buf[BUFSIZ]; time_t utc; time(&utc); if (!*fmt) fmt = "%c"; strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&utc) : localtime(&utc)); buf[sizeof(buf) - 1] = '\0'; return bmake_strdup(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 . * :S[1gW] * Substitute for in the value * :C[1gW] * 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). * :O ("Order") Alphabeticaly sort words in variable. * :Ox ("intermiX") Randomize words in variable. * :u ("uniq") Remove adjacent duplicate words. * :tu Converts the variable contents to uppercase. * :tl Converts the variable contents to lowercase. * :ts[c] Sets varSpace - the char used to * separate words to 'c'. If 'c' is * omitted then no separation is used. * :tW Treat the variable contents as a single * word, even if it contains spaces. * (Mnemonic: one big 'W'ord.) * :tw Treat the variable contents as multiple * space-separated words. * (Mnemonic: many small 'w'ords.) * :[index] Select a single word from the value. * :[start..end] Select multiple words from the value. * :[*] or :[0] Select the entire value, as a single * word. Equivalent to :tW. * :[@] Select the entire value, as multiple * words. Undoes the effect of :[*]. * Equivalent to :tw. * :[#] Returns the number of words in the value. * * :?: * If the variable evaluates to true, return * true value, else return the second value. * :lhs=rhs Like :S, but the rhs goes to the end of * the invocation. * :sh Treat the current value as a command * to be run, new value is its output. * The following added so we can handle ODE makefiles. * :@@@ * Assign a temporary local variable * to the current value of each word in turn * and replace each word with the result of * evaluating * :D Use as value if variable defined * :U Use as value if variable undefined * :L Use the name of the variable as the value. * :P Use the path of the node that has the same * name as the variable as the value. This * basically includes an implied :L so that * the common method of refering to the path * of your dependent 'x' in a rule is to use * the form '${x:P}'. * :!! Run cmd much the same as :sh run's the * current value of the variable. * The ::= modifiers, actually assign a value to the variable. * Their main purpose is in supporting modifiers of .for loop * iterators and other obscure uses. They always expand to * nothing. In a target rule that would otherwise expand to an * empty line they can be preceded with @: to keep make happy. * Eg. * * foo: .USE * .for i in ${.TARGET} ${.TARGET:R}.gz * @: ${t::=$i} * @echo blah ${t:T} * .endfor * * ::= Assigns as the new value of variable. * ::?= Assigns as value of variable if * it was not already set. * ::+= Appends to variable. * ::!= Assigns output of as the new value of * variable. */ /* we now have some modifiers with long names */ #define STRMOD_MATCH(s, want, n) \ (strncmp(s, want, n) == 0 && (s[n] == endc || s[n] == ':')) static char * ApplyModifiers(char *nstr, const char *tstr, int startc, int endc, Var *v, GNode *ctxt, Boolean errnum, int *lengthPtr, void **freePtr) { const char *start; const char *cp; /* Secondary pointer into str (place marker * for tstr) */ char *newStr; /* New value to return */ char termc; /* Character which terminated scan */ int cnt; /* Used to count brace pairs when variable in * in parens or braces */ char delim; int modifier; /* that we are processing */ Var_Parse_State parsestate; /* Flags passed to helper functions */ delim = '\0'; parsestate.oneBigWord = FALSE; parsestate.varSpace = ' '; /* word separator */ start = cp = tstr; while (*tstr && *tstr != endc) { if (*tstr == '$') { /* * We may have some complex modifiers in a variable. */ void *freeIt; char *rval; int rlen; int c; rval = Var_Parse(tstr, ctxt, errnum, &rlen, &freeIt); /* * If we have not parsed up to endc or ':', * we are not interested. */ if (rval != NULL && *rval && (c = tstr[rlen]) != '\0' && c != ':' && c != endc) { if (freeIt) free(freeIt); goto apply_mods; } if (DEBUG(VAR)) { fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n", rval, rlen, tstr, rlen, tstr + rlen); } tstr += rlen; if (rval != NULL && *rval) { int used; nstr = ApplyModifiers(nstr, rval, 0, 0, v, ctxt, errnum, &used, freePtr); if (nstr == var_Error || (nstr == varNoError && errnum == 0) || strlen(rval) != (size_t) used) { if (freeIt) free(freeIt); goto out; /* error already reported */ } } if (freeIt) free(freeIt); if (*tstr == ':') tstr++; else if (!*tstr && endc) { Error("Unclosed variable specification after complex modifier (expecting '%c') for %s", endc, v->name); goto out; } continue; } apply_mods: if (DEBUG(VAR)) { fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", v->name, *tstr, nstr); } newStr = var_Error; switch ((modifier = *tstr)) { case ':': { if (tstr[1] == '=' || (tstr[2] == '=' && (tstr[1] == '!' || tstr[1] == '+' || tstr[1] == '?'))) { /* * "::=", "::!=", "::+=", or "::?=" */ GNode *v_ctxt; /* context where v belongs */ const char *emsg; char *sv_name; VarPattern pattern; int how; if (v->name[0] == 0) goto bad_modifier; v_ctxt = ctxt; sv_name = NULL; ++tstr; if (v->flags & VAR_JUNK) { /* * We need to bmake_strdup() it incase * VarGetPattern() recurses. */ sv_name = v->name; v->name = bmake_strdup(v->name); } else if (ctxt != VAR_GLOBAL) { Var *gv = VarFind(v->name, ctxt, 0); if (gv == NULL) v_ctxt = VAR_GLOBAL; else VarFreeEnv(gv, TRUE); } switch ((how = *tstr)) { case '+': case '?': case '!': cp = &tstr[2]; break; default: cp = ++tstr; break; } delim = startc == PROPEN ? PRCLOSE : BRCLOSE; pattern.flags = 0; pattern.rhs = VarGetPattern(ctxt, &parsestate, errnum, &cp, delim, NULL, &pattern.rightLen, NULL); if (v->flags & VAR_JUNK) { /* restore original name */ free(v->name); v->name = sv_name; } if (pattern.rhs == NULL) goto cleanup; termc = *--cp; delim = '\0'; switch (how) { case '+': Var_Append(v->name, pattern.rhs, v_ctxt); break; case '!': newStr = Cmd_Exec(pattern.rhs, &emsg); if (emsg) Error(emsg, nstr); else Var_Set(v->name, newStr, v_ctxt, 0); if (newStr) free(newStr); break; case '?': if ((v->flags & VAR_JUNK) == 0) break; /* FALLTHROUGH */ default: Var_Set(v->name, pattern.rhs, v_ctxt, 0); break; } free(UNCONST(pattern.rhs)); newStr = varNoError; break; } goto default_case; /* "::" */ } case '@': { VarLoop_t loop; int flags = VAR_NOSUBST; cp = ++tstr; delim = '@'; if ((loop.tvar = VarGetPattern(ctxt, &parsestate, errnum, &cp, delim, &flags, &loop.tvarLen, NULL)) == NULL) goto cleanup; if ((loop.str = VarGetPattern(ctxt, &parsestate, errnum, &cp, delim, &flags, &loop.strLen, NULL)) == NULL) goto cleanup; termc = *cp; delim = '\0'; loop.errnum = errnum; loop.ctxt = ctxt; newStr = VarModify(ctxt, &parsestate, nstr, VarLoopExpand, &loop); free(loop.tvar); free(loop.str); break; } case 'D': case 'U': { Buffer buf; /* Buffer for patterns */ int wantit; /* want data in buffer */ /* * Pass through 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). * The result is left in the Buffer buf. */ Buf_Init(&buf, 0); for (cp = tstr + 1; *cp != endc && *cp != ':' && *cp != '\0'; cp++) { if ((*cp == '\\') && ((cp[1] == ':') || (cp[1] == '$') || (cp[1] == endc) || (cp[1] == '\\'))) { Buf_AddByte(&buf, cp[1]); cp++; } else if (*cp == '$') { /* * If unescaped dollar sign, assume it's a * variable substitution and recurse. */ char *cp2; int len; void *freeIt; cp2 = Var_Parse(cp, ctxt, errnum, &len, &freeIt); Buf_AddBytes(&buf, strlen(cp2), cp2); if (freeIt) free(freeIt); cp += len - 1; } else { Buf_AddByte(&buf, *cp); } } termc = *cp; if (*tstr == 'U') wantit = ((v->flags & VAR_JUNK) != 0); else wantit = ((v->flags & VAR_JUNK) == 0); if ((v->flags & VAR_JUNK) != 0) v->flags |= VAR_KEEP; if (wantit) { newStr = Buf_Destroy(&buf, FALSE); } else { newStr = nstr; Buf_Destroy(&buf, TRUE); } break; } case 'L': { if ((v->flags & VAR_JUNK) != 0) v->flags |= VAR_KEEP; newStr = bmake_strdup(v->name); cp = ++tstr; termc = *tstr; break; } case 'P': { GNode *gn; if ((v->flags & VAR_JUNK) != 0) v->flags |= VAR_KEEP; gn = Targ_FindNode(v->name, TARG_NOCREATE); if (gn == NULL || gn->type & OP_NOPATH) { newStr = NULL; } else if (gn->path) { newStr = bmake_strdup(gn->path); } else { newStr = Dir_FindFile(v->name, Suff_FindPath(gn)); } if (!newStr) { newStr = bmake_strdup(v->name); } cp = ++tstr; termc = *tstr; break; } case '!': { const char *emsg; VarPattern pattern; pattern.flags = 0; delim = '!'; cp = ++tstr; if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, errnum, &cp, delim, NULL, &pattern.rightLen, NULL)) == NULL) goto cleanup; newStr = Cmd_Exec(pattern.rhs, &emsg); free(UNCONST(pattern.rhs)); if (emsg) Error(emsg, nstr); termc = *cp; delim = '\0'; if (v->flags & VAR_JUNK) { v->flags |= VAR_KEEP; } break; } case '[': { /* * Look for the closing ']', recursively * expanding any embedded variables. * * estr is a pointer to the expanded result, * which we must free(). */ char *estr; cp = tstr+1; /* point to char after '[' */ delim = ']'; /* look for closing ']' */ estr = VarGetPattern(ctxt, &parsestate, errnum, &cp, delim, NULL, NULL, NULL); if (estr == NULL) goto cleanup; /* report missing ']' */ /* now cp points just after the closing ']' */ delim = '\0'; if (cp[0] != ':' && cp[0] != endc) { /* Found junk after ']' */ free(estr); goto bad_modifier; } if (estr[0] == '\0') { /* Found empty square brackets in ":[]". */ free(estr); goto bad_modifier; } else if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */ /* * We will need enough space for the decimal * representation of an int. We calculate the * space needed for the octal representation, * and add enough slop to cope with a '-' sign * (which should never be needed) and a '\0' * string terminator. */ int newStrSize = (sizeof(int) * CHAR_BIT + 2) / 3 + 2; newStr = bmake_malloc(newStrSize); if (parsestate.oneBigWord) { strncpy(newStr, "1", newStrSize); } else { /* XXX: brk_string() is a rather expensive * way of counting words. */ char **av; char *as; int ac; av = brk_string(nstr, &ac, FALSE, &as); snprintf(newStr, newStrSize, "%d", ac); free(as); free(av); } termc = *cp; free(estr); break; } else if (estr[0] == '*' && estr[1] == '\0') { /* Found ":[*]" */ parsestate.oneBigWord = TRUE; newStr = nstr; termc = *cp; free(estr); break; } else if (estr[0] == '@' && estr[1] == '\0') { /* Found ":[@]" */ parsestate.oneBigWord = FALSE; newStr = nstr; termc = *cp; free(estr); break; } else { /* * We expect estr to contain a single * integer for :[N], or two integers * separated by ".." for :[start..end]. */ char *ep; VarSelectWords_t seldata = { 0, 0 }; seldata.start = strtol(estr, &ep, 0); if (ep == estr) { /* Found junk instead of a number */ free(estr); goto bad_modifier; } else if (ep[0] == '\0') { /* Found only one integer in :[N] */ seldata.end = seldata.start; } else if (ep[0] == '.' && ep[1] == '.' && ep[2] != '\0') { /* Expecting another integer after ".." */ ep += 2; seldata.end = strtol(ep, &ep, 0); if (ep[0] != '\0') { /* Found junk after ".." */ free(estr); goto bad_modifier; } } else { /* Found junk instead of ".." */ free(estr); goto bad_modifier; } /* * Now seldata is properly filled in, * but we still have to check for 0 as * a special case. */ if (seldata.start == 0 && seldata.end == 0) { /* ":[0]" or perhaps ":[0..0]" */ parsestate.oneBigWord = TRUE; newStr = nstr; termc = *cp; free(estr); break; } else if (seldata.start == 0 || seldata.end == 0) { /* ":[0..N]" or ":[N..0]" */ free(estr); goto bad_modifier; } /* * Normal case: select the words * described by seldata. */ newStr = VarSelectWords(ctxt, &parsestate, nstr, &seldata); termc = *cp; free(estr); break; } } case 'g': cp = tstr + 1; /* make sure it is set */ if (STRMOD_MATCH(tstr, "gmtime", 6)) { newStr = VarStrftime(nstr, 1); cp = tstr + 6; termc = *cp; } else { goto default_case; } break; case 'h': cp = tstr + 1; /* make sure it is set */ if (STRMOD_MATCH(tstr, "hash", 4)) { newStr = VarHash(nstr); cp = tstr + 4; termc = *cp; } else { goto default_case; } break; case 'l': cp = tstr + 1; /* make sure it is set */ if (STRMOD_MATCH(tstr, "localtime", 9)) { newStr = VarStrftime(nstr, 0); cp = tstr + 9; termc = *cp; } else { goto default_case; } break; case 't': { cp = tstr + 1; /* make sure it is set */ if (tstr[1] != endc && tstr[1] != ':') { if (tstr[1] == 's') { /* * Use the char (if any) at tstr[2] * as the word separator. */ VarPattern pattern; if (tstr[2] != endc && (tstr[3] == endc || tstr[3] == ':')) { /* ":ts" or * ":ts:" */ parsestate.varSpace = tstr[2]; cp = tstr + 3; } else if (tstr[2] == endc || tstr[2] == ':') { /* ":ts" or ":ts:" */ parsestate.varSpace = 0; /* no separator */ cp = tstr + 2; } else if (tstr[2] == '\\') { switch (tstr[3]) { case 'n': parsestate.varSpace = '\n'; cp = tstr + 4; break; case 't': parsestate.varSpace = '\t'; cp = tstr + 4; break; default: if (isdigit((unsigned char)tstr[3])) { char *ep; parsestate.varSpace = strtoul(&tstr[3], &ep, 0); if (*ep != ':' && *ep != endc) goto bad_modifier; cp = ep; } else { /* * ":ts". */ goto bad_modifier; } break; } } else { /* * Found ":ts". */ goto bad_modifier; } termc = *cp; /* * We cannot be certain that VarModify * will be used - even if there is a * subsequent modifier, so do a no-op * VarSubstitute now to for str to be * re-expanded without the spaces. */ pattern.flags = VAR_SUB_ONE; pattern.lhs = pattern.rhs = "\032"; pattern.leftLen = pattern.rightLen = 1; newStr = VarModify(ctxt, &parsestate, nstr, VarSubstitute, &pattern); } else if (tstr[2] == endc || tstr[2] == ':') { /* * Check for two-character options: * ":tu", ":tl" */ if (tstr[1] == 'A') { /* absolute path */ newStr = VarModify(ctxt, &parsestate, nstr, VarRealpath, NULL); cp = tstr + 2; termc = *cp; } else if (tstr[1] == 'u') { char *dp = bmake_strdup(nstr); for (newStr = dp; *dp; dp++) *dp = toupper((unsigned char)*dp); cp = tstr + 2; termc = *cp; } else if (tstr[1] == 'l') { char *dp = bmake_strdup(nstr); for (newStr = dp; *dp; dp++) *dp = tolower((unsigned char)*dp); cp = tstr + 2; termc = *cp; } else if (tstr[1] == 'W' || tstr[1] == 'w') { parsestate.oneBigWord = (tstr[1] == 'W'); newStr = nstr; cp = tstr + 2; termc = *cp; } else { /* Found ":t:" or * ":t". */ goto bad_modifier; } } else { /* * Found ":t". */ goto bad_modifier; } } else { /* * Found ":t" or ":t:". */ goto bad_modifier; } break; } case 'N': case 'M': { char *pattern; const char *endpat; /* points just after end of pattern */ char *cp2; Boolean copy; /* pattern should be, or has been, copied */ Boolean needSubst; int nest; copy = FALSE; needSubst = FALSE; nest = 1; /* * In the loop below, ignore ':' unless we are at * (or back to) the original brace level. * XXX This will likely not work right if $() and ${} * are intermixed. */ for (cp = tstr + 1; *cp != '\0' && !(*cp == ':' && nest == 1); cp++) { if (*cp == '\\' && (cp[1] == ':' || cp[1] == endc || cp[1] == startc)) { if (!needSubst) { copy = TRUE; } cp++; continue; } if (*cp == '$') { needSubst = TRUE; } if (*cp == '(' || *cp == '{') ++nest; if (*cp == ')' || *cp == '}') { --nest; if (nest == 0) break; } } termc = *cp; endpat = cp; if (copy) { /* * Need to compress the \:'s out of the pattern, so * allocate enough room to hold the uncompressed * pattern (note that cp started at tstr+1, so * cp - tstr takes the null byte into account) and * compress the pattern into the space. */ pattern = bmake_malloc(cp - tstr); for (cp2 = pattern, cp = tstr + 1; cp < endpat; cp++, cp2++) { if ((*cp == '\\') && (cp+1 < endpat) && (cp[1] == ':' || cp[1] == endc)) { cp++; } *cp2 = *cp; } *cp2 = '\0'; endpat = cp2; } else { /* * Either Var_Subst or VarModify will need a * nul-terminated string soon, so construct one now. */ pattern = bmake_strndup(tstr+1, endpat - (tstr + 1)); } if (needSubst) { /* * pattern contains embedded '$', so use Var_Subst to * expand it. */ cp2 = pattern; pattern = Var_Subst(NULL, cp2, ctxt, errnum); free(cp2); } if (DEBUG(VAR)) fprintf(debug_file, "Pattern[%s] for [%s] is [%s]\n", v->name, nstr, pattern); if (*tstr == 'M') { newStr = VarModify(ctxt, &parsestate, nstr, VarMatch, pattern); } else { newStr = VarModify(ctxt, &parsestate, nstr, VarNoMatch, pattern); } free(pattern); break; } case 'S': { VarPattern pattern; Var_Parse_State tmpparsestate; pattern.flags = 0; tmpparsestate = parsestate; delim = tstr[1]; tstr += 2; /* * If pattern begins with '^', it is anchored to the * start of the word -- skip over it and flag pattern. */ if (*tstr == '^') { pattern.flags |= VAR_MATCH_START; tstr += 1; } cp = tstr; if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, errnum, &cp, delim, &pattern.flags, &pattern.leftLen, NULL)) == NULL) goto cleanup; if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, errnum, &cp, delim, NULL, &pattern.rightLen, &pattern)) == NULL) goto cleanup; /* * Check for global substitution. If 'g' after the final * delimiter, substitution is global and is marked that * way. */ for (;; cp++) { switch (*cp) { case 'g': pattern.flags |= VAR_SUB_GLOBAL; continue; case '1': pattern.flags |= VAR_SUB_ONE; continue; case 'W': tmpparsestate.oneBigWord = TRUE; continue; } break; } termc = *cp; newStr = VarModify(ctxt, &tmpparsestate, nstr, VarSubstitute, &pattern); /* * Free the two strings. */ free(UNCONST(pattern.lhs)); free(UNCONST(pattern.rhs)); delim = '\0'; break; } case '?': { VarPattern pattern; Boolean value; /* find ':', and then substitute accordingly */ pattern.flags = 0; cp = ++tstr; delim = ':'; if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, errnum, &cp, delim, NULL, &pattern.leftLen, NULL)) == NULL) goto cleanup; /* BROPEN or PROPEN */ delim = endc; if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, errnum, &cp, delim, NULL, &pattern.rightLen, NULL)) == NULL) goto cleanup; termc = *--cp; delim = '\0'; - if (Cond_EvalExpression(NULL, v->name, &value, 0) + if (Cond_EvalExpression(NULL, v->name, &value, 0, FALSE) == COND_INVALID) { Error("Bad conditional expression `%s' in %s?%s:%s", v->name, v->name, pattern.lhs, pattern.rhs); goto cleanup; } if (value) { newStr = UNCONST(pattern.lhs); free(UNCONST(pattern.rhs)); } else { newStr = UNCONST(pattern.rhs); free(UNCONST(pattern.lhs)); } if (v->flags & VAR_JUNK) { v->flags |= VAR_KEEP; } break; } #ifndef NO_REGEX case 'C': { VarREPattern pattern; char *re; int error; Var_Parse_State tmpparsestate; pattern.flags = 0; tmpparsestate = parsestate; delim = tstr[1]; tstr += 2; cp = tstr; if ((re = VarGetPattern(ctxt, &parsestate, errnum, &cp, delim, NULL, NULL, NULL)) == NULL) goto cleanup; if ((pattern.replace = VarGetPattern(ctxt, &parsestate, errnum, &cp, delim, NULL, NULL, NULL)) == NULL){ free(re); goto cleanup; } for (;; cp++) { switch (*cp) { case 'g': pattern.flags |= VAR_SUB_GLOBAL; continue; case '1': pattern.flags |= VAR_SUB_ONE; continue; case 'W': tmpparsestate.oneBigWord = TRUE; continue; } break; } termc = *cp; error = regcomp(&pattern.re, re, REG_EXTENDED); free(re); if (error) { *lengthPtr = cp - start + 1; VarREError(error, &pattern.re, "RE substitution error"); free(pattern.replace); goto cleanup; } pattern.nsub = pattern.re.re_nsub + 1; if (pattern.nsub < 1) pattern.nsub = 1; if (pattern.nsub > 10) pattern.nsub = 10; pattern.matches = bmake_malloc(pattern.nsub * sizeof(regmatch_t)); newStr = VarModify(ctxt, &tmpparsestate, nstr, VarRESubstitute, &pattern); regfree(&pattern.re); free(pattern.replace); free(pattern.matches); delim = '\0'; break; } #endif case 'Q': if (tstr[1] == endc || tstr[1] == ':') { newStr = VarQuote(nstr); cp = tstr + 1; termc = *cp; break; } goto default_case; case 'T': if (tstr[1] == endc || tstr[1] == ':') { newStr = VarModify(ctxt, &parsestate, nstr, VarTail, NULL); cp = tstr + 1; termc = *cp; break; } goto default_case; case 'H': if (tstr[1] == endc || tstr[1] == ':') { newStr = VarModify(ctxt, &parsestate, nstr, VarHead, NULL); cp = tstr + 1; termc = *cp; break; } goto default_case; case 'E': if (tstr[1] == endc || tstr[1] == ':') { newStr = VarModify(ctxt, &parsestate, nstr, VarSuffix, NULL); cp = tstr + 1; termc = *cp; break; } goto default_case; case 'R': if (tstr[1] == endc || tstr[1] == ':') { newStr = VarModify(ctxt, &parsestate, nstr, VarRoot, NULL); cp = tstr + 1; termc = *cp; break; } goto default_case; case 'O': { char otype; cp = tstr + 1; /* skip to the rest in any case */ if (tstr[1] == endc || tstr[1] == ':') { otype = 's'; termc = *cp; } else if ( (tstr[1] == 'x') && (tstr[2] == endc || tstr[2] == ':') ) { otype = tstr[1]; cp = tstr + 2; termc = *cp; } else { goto bad_modifier; } newStr = VarOrder(nstr, otype); break; } case 'u': if (tstr[1] == endc || tstr[1] == ':') { newStr = VarUniq(nstr); cp = tstr + 1; termc = *cp; break; } goto default_case; #ifdef SUNSHCMD case 's': if (tstr[1] == 'h' && (tstr[2] == endc || tstr[2] == ':')) { const char *emsg; newStr = Cmd_Exec(nstr, &emsg); if (emsg) Error(emsg, nstr); cp = tstr + 2; termc = *cp; break; } goto default_case; #endif default: default_case: { #ifdef SYSVVARSUB /* * This can either be a bogus modifier or a System-V * substitution command. */ VarPattern pattern; Boolean eqFound; pattern.flags = 0; eqFound = FALSE; /* * First we make a pass through the string trying * to verify it is a SYSV-make-style translation: * it must be: =) */ cp = tstr; 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. We must null terminate them of course. */ delim='='; cp = tstr; if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, errnum, &cp, delim, &pattern.flags, &pattern.leftLen, NULL)) == NULL) goto cleanup; delim = endc; if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, errnum, &cp, delim, NULL, &pattern.rightLen, &pattern)) == NULL) goto cleanup; /* * SYSV modifications happen through the whole * string. Note the pattern is anchored at the end. */ termc = *--cp; delim = '\0'; if (pattern.leftLen == 0 && *nstr == '\0') { newStr = nstr; /* special case */ } else { newStr = VarModify(ctxt, &parsestate, nstr, VarSYSVMatch, &pattern); } free(UNCONST(pattern.lhs)); free(UNCONST(pattern.rhs)); } else #endif { Error("Unknown modifier '%c'", *tstr); for (cp = tstr+1; *cp != ':' && *cp != endc && *cp != '\0'; cp++) continue; termc = *cp; newStr = var_Error; } } } if (DEBUG(VAR)) { fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n", v->name, modifier, newStr); } if (newStr != nstr) { if (*freePtr) { free(nstr); *freePtr = NULL; } nstr = newStr; if (nstr != var_Error && nstr != varNoError) { *freePtr = nstr; } } if (termc == '\0' && endc != '\0') { Error("Unclosed variable specification (expecting '%c') for \"%s\" (value \"%s\") modifier %c", endc, v->name, nstr, modifier); } else if (termc == ':') { cp++; } tstr = cp; } out: *lengthPtr = tstr - start; return (nstr); bad_modifier: /* "{(" */ Error("Bad modifier `:%.*s' for %s", (int)strcspn(tstr, ":)}"), tstr, v->name); cleanup: *lengthPtr = cp - start; if (delim != '\0') Error("Unclosed substitution for %s (%c missing)", v->name, delim); if (*freePtr) { free(*freePtr); *freePtr = NULL; } return (var_Error); } /*- *----------------------------------------------------------------------- * Var_Parse -- * Given the start of a variable invocation, extract the variable * name and find its value, then modify it according to the * specification. * * Input: * str The string to parse * ctxt The context for the variable * errnum TRUE if undefined variables are an error * lengthPtr OUT: The length of the specification * freePtr OUT: Non-NULL if caller should free *freePtr * * Results: * The (possibly-modified) value of the variable or var_Error if the * specification is invalid. The length of the specification is * placed in *lengthPtr (for invalid specifications, this is just * 2...?). * If *freePtr is non-NULL then it's a pointer that the caller * should pass to free() to free memory used by the result. * * Side Effects: * None. * *----------------------------------------------------------------------- */ /* coverity[+alloc : arg-*4] */ char * Var_Parse(const char *str, GNode *ctxt, Boolean errnum, int *lengthPtr, void **freePtr) { const char *tstr; /* Pointer into str */ Var *v; /* Variable in invocation */ Boolean haveModifier;/* TRUE if have modifiers for the variable */ char endc; /* Ending character when variable in parens * or braces */ char startc; /* Starting character when variable in parens * or braces */ int vlen; /* Length of variable name */ const char *start; /* Points to original start of str */ char *nstr; /* New string, used during expansion */ Boolean dynamic; /* TRUE if the variable is local and we're * expanding it in a non-local context. This * is done to support dynamic sources. The * result is just the invocation, unaltered */ const char *extramodifiers; /* extra modifiers to apply first */ char name[2]; *freePtr = NULL; extramodifiers = NULL; dynamic = FALSE; start = str; startc = str[1]; if (startc != PROPEN && startc != BROPEN) { /* * If it's not bounded by braces of some sort, life is much simpler. * We just need to check for the first character and return the * value if it exists. */ /* Error out some really stupid names */ if (startc == '\0' || strchr(")}:$", startc)) { *lengthPtr = 1; return var_Error; } name[0] = startc; name[1] = '\0'; v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); if (v == NULL) { *lengthPtr = 2; if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) { /* * 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. */ switch (str[1]) { case '@': return UNCONST("$(.TARGET)"); case '%': return UNCONST("$(.ARCHIVE)"); case '*': return UNCONST("$(.PREFIX)"); case '!': return UNCONST("$(.MEMBER)"); } } /* * Error */ return (errnum ? var_Error : varNoError); } else { haveModifier = FALSE; tstr = &str[1]; endc = str[1]; } } else { Buffer buf; /* Holds the variable name */ int depth = 1; endc = startc == PROPEN ? PRCLOSE : BRCLOSE; Buf_Init(&buf, 0); /* * Skip to the end character or a colon, whichever comes first. */ for (tstr = str + 2; *tstr != '\0'; tstr++) { /* * Track depth so we can spot parse errors. */ if (*tstr == startc) { depth++; } if (*tstr == endc) { if (--depth == 0) break; } if (depth == 1 && *tstr == ':') { break; } /* * A variable inside a variable, expand */ if (*tstr == '$') { int rlen; void *freeIt; char *rval = Var_Parse(tstr, ctxt, errnum, &rlen, &freeIt); if (rval != NULL) { Buf_AddBytes(&buf, strlen(rval), rval); } if (freeIt) free(freeIt); tstr += rlen - 1; } else Buf_AddByte(&buf, *tstr); } if (*tstr == ':') { haveModifier = TRUE; } else if (*tstr == endc) { haveModifier = FALSE; } else { /* * If we never did find the end character, return NULL * right now, setting the length to be the distance to * the end of the string, since that's what make does. */ *lengthPtr = tstr - str; Buf_Destroy(&buf, TRUE); return (var_Error); } str = Buf_GetAll(&buf, &vlen); /* * At this point, str points into newly allocated memory from * buf, containing only the name of the variable. * * start and tstr point into the const string that was pointed * to by the original value of the str parameter. start points * to the '$' at the beginning of the string, while tstr points * to the char just after the end of the variable name -- this * will be '\0', ':', PRCLOSE, or BRCLOSE. */ v = VarFind(str, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); /* * Check also for bogus D and F forms of local variables since we're * in a local context and the name is the right length. */ if ((v == NULL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) && (vlen == 2) && (str[1] == 'F' || str[1] == 'D') && strchr("@%?*!<>", str[0]) != NULL) { /* * Well, it's local -- go look for it. */ name[0] = *str; name[1] = '\0'; v = VarFind(name, ctxt, 0); if (v != NULL) { if (str[1] == 'D') { extramodifiers = "H:"; } else { /* F */ extramodifiers = "T:"; } } } if (v == NULL) { if (((vlen == 1) || (((vlen == 2) && (str[1] == 'F' || str[1] == 'D')))) && ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL))) { /* * 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. */ switch (*str) { case '@': case '%': case '*': case '!': dynamic = TRUE; break; } } else if ((vlen > 2) && (*str == '.') && isupper((unsigned char) str[1]) && ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL))) { int len; len = vlen - 1; if ((strncmp(str, ".TARGET", len) == 0) || (strncmp(str, ".ARCHIVE", len) == 0) || (strncmp(str, ".PREFIX", len) == 0) || (strncmp(str, ".MEMBER", len) == 0)) { dynamic = TRUE; } } if (!haveModifier) { /* * No modifiers -- have specification length so we can return * now. */ *lengthPtr = tstr - start + 1; if (dynamic) { char *pstr = bmake_strndup(start, *lengthPtr); *freePtr = pstr; Buf_Destroy(&buf, TRUE); return(pstr); } else { Buf_Destroy(&buf, TRUE); return (errnum ? var_Error : varNoError); } } else { /* * Still need to get to the end of the variable specification, * so kludge up a Var structure for the modifications */ v = bmake_malloc(sizeof(Var)); v->name = UNCONST(str); Buf_Init(&v->val, 1); v->flags = VAR_JUNK; Buf_Destroy(&buf, FALSE); } } else Buf_Destroy(&buf, TRUE); } if (v->flags & VAR_IN_USE) { Fatal("Variable %s is recursive.", v->name); /*NOTREACHED*/ } else { 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. */ nstr = Buf_GetAll(&v->val, NULL); if (strchr(nstr, '$') != NULL) { nstr = Var_Subst(NULL, nstr, ctxt, errnum); *freePtr = nstr; } v->flags &= ~VAR_IN_USE; if ((nstr != NULL) && (haveModifier || extramodifiers != NULL)) { void *extraFree; int used; extraFree = NULL; if (extramodifiers != NULL) { nstr = ApplyModifiers(nstr, extramodifiers, '(', ')', v, ctxt, errnum, &used, &extraFree); } if (haveModifier) { /* Skip initial colon. */ tstr++; nstr = ApplyModifiers(nstr, tstr, startc, endc, v, ctxt, errnum, &used, freePtr); tstr += used; if (extraFree) { free(extraFree); } } else { *freePtr = extraFree; } } if (*tstr) { *lengthPtr = tstr - start + 1; } else { *lengthPtr = tstr - start; } if (v->flags & VAR_FROM_ENV) { Boolean destroy = FALSE; if (nstr != Buf_GetAll(&v->val, NULL)) { destroy = TRUE; } else { /* * Returning the value unmodified, so tell the caller to free * the thing. */ *freePtr = nstr; } VarFreeEnv(v, destroy); } else if (v->flags & VAR_JUNK) { /* * Perform any free'ing needed and set *freePtr to NULL so the caller * doesn't try to free a static pointer. * If VAR_KEEP is also set then we want to keep str as is. */ if (!(v->flags & VAR_KEEP)) { if (*freePtr) { free(nstr); *freePtr = NULL; } if (dynamic) { nstr = bmake_strndup(start, *lengthPtr); *freePtr = nstr; } else { nstr = errnum ? var_Error : varNoError; } } if (nstr != Buf_GetAll(&v->val, NULL)) Buf_Destroy(&v->val, TRUE); free(v->name); free(v); } return (nstr); } /*- *----------------------------------------------------------------------- * Var_Subst -- * Substitute for all variables in the given string in the given context * If undefErr is TRUE, Parse_Error will be called when an undefined * variable is encountered. * * Input: * var Named variable || NULL for all * str the string which to substitute * ctxt the context wherein to find variables * undefErr TRUE if undefineds are an error * * Results: * The resulting string. * * Side Effects: * None. The old string must be freed by the caller *----------------------------------------------------------------------- */ char * Var_Subst(const char *var, const char *str, GNode *ctxt, Boolean undefErr) { Buffer buf; /* Buffer for forming things */ char *val; /* Value to substitute for a variable */ int length; /* Length of the variable invocation */ Boolean trailingBslash; /* variable ends in \ */ void *freeIt = NULL; /* Set if it should be freed */ static Boolean errorReported; /* Set true if an error has already * been reported to prevent a plethora * of messages when recursing */ Buf_Init(&buf, 0); errorReported = FALSE; trailingBslash = FALSE; while (*str) { if (*str == '\n' && trailingBslash) Buf_AddByte(&buf, ' '); if (var == NULL && (*str == '$') && (str[1] == '$')) { /* * A dollar sign may be escaped either 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, *str); str++; } else if (*str != '$') { /* * Skip as many characters as possible -- either to the end of * the string or to the next dollar sign (variable invocation). */ const char *cp; for (cp = str++; *str != '$' && *str != '\0'; str++) continue; Buf_AddBytes(&buf, str - cp, cp); } else { if (var != NULL) { int expand; for (;;) { if (str[1] == '\0') { /* A trailing $ is kind of a special case */ Buf_AddByte(&buf, str[0]); str++; expand = FALSE; } else if (str[1] != PROPEN && str[1] != BROPEN) { if (str[1] != *var || strlen(var) > 1) { Buf_AddBytes(&buf, 2, str); str += 2; expand = FALSE; } else expand = TRUE; break; } else { const char *p; /* * Scan up to the end of the variable name. */ for (p = &str[2]; *p && *p != ':' && *p != PRCLOSE && *p != BRCLOSE; p++) if (*p == '$') break; /* * A variable inside the variable. We cannot expand * the external variable yet, so we try again with * the nested one */ if (*p == '$') { Buf_AddBytes(&buf, p - str, str); str = p; continue; } if (strncmp(var, str + 2, p - str - 2) != 0 || var[p - str - 2] != '\0') { /* * Not the variable we want to expand, scan * until the next variable */ for (;*p != '$' && *p != '\0'; p++) continue; Buf_AddBytes(&buf, p - str, str); str = p; expand = FALSE; } else expand = TRUE; break; } } if (!expand) continue; } val = Var_Parse(str, ctxt, undefErr, &length, &freeIt); /* * 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 (val == var_Error || val == 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 += length; } else if (undefErr || val == var_Error) { /* * 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\"",length,str); } str += length; errorReported = TRUE; } else { Buf_AddByte(&buf, *str); str += 1; } } else { /* * We've now got a variable structure to store in. But first, * advance the string pointer. */ str += length; /* * Copy all the characters from the variable value straight * into the new string. */ length = strlen(val); Buf_AddBytes(&buf, length, val); trailingBslash = length > 0 && val[length - 1] == '\\'; } if (freeIt) { free(freeIt); freeIt = NULL; } } } return Buf_DestroyCompact(&buf); } /*- *----------------------------------------------------------------------- * Var_GetTail -- * Return the tail from each of a list of words. Used to set the * System V local variables. * * Input: * file Filename to modify * * Results: * The resulting string. * * Side Effects: * None. * *----------------------------------------------------------------------- */ #if 0 char * Var_GetTail(char *file) { return(VarModify(file, VarTail, NULL)); } /*- *----------------------------------------------------------------------- * Var_GetHead -- * Find the leading components of a (list of) filename(s). * XXX: VarHead does not replace foo by ., as (sun) System V make * does. * * Input: * file Filename to manipulate * * Results: * The leading components. * * Side Effects: * None. * *----------------------------------------------------------------------- */ char * Var_GetHead(char *file) { return(VarModify(file, VarHead, NULL)); } #endif /*- *----------------------------------------------------------------------- * Var_Init -- * Initialize the module * * Results: * None * * Side Effects: * The VAR_CMD and VAR_GLOBAL contexts are created *----------------------------------------------------------------------- */ void Var_Init(void) { VAR_INTERNAL = Targ_NewGN("Internal"); VAR_GLOBAL = Targ_NewGN("Global"); VAR_CMD = Targ_NewGN("Command"); } void Var_End(void) { } /****************** PRINT DEBUGGING INFO *****************/ static void VarPrintVar(void *vp) { Var *v = (Var *)vp; fprintf(debug_file, "%-16s = %s\n", v->name, Buf_GetAll(&v->val, NULL)); } /*- *----------------------------------------------------------------------- * Var_Dump -- * print all variables in a context *----------------------------------------------------------------------- */ void Var_Dump(GNode *ctxt) { Hash_Search search; Hash_Entry *h; for (h = Hash_EnumFirst(&ctxt->context, &search); h != NULL; h = Hash_EnumNext(&search)) { VarPrintVar(Hash_GetValue(h)); } }